Skip to content

Commit

Permalink
[Editor] Add the possibility to update an existing annotation with so…
Browse files Browse the repository at this point in the history
…me new properties when saving or printing
  • Loading branch information
calixteman committed Jun 6, 2023
1 parent 22d350c commit ff265f0
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 11 deletions.
18 changes: 15 additions & 3 deletions src/core/annotation.js
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,9 @@ class AnnotationFactory {
const promises = [];

for (const annotation of annotations) {
if (annotation.deleted) {
continue;
}
switch (annotation.annotationType) {
case AnnotationEditorType.FREETEXT:
if (!baseFontRef) {
Expand Down Expand Up @@ -308,6 +311,9 @@ class AnnotationFactory {
const { isOffscreenCanvasSupported } = evaluator.options;
const promises = [];
for (const annotation of annotations) {
if (annotation.deleted) {
continue;
}
switch (annotation.annotationType) {
case AnnotationEditorType.FREETEXT:
promises.push(
Expand Down Expand Up @@ -466,6 +472,7 @@ class Annotation {
const MK = dict.get("MK");
this.setBorderAndBackgroundColors(MK);
this.setRotation(MK);
this.ref = params.ref;

this._streams = [];
if (this.appearance) {
Expand Down Expand Up @@ -1467,7 +1474,7 @@ class MarkupAnnotation extends Annotation {
}

static async createNewAnnotation(xref, annotation, dependencies, params) {
const annotationRef = xref.getNewTemporaryRef();
const annotationRef = annotation.ref || xref.getNewTemporaryRef();
const ap = await this.createNewAppearanceStream(annotation, xref, params);
const buffer = [];
let annotationDict;
Expand Down Expand Up @@ -1497,11 +1504,17 @@ class MarkupAnnotation extends Annotation {
const ap = await this.createNewAppearanceStream(annotation, xref, params);
const annotationDict = this.createNewDict(annotation, xref, { ap });

return new this.prototype.constructor({
const newAnnotation = new this.prototype.constructor({
dict: annotationDict,
xref,
isOffscreenCanvasSupported: params.isOffscreenCanvasSupported,
});

if (annotation.ref) {
newAnnotation.refToReplace = annotation.ref;
}

return newAnnotation;
}
}

Expand All @@ -1511,7 +1524,6 @@ class WidgetAnnotation extends Annotation {

const { dict, xref } = params;
const data = this.data;
this.ref = params.ref;
this._needAppearances = params.needAppearances;

data.annotationType = AnnotationType.WIDGET;
Expand Down
67 changes: 62 additions & 5 deletions src/core/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,21 @@ class Page {
);
}

async replaceIdByRef(annotations, deletedAnnotations) {
for (const annotation of annotations) {
if (annotation.id) {
const idToRefMap = await this._idToRefMap;
const ref = idToRefMap.get(annotation.id);
if (annotation.deleted) {
deletedAnnotations.add(ref);
continue;
}
annotation.ref = ref;
delete annotation.id;
}
}
}

async saveNewAnnotations(handler, task, annotations) {
if (this.xfaFactory) {
throw new Error("XFA: Cannot save new annotations.");
Expand All @@ -276,8 +291,13 @@ class Page {
options: this.evaluatorOptions,
});

const deletedAnnotations = new Set();
await this.replaceIdByRef(annotations, deletedAnnotations);

const pageDict = this.pageDict;
const annotationsArray = this.annotations.slice();
const annotationsArray = this.annotations.filter(
a => !deletedAnnotations.has(a)
);
const newData = await AnnotationFactory.saveNewAnnotations(
partialEvaluator,
task,
Expand Down Expand Up @@ -401,15 +421,21 @@ class Page {
const newAnnotationsByPage = !this.xfaFactory
? getNewAnnotationsMap(annotationStorage)
: null;
const deletedAnnotations = new Set();

let newAnnotationsPromise = Promise.resolve(null);
if (newAnnotationsByPage) {
const newAnnotations = newAnnotationsByPage.get(this.pageIndex);
if (newAnnotations) {
newAnnotationsPromise = AnnotationFactory.printNewAnnotations(
partialEvaluator,
task,
newAnnotations
newAnnotationsPromise = this.replaceIdByRef(
newAnnotations,
deletedAnnotations
).then(() =>
AnnotationFactory.printNewAnnotations(
partialEvaluator,
task,
newAnnotations
)
);
}
}
Expand Down Expand Up @@ -446,6 +472,23 @@ class Page {
newAnnotationsPromise,
]).then(function ([pageOpList, annotations, newAnnotations]) {
if (newAnnotations) {
// Some annotations can already exist (if it has the refToReplace
// property). In this case, we replace the old annotation by the new
// one.
for (let i = 0, ii = newAnnotations.length; i < ii; i++) {
const newAnnotation = newAnnotations[i];
if (newAnnotation.refToReplace) {
const j = annotations.findIndex(
a => a.ref === newAnnotation.refToReplace
);
if (j >= 0) {
annotations.splice(j, 1, newAnnotation);
newAnnotations.splice(i--, 1);
ii--;
}
}
}
annotations = annotations.filter(a => !deletedAnnotations.has(a.ref));
annotations = annotations.concat(newAnnotations);
}
if (
Expand Down Expand Up @@ -688,6 +731,20 @@ class Page {
return shadow(this, "_parsedAnnotations", parsedAnnotations);
}

get _idToRefMap() {
const promise = this._parsedAnnotations.then(annotations => {
const idToRefMap = new Map();
for (const annotation of annotations) {
if (!annotation) {
continue;
}
idToRefMap.set(annotation.data.id, annotation.ref);
}
return idToRefMap;
});
return shadow(this, "_idToRefMap", promise);
}

get jsActions() {
const actions = collectActions(
this.xref,
Expand Down
9 changes: 7 additions & 2 deletions src/display/annotation_storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,13 @@ class AnnotationStorage {
const clone = new Map();

for (const [key, val] of this.#storage) {
const serialized =
val instanceof AnnotationEditor ? val.serialize() : val;
let serialized = val;
if (val instanceof AnnotationEditor) {
serialized = val.serialize();
if (!val.hasElementChanged(serialized)) {
serialized = null;
}
}
if (serialized) {
clone.set(key, serialized);
}
Expand Down
1 change: 1 addition & 0 deletions test/pdfs/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -598,3 +598,4 @@
!issue16473.pdf
!bug1529502.pdf
!issue16500.pdf
!freetexts.pdf
Binary file added test/pdfs/freetexts.pdf
Binary file not shown.
88 changes: 87 additions & 1 deletion test/test_manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7713,5 +7713,91 @@
"value": ["Three", "Five"]
}
}
}
},
{
"id": "freetexts-editor-print",
"file": "pdfs/freetexts.pdf",
"md5": "da1310a25ab796c1201810070d5032a3",
"rounds": 1,
"lastPage": 1,
"type": "eq",
"print": true,
"annotationStorage": {
"pdfjs_internal_editor_0": {
"annotationType": 3,
"color": [0, 0, 255],
"fontSize": 21,
"value": "The content must have been changed",
"pageIndex": 0,
"rect": [ 92.58600000000003, 415.2426115258789, 449.1110015258789, 447.59261],
"rotation": 0,
"id": "36R"
}
}
},
{
"id": "freetexts-editor-save",
"file": "pdfs/freetexts.pdf",
"md5": "da1310a25ab796c1201810070d5032a3",
"rounds": 1,
"lastPage": 1,
"type": "eq",
"save": true,
"print": true,
"annotationStorage": {
"pdfjs_internal_editor_0": {
"annotationType": 3,
"color": [255, 0, 0],
"fontSize": 21,
"value": "The content must have been changed",
"pageIndex": 0,
"rect": [ 92.58600000000003, 415.2426115258789, 449.1110015258789, 447.59261],
"rotation": 0,
"id": "36R"
}
}
},
{
"id": "freetexts-delete-editor-print",
"file": "pdfs/freetexts.pdf",
"md5": "da1310a25ab796c1201810070d5032a3",
"rounds": 1,
"lastPage": 1,
"type": "eq",
"print": true,
"annotationStorage": {
"pdfjs_internal_editor_0": {
"pageIndex": 0,
"deleted": true,
"id": "36R"
},
"pdfjs_internal_editor_1": {
"pageIndex": 0,
"deleted": true,
"id": "53R"
}
}
},
{
"id": "freetexts-delete-editor-save",
"file": "pdfs/freetexts.pdf",
"md5": "da1310a25ab796c1201810070d5032a3",
"rounds": 1,
"lastPage": 1,
"type": "eq",
"save": true,
"print": true,
"annotationStorage": {
"pdfjs_internal_editor_0": {
"pageIndex": 0,
"deleted": true,
"id": "36R"
},
"pdfjs_internal_editor_1": {
"pageIndex": 0,
"deleted": true,
"id": "53R"
}
}
}
]

0 comments on commit ff265f0

Please sign in to comment.