PDF markup adding measurements not working

Which product are you using?

PDF.js Express Version

Detailed description of issue
Hi,

We are using 8.7.4 version of PDF Express in our react code. We are facing an issue of the adding markup, mentioned below.
Generally when we add simple markups, it works fine, but when I add the measurements, those markups are not applied on the PDF file.
I am attaching the video URL along with the issue report. https://drive.google.com/file/d/1t088eB7ZshlqOGqe4hx4f05GmQqOqus9/view?usp=sharing

Looking forward to hearing from you.
Thanks & Regards

Expected behaviour
{Provide a screenshot or description of the expected behaviour}

Does your issue happen with every document, or just one?
{Answer here}

Link to document
{Provide a link to the document in question if possible}

Code snippet
{Provide a relevant code snippet}

Hi there,

Could you please share the snippets for your save button? Can you reproduce the issue with version 8.7.5?

Hi @kkim

Thank you for the quick response.

Please find the code snippet at https://drive.google.com/file/d/1b85tcEULdqEx6yFzkowr5tYmfOkngpAP/view?usp=sharing

Also please note that we have tried version 8.75, and we are able to reproduce same issue in it.

Thanks & Regards

Hi there,

I see the following snippet in your ‘getFileData’ method:

  const getFileData = async (): Promise<PdfjsExpressPropsOnSaveValue> => {
    // Get the annotations and the documents data
    var xfdf = await instance.annotManager.exportAnnotations({
      links: false,
      widgets: false,
    });
    // Set the annotations and document into the Utility SDK, then merge them together
    utils.setFile(config.file_path).setXFDF(xfdf);
    const resp = await utils.merge(); // merge XFDF
    // Get the resulting blob from the merge operation
    var mergedBlob = await resp.getBlob();
    return {
      blobdata: mergedBlob,
      xfdf,
    };
  };

But you are not actually calling the Document class’ getFileData, but your own getFileData method with the same name.
Could you please try the method shown in this guide and see if that works for you:

best regards,
Kevin

Hi @kkim

Thank you for the quick response.

The issue is not related to the getFileData function currently in use. The problem specifically occurs within the annotationManager.importAnnotations method. We are successfully receiving the XFDF (annotation data) when exporting the annotations through the onSave function using exportAnnotations. However, when we attempt to reapply the same XFDF string using importAnnotations(xfdfString), the measurement annotations are not rendered in the document as expected.

We have also implemented the same approach suggested in your earlier comment, but the issue persists with the same behavior.

For your reference, we have attached a video demonstrating the problem, along with the exact XFDF string generated from exportAnnotations for the measurement annotations. Please verify this XFDF data and advise on a reliable solution to ensure proper import and rendering of these measurement annotations in the document.

Additional details that may be relevant:

- The document is fully loaded before calling importAnnotations.

- We have ensured that the same document is being used for both export and import.

- The annotations appear correctly in the original session before export.

- The XFDF contains valid measurement annotation entries.

- No errors are thrown during the importAnnotations call.

Kindly review and let us know if there are any known limitations, required configuration flags, or specific initialization steps needed for importing measurement annotations in PDF.js Express.

Please find thew measurements annotation on https://drive.google.com/file/d/1uskKf_B8hMBnVGHTeBj1o7p3k7GPnx7N/view?usp=drive_link

Please find the attached video on https://drive.google.com/file/d/1HXnykHUDxocOCaEyP93y83OqzPr6jXCU/view?usp=drive_link

Thanks & Regards

Hi there,

Thank you for confirming that your save button is exporting the annotation and you load the annotation when the document is fully loaded. This means you are not really going through the merge API to embed the annotations into the document, but importing it dynamically like this:

The issue is due to the element that was generated in the annotation. I recommend removing this from the XFDF and it should load as expected:

best regards,
Kevin

Hi @kkim

Thank you for the quick response.

We tried the proposed solution, and it is functioning as expected. However, we have identified an additional issue: the units for each measurement are currently overlapping at the last rendered position. Instead, each unit should be displayed within its respective measurement. We kindly request a solution to address this issue.

Please find the video at https://drive.google.com/file/d/1qvrrO_QpGY33Trh2qNHPIfoZ_fGoobEw/view?usp=sharing

Thanks & Regards

Hi there,

It looks like removing the above custom data will remove the measurement for the annotation. Please keep the custom data information when exporting, and please try updating to version 8.7.5 of pdf.js express and see if that works for you.

best regards,
Kevin

@kkim

Thank you for the details.
We are not permanently removing the custom data from the XFDF string during the export of annotation data; it is only temporarily removed during the import process. The complete XFDF string, including the custom data, is stored in the database. At the time of import, we dynamically replace the trn-custom-data value with a blank entry. Additionally, we attempted to resolve the issue by updating the version from 8.7.4 to 8.7.5; however, this update did not resolve the problem.

Below is the code that we have implemented for importing annotations. nothing else we are doing for importing feature.

docViewer.on(“documentLoaded”, async () => {

instance.UI.setFitMode(instance.FitMode.FitWidth);



const annotManager = instance.annotManager;



if (!config.annotation_data) return;



let xfdfString = config.annotation_data;

xfdfString = xfdfString

  .replace(/\\\\"/g, '"')

  .replace(/>\\s+</g, "><")

  .replace(/<trn-custom-data\[^>\]\*\\/>/g, "");



try {

  const parser = new DOMParser();

  const xmlDoc = parser.parseFromString(xfdfString, "application/xml");



  // Check if there were any errors while parsing XML

  const parseError = xmlDoc.getElementsByTagName("parsererror");

  if (parseError.length > 0) {

    return;

  }



  // Serialize the XML document back to a string after modifications

  const serializer = new XMLSerializer();

  let updatedXmlString = serializer.serializeToString(xmlDoc);



  // Ensure that the XFDF string is still valid (check if necessary)

  // For example, replace quotes in \`trn-custom-data\` bytes attribute if still required

  updatedXmlString = updatedXmlString.replace(

    /(<trn-custom-data bytes=")(.\*?)(" \\/>)/g,

    (match, p1, p2, p3) => \`${p1}${p2.replace(/"/g, "&quot;")}${p3}\`

  );



  // Import the updated annotation data

  await annotManager.importAnnotations(updatedXmlString);

} catch (error) {

  return error;

}

});

Thanks & Regards

It looks like there is an issue regarding copying the exported XFDF data from the console (chrome), and the JSON becomes malformed in the process causing the import issue.

I recommend not altering the XFDF during the import or export:
for import - to keep the measurement captions.
for export - to keep the annotation XFDF data exactly as-is.

best regards,
Kevin

Hi @kkim

If we export the XFDF without modifying it (i.e., without removing the trn-custom-data), the resulting PDF does not display any measurement annotations. However, if we remove the trn-custom-data, the annotations do appear in the PDF, but the measurement units are overlapped at the last drawn measurement index.

Regarding your concern about storing the annotation XFDF string, we are persisting it exactly as received from annotManager.exportAnnotations function, without any transformation or filtering.

We require a definitive solution that ensures:

- The annotations are rendered correctly in the exported PDF.

- The measurement data is preserved accurately without any overlap issues.

- No manual alteration of the XFDF (such as removing trn-custom-data) is necessary.

Please provide guidance on the correct export or processing approach to achieve consistent and accurate annotation rendering.

Thanks & Regards

Hi there,

Using localStorage to export/import the annotation data, I can bring measurement annotations back into the viewer without any issues.
Please see this video for reference, where I use only exportAnnotations & importAnnotations API:
Screen Recording 2025-12-10 at 4.31.13 PM.mov

best regards,
Kevin