Skip to content

Commit

Permalink
[Editor] Add a new dialog for the signature editor (bug 1945574)
Browse files Browse the repository at this point in the history
  • Loading branch information
calixteman committed Feb 3, 2025
1 parent d1f6250 commit 8c77d38
Show file tree
Hide file tree
Showing 16 changed files with 1,589 additions and 66 deletions.
1 change: 1 addition & 0 deletions gulpfile.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ function createWebpackAlias(defines) {
"web-download_manager": "",
"web-external_services": "",
"web-new_alt_text_manager": "web/new_alt_text_manager.js",
"web-signature_manager": "web/signature_manager.js",
"web-null_l10n": "",
"web-pdf_attachment_viewer": "web/pdf_attachment_viewer.js",
"web-pdf_cursor_tools": "web/pdf_cursor_tools.js",
Expand Down
61 changes: 61 additions & 0 deletions l10n/en-US/viewer.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,8 @@ pdfjs-editor-remove-stamp-button =
.title = Remove image
pdfjs-editor-remove-highlight-button =
.title = Remove highlight
pdfjs-editor-remove-signature-button =
.title = Remove signature
##

Expand Down Expand Up @@ -510,6 +512,7 @@ pdfjs-editor-undo-bar-message-highlight = Highlight removed
pdfjs-editor-undo-bar-message-freetext = Text removed
pdfjs-editor-undo-bar-message-ink = Drawing removed
pdfjs-editor-undo-bar-message-stamp = Image removed
pdfjs-editor-undo-bar-message-signature = Signature removed
# Variables:
# $count (Number) - the number of removed annotations.
pdfjs-editor-undo-bar-message-multiple =
Expand All @@ -524,3 +527,61 @@ pdfjs-editor-undo-bar-undo-button-label = Undo
pdfjs-editor-undo-bar-close-button =
.title = Close
pdfjs-editor-undo-bar-close-button-label = Close
## Add a signature dialog

pdfjs-editor-add-signature-dialog-label = This modal allows the user to create a signature to add to a PDF document. The user can edit the name (which also serves as the alt text), and optionally save the signature for repeated use.
pdfjs-editor-add-signature-dialog-title = Add a signature
## Tab names

# Type is a verb
pdfjs-editor-add-signature-type-button = Type
.title = Type
# Draw is a verb
pdfjs-editor-add-signature-draw-button = Draw
.title = Draw
pdfjs-editor-add-signature-image-button = Image
.title = Image
## Tab panels

pdfjs-editor-add-signature-type-input =
.aria-label = Type your signature
.placeholder = Type your signature
pdfjs-editor-add-signature-draw-placeholder = Draw your signature
pdfjs-editor-add-signature-draw-thickness-range-label = Thickness
# Variables:
# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
pdfjs-editor-add-signature-draw-thickness-range =
.title = Drawing thickness: { $thickness }
pdfjs-editor-add-signature-image-placeholder = Drag a file here to upload
pdfjs-editor-add-signature-image-browse-link =
{ PLATFORM() ->
[macos] Or choose image files
*[other] Or browse image files
}
## Controls

pdfjs-editor-add-signature-description-label = Description (alt text)
pdfjs-editor-add-signature-description-input =
.title = Description (alt text)
pdfjs-editor-add-signature-description-default-when-drawing = Signature
pdfjs-editor-add-signature-clear-button-label = Clear signature
pdfjs-editor-add-signature-clear-button =
.title = Clear signature
pdfjs-editor-add-signature-save-checkbox = Save signature
pdfjs-editor-add-signature-save-warning-message = You’ve reached the limit of 5 saved signatures. Remove one to save more.
pdfjs-editor-add-signature-image-upload-error-title = Couldn’t upload image
pdfjs-editor-add-signature-image-upload-error-description = Check your network connection or try another image.
pdfjs-editor-add-signature-error-close-button = Close
## Dialog buttons

pdfjs-editor-add-signature-cancel-button = Cancel
pdfjs-editor-add-signature-add-button = Add
4 changes: 4 additions & 0 deletions src/display/editor/drawers/inkdraw.js
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,10 @@ class InkDrawOutline extends Outline {
this.#computeBbox();
}

get thickness() {
return this.#thickness;
}

setLastElement(element) {
this.#lines.push(element);
return {
Expand Down
10 changes: 4 additions & 6 deletions src/display/editor/ink.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,9 @@ import { AnnotationEditor } from "./editor.js";
import { InkAnnotationElement } from "../annotation_layer.js";

class InkDrawingOptions extends DrawingOptions {
#viewParameters;

constructor(viewerParameters) {
super();
this.#viewParameters = viewerParameters;
this._viewParameters = viewerParameters;

super.updateProperties({
fill: "none",
Expand All @@ -45,13 +43,13 @@ class InkDrawingOptions extends DrawingOptions {
updateSVGProperty(name, value) {
if (name === "stroke-width") {
value ??= this["stroke-width"];
value *= this.#viewParameters.realScale;
value *= this._viewParameters.realScale;
}
super.updateSVGProperty(name, value);
}

clone() {
const clone = new InkDrawingOptions(this.#viewParameters);
const clone = new InkDrawingOptions(this._viewParameters);
clone.updateAll(this);
return clone;
}
Expand Down Expand Up @@ -284,4 +282,4 @@ class InkEditor extends DrawingEditor {
}
}

export { InkEditor };
export { InkDrawingOptions, InkEditor };
161 changes: 101 additions & 60 deletions src/display/editor/signature.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,13 @@
import { AnnotationEditorType, shadow } from "../../shared/util.js";
import { DrawingEditor, DrawingOptions } from "./draw.js";
import { AnnotationEditor } from "./editor.js";
import { ContourDrawOutline } from "./drawers/contour.js";
import { InkDrawingOptions } from "./ink.js";
import { SignatureExtractor } from "./drawers/signaturedraw.js";
import { SupportedImageMimeTypes } from "../display_utils.js";

class SignatureOptions extends DrawingOptions {
#viewParameters;

constructor(viewerParameters) {
constructor() {
super();
this.#viewParameters = viewerParameters;

super.updateProperties({
fill: "black",
Expand All @@ -33,7 +31,24 @@ class SignatureOptions extends DrawingOptions {
}

clone() {
const clone = new SignatureOptions(this.#viewParameters);
const clone = new SignatureOptions();
clone.updateAll(this);
return clone;
}
}

class DrawnSignatureOptions extends InkDrawingOptions {
constructor(viewerParameters) {
super(viewerParameters);

super.updateProperties({
stroke: "black",
"stroke-width": 1,
});
}

clone() {
const clone = new DrawnSignatureOptions(this._viewParameters);
clone.updateAll(this);
return clone;
}
Expand All @@ -44,6 +59,8 @@ class SignatureOptions extends DrawingOptions {
* a signature drawing.
*/
class SignatureEditor extends DrawingEditor {
#isExtracted = false;

static _type = "signature";

static _editorType = AnnotationEditorType.SIGNATURE;
Expand All @@ -52,13 +69,15 @@ class SignatureEditor extends DrawingEditor {

constructor(params) {
super({ ...params, mustBeCommitted: true, name: "signatureEditor" });
this._willKeepAspectRatio = false;
this._willKeepAspectRatio = true;
}

/** @inheritdoc */
static initialize(l10n, uiManager) {
AnnotationEditor.initialize(l10n, uiManager);
this._defaultDrawingOptions = new SignatureOptions(

this._defaultDrawingOptions = new SignatureOptions();
this._defaultDrawnSignatureOptions = new DrawnSignatureOptions(
uiManager.viewParameters
);
}
Expand Down Expand Up @@ -88,6 +107,11 @@ class SignatureEditor extends DrawingEditor {
return true;
}

/** @inheritdoc */
isEmpty() {
return this._drawId === null;
}

/** @inheritdoc */
render() {
if (this.div) {
Expand All @@ -98,70 +122,87 @@ class SignatureEditor extends DrawingEditor {
this.div.hidden = true;
this.div.setAttribute("role", "figure");

this.#extractSignature();
this._uiManager.getSignature(this);

return this.div;
}

async #extractSignature() {
const input = document.createElement("input");
input.type = "file";
input.accept = SupportedImageMimeTypes.join(",");
const signal = this._uiManager._signal;
const { promise, resolve } = Promise.withResolvers();

input.addEventListener(
"change",
async () => {
if (!input.files || input.files.length === 0) {
resolve();
} else {
this._uiManager.enableWaiting(true);
const data = await this._uiManager.imageManager.getFromFile(
input.files[0]
);
this._uiManager.enableWaiting(false);
resolve(data);
}
resolve();
},
{ signal }
);
input.addEventListener("cancel", resolve, { signal });
input.click();

const bitmap = await promise;
const {
rawDims: { pageWidth, pageHeight },
rotation,
} = this.parent.viewport;
let drawOutlines;
if (bitmap?.bitmap) {
drawOutlines = SignatureExtractor.process(
bitmap.bitmap,
pageWidth,
pageHeight,
rotation,
SignatureEditor._INNER_MARGIN
);
addSignature(outline, heightInPage) {
const { x: savedX, y: savedY } = this;
this.#isExtracted = outline instanceof ContourDrawOutline;
let drawingOptions;
if (this.#isExtracted) {
drawingOptions = SignatureEditor.getDefaultDrawingOptions();
} else {
drawOutlines = SignatureExtractor.extractContoursFromText(
"Hello PDF.js' World !!",
{ fontStyle: "italic", fontWeight: "400", fontFamily: "cursive" },
pageWidth,
pageHeight,
rotation,
SignatureEditor._INNER_MARGIN
);
drawingOptions = SignatureEditor._defaultDrawnSignatureOptions.clone();
drawingOptions.updateProperties({ "stroke-width": outline.thickness });
}
this._addOutlines({
drawOutlines,
drawingOptions: SignatureEditor.getDefaultDrawingOptions(),
drawOutlines: outline,
drawingOptions,
});
const [parentWidth, parentHeight] = this.parentDimensions;
const [, pageHeight] = this.pageDimensions;
let newHeight = heightInPage / pageHeight;
newHeight = newHeight >= 1 ? 0.5 : newHeight;
this.width *= newHeight / this.height;
this.height = newHeight;
this.setDims(parentWidth * this.width, parentHeight * this.height);
this.x = savedX;
this.y = savedY;
this.center();

this._onResized();
this.onScaleChanging();
this.rotate();

this.div.hidden = false;
}

extractSignature(bitmap) {
const {
rawDims: { pageWidth, pageHeight },
rotation,
} = this.parent.viewport;
return SignatureExtractor.process(
bitmap,
pageWidth,
pageHeight,
rotation,
SignatureEditor._INNER_MARGIN
);
}

extractFromText(text, fontInfo) {
const {
rawDims: { pageWidth, pageHeight },
rotation,
} = this.parent.viewport;
return SignatureExtractor.extractContoursFromText(
text,
fontInfo,
pageWidth,
pageHeight,
rotation,
SignatureEditor._INNER_MARGIN
);
}

getDrawnSignature(curves) {
const {
rawDims: { pageWidth, pageHeight },
rotation,
} = this.parent.viewport;
return SignatureExtractor.processDrawnLines({
lines: curves,
pageWidth,
pageHeight,
rotation,
innerMargin: SignatureEditor._INNER_MARGIN,
mustSmooth: false,
areContours: false,
});
}
}

export { SignatureEditor };
Loading

0 comments on commit 8c77d38

Please sign in to comment.