downloadPdf question

WebViewer Version:8

Do you have an issue with a specific file(s)? no
Can you reproduce using one of our samples or online demos?
Are you using the WebViewer server? no
Does the issue only happen on certain browsers? idk
Is your issue related to a front-end framework? React
Is your issue related to annotations?

Please give a brief summary of your issue:
Downloading PDF with annotation to local computer.

Please describe your issue and provide steps to reproduce it:
The API documentation says that the dowloadPdf
‘Downloads the pdf document with or without annotations added by WebViewer UI.’ and this does work.
https://docs.apryse.com/api/web/UI.html#.downloadPdf

However I am adding annotations programmatically, using annotation manager. I am able to get the xdxf data, but my annotations are not being merged in. Is there some nuance that I’m missing?

Thanks
Dave

Please provide a link to a minimal sample where the issue is reproducible:

I think my fundamental question is, can I use downloadPdf to save a file locally along with annotations that were added programatically? While the link that i reference about indicates those created by WebviewUI, other references in various pages are more ambiguous, including the description of this paramatet includeAnnotations
https://docs.apryse.com/api/web/UI.html#downloadPdf__anchor

Hello dcheli,

This should be doable. I have an example showing how to import annotations through XFDF and then download the PDF with the annotations available here:

Webviewer({
  initialDoc: hashFile,
  path: '/lib',
}, document.getElementById('viewer')).then(instance => {
  const { docViewer, annotManager } = instance;

  const xfdfStringOne = `<?xml version="1.0" encoding="UTF-8"?>
      <xfdf xmlns="http://ns.adobe.com/xfdf/" xml:space="preserve">
        <pdf-info xmlns="http://www.pdftron.com/pdfinfo" version="2" import-version="3" />
        <fields />
        <annots>
          <square page="0" rect="113.09,544.88,218.85,631.79" color="#4E7DE9" flags="print" name="f3b649c8-bcbc-1388-e976-350de25afc36" title="Guest" subject="Rectangle" date="D:20210611132758-07'00'" interior-color="#FFE6A2" width="6.9864055826723614" creationdate="D:20210611132757-07'00'" />
          <square page="0" rect="121.47,387.81,235.6,481.01" color="#4E7DE9" flags="print" name="81ee1f0a-4b2d-d162-0e9e-adfc4a4bb0fb" title="Guest" subject="Rectangle" date="D:20210611132811-07'00'" interior-color="#FFE6A2" width="6.9864055826723614" creationdate="D:20210611132800-07'00'" inreplyto="f3b649c8-bcbc-1388-e976-350de25afc36" replyType="group" />
        </annots>
        <pages>
          <defmtx matrix="1,0,0,-1,0,792" />
        </pages>
      </xfdf>`;

  docViewer.addEventListener('documentLoaded', async () => {
    annotManager.importAnnotations(xfdfStringOne);

    await instance.UI.downloadPdf();
  });
});

Maybe you can try something similar? If you are still having issues with this, it could be helpful if you can provide a code sample showing what you are doing so that we can try to help troubleshoot.

Best Regards,

Carlo Mendoza
Web Developer
Apryse

Carlo, thanks for the response. Here 2 ways that I’ve tried to do this based on this page

Option 1

`					const document = documentViewer?.getDocument();
					const xfdfString = await annotManager!.exportAnnotations();
					const data = await document!.getFileData({
						// saves the document with annotations in it
						xfdfString,
					});
					const arr = new Uint8Array(data);
					const blob = new Blob([arr], { type: 'application/pdf' });

					saveAs(blob, filename);`

Option 2:

` const document = documentViewer?.getDocument();
const xfdfString = await annotManager!.exportAnnotations();

				const options = {
					filename: filename,
					xfdfString: xfdfString,
					flags: instanceRef.current?.Core.SaveOptions.LINEARIZED,
					downloadType: 'pdf',
					useDisplayAuthor: true,
				};

				await instanceRef.current?.UI.downloadPdf(options);`

Here is info that is of interest:

  1. if I add annotations through Webviewer UI, the annotations are included.
  2. if I add annotations programatically, the annotations are not included.
  3. in both cases, I am getting the annotation data in the xdsfString, yet annotations are not inlcuded when they are added programatically.

Dave

Hello dcheli,

Would you be able to share how you are adding the annotations programatically?

Best Regards,

Carlo Mendoza
Web Developer
Apryse

This is the setup in my useEffect

	const approvedAnnot = new Annotations.FreeTextAnnotation(undefined, {
			Id: 'ilr-approve',
			PageNumber: 1,
			Y: 720,
			X: 150,
			Width: 300,
			Height: 10,
			FillColor: new Annotations.Color(255, 255, 255),
			TextColor: new Annotations.Color(0, 0, 0), // black, default is red
			FontSize: '6pt',
			ReadOnly: true,
			StrokeThickness: 0, // border thickness
			Hidden: true,
			NoResize: true,
			NoRotate: true,
			NoMove: true,
			Printable: true,
		});
		approvedAnnot.elementName = 'ilr-approve'; // this property cannot be set during the initialization above

		annotationManager.addAnnotation(approvedAnnot);
This is my code block to update it

		if (annotationList) {
			const { reportType, msg, author, dateTime } = workflowObj;
			annotationList.forEach(async (annotation) => {
				if (reportType.toLowerCase() === annotation.elementName.toLowerCase()) {
					selectedAnnotation = annotation;
					selectedAnnotation.setContents(msg);
					selectedAnnotation.Author = author;
					selectedAnnotation.DateModified = new Date(dateTime as string);
					selectedAnnotation.Hidden = false;
					// now you need the annotationManager
					if (!annotManager) alert('no annotManager');
					annotManager!.redrawAnnotation(selectedAnnotation);
				}
			});

This is my xfdf

<?xml version="1.0" encoding="UTF-8" ?><xfdf xmlns="http://ns.adobe.com/xfdf/" xml:space="preserve"><pdf-info xmlns="http://www.pdftron.com/pdfinfo" version="2" import-version="4" /><fields /><annots><ilr-approve page="0" rect="150,62,450,72" color="#FFFFFF" flags="print,norotate,readonly" name="ilr-approve" title="Dave" subject="annotation.freetext" date="D:20230221152656-07'00'" width="0" creationdate="D:20230221152639-07'00'" TextColor="#000000" FontSize="6"><trn-custom-data bytes="{&quot;trn-annot-no-resize&quot;:&quot;true&quot;,&quot;trn-annot-no-move&quot;:&quot;true&quot;,&quot;trn-wrapped-text-lines&quot;:&quot;[\&quot;Document Approved by Dr. Dave Cheli on 2023-02-21T22:26:56.916Z \&quot;]&quot;}"/><contents>Document Approved by Dr. Dave Cheli on 2023-02-21T22:26:56.916Z</contents><defaultappearance>0 0 0 rg /Helvetica 6 Tf</defaultappearance><defaultstyle>font: Helvetica 6pt; text-align: left; text-vertical-align: top; color: #000000</defaultstyle></ilr-approve><ilr-comments page="0" rect="32,84.963,587,154.963" color="#FFFFFF" flags="print,norotate,readonly" name="ilr-comments" title="Dave" subject="annotation.freetext" date="D:20230221152656-07'00'" width="0" creationdate="D:20230221152639-07'00'" TextColor="#000000" FontSize="8"><trn-custom-data bytes="{&quot;trn-annot-no-resize&quot;:&quot;true&quot;,&quot;trn-annot-no-move&quot;:&quot;true&quot;,&quot;trn-wrapped-text-lines&quot;:&quot;[\&quot;This is an annotation added programatically \&quot;]&quot;}"/><contents>This is an annotation added programatically</contents><defaultappearance>0 0 0 rg /Helvetica 8 Tf</defaultappearance><defaultstyle>font: Helvetica 8pt; text-align: left; text-vertical-align: top; color: #000000</defaultstyle></ilr-comments></annots><pages><defmtx matrix="1,0,0,-1,0,792" /><pgmtx matrix="1,0,0,-1,0,791" page="1" /><pgmtx matrix="1,0,0,-1,0,791" page="2" /><pgmtx matrix="1,0,0,-1,0,791" page="3" /><pgmtx matrix="1,0,0,-1,0,791" page="4" /><pgmtx matrix="1,0,0,-1,0,791" page="5" /><pgmtx matrix="1,0,0,-1,0,791" page="6" /><pgmtx 

Hello dcheli,

Thank you for the additional details. I think the issue might have something to do with how you are setting the elementName property in this line:

approvedAnnot.elementName = 'ilr-approve'; // this property cannot be set during the initialization above

I was able to save the annotation by changing this line to use setCustomData() to save the ‘elementName’ in the XFDF and later use getCustomData to retrieve it and set the element name as content using the code below which is similar to yours:

Webviewer({
  initialDoc: './blank.pdf',
  path: '/lib',
}, document.getElementById('viewer')).then(instance => {
  const { docViewer, annotManager, Annotations } = instance;

  const approvedAnnot = new Annotations.FreeTextAnnotation(undefined, {
    Id: 'ilr-approve',
    PageNumber: 1,
    Y: 720,
    X: 150,
    Width: 300,
    Height: 10,
    FillColor: new Annotations.Color(255, 255, 255),
    TextColor: new Annotations.Color(0, 0, 0), // black, default is red
    FontSize: '6pt',
    ReadOnly: true,
    StrokeThickness: 0, // border thickness
    Hidden: true,
    NoResize: true,
    NoRotate: true,
    NoMove: true,
    Printable: true,
  });
  approvedAnnot.setCustomData('elementName', 'ilr-approve');

  annotManager.addAnnotation(approvedAnnot);

  const annotationList = annotManager.getAnnotationsList();

  if (annotationList) {
    annotationList.forEach(async (annotation) => {
      selectedAnnotation = annotation;
      selectedAnnotation.setContents(annotation.getCustomData('elementName'));
      selectedAnnotation.Author = annotation.author;
      selectedAnnotation.DateModified = new Date();
      selectedAnnotation.Hidden = false;
      // now you need the annotationManager
      if (!annotManager) alert('no annotManager');
      annotManager.redrawAnnotation(selectedAnnotation);
    });
  };

  docViewer.addEventListener('annotationsLoaded', async () => {
    const xfdfString = await annotManager.exportAnnotations();

    const options = {
      filename: 'annotSaveTest',
      xfdfString: xfdfString,
      flags: instance.Core.SaveOptions.LINEARIZED,
      downloadType: 'pdf',
      useDisplayAuthor: true,
    };

    await instance.UI.downloadPdf(options);
  });

We have a guide available on saving and loading custom properties (like elementName in this case) here: Apryse Documentation | Documentation. Would you be able to try this and see if it works?

Best Regards,

Carlo Mendoza
Web Developer
Apryse

Carlo,
That didn’t seem to work for me, though your success is promising for me and at least indicates that it should work; so I will need to look closer into this and the page you recommend.

What isn’t clear to me though is why elementName would potentially be a problem, since I understand this as just a property of naming an annotation. Also, it’s not clear to me why setContent(), would work for you with getCustomData, rather then just setting the content with a string as I’m doing.

I assume that I am correct in that what is placed in setContent() is what is supposed to be downloaded/merged into the pdf, is that correct?

An interesting, unexpected effect of removing elementName and replacing that with setCustomData() was that my annotations no longer displayed on the screen. When I added elementName, they appeared again.

I’ll look closer at this today and get back to you, thanks for the suggestions.

Carlo, I did get this resolved. The problem was related to my assigning a value to elementName, as you suspected.

myAnnot.elementName =  'ilr-approve';

In comparing the xfdf between programmatically added annotations vs webViewer UI added annotations, I noticed that the annotations I added, despite appearing in the tag , were not being being included in the downloadPDF() call. See xfdf snippet below:

<annots>
	<ilr-approve ... >	// elementName that I added
		<contents>My added Content</contents>	
	</ilr-approve>
	
	<freetext  ...>		// elementName webViewer UI added
		<contents> My added Content	</contents>
	</freetext>
</annots>

A few other things:

  1. I didn’t need to use set/getCustomData in the setContents call.
  2. I did use setCustomData though in place of elementName as you suggested to help me name my annotations
  3. I would never have thought that using the elementName property would have caused this, I’m not really sure of it’s purpose.
  4. Also, I would have assumed that any annotations included in the annots section of the xfdf would have been merged into the downloaded PDF.

Thanks for your help with this.
Dave