diff --git a/src/core/annotation.js b/src/core/annotation.js index 4657daedf..f2f642b50 100644 --- a/src/core/annotation.js +++ b/src/core/annotation.js @@ -1810,8 +1810,8 @@ class MarkupAnnotation extends Annotation { }); const retRef = { ref: annotationRef }; - if (annotation.popup) { - const popup = annotation.popup; + const { popup } = annotation; + if (popup) { if (popup.deleted) { annotationDict.delete("Popup"); annotationDict.delete("Contents"); diff --git a/src/core/primitives.js b/src/core/primitives.js index aa79c24c3..decd4338c 100644 --- a/src/core/primitives.js +++ b/src/core/primitives.js @@ -309,7 +309,7 @@ class Dict { } delete(key) { - delete this._map[key]; + this._map.delete(key); } } diff --git a/src/display/editor/editor.js b/src/display/editor/editor.js index 19d34cf97..22e5a8be4 100644 --- a/src/display/editor/editor.js +++ b/src/display/editor/editor.js @@ -1749,7 +1749,14 @@ class AnnotationEditor { * @returns {Object | null} */ serialize(isForCopying = false, context = null) { - unreachable("An editor must be serializable"); + return { + annotationType: this.mode, + pageIndex: this.pageIndex, + rect: this.getPDFRect(), + rotation: this.rotation, + structTreeParentId: this._structTreeParentId, + popupRef: this._initialData?.popupRef || "", + }; } /** diff --git a/src/display/editor/freetext.js b/src/display/editor/freetext.js index bc47d21c2..90090e775 100644 --- a/src/display/editor/freetext.js +++ b/src/display/editor/freetext.js @@ -833,21 +833,14 @@ class FreeTextEditor extends AnnotationEditor { return this.serializeDeleted(); } - const rect = this.getPDFRect(); const color = AnnotationEditor._colorManager.convert( this.isAttachedToDOM ? getComputedStyle(this.editorDiv).color : this.color ); - - const serialized = { - annotationType: AnnotationEditorType.FREETEXT, + const serialized = Object.assign(super.serialize(isForCopying), { color, fontSize: this.#fontSize, value: this.#serializeContent(), - pageIndex: this.pageIndex, - rect, - rotation: this.rotation, - structTreeParentId: this._structTreeParentId, - }; + }); this.addComment(serialized); if (isForCopying) { diff --git a/src/display/editor/highlight.js b/src/display/editor/highlight.js index 53f43c8c0..2286268f6 100644 --- a/src/display/editor/highlight.js +++ b/src/display/editor/highlight.js @@ -1036,23 +1036,17 @@ class HighlightEditor extends AnnotationEditor { return this.serializeDeleted(); } - const rect = this.getPDFRect(); const color = AnnotationEditor._colorManager.convert( this._uiManager.getNonHCMColor(this.color) ); - - const serialized = { - annotationType: AnnotationEditorType.HIGHLIGHT, + const serialized = super.serialize(isForCopying); + Object.assign(serialized, { color, opacity: this.opacity, thickness: this.#thickness, quadPoints: this.#serializeBoxes(), - outlines: this.#serializeOutlines(rect), - pageIndex: this.pageIndex, - rect, - rotation: this.#getRotation(), - structTreeParentId: this._structTreeParentId, - }; + outlines: this.#serializeOutlines(serialized.rect), + }); this.addComment(serialized); if (this.annotationElementId && !this.#hasElementChanged(serialized)) { diff --git a/src/display/editor/ink.js b/src/display/editor/ink.js index 83823f179..52bb16673 100644 --- a/src/display/editor/ink.js +++ b/src/display/editor/ink.js @@ -247,7 +247,7 @@ class InkEditor extends DrawingEditor { return this.serializeDeleted(); } - const { lines, points, rect } = this.serializeDraw(isForCopying); + const { lines, points } = this.serializeDraw(isForCopying); const { _drawingOptions: { stroke, @@ -255,8 +255,7 @@ class InkEditor extends DrawingEditor { "stroke-width": thickness, }, } = this; - const serialized = { - annotationType: AnnotationEditorType.INK, + const serialized = Object.assign(super.serialize(isForCopying), { color: AnnotationEditor._colorManager.convert(stroke), opacity, thickness, @@ -264,11 +263,7 @@ class InkEditor extends DrawingEditor { lines, points, }, - pageIndex: this.pageIndex, - rect, - rotation: this.rotation, - structTreeParentId: this._structTreeParentId, - }; + }); this.addComment(serialized); if (isForCopying) { diff --git a/src/display/editor/signature.js b/src/display/editor/signature.js index 0dc38ecd1..c48d6e1ab 100644 --- a/src/display/editor/signature.js +++ b/src/display/editor/signature.js @@ -374,21 +374,16 @@ class SignatureEditor extends DrawingEditor { return null; } - const { lines, points, rect } = this.serializeDraw(isForCopying); + const { lines, points } = this.serializeDraw(isForCopying); const { _drawingOptions: { "stroke-width": thickness }, } = this; - const serialized = { - annotationType: AnnotationEditorType.SIGNATURE, + const serialized = Object.assign(super.serialize(isForCopying), { isSignature: true, areContours: this.#isExtracted, color: [0, 0, 0], thickness: this.#isExtracted ? 0 : thickness, - pageIndex: this.pageIndex, - rect, - rotation: this.rotation, - structTreeParentId: this._structTreeParentId, - }; + }); this.addComment(serialized); if (isForCopying) { serialized.paths = { lines, points }; diff --git a/src/display/editor/stamp.js b/src/display/editor/stamp.js index 9ba3db861..84621b723 100644 --- a/src/display/editor/stamp.js +++ b/src/display/editor/stamp.js @@ -842,15 +842,10 @@ class StampEditor extends AnnotationEditor { return this.serializeDeleted(); } - const serialized = { - annotationType: AnnotationEditorType.STAMP, + const serialized = Object.assign(super.serialize(isForCopying), { bitmapId: this.#bitmapId, - pageIndex: this.pageIndex, - rect: this.getPDFRect(), - rotation: this.rotation, isSvg: this.#isSvg, - structTreeParentId: this._structTreeParentId, - }; + }); this.addComment(serialized); if (isForCopying) { diff --git a/test/unit/annotation_spec.js b/test/unit/annotation_spec.js index ca728571b..056ce715f 100644 --- a/test/unit/annotation_spec.js +++ b/test/unit/annotation_spec.js @@ -5023,6 +5023,63 @@ describe("annotation", function () { "endobj\n" ); }); + + it("should update an existing Highlight annotation in removing its popup", async function () { + const popupRef = Ref.get(111, 0); + const highlightDict = new Dict(); + highlightDict.set("Type", Name.get("Annot")); + highlightDict.set("Subtype", Name.get("Highlight")); + highlightDict.set("Rotate", 0); + highlightDict.set("CreationDate", "D:20190423"); + highlightDict.set("Contents", "Hello PDF.js World !"); + highlightDict.set("Popup", popupRef); + const highlightRef = Ref.get(143, 0); + + const highlightPopupDict = new Dict(); + highlightPopupDict.set("Type", Name.get("Annot")); + highlightPopupDict.set("Subtype", Name.get("Popup")); + highlightPopupDict.set("Open", false); + highlightPopupDict.set("Rect", [1, 2, 3, 4]); + highlightPopupDict.set("Parent", highlightRef); + + const xref = (partialEvaluator.xref = new XRefMock([ + { ref: highlightRef, data: highlightDict }, + { ref: popupRef, data: highlightPopupDict }, + ])); + const changes = new RefSetCache(); + + const task = new WorkerTask("test Highlight update"); + await AnnotationFactory.saveNewAnnotations( + partialEvaluator, + task, + [ + { + annotationType: AnnotationEditorType.HIGHLIGHT, + rotation: 90, + popup: { + contents: "", + deleted: true, + rect: [1, 2, 3, 4], + }, + id: "143R", + ref: highlightRef, + oldAnnotation: highlightDict, + popupRef, + }, + ], + null, + changes + ); + + const data = await writeChanges(changes, xref); + const base = data[0].data.replaceAll(/\(D:\d+\)/g, "(date)"); + expect(base).toEqual( + "143 0 obj\n" + + "<< /Type /Annot /Subtype /Highlight /Rotate 90 /CreationDate (date) /M (date) " + + "/F 4>>\n" + + "endobj\n" + ); + }); }); describe("UnderlineAnnotation", function () {