Merge pull request #16523 from calixteman/restore_save
[Editor] Add the possibility to update an existing annotation with some new properties when saving or printing
This commit is contained in:
		
						commit
						b8447eb49f
					
				@ -264,6 +264,9 @@ class AnnotationFactory {
 | 
				
			|||||||
    const promises = [];
 | 
					    const promises = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (const annotation of annotations) {
 | 
					    for (const annotation of annotations) {
 | 
				
			||||||
 | 
					      if (annotation.deleted) {
 | 
				
			||||||
 | 
					        continue;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      switch (annotation.annotationType) {
 | 
					      switch (annotation.annotationType) {
 | 
				
			||||||
        case AnnotationEditorType.FREETEXT:
 | 
					        case AnnotationEditorType.FREETEXT:
 | 
				
			||||||
          if (!baseFontRef) {
 | 
					          if (!baseFontRef) {
 | 
				
			||||||
@ -308,6 +311,9 @@ class AnnotationFactory {
 | 
				
			|||||||
    const { isOffscreenCanvasSupported } = evaluator.options;
 | 
					    const { isOffscreenCanvasSupported } = evaluator.options;
 | 
				
			||||||
    const promises = [];
 | 
					    const promises = [];
 | 
				
			||||||
    for (const annotation of annotations) {
 | 
					    for (const annotation of annotations) {
 | 
				
			||||||
 | 
					      if (annotation.deleted) {
 | 
				
			||||||
 | 
					        continue;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      switch (annotation.annotationType) {
 | 
					      switch (annotation.annotationType) {
 | 
				
			||||||
        case AnnotationEditorType.FREETEXT:
 | 
					        case AnnotationEditorType.FREETEXT:
 | 
				
			||||||
          promises.push(
 | 
					          promises.push(
 | 
				
			||||||
@ -466,6 +472,7 @@ class Annotation {
 | 
				
			|||||||
    const MK = dict.get("MK");
 | 
					    const MK = dict.get("MK");
 | 
				
			||||||
    this.setBorderAndBackgroundColors(MK);
 | 
					    this.setBorderAndBackgroundColors(MK);
 | 
				
			||||||
    this.setRotation(MK);
 | 
					    this.setRotation(MK);
 | 
				
			||||||
 | 
					    this.ref = params.ref instanceof Ref ? params.ref : null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this._streams = [];
 | 
					    this._streams = [];
 | 
				
			||||||
    if (this.appearance) {
 | 
					    if (this.appearance) {
 | 
				
			||||||
@ -1467,7 +1474,7 @@ class MarkupAnnotation extends Annotation {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static async createNewAnnotation(xref, annotation, dependencies, params) {
 | 
					  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 ap = await this.createNewAppearanceStream(annotation, xref, params);
 | 
				
			||||||
    const buffer = [];
 | 
					    const buffer = [];
 | 
				
			||||||
    let annotationDict;
 | 
					    let annotationDict;
 | 
				
			||||||
@ -1497,11 +1504,17 @@ class MarkupAnnotation extends Annotation {
 | 
				
			|||||||
    const ap = await this.createNewAppearanceStream(annotation, xref, params);
 | 
					    const ap = await this.createNewAppearanceStream(annotation, xref, params);
 | 
				
			||||||
    const annotationDict = this.createNewDict(annotation, xref, { ap });
 | 
					    const annotationDict = this.createNewDict(annotation, xref, { ap });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return new this.prototype.constructor({
 | 
					    const newAnnotation = new this.prototype.constructor({
 | 
				
			||||||
      dict: annotationDict,
 | 
					      dict: annotationDict,
 | 
				
			||||||
      xref,
 | 
					      xref,
 | 
				
			||||||
      isOffscreenCanvasSupported: params.isOffscreenCanvasSupported,
 | 
					      isOffscreenCanvasSupported: params.isOffscreenCanvasSupported,
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (annotation.ref) {
 | 
				
			||||||
 | 
					      newAnnotation.ref = newAnnotation.refToReplace = annotation.ref;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return newAnnotation;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1511,7 +1524,6 @@ class WidgetAnnotation extends Annotation {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const { dict, xref } = params;
 | 
					    const { dict, xref } = params;
 | 
				
			||||||
    const data = this.data;
 | 
					    const data = this.data;
 | 
				
			||||||
    this.ref = params.ref;
 | 
					 | 
				
			||||||
    this._needAppearances = params.needAppearances;
 | 
					    this._needAppearances = params.needAppearances;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    data.annotationType = AnnotationType.WIDGET;
 | 
					    data.annotationType = AnnotationType.WIDGET;
 | 
				
			||||||
 | 
				
			|||||||
@ -41,7 +41,7 @@ import {
 | 
				
			|||||||
  XRefEntryException,
 | 
					  XRefEntryException,
 | 
				
			||||||
  XRefParseException,
 | 
					  XRefParseException,
 | 
				
			||||||
} from "./core_utils.js";
 | 
					} from "./core_utils.js";
 | 
				
			||||||
import { Dict, isName, Name, Ref } from "./primitives.js";
 | 
					import { Dict, isName, isRefsEqual, Name, Ref, RefSet } from "./primitives.js";
 | 
				
			||||||
import { getXfaFontDict, getXfaFontName } from "./xfa_fonts.js";
 | 
					import { getXfaFontDict, getXfaFontName } from "./xfa_fonts.js";
 | 
				
			||||||
import { BaseStream } from "./base_stream.js";
 | 
					import { BaseStream } from "./base_stream.js";
 | 
				
			||||||
import { calculateMD5 } from "./crypto.js";
 | 
					import { calculateMD5 } from "./crypto.js";
 | 
				
			||||||
@ -258,6 +258,24 @@ class Page {
 | 
				
			|||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  #replaceIdByRef(annotations, deletedAnnotations) {
 | 
				
			||||||
 | 
					    for (const annotation of annotations) {
 | 
				
			||||||
 | 
					      if (annotation.id) {
 | 
				
			||||||
 | 
					        const ref = Ref.fromString(annotation.id);
 | 
				
			||||||
 | 
					        if (!ref) {
 | 
				
			||||||
 | 
					          warn(`A non-linked annotation cannot be modified: ${annotation.id}`);
 | 
				
			||||||
 | 
					          continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (annotation.deleted) {
 | 
				
			||||||
 | 
					          deletedAnnotations.put(ref);
 | 
				
			||||||
 | 
					          continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        annotation.ref = ref;
 | 
				
			||||||
 | 
					        delete annotation.id;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async saveNewAnnotations(handler, task, annotations) {
 | 
					  async saveNewAnnotations(handler, task, annotations) {
 | 
				
			||||||
    if (this.xfaFactory) {
 | 
					    if (this.xfaFactory) {
 | 
				
			||||||
      throw new Error("XFA: Cannot save new annotations.");
 | 
					      throw new Error("XFA: Cannot save new annotations.");
 | 
				
			||||||
@ -276,8 +294,13 @@ class Page {
 | 
				
			|||||||
      options: this.evaluatorOptions,
 | 
					      options: this.evaluatorOptions,
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const deletedAnnotations = new RefSet();
 | 
				
			||||||
 | 
					    this.#replaceIdByRef(annotations, deletedAnnotations);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const pageDict = this.pageDict;
 | 
					    const pageDict = this.pageDict;
 | 
				
			||||||
    const annotationsArray = this.annotations.slice();
 | 
					    const annotationsArray = this.annotations.filter(
 | 
				
			||||||
 | 
					      a => !(a instanceof Ref && deletedAnnotations.has(a))
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
    const newData = await AnnotationFactory.saveNewAnnotations(
 | 
					    const newData = await AnnotationFactory.saveNewAnnotations(
 | 
				
			||||||
      partialEvaluator,
 | 
					      partialEvaluator,
 | 
				
			||||||
      task,
 | 
					      task,
 | 
				
			||||||
@ -401,11 +424,14 @@ class Page {
 | 
				
			|||||||
    const newAnnotationsByPage = !this.xfaFactory
 | 
					    const newAnnotationsByPage = !this.xfaFactory
 | 
				
			||||||
      ? getNewAnnotationsMap(annotationStorage)
 | 
					      ? getNewAnnotationsMap(annotationStorage)
 | 
				
			||||||
      : null;
 | 
					      : null;
 | 
				
			||||||
 | 
					    let deletedAnnotations = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let newAnnotationsPromise = Promise.resolve(null);
 | 
					    let newAnnotationsPromise = Promise.resolve(null);
 | 
				
			||||||
    if (newAnnotationsByPage) {
 | 
					    if (newAnnotationsByPage) {
 | 
				
			||||||
      const newAnnotations = newAnnotationsByPage.get(this.pageIndex);
 | 
					      const newAnnotations = newAnnotationsByPage.get(this.pageIndex);
 | 
				
			||||||
      if (newAnnotations) {
 | 
					      if (newAnnotations) {
 | 
				
			||||||
 | 
					        deletedAnnotations = new RefSet();
 | 
				
			||||||
 | 
					        this.#replaceIdByRef(newAnnotations, deletedAnnotations);
 | 
				
			||||||
        newAnnotationsPromise = AnnotationFactory.printNewAnnotations(
 | 
					        newAnnotationsPromise = AnnotationFactory.printNewAnnotations(
 | 
				
			||||||
          partialEvaluator,
 | 
					          partialEvaluator,
 | 
				
			||||||
          task,
 | 
					          task,
 | 
				
			||||||
@ -446,6 +472,25 @@ class Page {
 | 
				
			|||||||
      newAnnotationsPromise,
 | 
					      newAnnotationsPromise,
 | 
				
			||||||
    ]).then(function ([pageOpList, annotations, newAnnotations]) {
 | 
					    ]).then(function ([pageOpList, annotations, newAnnotations]) {
 | 
				
			||||||
      if (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.
 | 
				
			||||||
 | 
					        annotations = annotations.filter(
 | 
				
			||||||
 | 
					          a => !(a.ref && deletedAnnotations.has(a.ref))
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        for (let i = 0, ii = newAnnotations.length; i < ii; i++) {
 | 
				
			||||||
 | 
					          const newAnnotation = newAnnotations[i];
 | 
				
			||||||
 | 
					          if (newAnnotation.refToReplace) {
 | 
				
			||||||
 | 
					            const j = annotations.findIndex(
 | 
				
			||||||
 | 
					              a => a.ref && isRefsEqual(a.ref, newAnnotation.refToReplace)
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
 | 
					            if (j >= 0) {
 | 
				
			||||||
 | 
					              annotations.splice(j, 1, newAnnotation);
 | 
				
			||||||
 | 
					              newAnnotations.splice(i--, 1);
 | 
				
			||||||
 | 
					              ii--;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        annotations = annotations.concat(newAnnotations);
 | 
					        annotations = annotations.concat(newAnnotations);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (
 | 
					      if (
 | 
				
			||||||
 | 
				
			|||||||
@ -279,6 +279,23 @@ class Ref {
 | 
				
			|||||||
    return `${this.num}R${this.gen}`;
 | 
					    return `${this.num}R${this.gen}`;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static fromString(str) {
 | 
				
			||||||
 | 
					    const ref = RefCache[str];
 | 
				
			||||||
 | 
					    if (ref) {
 | 
				
			||||||
 | 
					      return ref;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const m = /^(\d+)R(\d*)$/.exec(str);
 | 
				
			||||||
 | 
					    if (!m || m[1] === "0") {
 | 
				
			||||||
 | 
					      return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // eslint-disable-next-line no-restricted-syntax
 | 
				
			||||||
 | 
					    return (RefCache[str] = new Ref(
 | 
				
			||||||
 | 
					      parseInt(m[1]),
 | 
				
			||||||
 | 
					      !m[2] ? 0 : parseInt(m[2])
 | 
				
			||||||
 | 
					    ));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  static get(num, gen) {
 | 
					  static get(num, gen) {
 | 
				
			||||||
    const key = gen === 0 ? `${num}R` : `${num}R${gen}`;
 | 
					    const key = gen === 0 ? `${num}R` : `${num}R${gen}`;
 | 
				
			||||||
    // eslint-disable-next-line no-restricted-syntax
 | 
					    // eslint-disable-next-line no-restricted-syntax
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										1
									
								
								test/pdfs/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								test/pdfs/.gitignore
									
									
									
									
										vendored
									
									
								
							@ -599,3 +599,4 @@
 | 
				
			|||||||
!bug1529502.pdf
 | 
					!bug1529502.pdf
 | 
				
			||||||
!issue16500.pdf
 | 
					!issue16500.pdf
 | 
				
			||||||
!issue16538.pdf
 | 
					!issue16538.pdf
 | 
				
			||||||
 | 
					!freetexts.pdf
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										
											BIN
										
									
								
								test/pdfs/freetexts.pdf
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								test/pdfs/freetexts.pdf
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							@ -7720,5 +7720,91 @@
 | 
				
			|||||||
   "md5": "35b691c3a343f4531bd287b001b67a77",
 | 
					   "md5": "35b691c3a343f4531bd287b001b67a77",
 | 
				
			||||||
   "rounds": 1,
 | 
					   "rounds": 1,
 | 
				
			||||||
   "type": "eq"
 | 
					   "type": "eq"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					   {
 | 
				
			||||||
 | 
					      "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"
 | 
				
			||||||
 | 
					         }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
   }
 | 
					   }
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user