Pdf-lib: How to get Annots from pdf

Created on 27 Feb 2019  ·  10Comments  ·  Source: Hopding/pdf-lib

Hi @Hopding ,
I want know how to get the annotations from pdf ?

Most helpful comment

The lib has been updated and this code doesn't work any longer :(

All 10 comments

Relate of #39

Hello @wuqi713.

There isn't currently a nice high-level API to get all the annotation from a PDF. But you can certainly still do it with pdf-lib. The code is just a bit low-level.

Essentially, to find all the annotations in a document, you'll have to visit each page and look at its Annots entry (which is an array of references to Annotation Dictionaries). I can write up an example script demonstrating how to do this, if you're able to provide me with a sample PDF that has some annotations in it.


If you're interested, here's the relevant section from the PDF specification describing how Annotation Dictionaries are stored in PDF documents:

12.5.2 Annotation Dictionaries
The optional Annots entry in a page object (see 7.7.3, “Page Tree”) holds an array of annotation dictionaries, each representing an annotation associated with the given page. Table 164 shows the required and optional entries that are common to all annotation dictionaries. The dictionary may contain additional entries specific to a particular annotation type; see the descriptions of individual annotation types in 12.5.6, “Annotation Types,” for details. A given annotation dictionary shall be referenced from the Annots array of only one page. This requirement applies only to the annotation dictionary itself, not to subsidiary objects, which may be shared among multiple annotations.

I'm going to close this issue for now. But please feel free to reopen it if you have more questions!

Hi @Hopding,
I would like to ask you to provide code for getting annotations from PDF document. I have attached the document with some annotations.
t.pdf

Hello @fortrenitalia!

Here's an example script demonstrating how to load a PDF and print out all the annotations it contains:

// These are *all* possible PDF annotation types
const annotationSubtypes = [
  PDFName.from('Text'),
  PDFName.from('Link'),
  PDFName.from('FreeText'),
  PDFName.from('Line'),
  PDFName.from('Square'),
  PDFName.from('Circle'),
  PDFName.from('Polygon'),
  PDFName.from('PolyLine'),
  PDFName.from('Highlight'),
  PDFName.from('Underline'),
  PDFName.from('Squiggly'),
  PDFName.from('StrikeOut'),
  PDFName.from('Stamp'),
  PDFName.from('Caret'),
  PDFName.from('Ink'),
  PDFName.from('Popup'),
  PDFName.from('FileAttachment'),
  PDFName.from('Sound'),
  PDFName.from('Movie'),
  PDFName.from('Widget'),
  PDFName.from('Screen'),
  PDFName.from('PrinterMark'),
  PDFName.from('TrapNet'),
  PDFName.from('Watermark'),
  PDFName.from('3D'),
  PDFName.from('Redact'),
];

// Load a PDF
const pdfDoc = PDFDocumentFactory.load(...);

// Get an array of all the objects in the PDF
const objects = Array.from(pdfDoc.index.index.entries());

// Print out all the annotations in the PDF
objects.forEach(([ref, object]) => {
  const subtype = object.getMaybe('Subtype');
  if (
    object instanceof PDFDictionary &&
    annotationSubtypes.includes(subtype)
  ) {
    console.log(`Found annotation (${ref}) of type: ${subtype}`);
    console.log('----------------------------------');
    console.log(object.toString());
    console.log('----------------------------------');
    console.log();
    console.log();
  }
});

When run on the PDF you provided, it outputs the following:

Found annotation (149 0 R) of type: /Text
----------------------------------
<<
/AP <<
/N 128 0 R
/R 129 0 R
>>
/C [ 1 0.819611 0 ]
/Contents (test)
/CreationDate (D:20190628095759+02'00')
/F 28
/M (D:20190628095806+02'00')
/NM (c174acef-700d-450e-886f-4e18afe2d43e)
/Name /Comment
/P 127 0 R
/Popup 150 0 R
/RC (<?xml version="1.0"?><body xmlns="http://www.w3.org/1999/xhtml" xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/" xfa:APIVersion="Acrobat:19.12.0" xfa:spec="2.0.2" ><p dir="ltr"><span dir="ltr" styweight:normal;font-style:normal">test</span></p></body>)\
/Rect [ 171.998 733.619 195.998 757.619 ]
/Subj (Sticky Note)
/Subtype /Text
/T (miculka)
/Type /Annot
>>
----------------------------------


Found annotation (150 0 R) of type: /Popup
----------------------------------
<<
/F 28
/Open false
/Parent 149 0 R
/Rect [ 595.32 643.619 799.32 757.619 ]
/Subtype /Popup
/Type /Annot
>>
----------------------------------


Found annotation (151 0 R) of type: /Text
----------------------------------
<<
/AP <<
/N 128 0 R
/R 129 0 R
>>
/C [ 1 0.819611 0 ]
/Contents (test2)
/CreationDate (D:20190628095813+02'00')
/F 28
/IRT 149 0 R
/M (D:20190628095813+02'00')
/NM (a865be06-8593-4035-8383-fc38bf15024c)
/Name /Comment
/P 127 0 R
/Popup 152 0 R
/RC (<?xml version="1.0"?><body xmlns="http://www.w3.org/1999/xhtml" xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/" xfa:APIVersion="Acrobat:19.12.0" xfa:spec="2.0.2" ><p dir="ltr"><span dir="ltr" styweight:normal;font-style:normal">test2</span></p></body>)
/Rect [ 171.998 733.619 195.998 757.619 ]
/Subj (Sticky Note)
/Subtype /Text
/T (miculka)
/Type /Annot
>>
----------------------------------


Found annotation (152 0 R) of type: /Popup
----------------------------------
<<
/F 28
/Open false
/Parent 151 0 R
/Rect [ 595.32 643.619 799.32 757.619 ]
/Subtype /Popup
/Type /Annot
>>
----------------------------------


Found annotation (153 0 R) of type: /Highlight
----------------------------------
<<
/AP <<
/N 130 0 R
>>
/C [ 1 0.819611 0 ]
/CA 0.399994
/CreationDate (D:20190628095817+02'00')
/F 4
/M (D:20190628095817+02'00')
/NM (f7a566ea-a03a-49e0-bea4-0bff70babdbd)
/P 127 0 R
/Popup 154 0 R
/QuadPoints [ 88.1014 574.51 322.148 574.51 88.1014 563.47 322.148 563.47 ]
/Rect [ 85.1542 563.125 325.096 574.855 ]
/Subj (Highlight)
/Subtype /Highlight
/T (miculka)
/Type /Annot
>>
----------------------------------


Found annotation (154 0 R) of type: /Popup
----------------------------------
<<
/F 28
/Open false
/Parent 153 0 R
/Rect [ 595.32 460.51 799.32 574.51 ]
/Subtype /Popup
/Type /Annot
>>
----------------------------------


Found annotation (155 0 R) of type: /Highlight
----------------------------------
<<
/AP <<
/N 133 0 R
>>
/C [ 1 0.819611 0 ]
/CA 0.399994
/CreationDate (D:20190628095819+02'00')
/F 4
/M (D:20190628095819+02'00')
/NM (76eef8d3-acdb-4a2c-866e-83725949a862)
/P 127 0 R
/Popup 156 0 R
/QuadPoints [ 196.051 560.11 284.768 560.11 196.051 549.07 284.768 549.07 ]
/Rect [ 193.104 548.725 287.715 560.455 ]
/Subj (Highlight)
/Subtype /Highlight
/T (miculka)
/Type /Annot
>>
----------------------------------


Found annotation (156 0 R) of type: /Popup
----------------------------------
<<
/F 28
/Open false
/Parent 155 0 R
/Rect [ 595.32 446.11 799.32 560.11 ]
/Subtype /Popup
/Type /Annot
>>
----------------------------------


Found annotation (17 0 R) of type: /Text
----------------------------------
<<
/AP <<
/N 128 0 R
/R 129 0 R
>>
/C [ 1 0.819611 0 ]
/Contents (aaa)
/CreationDate (D:20190628095914+02'00')
/F 28
/M (D:20190628095919+02'00')
/NM (ffec35f8-b929-45b6-9b59-3fd7c33be79d)
/Name /Comment
/P 1 0 R
/Popup 18 0 R
/RC (<?xml version="1.0"?><body xmlns="http://www.w3.org/1999/xhtml" xmlns:xfa="http://www.xfa.org/schema/xfa-data/1.0/" xfa:APIVersion="Acrobat:19.12.0" xfa:spec="2.0.2" ><p dir="ltr"><span dir="ltr" styweight:normal;font-style:normal">aaa</span></p></body>)-\
/Rect [ 329.562 610.625 353.562 634.625 ]
/Subj (Sticky Note)
/Subtype /Text
/T (miculka)
/Type /Annot
>>
----------------------------------


Found annotation (18 0 R) of type: /Popup
----------------------------------
<<
/F 28
/Open false
/Parent 17 0 R
/Rect [ 595.32 520.625 799.32 634.625 ]
/Subtype /Popup
/Type /Annot
>>
----------------------------------

I hope this helps. Please let me know if you have any additional questions!

(P.S. My apologies for the late reply. I've been working on the v1.0.0 release of pdf-lib.)

Hi @Hopding ,
thank you very much, it works perfectly.

But I have one more question. How can I get page number for each annotation?

I tried to get annotations per page:

```
//Load a PDF
const pdfDoc = PDFDocumentFactory.load(...);

const page1 = pdfDoc.getPages()[0];

// Get an array of all the objects in the PDF
const objects = Array.from(page1.index.index.entries());
```

But it always returns annotations from entire document (not only from provided page).

@fortrenitalia Here's a script that prints out annotations per-page:

const fs = require('fs');
const { PDFDocumentFactory } = require('pdf-lib');

// Load a PDF
const pdfDoc = PDFDocumentFactory.load(fs.readFileSync('./with_annots.pdf'));

// Print out the annotations per page
const pages = pdfDoc.getPages();
pages.forEach((page, idx) => {
  const pageAnnotRefs = pdfDoc.index.lookupMaybe(page.getMaybe('Annots'));
  if (pageAnnotRefs) {
    pageAnnotRefs.forEach(annotRef => {
      const annot = pdfDoc.index.lookup(annotRef);
      const subtype = annot.get('Subtype');
      console.log(
        `Found annotation (${annotRef}) of type ${subtype} on page ${idx}`,
      );
      console.log('----------------------------------');
      console.log(annot.toString());
      console.log('----------------------------------');
      console.log();
      console.log();
    });
  }
});

This is exactly what I need. Thank you very much

The lib has been updated and this code doesn't work any longer :(

Hi @Hopding

I have one more question. I can't get page number different first page.

const widget = pdf.ref({
    Type: 'Annot',
    Subtype: 'Widget',
    FT: 'Sig',
    Rect: [100, 200, 150, 250],
    V: signature,
    T: new String('Signature'),
    F: 4,
    P: pdf.page.dictionary, 
  });
  pdf.page.dictionary.data.Annots = [widget]; 

Thanks you!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

fatso83 picture fatso83  ·  3Comments

ihmc3jn09hk picture ihmc3jn09hk  ·  4Comments

sdfereday picture sdfereday  ·  4Comments

nachum37 picture nachum37  ·  3Comments

emilsedgh picture emilsedgh  ·  5Comments