Skip to content

v1.10.0

Choose a tag to compare

@github-actions github-actions released this 24 Oct 20:12
· 31 commits to main since this release

Fixed

  • Redaction reaches content that is not drawn by the page's own operators. Text, paths and image samples in the group of a soft mask are edited like page content, in the mask's own coordinate system, on copies of the graphics state and group. A tiling pattern's cell cannot be cut, so a path that meets an area and is painted with a tiling pattern is removed whole even with PdfRedactionVectorMode.ClipOut, and a pattern that no remaining paint uses is replaced by an empty cell. A Type 3 glyph is removed when anything its procedure paints meets an area, wherever the glyph stands, and the font is copied without the procedures of glyphs the page no longer shows (and the resources only they used). On a page something was removed from, fonts, XObjects, graphics states, patterns and shadings that the rewritten content no longer refers to are dropped from the page's resource dictionary and from the copies it makes; a font nothing remaining uses becomes a bare Helvetica reference, so its program is unreachable. Shared dictionaries and objects are copied, never changed. The Limits section of docs/redaction.md shrinks accordingly. A resource category stored as its own object (/Font 7 0 R) used to be dropped when redaction added an entry to it; it is now copied entry by entry.

  • A PDF/A or PDF/UA save never drops content. A PDF/UA-1 save of a damaged file used to pass the check and then write null for an embedded font program that did not exist (and keep unreadable streams without saying so). CheckPdfA, CheckPdfUA, PreparePdfA, PreparePdfUA and the conformance saves now share one scan that names every object a save would lose, by number, generation and kind (font program or other font part, ICC profile, image, content stream, XMP stream, embedded file, annotation, structure node): streams whose bytes cannot be read, cannot be decrypted cleanly, or whose filter data is truncated or invalid, and references to needed parts that lead to no object. Check and save agree, a save that would lose content throws PdfAException/PdfUAException with the finding and writes nothing, and an unreadable XMP packet is no longer replaced by one built from Info. Saves without PdfA/PdfUA are byte-identical to before. See docs/pdfa.md.

  • A stream's dictionary now reports the object identity of its stream: PdfStream.Dictionary.Reference and SourceOffset equal the stream's. Until now they were null and -1, so code that tells "the same object" from "a copy" through the dictionary (GetDictionary(key) on a stream-valued entry, or a stream's .Dictionary stored in a container) treated a shared stream's dictionary as a direct one: storing it copied the dictionary instead of referring to the stream, and identity checks keyed on Reference missed it. Saves, incremental saves, merge, split, import, redaction and flattening already shared streams through the stream's own reference and are unchanged; plain saves of the test files are byte-identical.

  • Structure destinations (ISO 32000-2 12.3.2.3) report a page. PdfDestination.PageIndex and Page were -1 and the structure element; they are now the page of the element's content (its /Pg, else the first page found in its marked-content and object references and descendants, else the nearest ancestor's /Pg), and stay -1 when none is a page of the document. New PdfDestination.IsStructureDestination and StructureElement; Page is now the page dictionary for these destinations. A GoTo action's /SD is preferred over /D (PDF 2.0 GoTo actions).

  • A PDF/A or PDF/UA check and save treat a string damaged by decryption (bad padding, partial last block) as lost content, like a damaged stream: the finding names the key and object and the save refuses. Saves without PdfA/PdfUA are unchanged. See docs/pdfa.md.

Added

  • SVG pictures in layout, as vector PDF content. SvgImage (Parse from bytes or text, Width, Height, Title, Description, Draw into any PdfContentBuilder), SvgDrawOptions, SvgLimits, the SvgPicture element, the fluent Slot.Svg(...) with SvgDescriptor (fit modes, DPI, alignment, AltText, Artifact) and CanvasSurface.DrawSvg. Output is paths, strokes with dashes, caps and joins, linear and radial gradients as PDF shadings (spread methods unrolled into stops), gradients and patterns on fills and strokes, clip paths, masks as soft masks, group opacity, blend modes, use/symbol/nested svg, markers, viewBox and preserveAspectRatio, a CSS subset (presentation attributes, style, <style> sheets with selectors), PNG and JPEG data URIs, and text shaped through OneFont with the layout's fonts, so it extracts as text. A tagged document writes the picture as a Figure whose alternate text is the author's, else the SVG <title>, else its <desc>; PDF/UA-1 output with an SVG passes veraPDF. Scripts, animation, foreignObject, external references and filters are dropped (filters draw the unfiltered content), each with a diagnostic; nothing is fetched or run. The XML reader refuses entity expansion and every size, depth, instance, path, stop, CSS, data-URI and text bound is a SvgLimits setting that raises PdfLimitException. There is an svg fuzz target. See docs/layout-svg.md.
  • Core: transparency groups and soft masks on the content builder. PdfFormContentBuilder.SetTransparencyGroup(isolated, knockout) marks a form as a transparency group, PdfContentBuilder.SetSoftMask(form, PdfSoftMaskKind) and ClearSoftMask() apply and remove a soft mask made from a form, and PdfSoftMaskKind chooses alpha or luminosity. The SVG renderer needs them for group opacity and masks; existing output does not change.
  • PDF/UA-2 (ISO 14289-2, on PDF 2.0) output and checking. PdfUAOptions.Part (PdfUAPart.Part1, the default and unchanged, or Part2), PdfDocument.CheckPdfUA(PdfUAPart, CancellationToken), PdfUAViolation.Part, XmpMetadata.PdfUARevision. A part-2 save writes PDF 2.0, lists the PDF 2.0 and PDF 1.7 structure namespaces on the structure tree root and names one in /NS on every element (Note becomes FENote), fills /Ref on table-of-contents items from the link inside them, and identifies the file with pdfuaid:part 2 and pdfuaid:rev 2024. It refuses what a person has to supply or what OnePDF cannot choose, with the clause of ISO 14289-2 for each finding: the unnumbered H, a list with labels and no ListNumbering, irregular tables, figures without alternate text, page destinations inside the document (PDF/UA-2 needs structure destinations), custom or unnamespaced structure types, and the part-1 findings that still apply. Combining it with PDF/A-2 or PDF/A-3 (PDF 1.7 formats) throws PdfAException. PdfDocumentWriter.SetBookmarkElement and SetDestinationElement write structure destinations in a PDF 2.0 writer; layout uses them so bookmarks, anchors and table-of-contents links work out of the box. Layout gains StructureGroup and Slot.Aside(), Footnote(), Title() and Group(type) for the 2.0 structure types. Checked with veraPDF's ua2 flavour as a black box. See docs/pdfua.md.
  • Colour glyphs in layout: OpenType COLR version 0 glyphs with CPAL palettes are drawn as their layers in palette colours, the foreground entry in the text colour. ColorPalette (Default, Light, Dark, FromIndex) chosen by TextStyle.Palette, Text.Palette, the fluent Palette(...) or LayoutOptions.ColorPalette. Each glyph's layers sit in one /ActualText span, so extraction returns the character once; PDF/A-2b and PDF/UA-1 output with colour glyphs passes veraPDF. Tables that are not valid, and glyphs described only in COLR version 1, are drawn in one colour with one diagnostic per font. See docs/layout-text.md.
  • Inline objects in layout text: an icon, a small picture, a badge with its own text or a drawn checkbox sits in a line of text and flows with it. TextSpan.Inline/TextSpan.ForInline, InlineObject (InlineBox for a drawn or picture box, InlineElement for an element subtree in a layout Text), InlineAlignment (baseline with an offset, top, middle, bottom, text top, text bottom), InnerBaseline, GrowsLine, KeepWithNeighbours, AltText, Artifact and Link; the fluent TextDescriptor.Inline, InlineImage and InlineCanvas with InlineDescriptor. An object is one unbreakable character (U+FFFC: line break class CB, bidi class ON) with breaks around it by first fit and Knuth-Plass, justification spreads the spaces and leaves it alone, the line grows to hold it unless the line height is fixed, and right-to-left lines place it with its neighbours. In tagged output it is a Figure inside the paragraph with /Alt (or an artifact), the text extractor returns its description through /ActualText and never a U+FFFC, and links and anchors work on it; PDF/A-2a/3a and PDF/UA-1 output stays compliant. A literal U+FFFC in span text is now dropped. Documents without inline objects are byte-identical to before. See docs/layout.md and docs/layout-text.md.
  • Per-page values in layout: Accumulate adds a decimal to a named account and Marker records a text under a key, both wrapping content (Slot.Accumulate, Slot.Marker); DynamicText (Slot.DynamicText, styled by DynamicTextDescriptor) is a line of text computed for each page by a callback from PageValues: Sum, Total, BroughtForward, First, Last, Current, Entering, page index, number, label and section. Values come from what actually landed on the page after page breaking, so "Carried forward" and "Brought forward" lines, page subtotals and running headers move with the rows that keep rules push to the next page. They work in headers, footers and the body, in tables, multi-column flow, sections, right-to-left documents and documents with a table of contents (no double counting), are artifacts in headers and footers and tagged text in the body, and are deterministic. See docs/layout.md.