Interceptor-Beispiel: Annotations einbrennen ("Flatten annotations")

Ähnlich wie Interceptor-Beispiel: Annotationen vor dem Speichern sperren in der Wirkung, geht dieser Interceptor noch etwas weiter: Wenn der Einbrennen-Button gedrückt wird, werden alle Annotationen im PDF dauerhaft in das PDF integriert:

class EDAnnotationFlattener {
    // code fragements taken from https://docs.apryse.com/documentation/web/guides/annotation/flatten-annotations/
    buttonDataElement = 'custom_annotation_flattener_button';
    dialogDataElement = 'custom_annotation_flattener_dialog';
  
    async flattenAllAnnotations(instance) {
      const { documentViewer, PDFNet, annotationManager } = instance.Core;
  
      await PDFNet.initialize();
      const theDocument = await documentViewer.getDocument().getPDFDoc();
  
      // export annotations from the document
      const allAnnotations = await annotationManager.exportAnnotations();
  
      // Run PDFNet methods with memory management
      await PDFNet.runWithCleanup(async () => {
        // lock the document before a write operation
        // runWithCleanup will auto unlock when complete
        theDocument.lock();
  
        // import annotations to PDFNet
        const fdfDocument = await PDFNet.FDFDoc.createFromXFDF(allAnnotations);
        await theDocument.fdfUpdate(fdfDocument);
  
        // flatten all annotations in the document
        // see https://docs.apryse.com/api/web/Core.PDFNet.PDFDoc.html#flattenAnnotations__anchor
        await theDocument.flattenAnnotations();
  
        // clear the original annotations
        annotationManager.deleteAnnotations(annotationManager.getAnnotationsList());
      });
  
      // clear the cache (rendered) data with the newly updated document
      documentViewer.refreshAll();
  
      // Update viewer to render with the new document
      documentViewer.updateView();
  
      // Refresh searchable and selectable text data with the new document
      documentViewer.getDocument().refreshTextData();
    }
  
    initEditorConfiguration(instance) {
      // Create a new action button
      const aButton = {
        dataElement: this.buttonDataElement,
        type: 'actionButton',
        img: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-fire" viewBox="0 0 16 16"><path d="M8 16c3.314 0 6-2 6-5.5 0-1.5-.5-4-2.5-6 .25 1.5-1.25 2-1.25 2C11 4 9 .5 6 0c.357 2 .5 4-2 6-1.25 1-2 2.729-2 4.5C2 14 4.686 16 8 16Zm0-1c-1.657 0-3-1-3-2.75 0-.75.25-2 1.25-3C6.125 10 7 10.5 7 10.5c-.375-1.25.5-3.25 2-3.5-.179 1-.25 2 1 3 .625.5 1 1.364 1 2.25C11 14 9.657 15 8 15Z"/></svg>',
        title: 'Alle Anmerkungen einbrennen',
        onClick: () => instance.UI.openElements([this.dialogDataElement]),
      };
  
      // Add the new button to the header
      instance.UI.setHeaderItems((header) => {
        header.push(aButton);
      });
  
      const body = document.createElement("div");
      body.innerHTML = "Alle Anmerkungen werden unwiderruflich in das PDF integriert. Sind Sie sicher, dass Sie dies möchten?";
  
      const modal = {
          dataElement: this.dialogDataElement,
          header: {
            title: 'Annotationen einbrennen',
          },
          body: {
            className: 'myCustomModal-body',
            style: {textAlign: "center"}, // optional inline styles
            children: [body], // HTML dom elements
          },
          footer: {
            className: 'myCustomModal-footer footer',
            style: {}, // optional inline styles
            children: [
              {
                title: 'Abbrechen',
                button: true,
                style: {},
                className: 'modal-button cancel-form-field-button',
                onClick: async (e) => {
                  instance.UI.closeElements([this.dialogDataElement]);
                },
              },
              {
                title: 'Einbrennen',
                button: true,
                style: {},
                className: 'modal-button confirm ok-btn',
                onClick: async (e) => {
                  await this.flattenAllAnnotations(instance);
                  instance.UI.closeElements([this.dialogDataElement]);
                },
              },
            ],
          },
        };
        instance.UI.addCustomModal(modal);
    }
  
    async updateEditorConfiguration(instance, info, config) {
      if (info.mode != 'edit') {
        instance.UI.disableElements([this.buttonDataElement]);
      } else {
        instance.UI.enableElements([this.buttonDataElement]);
      }
    }
  }
  
  window.ed.registerInterceptor(new EDAnnotationFlattener());

„Installiert“ werden kann dies wie üblich durch einfaches Abspeichern im Interceptors-Verzeichnis als .js-Datei:

Hinweis: Natürlich schützt dies nicht vor technisch versierter Manipulation des PDFs. So etwas lässt sich nur durch digitale Signaturen oder der Ablage in einem revisionssicheren Archiv verhindern.

3 Likes