Server status ...

loongson/pypi/: pypdfium2-4.16.0 metadata and description

Simple index Newer version available

Python bindings to PDFium

author pypdfium2-team
author_email geisserml <geisserml@gmail.com>
classifiers
  • Development Status :: 4 - Beta
  • Intended Audience :: Developers
  • Intended Audience :: Information Technology
  • Programming Language :: Python :: 3
  • Programming Language :: Python :: 3 :: Only
  • Programming Language :: Python :: Implementation :: CPython
  • Topic :: Multimedia :: Graphics
  • Topic :: Software Development :: Libraries
description_content_type text/markdown
keywords pdf,pdfium
license Apache-2.0 or BSD-3-Clause
project_urls
  • homepage, https://github.com/pypdfium2-team/pypdfium2
  • documentation, https://pypdfium2.readthedocs.io/
  • changelog, https://pypdfium2.readthedocs.io/en/stable/changelog.html
requires_python >=3.6
File Tox results History
pypdfium2-4.16.0-py3-none-linux_loongarch64.whl
Size
3 MB
Type
Python Wheel
Python
3

pypdfium2

Downloads

pypdfium2 is an ABI-level Python 3 binding to PDFium, a powerful and liberal-licensed library for PDF rendering, inspection, manipulation and creation.

This bindings project is built using ctypesgen and external PDFium binaries. Its custom setup infrastructure provides a seamless packaging and installation process. A wide range of platforms is supported with wheel packages.

pypdfium2 includes helpers to simplify common use cases, while the raw PDFium/ctypes API remains accessible as well.

Installation

Setup magic

As pypdfium2 uses external binaries, there are some special setup aspects to consider.

[^platform_ids]: This is mainly of internal interest for packaging, so that wheels can be crafted for any platform without access to a native host.

Runtime Dependencies

pypdfium2 does not have any mandatory runtime dependencies apart from Python and its standard library.

However, some optional support model features require additional packages:

Usage

Support model

Here are some examples of using the support model API.

Raw PDFium API

While helper classes conveniently wrap the raw PDFium API, it may still be accessed directly and is available in the namespace pypdfium2.raw. Lower-level helpers that may aid with using the raw API are provided in pypdfium2.internal.

import pypdfium2.raw as pdfium_c
import pypdfium2.internal as pdfium_i

Since PDFium is a large library, many components are not covered by helpers yet. You may seamlessly interact with the raw API while still using helpers where available. When used as ctypes function parameter, helper objects automatically resolve to the underlying raw object (but you may still access it explicitly if desired):

permission_flags = pdfium_c.FPDF_GetDocPermission(pdf.raw)  # explicit
permission_flags = pdfium_c.FPDF_GetDocPermission(pdf)      # implicit

For PDFium documentation, please look at the comments in its public header files.[^pdfium_docs] A large variety of examples on how to interface with the raw API using ctypes is already provided with support model source code. Nonetheless, the following guide may be helpful to get started with the raw API, especially for developers who are not familiar with ctypes yet.

[^pdfium_docs]: Unfortunately, no recent HTML-rendered documentation is available for PDFium at the moment.

[^bindings_decl]: From the auto-generated bindings file, which is not part of the repository. It is built into wheels, or created on installation. If you have an editable install, the bindings file may be found at src/raw.py.

Command-line Interface

pypdfium2 also ships with a simple command-line interface, providing access to key features of the support model in a shell environment (e. g. rendering, content extraction, document inspection, page rearranging, ...).

The primary motivation behind this is to have a nice testing interface, but it may be helpful in a variety of other situations as well. Usage should be largely self-explanatory, assuming a minimum of familiarity with the command-line.

Licensing

PDFium and pypdfium2 are available by the terms and conditions of either Apache-2.0 or BSD-3-Clause, at your choice. Various other open-source licenses apply to dependencies bundled with PDFium. Verbatim copies of their respective licenses are contained in the file LicenseRef-PdfiumThirdParty.txt, which also has to be shipped with binary redistributions. Documentation and examples of pypdfium2 are licensed under CC-BY-4.0.

pypdfium2 complies with the reuse standard by including SPDX headers in source files, and license information for data files in .reuse/dep5.

To the author's knowledge, pypdfium2 is one of the rare Python libraries that are capable of PDF rendering while not being covered by copyleft licenses (such as the GPL).[^liberal_pdf_renderlibs]

As of early 2023, a single developer is author and rightsholder of the code base (apart from a few minor code contributions).

[^liberal_pdf_renderlibs]: The only other liberal-licensed PDF rendering libraries known to the authors are pdf.js (JavaScript) and Apache PDFBox (Java). pdf.js is limited to a web environment. Creating Python bindings to PDFBox might be possible but there is no serious solution yet (apart from amateurish wrappers around its command-line API).

Issues

While using pypdfium2, you might encounter bugs or missing features. In this case, please file an issue report. Remember to include applicable details such as tracebacks, operating system and CPU architecture, as well as the versions of pypdfium2 and used dependencies.

In case your issue could be tracked down to a third-party dependency, we will accompany or conduct subsequent measures.

Here is a roadmap of relevant places:

Known limitations

pypdfium2 also has some drawbacks, of which you will be informed below.

Incompatibility with CPython 3.7.6 and 3.8.1

pypdfium2 built with mainstream ctypesgen cannot be used with releases 3.7.6 and 3.8.1 of the CPython interpreter due to a regression that broke ctypesgen-created string handling code.

However, we are currently making efforts to remove ctypesgen's wonky string code. Since version 4, pypdfium2 releases will be built with a patched variant of ctypesgen.

Risk of unknown object lifetime violations

As outlined in the raw API section, it is essential that Python-managed resources remain available as long as they are needed by PDFium.

The problem is that the Python interpreter may garbage collect objects with reference count zero at any time. Thus, it can happen that an unreferenced but still required object by chance stays around long enough before it is garbage collected. Such dangling objects are likely to cause non-deterministic segmentation faults. If the timeframe between reaching reference count zero and removal is sufficiently large and roughly consistent across different runs, it is even possible that mistakes regarding object lifetime remain unnoticed for a long time.

Although great care has been taken while developing the support model, it cannot be fully excluded that unknown object lifetime violations are still lurking around somewhere, especially if unexpected requirements were not documented by the time the code was written.

Missing raw PDF access

As of this writing, PDFium's public interface does not provide access to the raw PDF data structure (see issue 1694). It does not expose APIs to read/write PDF dictionaries, streams, name/number trees, etc. Instead, it merely offers a predefined set of abstracted functions. This considerably limits the library's potential, compared to other products such as pikepdf.

Theoretically, PDFium's non-public backend would provide these capabilities, but it is not exported into the ABI and written in C++ (not pure C), so we cannot access it with ctypes. This means it's out of scope for this project.

Drawbacks of ABI level bindings

While ABI FFI bindings tend to be more convenient, they do have technical drawbacks compared to API bindings (overview). With special platforms and/or code, sometimes unforseen problems can occur (case study).

Development

This section contains some key information relevant for project maintainers.

Documentation

pypdfium2 provides API documentation using Sphinx. It can be rendered to various formats, including HTML:

sphinx-build -b html ./docs/source ./docs/build/html/

Built documentation is primarily hosted on readthedocs.org. It may be configured using a .readthedocs.yaml file (see instructions), and the administration page on the web interface. RTD supports hosting multiple versions, so we currently have one linked to the main branch and another to stable. New builds are automatically triggered by a webhook whenever you push to a linked branch.

Additionally, one documentation build can also be hosted on GitHub Pages. It is implemented with a CI workflow, which is currently linked to main and triggered on push as well. This provides us with full control over the build environment and the used commands, whereas RTD is kind of limited in this regard.

Testing

pypdfium2 contains a small test suite to verify the library's functionality. It is written with pytest:

python3 -m pytest tests/ tests_old/

Note that ...

To get code coverage statistics, you can run

make coverage

Sometimes, it can also be helpful to test code on many PDFs.[^testing_corpora] In this case, the command-line interface and find come in handy:

# Example A: Analyse PDF images (in the current working directory)
find . -name '*.pdf' -exec bash -c "echo \"{}\" && pypdfium2 pageobjects \"{}\" --types image" \;
# Example B: Parse PDF table of contents
find . -name '*.pdf' -exec bash -c "echo \"{}\" && pypdfium2 toc \"{}\"" \;

[^testing_corpora]: For instance, one could use the testing corpora of open-source PDF libraries (pdfium, pikepdf/ocrmypdf, mupdf/ghostscript, tika/pdfbox, pdfjs, ...)

Release workflow

The release process is fully automated using Python scripts and a CI setup for GitHub Actions. A new release is triggered every Tuesday, one day after pdfium-binaries. You may also trigger the workflow manually using the GitHub Actions panel or the gh command-line tool.

Python release scripts are located in the folder setupsrc/pypdfium2_setup, along with custom setup code:

The autorelease script has some peculiarities maintainers should know about:

In case of necessity, you may also forego autorelease/CI and do the release manually, which will roughly work like this (though ideally it should never be needed):

If something went wrong with commit or tag, you can still revert the changes:

# perform an interactive rebase to change history (substitute $N_COMMITS with the number of commits to drop or modify)
git rebase -i HEAD~$N_COMMITS
git push --force
# delete local tag (substitute $TAGNAME accordingly)
git tag -d $TAGNAME
# delete remote tag
git push --delete origin $TAGNAME

Faulty PyPI releases may be yanked using the web interface.

Thanks to[^thanks_to]

... and further code contributors (GitHub stats).

If you have somehow contributed to this project but we forgot to mention you here, please let us know.

[^thanks_to]: People listed in this section may not necessarily have contributed any copyrightable code to the repository. Some have rather helped with ideas, or contributions to dependencies of pypdfium2.

History

PDFium

The PDFium code base was originally developped as part of the commercial Foxit SDK, before being acquired and open-sourced by Google, which maintains PDFium independently ever since, while Foxit continue to develop their SDK closed-source.

pypdfium2

pypdfium2 is the successor of pypdfium and pypdfium-reboot.

Inspired by wowpng, the first known proof of concept Python binding to PDFium using ctypesgen, the initial pypdfium package was created. It had to be updated manually, which did not happen frequently. There were no platform-specific wheels, but only a single wheel that contained binaries for 64-bit Linux, Windows and macOS.

pypdfium-reboot then added a script to automate binary deployment and bindings generation to simplify regular updates. However, it was still not platform specific.

pypdfium2 is a full rewrite of pypdfium-reboot to build platform-specific wheels and consolidate the setup scripts. Further additions include ...