Skip to content

Tutorials or better demos to manipulate annotations #107

@ubuntuslave

Description

@ubuntuslave

edit by Martin to show the current state:

Number of files with at least one annotations in my big dataset:

✔️ /Link: 2694x
❌ /Widget: 431x - #1207
✔️ /Popup: 189x - #1198 - now #1665
✔️ /FreeText: 85x
✔️ /Text: 77x
✔️ /Square: 47x - #1388
/Stamp: 40x
✔️ /Line: 22x
/DGAP:RedaxBox: 3x
✔️ /Circle: 2x - #1556
/FileAttachment: 2x - don' confuse it with /EmbeddedFiles
/Ink: 1x - https://pyfpdf.github.io/fpdf2/Annotations.html#ink-annotations
/Caret: 1x
✔️ /Polygon - #1557
✔️ /PolyLine - see #1726

Text markup annotations:
✔️ /Highlight: 22x - https://stackoverflow.com/q/9099497/562769 - see #1740
/StrikeOut: 2x
/Underline: 2x


Original post:

I'm trying to understand how PyPDF2 works with existing annotation objects, such as highlights, and Popups. The demos provided don't show how to _add_ new DictionaryObjects to the current list of annotations. I believe my problem resides around not having a way to obtain (find out) idnum for the new object that it's needed by its parent's to refer to. Here is what I've been doing so far... (To be honest, I gave up looking at the code inside pdf.py and generic.py because it's taking too long at the moment)

from typing import cast

from PyPDF2 import PdfReader, PdfWriter
from PyPDF2.generic import ArrayObject

writer = PdfWriter()
reader = PdfReader("commented.pdf")

# print how many pages input1 has:
print(f"document1.pdf has {len(reader.pages)} pages.")

# add page 1 from input1 to output document, unchanged
page = reader.pages[0]

annots = cast(ArrayObject, page["/Annots"])
annot0 = annots[0].getObject()
annot1 = annots[1].getObject()
annot2 = annots[2].getObject()
annot3 = annots[3].getObject()
annot4 = annots[4].getObject()

# TEST: changing postition of the Popup's rectangle (Works!)
from PyPDF2.generic import *

popup_size = (180, 120)

rect = RectangleObject(annot0["/Rect"])
rect_x0 = rect.left
rect_y0 = rect.top
annot2.update(
    {
        NameObject("/Open"): BooleanObject(False),
        NameObject("/Rect"): RectangleObject(
            [rect_x0, rect_y0, rect_x0 + popup_size[0], rect_y0 + popup_size[1]]
        ),
    }
)

# Test make new Popup Annotation
rect = RectangleObject(annot1["/Rect"])
rect_x0 = rect.left
rect_y0 = rect.top

popup = DictionaryObject()
popup.update(
    {
        NameObject("/Type"): NameObject("/Annot"),
        NameObject("/Subtype"): NameObject("/Popup"),
        NameObject("/Parent"): IndirectObject(
            15, 0, reader
        ),  # TODO: How to find the parent's idnum? Manually: this is 15 for this object
        NameObject("/Open"): BooleanObject(False),
        NameObject("/Rect"): RectangleObject(
            [rect_x0, rect_y0, rect_x0 + popup_size[0], rect_y0 + popup_size[1]]
        ),
        NameObject("/F"): NumberObject(28),  # The type of object? A popup?
    }
)

popup_ref = writer._add_object(popup)

if "/Annots" in page:
    page["/Annots"].append(popup_ref)
else:
    page[NameObject("/Annots")] = ArrayObject([popup_ref])

# Adding the reference to its new popup:
annot1.update(
    {NameObject("/Popup"): popup_ref}  # TODO: put the number for the new reference
)

annots_ref = writer._add_object(annots)

writer.add_page(page)  # FIXME: not adding the new Popup annotation
# finally, write "output" to document-output.pdf
with open("PyPDF2-output.pdf", "wb") as fp:
    writer.write(fp)

P.S: My motivation for this little script is to give it to users of docear since mind-mapping of highlights requires retroactively adding missing popups to highlight annotations (in adobe acrobat) like the proprietary program done by this guy.

Metadata

Metadata

Assignees

No one assigned

    Labels

    is-maintenanceAnything that is just internal: Simplifying code, syntax changes, updating docs, speed improvementsnf-documentationNon-functional change: Documentation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions