1

In my application annotations are stored in the database as single annotations. For one document in the document table I store many annotations (multiple xfdf strings) in the annotation table. I wrote a code to generate the pdf and import these annotations. I referred following links for this code,

params,

  • annotations : list of annotations with xfdf String
  • downloadedFile : pdf file as a buffer
  • isFlatternAnnotations - is a boolean option to flatten annotations
async importAnnotationsToDocument(
    annotations: any,
    downloadedFile: any,
    isFlatternAnnotations: any,
  ) {
    await PDFNet.initialize();
    const pdfDocument = await PDFNet.PDFDoc.createFromBuffer(downloadedFile);
    pdfDocument.lock();

    let fdfDocument = null;
    annotations.forEach(async annotation => {
      fdfDocument = await PDFNet.FDFDoc.createFromXFDF(annotation.xfdfString);
      await pdfDocument.fdfMerge(fdfDocument);
    });

    if (isFlatternAnnotations === 'true') {
      await pdfDocument.flattenAnnotations();
    } 

    const documentBuffer = await pdfDocument.saveMemoryBuffer(
      PDFNet.SDFDoc.SaveOptions.e_remove_unused,
    );
    
    const documentBufferResponse = Buffer.from(documentBuffer);
    PDFNet.shutdown();
    return documentBufferResponse;
}

However I noticed the code is working only the await pdfDocument.flattenAnnotations(); is running. If it is not running annotations are not merged in the document. And also if it runs a single time, the annotations are displayed without flattening. But if I add the same line three times it works correctly. I think the way I have done this is not correct. I need your help to write this code correctly.

Following code works correctly, but there should be a proper way to do this.

async importAnnotationsToDocument(
    annotations: any,
    downloadedFile: any,
    isFlatternAnnotations: any,
  ) {
    await PDFNet.initialize();
    const pdfDocument = await PDFNet.PDFDoc.createFromBuffer(downloadedFile);
    pdfDocument.lock();

    let fdfDocument = null;
    annotations.forEach(async annotation => {
      fdfDocument = await PDFNet.FDFDoc.createFromXFDF(annotation.xfdfString);
      await pdfDocument.fdfMerge(fdfDocument);
    });

    if (isFlatternAnnotations === 'true') {
      await pdfDocument.flattenAnnotations();
      await pdfDocument.flattenAnnotations();
      await pdfDocument.flattenAnnotations();
    } else {
      // This shows the annotations without flattening 
      await pdfDocument.flattenAnnotations();
    }

    const documentBuffer = await pdfDocument.saveMemoryBuffer(
      PDFNet.SDFDoc.SaveOptions.e_remove_unused,
    );
    
    const documentBufferResponse = Buffer.from(documentBuffer);
    PDFNet.shutdown();
    return documentBufferResponse;
  }

Following is the xfdf String for a single annotation

<?xml version="1.0" encoding="UTF-8"?>
<xfdf xmlns="http://ns.adobe.com/xfdf/" xml:space="preserve">
    <fields />
    <add>
        <square page="0" 
            rect="387.88,525.73,525,609.07" 
            color="#FFCD45" flags="print" 
            name="d1aa1a2a-822f-507b-6ff6-d61bcc6bd862" 
            title="test.title" subject="Rectangle" 
            date="D:20210405104448+08'00'" 
            interior-color="#FFCD45" 
            opacity="0.5" 
            creationdate="D:20210405104445+08'00'" />
    </add>
    <modify /><delete />
</xfdf>
  • There are two types of XFDF files with PDFNet, Regular and Command. You can tell Command ones by looking at the XFDF and seeing if there is top level elements. If that is the format of your XFDF strings, then you use different API's. If those values are present let me know and I can advise further (ideally you can provide example in your question of one of these XFDF strings). – Ryan Mar 26 '21 at 18:34
  • @Ryan Sorry for the very late reply. I have added the xfdf string. – Daratha Galkissa Jun 04 '21 at 07:50
  • Thank you for the update, this confirms you are using the alternate XFDF format. See my new answer on how to apply those server side. – Ryan Jun 08 '21 at 23:41

2 Answers2

1

You are loading a variant of XFDF, called Command, which you can see documented here. https://www.pdftron.com/documentation/web/guides/xfdf/

The following code is how you would load and apply XFDF command XML data to a PDFDoc instance.

let fdfDoc = await pdfDoc.fdfExtract(PDFNet.PDFDoc.ExtractFlag.e_both);
await fdfDoc.saveAsXFDF('data.xfdf');
fdfDoc = await PDFNet.FDFDoc.createFromXFDF('data.xfdf');
await fdfDoc.mergeAnnots(str);
await pdfDoc.fdfUpdate(fdfDoc);
await pdfDoc.refreshAnnotAppearances();
Ryan
  • 2,473
  • 1
  • 11
  • 14
0

The API pdfDocument.flattenAnnotations() by default only flattens FormFields, and not annotations. https://www.pdftron.com/api/pdfnet-node/PDFNet.PDFDoc.html#flattenAnnotations__anchor

So I would recommend changing the call to

pdfDocument.flattenAnnotations(false);
Ryan
  • 2,473
  • 1
  • 11
  • 14