• Fixed support for outline items that have PDF 1.1-style named destinations. #258, #261

  • We now issue a warning if an unnecessary password was provided when opening an unencrypted PDF.


  • Fixed errors that occurred on import pikepdf for an extension module built with pybind11 2.8.0.


  • Extraction of common inline image file formats is now supported.

  • Some refactoring and documentation improvements.


Breaking changes

  • libqpdf 10.3.1 is now required and other requirements were adjusted.

  • pybind11 2.7.1 is now required.

  • Improved page API. Pdf.pages now returns Page instead of page object dictionaries, so it is no longer necessary to wrap page objects as in the previous idiom page = Page(pdf.pages[0]). In most cases, if you use the Dictionary object API on a page, it will automatically do the right thing to the underlying dictionary.

  • Improved content stream API. parse_content_stream now returns a list of pikepdf.ContentStreamInstruction or pikepdf.ContentStreamInlineImage. These are “duck type”-compatible with the previous data structure but may affect code that strongly depended on the return types. unparse_content_stream still accepts the same inputs.

  • TokenType.name and ObjectType.name were renamed to TokenType.name_ and ObjectType.name_, respectively. Unfortunately, Python’s Enum class (of which these are both a subclass) uses the .name attribute in a special way that interfered.

  • Deprecated or private functions were removed: - Object.page_contents_* (use Page.contents_*) - Object.images (use Page.images) - Page._attach (use the new attachment API) - Stream(obj=) (deprecated obj parameter removed) - Pdf.root (use Pdf.Root) - Pdf._process (use Pdf.open(BytesIO(...)) instead)

  • pikepdf.Page.calc_form_xobject_placement() previously returned str when it should have returned bytes. It now returns the correct type.

  • pikepdf.open() and pikepdf.save(), and their counterparts in pikepdf.Pdf, now expect keyword arguments for all except the first parameter.

  • Some other functions have stricter typing, required keyword arguments, etc., for clarity.

  • If a calculating the repr() of a page, we now describe a reference to that page rather than printing the page’s representation. This makes the output of repr(obj) more useful when examining data structures that reference many pages, such as /Outlines.

  • Build scripts and wheel building updated.

  • We now internally use a different API call to close a PDF in libqpdf. This may change the behavior of attempts to manipulate a PDF after it has been closed. In any case, accessing a closed file was never supported.

New functionality

  • Added pikepdf.NameTree. We now bind to QPDF’s Name Tree API, for manipulating these complex and important data structures.

  • We now support adding and removing PDF attachments. #209

  • Improved support for PDF images that use special printer colorspaces such as DeviceN and Separation, and support extracting more types of images. #237

  • Improved error message when Pdf.save() is called on PDFs without a known source file.

  • Many documentation fixes to StreamParser, return types, PdfImage.

  • x in pikepdf.Array() is now supported; previously this construct raised a TypeError. #232

  • It is now possible to test our cibuildwheel configuration on a local machine.


  • repr(pikepdf.Stream(...)) now returns syntax matching what the constructor expects.

  • Fixed certain wrong exception types that occurred when attempting to extract special printer colorspace images.

  • Lots of typing fixes.