Issue with annotationManager.importAnnotations() and measurement captions

Product: @pdftron/webviewer npm package
Product Version: 8.11.0-20230102

I have a React application that stores annotations in XFDF string format in a database. The strings originate from annotationManager.exportAnnotation calls and I never touch the strings manually.

My application uses documentViewer.addEventListener('documentLoaded', () => { ... }) as the trigger for loading annotations into my instance of the WebViewer UI.

As part of that event handler, I want to provide a number of annotations in XFDF string format to annotationManager.importAnnotations. I have an array of strings where each string represents an annotation in XFDF format, and the two approaches that I have tried so far are these:

  • loop over the array and call importAnnotations() with each individual XFDF string in sequence
  • turn all of my individual XFDF strings into one big one and provide that to a single importAnnotations() call

The result of both approaches is the same: The annotations get drawn to the UI and they are all in the proper position, however there is one snag: If any of the annotations in the list are area annotations, like rectangles, and they have a measurement caption, then all of the captions will get drawn on top of each other in the same place.

I have created a minimal reproduction of the issue that you can clone and run from here: GitHub - jpkempf/webviewer-import-annotations-bug-repro: A minimal reproduction of a bug with annotationManager.importAnnotations

Any advice on how to circumvent this issue is appreciated. Thanks!

Hi Jan,

Thank you for reporting this issue. We will investigate and let you know what we find.

Best Regards,
Ahmad Moaaz
Software Developer
Apryse

Hello jan-philipp.kempf,

I ran the sample project and saw the caption you are seeing,
I did notice you aren’t using await before importAnnotations , can you try adding this before importAnnotations and exportAnnotations? both are asynchronous functions.

Best regards,
Tyler Gordon

Hi Ahmad, hi Tyler, thanks for the responses!

I’ve just pushed a small change to my example repo that adds the async and await keywords, but as you’ll see it makes no difference for the result. This is to be expected, since the entire drawing process is an internal side effect of importAnnotations and the return value never matter unless I’d want to modify the annotations after drawing them.

I could understand that in the case of option #1, where I’m looping over a list of XFDF strings, the bug might get triggered by not awaiting each individual draw step, but since the same bug also appears when providing a single combined XFDF string, that leads me to believe the issue is with the internal logic of importAnnotations.

Looking forward to what you can find out and happy to assist further if i can. :slight_smile:

Hello jan-phillipp.kempf,

Ah yes the await doesnt work on the import, have you tried with the export?

Can you provide steps to reproduce this issue with the XFDF? ie how you generated the XFDF?

Best regards,
Tyler Gordon
Apryse

Hi Tyler,

Ah yes the await doesnt work on the import, have you tried with the export?

I’m confident the problem lies with importing and drawing annotations and not faulty export data. The exported XFDF strings are fine, as you can confirm by drawing any one of them individually. I’ve just pushed another update to my example repo that lets you easily “switch” between which individual annotation(s) you want to draw.

The XFDF strings in my example are real strings copied from my actual app. They are the result of calling annotationManager.exportAnnotations in different scenarios:

  • inside of annotationChanged event listeners, where the annotation objects I provide to the export method are from the arguments the event listener is called with
  • as part of custom application logic, where the annotation objects are return values from annotationManager.getAnnotationById

In both cases I never fiddle with the annotation data; it is 100% the way I receive it from the annotation manager. And yes, in all cases where I am using exportAnnotations in my code, I am using await since otherwise I wouldn’t be able to do anything useful with the return value. :wink:

Hi all, is there anything new that you are able share about this yet? :innocent:

Hello jan-phillipp.kempf

I have attached the code and XFDF of area annotations that I have generated + the code to import them all in a loop as you have where no issue occurs.
test.txt (57.7 KB)

I think the next steps here are getting exactly how this XFDF was generated, ie exact steps to generate the XFDF

Best regards,
Tyler Gordon

Thanks, I’ll take a look at that! I agree, if you are able to demonstrate a working version of this flow then that changes things. I’ll test this and see what hints it might give me about my own situation.

Hi, and my apologies for the long radio silence. I’ve finally gotten around to testing the example code you’ve provided and I can confirm that they do seem to render better than the ones that I’m using! They work fine when I draw them using a loop and equally fine when I draw each one individually.

Of the three provided XFDF strings, I can only see two resulting annotations when I draw them to the plan from my example repo; two of them are barely in the viewport but I can select and drag them over. The third one might just be too far off-canvas for me to see or select it. When I do drag them over, I can see that each of the two annotations have their area displayed correctly in the center of each respective rectangle.

When I compare your XFDF strings to mine, the main difference I notice is that yours are much, much larger. Especially the <appearance> tag, which is enormously long. Although I also tried what happens when I remove that tag and it did not seem to have any adverse effect on the output at all.

Aside from appearance, I looked at the remaining differences:

  • pdf-info → can apparently be removed with no effect
  • fields → same, can be removed
  • pages and child elements of that → ditto
  • trn-custom-data contains an object trn-measurement-caption-options which is missing from my own XFDF strings

If I remove the trn-measurement-caption-options object, or replace the entire trn-custom-data block with the one from my own XFDF strings, then none of your example annotations render any more. Since this seems to be the only significant difference between your examples and mine, I have to assume that this is the source of the issue.

On the other hand, when I completely replace the trn-custom-data block in my examples with the ones from yours, then all of my annotations render without any area captions at all.

So my question is: How exactly did you create these XFDF strings? What can I do to make sure the caption options are there for me as well? As I stated earlier, I am not doing anything fancy; just using the standard annotationManager.exportAnnotation method inside of an annotationChanged event listener. Should I perhaps explicitly configure global options for captions when I initialize WebViewer somehow, or anything else like that?

Hello jan-philip.kempf

This could be because you haven’t enabled measurements in the WebViewer constructor. You can do so with:

WebViewer({
...
enableMeasurements: true,
...
})

Best regards,
Tyler

Are you sure you mean enableMeasurements and not enableMeasurement? The latter I do have in my config; the former I get a type error for when I try adding it. And even if I just ignore the error, this does not fix the issue for me.

Hello jan-philipp.kempf,

My apologies, I misread and confused myself.

The tag is sort of like an image that is generated for the annotation, since some viewers do not handle the measurements correctly, an appearance is generated to make the annotation appear correct in the viewers.

I generated my XFDF through exportAnnotations as well.

We highly suggest not manually modifying XFDF as it can cause it to not be spec. I’ll pass this to our development team to investigate this as a bug, seems like it could be an issue with how we are generating our caption rect.

Thank you for your patience!

Best regards
Tyler Gordon

Believe me, I am definitely not keen on manually editing XFDF strings :sweat_smile: I wonder what the difference is between your setup and mine that makes this work for you and fail for me. I appreciate you passing this to the dev team—if I can give any further input, let me know.