1
0
Fork 0
mirror of https://github.com/mozilla/pdf.js.git synced 2025-04-19 14:48:08 +02:00

[Editor] Add the ability to print and save some newly added signatures (bug 1946795)

This commit is contained in:
Calixte Denizet 2025-02-07 16:58:09 +01:00
parent 651d712109
commit 24417a1a0b
6 changed files with 790 additions and 5 deletions

View file

@ -410,6 +410,11 @@ class AnnotationFactory {
})
);
break;
case AnnotationEditorType.SIGNATURE:
promises.push(
StampAnnotation.createNewAnnotation(xref, annotation, changes, {})
);
break;
}
}
@ -511,6 +516,18 @@ class AnnotationFactory {
)
);
break;
case AnnotationEditorType.SIGNATURE:
promises.push(
StampAnnotation.createNewPrintAnnotation(
annotationGlobals,
xref,
annotation,
{
evaluatorOptions: options,
}
)
);
break;
}
}
@ -5025,11 +5042,61 @@ class StampAnnotation extends MarkupAnnotation {
return stamp;
}
static async #createNewAppearanceStreamForDrawing(annotation, xref) {
const { areContours, color, rect, lines, thickness } = annotation;
const appearanceBuffer = [
`${thickness} w 1 J 1 j`,
`${getPdfColor(color, /* isFill */ areContours)}`,
];
for (const line of lines) {
appearanceBuffer.push(
`${numberToString(line[4])} ${numberToString(line[5])} m`
);
for (let i = 6, ii = line.length; i < ii; i += 6) {
if (isNaN(line[i])) {
appearanceBuffer.push(
`${numberToString(line[i + 4])} ${numberToString(line[i + 5])} l`
);
} else {
const [c1x, c1y, c2x, c2y, x, y] = line.slice(i, i + 6);
appearanceBuffer.push(
[c1x, c1y, c2x, c2y, x, y].map(numberToString).join(" ") + " c"
);
}
}
if (line.length === 6) {
appearanceBuffer.push(
`${numberToString(line[4])} ${numberToString(line[5])} l`
);
}
}
appearanceBuffer.push(areContours ? "F" : "S");
const appearance = appearanceBuffer.join("\n");
const appearanceStreamDict = new Dict(xref);
appearanceStreamDict.set("FormType", 1);
appearanceStreamDict.set("Subtype", Name.get("Form"));
appearanceStreamDict.set("Type", Name.get("XObject"));
appearanceStreamDict.set("BBox", rect);
appearanceStreamDict.set("Length", appearance.length);
const ap = new StringStream(appearance);
ap.dict = appearanceStreamDict;
return ap;
}
static async createNewAppearanceStream(annotation, xref, params) {
if (annotation.oldAnnotation) {
// We'll use the AP we already have.
return null;
}
if (annotation.isSignature) {
return this.#createNewAppearanceStreamForDrawing(annotation, xref);
}
const { rotation } = annotation;
const { imageRef, width, height } = params.image;

View file

@ -30,7 +30,9 @@ class DrawingOptions {
return;
}
for (const [name, value] of Object.entries(properties)) {
this.updateProperty(name, value);
if (!name.startsWith("_")) {
this.updateProperty(name, value);
}
}
}

View file

@ -18,6 +18,7 @@ import { DrawingEditor, DrawingOptions } from "./draw.js";
import { AnnotationEditor } from "./editor.js";
import { ContourDrawOutline } from "./drawers/contour.js";
import { InkDrawingOptions } from "./ink.js";
import { InkDrawOutline } from "./drawers/inkdraw.js";
import { SignatureExtractor } from "./drawers/signaturedraw.js";
class SignatureOptions extends DrawingOptions {
@ -70,6 +71,7 @@ class SignatureEditor extends DrawingEditor {
constructor(params) {
super({ ...params, mustBeCommitted: true, name: "signatureEditor" });
this._willKeepAspectRatio = true;
this._description = "";
}
/** @inheritdoc */
@ -122,17 +124,20 @@ class SignatureEditor extends DrawingEditor {
}
super.render();
this.div.hidden = true;
this.div.setAttribute("role", "figure");
this._uiManager.getSignature(this);
if (this._drawId === null) {
this.div.hidden = true;
this._uiManager.getSignature(this);
}
return this.div;
}
addSignature(outline, heightInPage) {
addSignature(outline, heightInPage, description) {
const { x: savedX, y: savedY } = this;
this.#isExtracted = outline instanceof ContourDrawOutline;
this._description = description;
let drawingOptions;
if (this.#isExtracted) {
drawingOptions = SignatureEditor.getDefaultDrawingOptions();
@ -210,6 +215,87 @@ class SignatureEditor extends DrawingEditor {
areContours: false,
});
}
/** @inheritdoc */
createDrawingOptions({ areContours, thickness }) {
if (areContours) {
this._drawingOptions = SignatureEditor.getDefaultDrawingOptions();
} else {
this._drawingOptions =
SignatureEditor._defaultDrawnSignatureOptions.clone();
this._drawingOptions.updateProperties({ "stroke-width": thickness });
}
}
/** @inheritdoc */
serialize(isForCopying = false) {
if (this.isEmpty()) {
return null;
}
const { lines, points, rect } = this.serializeDraw(isForCopying);
const {
_drawingOptions: { "stroke-width": thickness },
} = this;
const serialized = {
annotationType: AnnotationEditorType.SIGNATURE,
isSignature: true,
areContours: this.#isExtracted,
color: [0, 0, 0],
thickness: this.#isExtracted ? 0 : thickness,
pageIndex: this.pageIndex,
rect,
rotation: this.rotation,
structTreeParentId: this._structTreeParentId,
};
if (isForCopying) {
serialized.paths = { lines, points };
} else {
serialized.lines = lines;
}
if (this._description) {
serialized.accessibilityData = { type: "Figure", alt: this._description };
}
return serialized;
}
/** @inheritdoc */
static deserializeDraw(
pageX,
pageY,
pageWidth,
pageHeight,
innerMargin,
data
) {
if (data.areContours) {
return ContourDrawOutline.deserialize(
pageX,
pageY,
pageWidth,
pageHeight,
innerMargin,
data
);
}
return InkDrawOutline.deserialize(
pageX,
pageY,
pageWidth,
pageHeight,
innerMargin,
data
);
}
/** @inheritdoc */
static async deserialize(data, parent, uiManager) {
const editor = await super.deserialize(data, parent, uiManager);
editor.#isExtracted = data.areContours;
editor._description = data.accessibilityData?.alt || "";
return editor;
}
}
export { SignatureEditor };

View file

@ -11301,5 +11301,580 @@
"md5": "b2de376f7e96fa2b6afc00dac016c40a",
"rounds": 1,
"type": "eq"
},
{
"id": "signature-rotation-print",
"file": "pdfs/tracemonkey.pdf",
"md5": "9a192d8b1a7dc652a19835f6f08098bd",
"rounds": 1,
"lastPage": 1,
"type": "eq",
"print": true,
"annotationStorage": {
"pdfjs_internal_editor_0": {
"annotationType": 101,
"isSignature": true,
"areContours": true,
"color": [0, 0, 0],
"thickness": 0,
"pageIndex": 0,
"rect": [
30.33709076317874, 528.4258915511044, 92.2465096088973,
605.8765082034198
],
"rotation": 0,
"structTreeParentId": null,
"lines": [
[
null,
null,
null,
null,
30.337093353271484,
605.8765258789062,
30.337093353271484,
598.2304077148438,
34.63264083862305,
596.6561889648438,
43.22381591796875,
596.5662841796875,
51.8149528503418,
596.476318359375,
56.11055374145508,
585.0970458984375,
56.11055374145508,
562.4286499023438,
56.11055374145508,
539.7601928710938,
57.83761978149414,
528.4259643554688,
61.29179763793945,
528.4259643554688,
64.74597930908203,
528.4259643554688,
66.4730453491211,
539.7601928710938,
66.4730453491211,
562.4286499023438,
66.4730453491211,
585.0970458984375,
70.76863098144531,
596.476318359375,
79.35980224609375,
596.5662841796875,
87.9509048461914,
596.6561889648438,
92.24649810791016,
598.2304077148438,
92.24649810791016,
601.288818359375,
92.24649810791016,
604.3472900390625,
81.9282455444336,
605.8765258789062,
61.29179763793945,
605.8765258789062
]
]
},
"pdfjs_internal_editor_1": {
"annotationType": 101,
"isSignature": true,
"areContours": true,
"color": [0, 0, 0],
"thickness": 0,
"pageIndex": 0,
"rect": [
115.2826878157529, 438.45786562832916, 250.9453054937449,
540.3920820626346
],
"rotation": 90,
"structTreeParentId": null,
"lines": [
[
null,
null,
null,
null,
115.2826919555664,
438.4578552246094,
128.67564392089844,
438.4578552246094,
131.4329833984375,
445.5304870605469,
131.59056091308594,
459.6759033203125,
131.7481231689453,
473.8213806152344,
151.6800079345703,
480.8940734863281,
191.38607788085938,
480.8940734863281,
231.09228515625,
480.8940734863281,
250.94525146484375,
483.7376708984375,
250.94525146484375,
489.425048828125,
250.94525146484375,
495.1123046875,
231.09228515625,
497.955810546875,
191.38607788085938,
497.955810546875,
151.6800079345703,
497.955810546875,
131.7481231689453,
505.0286865234375,
131.59056091308594,
519.1740112304688,
131.4329833984375,
533.3192749023438,
128.67564392089844,
540.3919067382812,
123.31848907470703,
540.3919067382812,
117.96131134033203,
540.3919067382812,
115.2826919555664,
523.4029541015625,
115.2826919555664,
489.425048828125
]
],
"accessibilityData": {
"type": "Figure",
"alt": "T"
}
},
"pdfjs_internal_editor_2": {
"annotationType": 101,
"isSignature": true,
"areContours": true,
"color": [0, 0, 0],
"thickness": 0,
"pageIndex": 0,
"rect": [
394.41588899764145, 521.6146706667813, 429.2137094410983,
565.6428880366412
],
"rotation": 180,
"structTreeParentId": null,
"lines": [
[
null,
null,
null,
null,
429.2137145996094,
521.6146850585938,
429.2137145996094,
525.9612426757812,
426.7992858886719,
526.8561401367188,
421.97039794921875,
526.9072265625,
417.1415100097656,
526.9583740234375,
414.72705078125,
533.4271240234375,
414.72705078125,
546.3134155273438,
414.72705078125,
559.1997680664062,
413.7563171386719,
565.6429443359375,
411.8147888183594,
565.6429443359375,
409.873291015625,
565.6429443359375,
408.9025573730469,
559.1997680664062,
408.9025573730469,
546.3134155273438,
408.9025573730469,
533.4271240234375,
406.48809814453125,
526.9583740234375,
401.6592102050781,
526.9072265625,
396.8303527832031,
526.8561401367188,
394.4158935546875,
525.9612426757812,
394.4158935546875,
524.2225952148438,
394.4158935546875,
522.4840087890625,
400.2155456542969,
521.6146850585938,
411.8147888183594,
521.6146850585938
]
],
"accessibilityData": {
"type": "Figure",
"alt": "T"
}
},
"pdfjs_internal_editor_3": {
"annotationType": 101,
"isSignature": true,
"areContours": true,
"color": [0, 0, 0],
"thickness": 0,
"pageIndex": 0,
"rect": [
527.772727521983, 549.8299978104504, 563.1363680037585,
575.0790592106906
],
"rotation": 270,
"structTreeParentId": null,
"lines": [
[
null,
null,
null,
null,
563.1363525390625,
575.0791015625,
559.6452026367188,
575.0791015625,
558.9263916015625,
573.3272094726562,
558.8853149414062,
569.8233642578125,
558.8442993164062,
566.319580078125,
553.6485595703125,
564.5676879882812,
543.2982177734375,
564.5676879882812,
532.9478759765625,
564.5676879882812,
527.772705078125,
563.86328125,
527.772705078125,
562.4545288085938,
527.772705078125,
561.0458374023438,
532.9478759765625,
560.3414306640625,
543.2982177734375,
560.3414306640625,
553.6485595703125,
560.3414306640625,
558.8442993164062,
558.5894775390625,
558.8853149414062,
555.085693359375,
558.9263916015625,
551.5819091796875,
559.6452026367188,
549.8300170898438,
561.0416259765625,
549.8300170898438,
562.4381103515625,
549.8300170898438,
563.1363525390625,
554.0382080078125,
563.1363525390625,
562.4545288085938
]
],
"accessibilityData": {
"type": "Figure",
"alt": "T"
}
}
}
},
{
"id": "signature-rotation-save",
"file": "pdfs/tracemonkey.pdf",
"md5": "9a192d8b1a7dc652a19835f6f08098bd",
"rounds": 1,
"lastPage": 1,
"type": "eq",
"print": true,
"save": true,
"annotationStorage": {
"pdfjs_internal_editor_0": {
"annotationType": 101,
"isSignature": true,
"areContours": true,
"color": [0, 0, 0],
"thickness": 0,
"pageIndex": 0,
"rect": [
30.33709076317874, 528.4258915511044, 92.2465096088973,
605.8765082034198
],
"rotation": 0,
"structTreeParentId": null,
"lines": [
[
null,
null,
null,
null,
30.337093353271484,
605.8765258789062,
30.337093353271484,
598.2304077148438,
34.63264083862305,
596.6561889648438,
43.22381591796875,
596.5662841796875,
51.8149528503418,
596.476318359375,
56.11055374145508,
585.0970458984375,
56.11055374145508,
562.4286499023438,
56.11055374145508,
539.7601928710938,
57.83761978149414,
528.4259643554688,
61.29179763793945,
528.4259643554688,
64.74597930908203,
528.4259643554688,
66.4730453491211,
539.7601928710938,
66.4730453491211,
562.4286499023438,
66.4730453491211,
585.0970458984375,
70.76863098144531,
596.476318359375,
79.35980224609375,
596.5662841796875,
87.9509048461914,
596.6561889648438,
92.24649810791016,
598.2304077148438,
92.24649810791016,
601.288818359375,
92.24649810791016,
604.3472900390625,
81.9282455444336,
605.8765258789062,
61.29179763793945,
605.8765258789062
]
]
},
"pdfjs_internal_editor_1": {
"annotationType": 101,
"isSignature": true,
"areContours": true,
"color": [0, 0, 0],
"thickness": 0,
"pageIndex": 0,
"rect": [
115.2826878157529, 438.45786562832916, 250.9453054937449,
540.3920820626346
],
"rotation": 90,
"structTreeParentId": null,
"lines": [
[
null,
null,
null,
null,
115.2826919555664,
438.4578552246094,
128.67564392089844,
438.4578552246094,
131.4329833984375,
445.5304870605469,
131.59056091308594,
459.6759033203125,
131.7481231689453,
473.8213806152344,
151.6800079345703,
480.8940734863281,
191.38607788085938,
480.8940734863281,
231.09228515625,
480.8940734863281,
250.94525146484375,
483.7376708984375,
250.94525146484375,
489.425048828125,
250.94525146484375,
495.1123046875,
231.09228515625,
497.955810546875,
191.38607788085938,
497.955810546875,
151.6800079345703,
497.955810546875,
131.7481231689453,
505.0286865234375,
131.59056091308594,
519.1740112304688,
131.4329833984375,
533.3192749023438,
128.67564392089844,
540.3919067382812,
123.31848907470703,
540.3919067382812,
117.96131134033203,
540.3919067382812,
115.2826919555664,
523.4029541015625,
115.2826919555664,
489.425048828125
]
],
"accessibilityData": {
"type": "Figure",
"alt": "T"
}
},
"pdfjs_internal_editor_2": {
"annotationType": 101,
"isSignature": true,
"areContours": true,
"color": [0, 0, 0],
"thickness": 0,
"pageIndex": 0,
"rect": [
394.41588899764145, 521.6146706667813, 429.2137094410983,
565.6428880366412
],
"rotation": 180,
"structTreeParentId": null,
"lines": [
[
null,
null,
null,
null,
429.2137145996094,
521.6146850585938,
429.2137145996094,
525.9612426757812,
426.7992858886719,
526.8561401367188,
421.97039794921875,
526.9072265625,
417.1415100097656,
526.9583740234375,
414.72705078125,
533.4271240234375,
414.72705078125,
546.3134155273438,
414.72705078125,
559.1997680664062,
413.7563171386719,
565.6429443359375,
411.8147888183594,
565.6429443359375,
409.873291015625,
565.6429443359375,
408.9025573730469,
559.1997680664062,
408.9025573730469,
546.3134155273438,
408.9025573730469,
533.4271240234375,
406.48809814453125,
526.9583740234375,
401.6592102050781,
526.9072265625,
396.8303527832031,
526.8561401367188,
394.4158935546875,
525.9612426757812,
394.4158935546875,
524.2225952148438,
394.4158935546875,
522.4840087890625,
400.2155456542969,
521.6146850585938,
411.8147888183594,
521.6146850585938
]
],
"accessibilityData": {
"type": "Figure",
"alt": "T"
}
},
"pdfjs_internal_editor_3": {
"annotationType": 101,
"isSignature": true,
"areContours": true,
"color": [0, 0, 0],
"thickness": 0,
"pageIndex": 0,
"rect": [
527.772727521983, 549.8299978104504, 563.1363680037585,
575.0790592106906
],
"rotation": 270,
"structTreeParentId": null,
"lines": [
[
null,
null,
null,
null,
563.1363525390625,
575.0791015625,
559.6452026367188,
575.0791015625,
558.9263916015625,
573.3272094726562,
558.8853149414062,
569.8233642578125,
558.8442993164062,
566.319580078125,
553.6485595703125,
564.5676879882812,
543.2982177734375,
564.5676879882812,
532.9478759765625,
564.5676879882812,
527.772705078125,
563.86328125,
527.772705078125,
562.4545288085938,
527.772705078125,
561.0458374023438,
532.9478759765625,
560.3414306640625,
543.2982177734375,
560.3414306640625,
553.6485595703125,
560.3414306640625,
558.8442993164062,
558.5894775390625,
558.8853149414062,
555.085693359375,
558.9263916015625,
551.5819091796875,
559.6452026367188,
549.8300170898438,
561.0416259765625,
549.8300170898438,
562.4381103515625,
549.8300170898438,
563.1363525390625,
554.0382080078125,
563.1363525390625,
562.4545288085938
]
],
"accessibilityData": {
"type": "Figure",
"alt": "T"
}
}
}
}
]

View file

@ -5090,4 +5090,55 @@ describe("annotation", function () {
);
});
});
describe("StampAnnotation for signatures", function () {
it("should create a new Stamp annotation", async function () {
const xref = (partialEvaluator.xref = new XRefMock());
const changes = new RefSetCache();
const task = new WorkerTask("test Stamp creation");
await AnnotationFactory.saveNewAnnotations(
partialEvaluator,
task,
[
{
annotationType: 101,
isSignature: true,
areContours: true,
color: [0, 0, 0],
thickness: 0,
pageIndex: 0,
rect: [12, 34, 56, 78],
rotation: 0,
structTreeParentId: null,
lines: [[NaN, NaN, NaN, NaN, 1, 2, 3, 4, 5, 6, 7, 8]],
},
],
null,
changes
);
const data = await writeChanges(changes, xref);
const base = data[0].data.replace(/\(D:\d+\)/, "(date)");
expect(base).toEqual(
"1 0 obj\n" +
"<< /Type /Annot /Subtype /Stamp /CreationDate (date) /Rect [12 34 56 78] " +
"/F 4 /Border [0 0 0] " +
"/Rotate 0 /AP << /N 2 0 R>>>>\n" +
"endobj\n"
);
const appearance = data[1].data;
expect(appearance).toEqual(
"2 0 obj\n" +
"<< /FormType 1 /Subtype /Form /Type /XObject /BBox [12 34 56 78] /Length 37>> stream\n" +
"0 w 1 J 1 j\n" +
"0 g\n" +
"1 2 m\n" +
"3 4 5 6 7 8 c\n" +
"F\n" +
"endstream\n" +
"endobj\n"
);
});
});
});

View file

@ -666,7 +666,11 @@ class SignatureManager {
data = this.#extractedSignatureData;
break;
}
this.#currentEditor.addSignature(data, /* heightInPage */ 40);
this.#currentEditor.addSignature(
data,
/* heightInPage */ 40,
this.#description.value
);
if (this.#saveCheckbox.checked) {
// TODO
}