4 Commits
Author SHA1 Message Date
Leon Anavi 0577713ac7 python3-pikepdf: Upgrade 10.17.0 -> 10.18.0
Upgrade to release 10.18.0:

- pikepdf.Pdf.add_pages_from now carries layers (optional
  content) with the pages it copies. The optional content groups
  that the copied pages depend on are listed in the destination's
  /OCProperties, with the default visibility, place in the layer
  list, lock, radio button groups and automatic states that the
  source's default configuration gave them. Previously the groups
  were copied but not listed, so viewers ignored them: the layer
  list was empty and content hidden in the source was shown.
- pikepdf.Pdf.add_pages_from now carries bookmarks. Outline
  items of the source that lead to a copied page are appended to
  the destination's outline, keeping their hierarchy, titles and
  style; items that lead to pages that were not copied are dropped.
- Both are on by default, which changes what existing callers of
  add_pages_from get: the destination may gain an /OCProperties and
  outline items it did not gain before. Pass layers='ignore' or
  outlines='ignore' for the previous behaviour, for example if you
  build the merged outline yourself. pikepdf.PageCopyResult
  reports layers_added, outline_items_added and
  outline_items_dropped.
- pikepdf.Pdf.check_pdf_syntax now performs the same checks
  as qpdf --check and reports the same problems. It checks the
  linearization data and hint tables of linearized files, which
  previously required a separate call to
  pikepdf.Pdf.check_linearization, and checks the interactive
  form, embedded files, page labels and outlines. A document with
  no pages is reported as ERROR: file does not contain any pages,
  and a page whose content stream cannot be read is reported as
  ERROR: page N: ... along with the other problems found, where it
  previously raised pikepdf.PdfError.
- Inserting a pikepdf.Dictionary or pikepdf.Array
  that refers to another Pdf into a Pdf now raises
  pikepdf.ForeignObjectError, naming the key or index where the
  foreign object was found, and leaves the target unchanged.
  This covers an indirect object of another Pdf held anywhere in
  the value, such as pdf3.Root.X = Dictionary(P=pdf1.Root.Y), and a
  direct dictionary or array that another Pdf already contains.
  Previously the value was accepted: the first kind made the Pdf
  impossible to save, failing part way through writing, and the
  second left two documents sharing one object. It applies to every
  way of inserting a value, including
  pikepdf.Pdf.make_indirect, pikepdf.Page.add_resource,
  adding a page built from a dictionary, name and number trees, and
  stream dictionaries. Use pikepdf.Pdf.copy_foreign to bring
  the foreign object over first.
- A password containing a NUL character now raises {exc}ValueError,
  both when opening a PDF and when encrypting one. Previously the
  password was silently cut short at the NUL, so a wrong password
  could open a file, and an encrypted file could be written with a
  shorter password than requested. PDF passwords may not contain
  NUL.
- Fixed threads interfering with each other inside one Pdf on
  GIL-enabled builds, which could cause an object to be read as
  None. The per-Pdf lock is now in force on every build, and
  pikepdf.Pdf.lock works on GIL-enabled builds too.
- Methods implemented in Python that change a Pdf in several steps,
  such as pikepdf.Page.add_overlay,
  pikepdf.Pdf.add_pages_from and the pikepdf.sanitize functions,
  now hold its lock until they finish. The thread safety section of
  the architecture notes now says which calls are atomic.
- Two threads that each hold the lock of one Pdf and then need the
  other's no longer deadlock; one of them gets a RuntimeError
  instead. What a callback such as a pikepdf.TokenFilter may
  do is now documented: see {ref}callback-restrictions.
- Fixed a crash, a native stack overflow that no Python except can
  catch, when reading, saving or checking a PDF in which a JBIG2
  image's /JBIG2Globals stream is itself JBIG2-encoded and leads
  back to the image, directly or through other streams. Such an
  image is now reported as unfilterable, as JBIG2-encoded globals
  without a cycle already were: reading it raises
  ~pikepdf.exceptions.PdfError, extracting it raises
  ~pikepdf.exceptions.UnsupportedImageTypeError, and saving
  writes it unchanged with a warning.
- A JBIG2 image's /JBIG2Globals are now read only when the image is
  being JBIG2-decoded, rather than every time qpdf checks whether
  the image can be decoded, which included every save.
- Reading the label of a page whose page label style is an unknown
  name, such as /S /Z, now warns and keeps the label prefix, as an
  invalid non-name style already did. Previously it raised
  KeyError.
- Reading the label of a page whose number cannot be written in its
  page label style, such as /S /R /St 0 or a Roman numeral above
  5000, now warns and writes the number in decimal digits.
  Previously it raised ValueError.
- Extracting an image whose /CalGray or /CalRGB colour space array
  lacks its parameter dictionary now decodes it as the
  corresponding device space, without an ICC profile, as a missing
  /WhitePoint already did. Previously it raised IndexError.
- An ICCBased image whose profile stream omits the required /N, or
  gives one that is not an integer, now takes its mode and default
  /Decode from the profile's colour space. Previously its mode
  raised KeyError.
- Fixed pikepdf.form.SignatureField.stamp_overlay stamping
  the overlay twice when the signature widget names its page with
  /P.
- Fixed a Pdf returned by pikepdf.Job.create_pdf not being
  set up like other Pdf objects: setting its conversion_mode raised
  pikepdf.PdfError, and on free-threaded Python none of its
  methods were protected by a lock.
- Matrix.__array__(copy=False) now raises ValueError, as numpy
  expects of an object that cannot share its memory. The check for
  this was written in a way that never fired.
- A progress argument to pikepdf.Pdf.save that is not
  callable is now rejected with TypeError before anything is
  written. Previously the error was raised part of the way through
  writing the file.
- Fixed a small memory leak each time
  pikepdf.AcroForm.get_fields_with_qualified_name or
  pikepdf.AcroForm.fix_copied_annotations returned a field.
- Iterating over a pikepdf.NameTree or
  pikepdf.NumberTree now iterates over the keys it had when
  the iteration began. Previously the tree was read as the
  iteration went on, so changing it meanwhile gave undefined
  results.
- Putting an object that belongs to another Pdf in a
  pikepdf.NameTree or pikepdf.NumberTree now raises
  pikepdf.ForeignObjectError at once, as it does for a
  dictionary or an array. Previously the error was not raised until
  the Pdf was saved.
- x in tree is now False for an x that cannot be a key of a
  pikepdf.NameTree, such as an int, and for None in a
  pikepdf.NumberTree. Previously these raised TypeError.
- Corrected the documentation and type hints of
  pikepdf.NameTree, which said that names are bytes. Names
  are, and have always been, str: qpdf reads each name as a PDF
  text string and compares names by that text.
- Fixed building from source on Android (Termux), where importing
  pikepdf failed with cannot locate symbol "_Py_TrueStruct" since
  v10.6.0. The extension module is now linked against libpython
  when the build interpreter is an Android Python, as that platform
  requires. Android is not a tested platform.

Free-threaded Python fixes:

Many crashes and data races that occurred when several threads used the
same Pdf at once have been fixed. The test suite now runs under
ThreadSanitizer in continuous integration, which is how most of them
were found ().

- Every binding that reads or changes a Pdf now takes that Pdf's
  lock, and the lock of any other Pdf among its arguments, enforced
  at compile time. Many bindings previously did not, notably most
  methods of pikepdf.NameTree, pikepdf.NumberTree,
  attachments, annotations and pikepdf.AcroForm.
- Fixed crashes and data races in pikepdf.Page methods,
  content stream parsing, adding pages from one Pdf to another, and
  dropping the last reference to a Pdf while another thread used
  one of its objects.
- A pikepdf.Dictionary or pikepdf.Array that belongs
  to no Pdf is now protected by a lock shared by all such objects.
  Threads that each build objects of their own contend for it, so
  add a Dictionary or Array to its Pdf as soon as it is created
  rather than building large structures before adding them.
- Fixed "dictionary changed size during iteration" when several
  threads opened a Pdf's metadata for the first time at once.
- Threads that take turns using the same Pdf are no longer slowed
  to a crawl when every CPU is busy.

This work was sponsored by GOVCERT.LU.

Signed-off-by: Leon Anavi <leon.anavi@konsulko.com>
Signed-off-by: Khem Raj <khem.raj@oss.qualcomm.com>
2026-11-10 06:18:49 -08:00
Leon Anavi 23a17447f1 python3-pikepdf: Upgrade 10.13.0.post1 -> 10.17.0
Upgrade to release 10.17.0:

- Added {class}pikepdf.ObjectSet, which records the objects that a
  walk of a PDF's object graph has already visited. Objects in a
  PDF are shared and may refer back to their ancestors, so a search
  that only limits its depth can take exponential time on quite
  ordinary files. ObjectSet.add() reports whether an object is new,
  and tells apart direct objects and objects of different Pdf,
  which a set of objgen cannot. See {ref}walking-object-graphs.
- Added {meth}pikepdf.Object.is_same_object_as, which tests whether
  two references lead to the same object. Neither is, == nor
  comparing objgen answers this reliably.
- Added {meth}pikepdf.Pdf.content_scopes and
  {meth}pikepdf.Page.content_scopes, which iterate over every
  content stream that pages can draw, each with the resource
  dictionary it uses: the page itself, form XObjects, annotation
  appearance streams, tiling patterns, Type 3 glyph procedures and
  soft masks, however they are nested or shared. This is the way to
  find every font, image or colour space a document uses. Each
  {class}pikepdf.ContentScope is reported once for the document;
  pages= selects pages and kinds= selects what is reported.
- Added {meth}pikepdf.Page.get_resources, which returns the
  resources of a page or form XObject for reading. Unlike
  {attr}pikepdf.Page.resources, it finds resources inherited from
  the page tree, does not create an empty dictionary when there are
  none, and returns None instead of raising when /Resources is
  malformed.
- Fixed comparing two objects with == taking exponential time when
  the objects being compared share children, such as the same file
  opened twice. Each pair of objects is now compared once.
- Fixed {meth}pikepdf.Pdf.add_pages_from hanging on a page with an
  action whose /Next actions are shared or form a loop.
- Fixed {meth}pikepdf.Pdf.open_outline reading only the first item
  at each level of an outline whose items are direct objects. Such
  items are now made indirect when the outline is saved, as the PDF
  specification requires.
- Reading a stream that will not decode now raises
  {exc}~pikepdf.exceptions.DataDecodingError with the reason,
  whether the stream's data was read from a file or set from
  memory. Previously a stream read from a file raised a
  {exc}~pikepdf.exceptions.PdfError that said only "read_bytes
  called on unfilterable stream", and the reason was available only
  from {meth}pikepdf.Pdf.get_warnings. DataDecodingError is a
  PdfError, so existing handlers are unaffected.
- An exception raised by a JBIG2 decoder now reaches the caller of
  {meth}pikepdf.PdfImage.as_pil_image,
  {meth}pikepdf.PdfImage.extract_to and
  {meth}pikepdf.PdfImage.read_bytes unchanged, with its own type,
  message and traceback. Previously, for an image read from a file,
  it was replaced by a generic DataDecodingError or PdfError.
- Added {exc}~pikepdf.exceptions.QpdfRuntimeError, raised for
  errors from qpdf that pikepdf has no more specific exception for.
  These were previously raised as a bare RuntimeError, which except
  pikepdf.PikepdfError did not catch. The new exception derives
  from both {exc}~pikepdf.exceptions.PikepdfError and RuntimeError,
  so handlers written for RuntimeError still work.
- The empty name / is now supported. The PDF 1.7 and 2.0
  specifications define a lone slash as a valid name made of zero
  characters, but pikepdf.Name('/') raised ValueError, and
  dictionaries refused / as a key. This broke
  {meth}pikepdf.Pdf.add_pages_from on files with an empty-named
  destination such as /Dests << / 3 0 R >>. Such names can now be
  created, used as dictionary keys, and migrated during page
  copying. bool(Name('/')) is False, like an empty
  {class}pikepdf.String. Name(''), which lacks the leading slash,
  is still rejected. PDF/A does not forbid empty names, and the
  PDF/A validator accepts them.
- AcroFormField.get_inheritable_field_value_as_name() now returns a
  {class}pikepdf.Name, as documented, instead of a str. When the
  value is missing or not a name, it returns the empty name
  Name('/'), which is falsy, instead of ''. Comparisons such as ==
  '/Tx' are unaffected.
- Fixed an out-of-bounds read when opening a PDF from a Python file
  object whose readinto() reports more bytes than were requested.
  This now raises ValueError, as writing to such a stream already
  did. Non-blocking streams, whose readinto() returns None, now
  raise ValueError instead of hanging.
- Fixed building from source on PyPy, which failed to compile since
  v10.0. PyPy now reads Python file objects through readinto(),
  like CPython, instead of copying the result of read().
- {func}pikepdf.open reads directly from the file descriptor when
  given a filename, instead of calling the seek() and readinto()
  methods of a Python file object for every read. Opening and
  reading a large file with many objects is about four to five
  times faster, matching the speed of memory mapping
  (access_mode=AccessMode.mmap). Streams passed to
  {func}pikepdf.open, including plain file objects, are read
  through their methods as before.
- Documented {class}pikepdf.TokenFilter with worked examples that
  shorten numbers and convert RGB colors to grayscale, and
  explained when to use a token filter instead of
  {func}pikepdf.parse_content_stream. The API reference no longer
  says that the parser should not be used to edit content streams.
  The TokenFilter.handle_token documentation now says correctly
  that exceptions it raises propagate to the caller.

Extend RDEPENDS with the missing runtime dependencies
python3-fonttools and python3-jsonschema which are required
to import pikepdf.pdfa.

Install pdfa_differential.py to pass the tests from
test_pdfa_differential.py. Fixes:

E   ModuleNotFoundError: No module named 'pdfa_differential'

This work was sponsored by GOVCERT.LU.

Signed-off-by: Leon Anavi <leon.anavi@konsulko.com>
Signed-off-by: Khem Raj <raj.khem@gmail.com>
2026-10-24 09:24:02 -07:00
Leon Anavi ae0db48cac python3-pikepdf: Upgrade 10.11.0 -> 10.13.0.post1
Upgrade to release 10.13.0.post1:

- Behavior change: pikepdf.DataDecodingError now derives from
  pikepdf.PdfError. A stream that will not decode is a defect in
  the document, and the same call that raises it -
  Object.read_bytes() - already raised PdfError for other kinds of
  damage, so except PdfError was a handler that looked correct,
  passed on healthy files, and let a traceback escape on damaged
  ones. Code catching DataDecodingError by name is unaffected. Code
  that orders except PdfError before except DataDecodingError will
  now take the first branch; if the distinction matters, reverse
  the order.
- Behavior change: pikepdf.PdfParsingError now derives from
  pikepdf.PdfError, for the same reason.
- pikepdf.PasswordError remains a sibling of PdfError, not a
  subclass. A wrong password does not mean the document is
  defective, and handlers that report the two separately depend on
  except PdfError not catching it.
- pikepdf.NotExtractableError is now exported. It was already the
  base class of the exported HifiPrintImageNotTranscodableError but
  could not be caught by name.
- Fixed the exceptions documentation, which referenced a nonexistent
  FormCopyWarning (the class is PageCopyWarning) and omitted
  ReferenceCycleError, PageCopyWarning and NotExtractableError.
- XMP assigns a type to every standard property, and software that
  reads XMP discards a property whose type is wrong - Ghostscript
  strips these silently, and PDF/A validators reject them. pikepdf
  used to choose the RDF container from the Python type of the
  value it was handed, so meta['dc:subject'] = ['a', 'b'] wrote an
  rdf:Seq where the specification requires an rdf:Bag, and
  meta['dc:creator'] = 'Author' wrote a bare string where an
  rdf:Seq belongs. pikepdf now knows the type of the properties in
  the standard schemas and converts values to it.

This work was sponsored by GOVCERT.LU.

Signed-off-by: Leon Anavi <leon.anavi@konsulko.com>
Signed-off-by: Khem Raj <khem.raj@oss.qualcomm.com>
2026-09-22 11:36:20 -07:00
Leon Anavi d8b0db4279 python3-pikepdf: Upgrade 10.5.1 -> 10.9.1
Upgrade to release 10.9.1:

- Fixed a crash (SIGABRT via std::terminate) that could occur when
  a file-backed {class}pikepdf.Pdf was deallocated while a Python
  exception was already propagating -- for example when
  pikepdf.open(filename) appears as a transient element of a
  list/tuple literal whose later element raises. Opening from a
  filename closes the file in the input source destructor, which
  calls back into Python; with an exception already in flight that
  call raised an error that escaped the destructor. The in-flight
  exception is now preserved and propagates normally. Added a guard
  for a likely non-reproducible related case with DecimalPrecision.

This work was sponsored by GOVCERT.LU.

Signed-off-by: Leon Anavi <leon.anavi@konsulko.com>
Signed-off-by: Khem Raj <khem.raj@oss.qualcomm.com>
2026-07-08 11:05:07 -07:00