From b8266a2ecf69ed7bf65675109e39f65b25c58efa Mon Sep 17 00:00:00 2001 From: Edoardo Cavazza Date: Mon, 27 Jan 2025 10:20:25 +0100 Subject: [PATCH] Add unit tests for FreeTextCallout annotation --- src/core/annotation.js | 28 ++++++++++++--- test/unit/annotation_spec.js | 66 ++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 5 deletions(-) diff --git a/src/core/annotation.js b/src/core/annotation.js index f6007c5cc..0092720a9 100644 --- a/src/core/annotation.js +++ b/src/core/annotation.js @@ -3882,12 +3882,12 @@ class FreeTextAnnotation extends MarkupAnnotation { this._hasAppearance = !!this.appearance; if (typeof PDFJSDev === "undefined" || !PDFJSDev.test("MOZCENTRAL")) { - if (dict.has("CL")) { - this.setLineEnding(dict.getArray("LE")); + if (this.data.it === "FreeTextCallout") { + this.setLineEnding(dict.get("LE")); this.data.lineEnding = this.lineEnding; const calloutLine = dict.getArray("CL"); - if (isNumberArray(calloutLine)) { + if (isNumberArray(calloutLine, 4) || isNumberArray(calloutLine, 6)) { this.data.calloutLine = calloutLine; } } @@ -3940,8 +3940,17 @@ class FreeTextAnnotation extends MarkupAnnotation { } static createNewDict(annotation, xref, { apRef, ap }) { - const { color, fontSize, oldAnnotation, rect, rotation, user, value } = - annotation; + const { + calloutLine, + color, + fontSize, + lineEnding, + oldAnnotation, + rect, + rotation, + user, + value, + } = annotation; const freetext = oldAnnotation || new Dict(xref); freetext.set("Type", Name.get("Annot")); freetext.set("Subtype", Name.get("FreeText")); @@ -3961,6 +3970,15 @@ class FreeTextAnnotation extends MarkupAnnotation { freetext.set("Border", [0, 0, 0]); freetext.set("Rotate", rotation); + if (calloutLine) { + freetext.set("IT", Name.get("FreeTextCallout")); + + freetext.set("CL", calloutLine); + if (lineEnding) { + freetext.set("LE", Name.get(lineEnding)); + } + } + if (user) { freetext.set("T", stringToAsciiOrUTF16BE(user)); } diff --git a/test/unit/annotation_spec.js b/test/unit/annotation_spec.js index a7c968644..69c2cac70 100644 --- a/test/unit/annotation_spec.js +++ b/test/unit/annotation_spec.js @@ -4257,6 +4257,40 @@ describe("annotation", function () { ); }); + it("should create a new FreeTextCallout annotation", async () => { + const xref = (partialEvaluator.xref = new XRefMock()); + const task = new WorkerTask("test FreeText creation"); + const changes = new RefSetCache(); + await AnnotationFactory.saveNewAnnotations( + partialEvaluator, + task, + [ + { + annotationType: AnnotationEditorType.FREETEXT, + rect: [12, 34, 56, 78], + rotation: 0, + fontSize: 10, + color: [0, 0, 0], + calloutLine: [0, 0, 10, 56, 12, 56], + lineEnding: "OpenArrow", + value: "Hello PDF.js World!", + }, + ], + null, + changes + ); + const data = await writeChanges(changes, xref); + + const base = data[1].data.replace(/\(D:\d+\)/, "(date)"); + expect(base).toEqual( + "2 0 obj\n" + + "<< /Type /Annot /Subtype /FreeText /CreationDate (date) " + + "/Rect [12 34 56 78] /DA (/Helv 10 Tf 0 g) /Contents (Hello PDF.js World!) " + + "/F 4 /Border [0 0 0] /Rotate 0 /IT /FreeTextCallout /CL [0 0 10 56 12 56] /LE /OpenArrow /AP << /N 3 0 R>>>>\n" + + "endobj\n" + ); + }); + it("should render an added FreeText annotation for printing", async function () { partialEvaluator.xref = new XRefMock(); const task = new WorkerTask("test FreeText printing"); @@ -4384,6 +4418,38 @@ describe("annotation", function () { "World !", ]); }); + + it("should parse callout line from a FreeTextCallout annotation", async function () { + partialEvaluator.xref = new XRefMock(); + const task = new WorkerTask("test FreeTextCallout line parsing"); + const freetextAnnotation = ( + await AnnotationFactory.printNewAnnotations( + annotationGlobalsMock, + partialEvaluator, + task, + [ + { + annotationType: AnnotationEditorType.FREETEXT, + rect: [12, 34, 56, 78], + rotation: 0, + fontSize: 10, + color: [0, 0, 0], + calloutLine: [0, 0, 10, 56, 12, 56], + lineEnding: "OpenArrow", + value: "Hello PDF.js\nWorld !", + }, + ] + ) + )[0]; + + expect(freetextAnnotation.data.it).toEqual("FreeTextCallout"); + + expect(freetextAnnotation.data.calloutLine).toEqual([ + 0, 0, 10, 56, 12, 56, + ]); + + expect(freetextAnnotation.data.lineEnding).toEqual("OpenArrow"); + }); }); describe("InkAnnotation", function () {