Skip to contents

pdfium (development version)

Distribution

  • No CRAN release is planned (ADR-026). Binary packages for Windows and macOS will be published through r-universe: install.packages("pdfium", repos = c("https://humanpred.r-universe.dev", "https://cloud.r-project.org")). The development version still installs from GitHub. The package stays held to CRAN’s quality bar (R CMD check --as-cran clean).

PDFium update

  • The bundled PDFium moves from chromium/7857 to chromium/8066 (Chromium 156). No PDFium function the package uses was removed or changed signature.

New features

Behaviour changes from the PDFium update

  • pdf_attachment_set_dict_value() now round-trips non-ASCII text; PDFium used to store the raw UTF-8 bytes, which read back garbled.
  • pdf_page_flatten() also removes the flattened fields from the document’s interactive form; flattening the last field removes the form, so pdf_doc_form_type() then reports "none".
  • pdf_annot_set_bounds() no longer enlarges an existing appearance stream’s bounding box, so the appearance is scaled to the new rectangle.
  • pdf_doc_new() documents get a /CreationDate with a +00'00' offset. PDFium applies it to the local wall-clock time, so the parsed value is unchanged from before (see ?pdf_doc_new).

Bug fixes

  • Installed and binary packages now carry PDFium’s licence notices in pdfium-licenses/ (system.file("pdfium-licenses", package = "pdfium")): PDFium’s BSD-3-Clause licence, the licences of the third-party code compiled into libpdfium, and bblanchon/pdfium-binaries’ MIT licence. They were dropped when the PDFium archive was unpacked, and LICENSE.md pointed at a file that was never installed; it also misnamed bblanchon/pdfium-binaries’ licence as Apache-2.0. Installation now stops if a PDFium archive lacks PDFium’s own notice.
  • Installing from source no longer reuses an incomplete PDFium download. Every archive, whether downloaded, cached or vendored, must now match the SHA-256 pinned for it in tools/pdfium-checksums.txt (on R < 4.5, which cannot compute SHA-256, it must at least be complete). A download is moved into the cache only once it passes, and a cached archive that fails is downloaded again. Before, an interrupted download stayed in the cache and broke every later install, and a truncated archive was unpacked without an error, leaving a truncated libpdfium for the link step to fail on (ADR-027).
  • pdf_annot_objects() reports each embedded object’s own type ("path", "text", "image", "shading" or "form") instead of "unknown", so the type-specific readers and setters such as pdf_path_fill(), pdf_path_set_fill() and pdf_text_set_content() accept objects inside an annotation; pdf_annot_update_object() then writes a change into the appearance stream. pdf_text_content() refuses these objects with an error, because PDFium only reads the text of objects in the page’s own content.
  • pdf_render_page(), pdf_image_bitmap(), pdf_image_rendered() and pdf_text_obj_rendered_bitmap() now return a conformant nativeRaster: the backing integer buffer is laid out row-major, so the bitmap can be passed straight to png::writePNG(), grid::grid.raster() and R’s graphics engine with no reshape. Prior versions stored the buffer column-major, which sheared every row sideways when a consumer trusted the nativeRaster class (“stride streak” garble). as.array() / as.raster() are updated to match and remain correct. Output now matches png::readPNG() / magick::image_read() in dims, RGBA channel order and 0..1 range.
  • pdf_render_page() and pdf_render_page_with_matrix() no longer modify the document. Every render used to rewrite the bounding box of annotation appearance streams, which drew some annotations at the wrong size and carried into later pdf_save() output.
  • pdf_form_field_set_value()’s documentation no longer claims that the field’s appearance is regenerated; PDFium’s API has no way to do that outside its interactive form-fill layer.
  • pdf_annot_append_object() no longer frees its object twice. PDFium’s FPDFAnnot_AppendObject takes ownership of the object, but the object was still on its page as well, so closing the page or collecting the annotation handle could crash R. The object is now moved: it leaves the annotation’s page, its handle is closed, and pdf_annot_objects() reaches it inside the annotation. Annotations other than "ink" and "stamp", and objects that are not top-level objects of the annotation’s page, are refused with an error that leaves everything in place (ADR-023). The documentation of pdf_annot_append_object(), pdf_annot_remove_object() and pdf_annot_update_object() named "stamp" or "freetext"; PDFium supports "ink" and "stamp".
  • pdf_form_obj_remove_object() frees the removed child (it used to leak) and closes the child’s handle. Its documentation now says that PDFium does not save the removal: the saved file still draws the removed child.
  • Annotation handles collected after their page was closed now release PDFium’s annotation context while the document is still open; before, the context leaked.
  • pdf_annot_delete() removes the handle’s own annotation. It used the position recorded when the handle was made, so after an earlier delete on the same page it removed the next annotation or failed, and for a form field it removed an unrelated annotation. Deleting an annotation that is no longer on its page, for example through a second handle to it, is now an error that changes nothing.
  • pdf_annot_delete() no longer leaks PDFium’s annotation context, and with it any page-objects of the annotation’s appearance stream.
  • pdf_doc_close(), and the finalizer of a collected document, first close the annotation handles still open on the document, including form-field handles from pdf_form_fields(). Those handles print as closed afterwards, and pdf_annot_*() calls on them raise an error. An annotation handle collected after both its page and its document had been closed used to leak PDFium’s annotation context, together with the page-objects of its appearance stream (ADR-024).
  • pdf_doc_close(), and the finalizer of a collected document, now also close the document’s pages, including the pages of pdf_form_fields(). Page and page-object calls on them raise an error (“Page has been closed: its document was closed.”) instead of reading freed memory. Rendering or extracting text from a page whose document had been closed read, and for text also wrote, the freed document; the results looked right, so nothing noticed. A page collected after its document had been closed also closed itself after the document, the reverse of the order PDFium expects (ADR-025).
  • pdf_doc_close() also closes the document’s font and XObject handles. pdf_obj_form_from_xobject() with an XObject whose document had been closed built the form object from the freed document; it now raises an error.
  • pdf_text_new() and pdf_obj_form_from_xobject() refuse a font or XObject that belongs to a document other than the page’s. With a font from pdf_font_load() or an XObject, the new object pointed into the other document: pdf_save() wrote it out wrongly, and once the other document was closed, reading the page read freed memory.
  • The form object from pdf_obj_form_from_xobject() stays usable after pdf_xobject_close(), as documented; it used to raise an error.
  • pdf_page_insert_clip_path() no longer closes clip_path. PDFium never takes ownership of an inserted clip path, so the path was never freed. The handle now stays open, can be inserted into other pages, and is released by pdf_clip_path_close() or garbage collection.
  • pdf_system_fonts_install_default() installs PDFium’s default system-font provider once per library lifetime, and the package frees it when it shuts the library down. Each call used to allocate a new provider that was never completely freed.
  • Page-objects read with pdf_annot_objects(), and the objects of forms among them, print as closed once their annotation is deleted with pdf_annot_delete(), and page-object functions refuse them with “Parent annotation has been closed: it was deleted with pdf_annot_delete().” They used to print as open and fail with an internal message. pdf_annot_update_object() and pdf_form_obj_remove_object() now refuse a closed page-object with the same messages as the other page-object functions.
  • A clip path from pdf_obj_clip_path() belongs to its page-object, not to the page: pdf_clip_path_count() and pdf_clip_path_segments() refuse it once the object is deleted with pdf_obj_delete() or pdf_form_obj_remove_object(), moved into an annotation with pdf_annot_append_object(), or once the annotation or form holding it is deleted. They used to read the freed object, and for an annotation’s object after pdf_annot_delete() they crashed R (ADR-029).
  • The objects pdf_form_objects() returns belong to the form handle they were read through: they are refused once that form is deleted with pdf_obj_delete(), removed with pdf_form_obj_remove_object() or moved into an annotation with pdf_annot_append_object(). After a move, read them again through pdf_annot_objects() and pdf_form_objects(). They used to read the freed objects once the form was destroyed (ADR-029).
  • pdf_annot_remove_object() closes the handles to the object it removes, from every earlier pdf_annot_objects() call on the annotation handle, together with the clip paths and nested objects read from them; they now fail with “The object was removed from its annotation by pdf_annot_remove_object().” They used to read the freed object (ADR-032).
  • Shutting PDFium down, as unloading the package does, first closes every open document together with its pages, annotations, fonts and XObjects, and every clip path and bitmap from pdf_clip_path_new() and pdf_bitmap_new(); their handles read as closed afterwards. Closing, using or collecting one of them after the shutdown, or after PDFium was initialised again by opening a document or by pdf_system_fonts_install_default(), crashed R (ADR-028).
  • Unloading the package no longer leaves handles that crash R when they are collected or when R exits. After unloadNamespace(), detach(unload = TRUE), pkgload::unload() or a pkgload::load_all() reload, every handle still around, whether open, closed or waiting to be collected, kept a finalizer that pointed into the unloaded compiled code. The finalizer is now an R function that calls into pdfium’s compiled code only while that code is loaded, and the code releases only the handles it made itself (ADR-031). pdf_doc_open(source = ) now keeps its copy of the bytes as an R raw vector, so R’s memory accounting sees it.
  • pdf_form_fields()’s documentation says what it returns, a pdfium_form_field_list of form-field handles, instead of describing a tibble; the tibble’s columns are now documented on as_tibble.pdfium_form_field_list(), which builds it.

pdfium 0.1.0

  • Initial release.