PDFium
Native bindings for pdfium project
Installing
-
for Mix projects, add the following under
depsinmix.exs:{:pdfium, "~> 0.1"} -
for single-file Elixir scripts, add the following:
Mix.install([pdfium: "~> 0.1"])
Developing
The development environment is a Nix shell carrying Erlang, Elixir, zig, the
Dagger CLI at the version the module pins and gh:
nix develop
mix compile builds the NIF for this machine with zig build, driven by
build.zig, which fetches the libpdfium archive and the Fine headers declared in
build.zig.zon.
Usage
-
open a PDF file descriptor:
{:ok, document} = PDFium.load_document("file.pdf") # => {:ok, #Reference<0.2181297728.2193227786.166499>} -
get the number of pages in the file:
{:ok, pages} = PDFium.get_page_count(document) # => {:ok, 1} -
render a page to file:
{:ok, ref} = PDFium.load_document("/Users/eugene/Downloads/7ade6db09604a8b41104763c6f16a987.pdf") {:ok, binary, w, h} = PDFium.get_page_bitmap(ref, 0, 300) # 300 for DPI {:ok, image} = Vix.Vips.Image.new_from_binary(binary, w, h, 4, :VIPS_FORMAT_UCHAR) {:ok, _image} = Image.write(image, "/tmp/sample.png")
Releasing
Every Monday the Update to latest libpdfium workflow opens a pull request that
bumps the libpdfium archives and the version in build.zig.zon. Merging
it into main runs the Release workflow, which builds the artifacts, creates
the GitHub release and publishes the package to hex. Run the workflow by hand to
release outside the schedule:
gh workflow run update-libpdfium.yaml
For any other tag or version, open a pull request that sets .version in
build.zig.zon by hand and points it at the archives of that tag with
zig fetch --save. Every change to that file is released, so bump the version
with it. Merging releases the same way.
Running CI steps locally
ci builds the NIF for one target, runs the test suite against it where the
target can run in a container, and returns the archive:
dagger call ci --target aarch64-linux-musl archive export --path .
The targets are aarch64-linux-gnu, aarch64-linux-musl, x86_64-linux-gnu,
x86_64-linux-musl, aarch64-apple-darwin and x86_64-apple-darwin, all
compiled with zig in one image. The macOS ones are only built, so mix test on
a Mac is their check. dagger check runs all six. The workflows load the workspace from git
rather than from a checkout, and the same works from any directory:
dagger --workspace github.com/gmile/pdfium@main check
CI keeps zig's cache per target. After changing the zig version, warm the
caches on main once so pull requests start from them:
gh workflow run ci.yaml --ref main
When a release fails
Releases are immutable, so a tag can never be reused, not even after deleting
the release. Whatever failed, the way forward is another pull request bumping
.version in build.zig.zon to the next patch. The same holds for a change to
that file that forgot to bump the version: the release run goes red once and
the next bump releases normally.
The six archives of any run can be fetched for inspection:
gh run download 42028488533 --dir artifacts
Repository settings the workflows rely on
- a GitHub App installed on the repository with write access to contents and
pull requests; its id is the
GH_APP_IDvariable and its private key theGH_APP_PRIVATE_KEYsecret - the
HEX_API_KEYsecret formix hex.publish - required checks named after the CI jobs, one per matrix entry
- immutable releases, which is why a failed release is followed by a bump
Known issues
- Installing the library was tested and will work in macOS and inside Docker images built by Bob. Installing
currently doesn't work under Elixir installed via package managers, such as via
apk add elixirfor example.
License
See [LICENSE].