Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Editor] Add a new dialog for the signature editor (bug 1945574) #19414

Merged
merged 1 commit into from
Feb 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions gulpfile.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ function createWebpackAlias(defines) {
"web-preferences": "",
"web-print_service": "",
"web-secondary_toolbar": "web/secondary_toolbar.js",
"web-signature_manager": "web/signature_manager.js",
"web-toolbar": "web/toolbar.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 (you can type your name as signature)
pdfjs-editor-add-signature-type-button = Type
.title = Type
# Draw is a verb (you can draw your signature)
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@calixteman
Question that came to me while translating. Is plural (files) correct here? Shouldn't it be singular (can only select one file)?

P.S. In case this needs to be updated, it will require a new ID at this point.

*[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 };
168 changes: 108 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,14 @@ class SignatureEditor extends DrawingEditor {
return true;
}

/** @inheritdoc */
onScaleChanging() {
if (this._drawId === null) {
return;
}
super.onScaleChanging();
}

/** @inheritdoc */
render() {
if (this.div) {
Expand All @@ -98,70 +125,91 @@ 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;
// Ensure the signature doesn't exceed the page height.
// If the signature is too big, we scale it down to 50% of the page height.
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._uiManager.addToAnnotationStorage(this);

this.div.hidden = false;
}

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

getFromText(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