Skip to content

Commit 08663f7

Browse files
authored
Merge pull request #19414 from calixteman/signature_dialog2
[Editor] Add a new dialog for the signature editor (bug 1945574)
2 parents 90a5c37 + fa25ab9 commit 08663f7

16 files changed

+1596
-66
lines changed

gulpfile.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ function createWebpackAlias(defines) {
217217
"web-preferences": "",
218218
"web-print_service": "",
219219
"web-secondary_toolbar": "web/secondary_toolbar.js",
220+
"web-signature_manager": "web/signature_manager.js",
220221
"web-toolbar": "web/toolbar.js",
221222
};
222223

l10n/en-US/viewer.ftl

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,8 @@ pdfjs-editor-remove-stamp-button =
331331
.title = Remove image
332332
pdfjs-editor-remove-highlight-button =
333333
.title = Remove highlight
334+
pdfjs-editor-remove-signature-button =
335+
.title = Remove signature
334336
335337
##
336338

@@ -510,6 +512,7 @@ pdfjs-editor-undo-bar-message-highlight = Highlight removed
510512
pdfjs-editor-undo-bar-message-freetext = Text removed
511513
pdfjs-editor-undo-bar-message-ink = Drawing removed
512514
pdfjs-editor-undo-bar-message-stamp = Image removed
515+
pdfjs-editor-undo-bar-message-signature = Signature removed
513516
# Variables:
514517
# $count (Number) - the number of removed annotations.
515518
pdfjs-editor-undo-bar-message-multiple =
@@ -524,3 +527,61 @@ pdfjs-editor-undo-bar-undo-button-label = Undo
524527
pdfjs-editor-undo-bar-close-button =
525528
.title = Close
526529
pdfjs-editor-undo-bar-close-button-label = Close
530+
531+
## Add a signature dialog
532+
533+
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.
534+
pdfjs-editor-add-signature-dialog-title = Add a signature
535+
536+
## Tab names
537+
538+
# Type is a verb (you can type your name as signature)
539+
pdfjs-editor-add-signature-type-button = Type
540+
.title = Type
541+
# Draw is a verb (you can draw your signature)
542+
pdfjs-editor-add-signature-draw-button = Draw
543+
.title = Draw
544+
pdfjs-editor-add-signature-image-button = Image
545+
.title = Image
546+
547+
## Tab panels
548+
549+
pdfjs-editor-add-signature-type-input =
550+
.aria-label = Type your signature
551+
.placeholder = Type your signature
552+
pdfjs-editor-add-signature-draw-placeholder = Draw your signature
553+
pdfjs-editor-add-signature-draw-thickness-range-label = Thickness
554+
555+
# Variables:
556+
# $thickness (Number) - the thickness (in pixels) of the line used to draw a signature.
557+
pdfjs-editor-add-signature-draw-thickness-range =
558+
.title = Drawing thickness: { $thickness }
559+
560+
pdfjs-editor-add-signature-image-placeholder = Drag a file here to upload
561+
pdfjs-editor-add-signature-image-browse-link =
562+
{ PLATFORM() ->
563+
[macos] Or choose image files
564+
*[other] Or browse image files
565+
}
566+
567+
## Controls
568+
569+
pdfjs-editor-add-signature-description-label = Description (alt text)
570+
pdfjs-editor-add-signature-description-input =
571+
.title = Description (alt text)
572+
pdfjs-editor-add-signature-description-default-when-drawing = Signature
573+
574+
575+
pdfjs-editor-add-signature-clear-button-label = Clear signature
576+
pdfjs-editor-add-signature-clear-button =
577+
.title = Clear signature
578+
pdfjs-editor-add-signature-save-checkbox = Save signature
579+
pdfjs-editor-add-signature-save-warning-message = You’ve reached the limit of 5 saved signatures. Remove one to save more.
580+
pdfjs-editor-add-signature-image-upload-error-title = Couldn’t upload image
581+
pdfjs-editor-add-signature-image-upload-error-description = Check your network connection or try another image.
582+
pdfjs-editor-add-signature-error-close-button = Close
583+
584+
## Dialog buttons
585+
586+
pdfjs-editor-add-signature-cancel-button = Cancel
587+
pdfjs-editor-add-signature-add-button = Add

src/display/editor/drawers/inkdraw.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,10 @@ class InkDrawOutline extends Outline {
318318
this.#computeBbox();
319319
}
320320

321+
get thickness() {
322+
return this.#thickness;
323+
}
324+
321325
setLastElement(element) {
322326
this.#lines.push(element);
323327
return {

src/display/editor/ink.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,9 @@ import { AnnotationEditor } from "./editor.js";
2525
import { InkAnnotationElement } from "../annotation_layer.js";
2626

2727
class InkDrawingOptions extends DrawingOptions {
28-
#viewParameters;
29-
3028
constructor(viewerParameters) {
3129
super();
32-
this.#viewParameters = viewerParameters;
30+
this._viewParameters = viewerParameters;
3331

3432
super.updateProperties({
3533
fill: "none",
@@ -45,13 +43,13 @@ class InkDrawingOptions extends DrawingOptions {
4543
updateSVGProperty(name, value) {
4644
if (name === "stroke-width") {
4745
value ??= this["stroke-width"];
48-
value *= this.#viewParameters.realScale;
46+
value *= this._viewParameters.realScale;
4947
}
5048
super.updateSVGProperty(name, value);
5149
}
5250

5351
clone() {
54-
const clone = new InkDrawingOptions(this.#viewParameters);
52+
const clone = new InkDrawingOptions(this._viewParameters);
5553
clone.updateAll(this);
5654
return clone;
5755
}
@@ -284,4 +282,4 @@ class InkEditor extends DrawingEditor {
284282
}
285283
}
286284

287-
export { InkEditor };
285+
export { InkDrawingOptions, InkEditor };

src/display/editor/signature.js

Lines changed: 108 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,13 @@
1616
import { AnnotationEditorType, shadow } from "../../shared/util.js";
1717
import { DrawingEditor, DrawingOptions } from "./draw.js";
1818
import { AnnotationEditor } from "./editor.js";
19+
import { ContourDrawOutline } from "./drawers/contour.js";
20+
import { InkDrawingOptions } from "./ink.js";
1921
import { SignatureExtractor } from "./drawers/signaturedraw.js";
20-
import { SupportedImageMimeTypes } from "../display_utils.js";
2122

2223
class SignatureOptions extends DrawingOptions {
23-
#viewParameters;
24-
25-
constructor(viewerParameters) {
24+
constructor() {
2625
super();
27-
this.#viewParameters = viewerParameters;
2826

2927
super.updateProperties({
3028
fill: "black",
@@ -33,7 +31,24 @@ class SignatureOptions extends DrawingOptions {
3331
}
3432

3533
clone() {
36-
const clone = new SignatureOptions(this.#viewParameters);
34+
const clone = new SignatureOptions();
35+
clone.updateAll(this);
36+
return clone;
37+
}
38+
}
39+
40+
class DrawnSignatureOptions extends InkDrawingOptions {
41+
constructor(viewerParameters) {
42+
super(viewerParameters);
43+
44+
super.updateProperties({
45+
stroke: "black",
46+
"stroke-width": 1,
47+
});
48+
}
49+
50+
clone() {
51+
const clone = new DrawnSignatureOptions(this._viewParameters);
3752
clone.updateAll(this);
3853
return clone;
3954
}
@@ -44,6 +59,8 @@ class SignatureOptions extends DrawingOptions {
4459
* a signature drawing.
4560
*/
4661
class SignatureEditor extends DrawingEditor {
62+
#isExtracted = false;
63+
4764
static _type = "signature";
4865

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

5370
constructor(params) {
5471
super({ ...params, mustBeCommitted: true, name: "signatureEditor" });
55-
this._willKeepAspectRatio = false;
72+
this._willKeepAspectRatio = true;
5673
}
5774

5875
/** @inheritdoc */
5976
static initialize(l10n, uiManager) {
6077
AnnotationEditor.initialize(l10n, uiManager);
61-
this._defaultDrawingOptions = new SignatureOptions(
78+
79+
this._defaultDrawingOptions = new SignatureOptions();
80+
this._defaultDrawnSignatureOptions = new DrawnSignatureOptions(
6281
uiManager.viewParameters
6382
);
6483
}
@@ -88,6 +107,14 @@ class SignatureEditor extends DrawingEditor {
88107
return true;
89108
}
90109

110+
/** @inheritdoc */
111+
onScaleChanging() {
112+
if (this._drawId === null) {
113+
return;
114+
}
115+
super.onScaleChanging();
116+
}
117+
91118
/** @inheritdoc */
92119
render() {
93120
if (this.div) {
@@ -98,70 +125,91 @@ class SignatureEditor extends DrawingEditor {
98125
this.div.hidden = true;
99126
this.div.setAttribute("role", "figure");
100127

101-
this.#extractSignature();
128+
this._uiManager.getSignature(this);
102129

103130
return this.div;
104131
}
105132

106-
async #extractSignature() {
107-
const input = document.createElement("input");
108-
input.type = "file";
109-
input.accept = SupportedImageMimeTypes.join(",");
110-
const signal = this._uiManager._signal;
111-
const { promise, resolve } = Promise.withResolvers();
112-
113-
input.addEventListener(
114-
"change",
115-
async () => {
116-
if (!input.files || input.files.length === 0) {
117-
resolve();
118-
} else {
119-
this._uiManager.enableWaiting(true);
120-
const data = await this._uiManager.imageManager.getFromFile(
121-
input.files[0]
122-
);
123-
this._uiManager.enableWaiting(false);
124-
resolve(data);
125-
}
126-
resolve();
127-
},
128-
{ signal }
129-
);
130-
input.addEventListener("cancel", resolve, { signal });
131-
input.click();
132-
133-
const bitmap = await promise;
134-
const {
135-
rawDims: { pageWidth, pageHeight },
136-
rotation,
137-
} = this.parent.viewport;
138-
let drawOutlines;
139-
if (bitmap?.bitmap) {
140-
drawOutlines = SignatureExtractor.process(
141-
bitmap.bitmap,
142-
pageWidth,
143-
pageHeight,
144-
rotation,
145-
SignatureEditor._INNER_MARGIN
146-
);
133+
addSignature(outline, heightInPage) {
134+
const { x: savedX, y: savedY } = this;
135+
this.#isExtracted = outline instanceof ContourDrawOutline;
136+
let drawingOptions;
137+
if (this.#isExtracted) {
138+
drawingOptions = SignatureEditor.getDefaultDrawingOptions();
147139
} else {
148-
drawOutlines = SignatureExtractor.extractContoursFromText(
149-
"Hello PDF.js' World !!",
150-
{ fontStyle: "italic", fontWeight: "400", fontFamily: "cursive" },
151-
pageWidth,
152-
pageHeight,
153-
rotation,
154-
SignatureEditor._INNER_MARGIN
155-
);
140+
drawingOptions = SignatureEditor._defaultDrawnSignatureOptions.clone();
141+
drawingOptions.updateProperties({ "stroke-width": outline.thickness });
156142
}
157143
this._addOutlines({
158-
drawOutlines,
159-
drawingOptions: SignatureEditor.getDefaultDrawingOptions(),
144+
drawOutlines: outline,
145+
drawingOptions,
160146
});
147+
const [parentWidth, parentHeight] = this.parentDimensions;
148+
const [, pageHeight] = this.pageDimensions;
149+
let newHeight = heightInPage / pageHeight;
150+
// Ensure the signature doesn't exceed the page height.
151+
// If the signature is too big, we scale it down to 50% of the page height.
152+
newHeight = newHeight >= 1 ? 0.5 : newHeight;
153+
154+
this.width *= newHeight / this.height;
155+
this.height = newHeight;
156+
this.setDims(parentWidth * this.width, parentHeight * this.height);
157+
this.x = savedX;
158+
this.y = savedY;
159+
this.center();
160+
161+
this._onResized();
161162
this.onScaleChanging();
162163
this.rotate();
164+
this._uiManager.addToAnnotationStorage(this);
165+
163166
this.div.hidden = false;
164167
}
168+
169+
getFromImage(bitmap) {
170+
const {
171+
rawDims: { pageWidth, pageHeight },
172+
rotation,
173+
} = this.parent.viewport;
174+
return SignatureExtractor.process(
175+
bitmap,
176+
pageWidth,
177+
pageHeight,
178+
rotation,
179+
SignatureEditor._INNER_MARGIN
180+
);
181+
}
182+
183+
getFromText(text, fontInfo) {
184+
const {
185+
rawDims: { pageWidth, pageHeight },
186+
rotation,
187+
} = this.parent.viewport;
188+
return SignatureExtractor.extractContoursFromText(
189+
text,
190+
fontInfo,
191+
pageWidth,
192+
pageHeight,
193+
rotation,
194+
SignatureEditor._INNER_MARGIN
195+
);
196+
}
197+
198+
getDrawnSignature(curves) {
199+
const {
200+
rawDims: { pageWidth, pageHeight },
201+
rotation,
202+
} = this.parent.viewport;
203+
return SignatureExtractor.processDrawnLines({
204+
lines: curves,
205+
pageWidth,
206+
pageHeight,
207+
rotation,
208+
innerMargin: SignatureEditor._INNER_MARGIN,
209+
mustSmooth: false,
210+
areContours: false,
211+
});
212+
}
165213
}
166214

167215
export { SignatureEditor };

0 commit comments

Comments
 (0)