1
0
Fork 0
mirror of https://github.com/mozilla/pdf.js.git synced 2025-04-22 16:18: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 };