Skip to content

v2.6.0

Choose a tag to compare

@lxman lxman released this 06 Sep 13:41

Fixed

  • Saves write every xref entry with the object's real generation number (issue 80). Every entry
    was written with generation 0 even when the object header said N G obj with G > 0. Our own reader
    and pypdf tolerated it; veraPDF and PDFBox did not. Affects any document that carried a
    non-zero-generation object through a save.
  • Strings written as hex in the source are written as hex on save (issue 57), so byte-level
    conformance checks (PDF/A 6.1.6) see the same form after a round-trip.
  • Real-number operands keep their written precision on save instead of being re-formatted
    through a double, which could change low-order digits.
  • Page-tree traversal is bounded: a /Kids cycle no longer recurses without limit.
  • Transparency-group resource cycles are guarded during rendering and content walks.
  • Atomic-file-write retry no longer races its own budget on a transiently locked destination (issue 55).
  • CID-to-GID mapping is split by consumer (issue 42): rendering keeps the identity mapping the font
    program requires; conformance uses the strict map.
  • Glyph selection for a CIDFontType2 descendant whose embedded program is a CFF-outline (OTTO)
    sfnt
    (issue 36): the charset lookup is keyed on the descendant's own /Subtype rather than the
    program's outline flavour, which previously scrambled every glyph in such a font.
  • XMP: structured properties are no longer destroyed on save. Setting any document property
    (PdfDocumentEditor.Metadata.Title and friends) re-serialized the XMP packet through a model with
    no struct representation, flattening xmpMM:History, xmpMM:DerivedFrom, xmpTPg:Fonts and
    similar into a single concatenated text blob — irrecoverably. XmpPacket is now backed by the
    recursive XmpNode model and emits structs and arrays-of-structs faithfully. Shapes the model
    still cannot express (a general XMP qualifier — rdf:value plus a non-xml:lang qualifier field
    or attribute) are preserved verbatim rather than dropped.

Changed

  • The XMP format layer moved to its own assembly, PdfLibrary.Xmp, bundled in the package as with
    ICCSharp and FontParser. Namespaces are unchanged and PdfLibrary forwards the four public
    types, so this is source- and binary-compatible. The forwarders are transitional and are due for
    removal at 3.0.0
    , which will require a recompile for consumers still binding to the old
    assembly.
  • XmpProperty's read projection of a struct-shaped property changed. The old flat parser
    returned the concatenated text of a struct's descendants as Value; now that structs are modelled
    faithfully (see Fixed, above), a struct has no scalar value and XmpProperty.FromNode projects it
    to Value = "" instead. This is deliberate and more correct, but it is a read-side behaviour
    change on a public type, and it reaches conformance: UaTitleRule reads dc:title through this
    projection, so a struct-shaped (qualified) title now reads as empty rather than as its
    concatenated text. Note also that the verbatim-preservation fallback this release adds is narrow —
    it only preserves an rdf:value-plus-qualifiers shape, not any unfamiliar XMP in general; see
    Docs/Architecture.md for what it does and does not cover (e.g. rdf:type on a struct is still
    dropped).
  • Preflight reaches full verdict parity with veraPDF on every profile with a committed snapshot:
    986/986 whole-file agreement on the PDF/A-2b corpus, 22/22 on PDF/A-2u, with zero false positives
    across all 1,316 corpus files. The clause-by-clause table is
    PdfLibrary.Tests/Conformance/parity/PARITY-REPORT.md; clauses at full parity — PDF/A-2b (35/40):
    6.6.2.3.1, 6.2.4.3, 6.2.10, 6.3.3, 6.3.2, 6.6.2.3.3, 6.1.13, 6.5.1, 6.3.1, 6.1.7.1, 6.1.9, 6.2.4.4,
    6.4.1, 6.2.2, 6.2.5, 6.6.4, 6.2.11.3.3, 6.2.11.6, 6.2.3, 6.2.8.3, 6.2.9, 6.1.12, 6.1.3, 6.2.6, 6.2.8,
    6.2.11.3.2, 6.2.4.2, 6.6.2.1, 6.1.10, 6.1.4, 6.1.6, 6.1.8, 6.2.11.4.2, 6.4.2, 6.5.2; PDF/A-2u (3/3):
    6.2.11.7.2, 6.2.11.3.1, 6.6.4.
  • Font scans no longer parse every charstring eagerly; a conformance scan of a font-heavy document
    is roughly half the time it was.
  • The core package is 5.4 MB, up from 3.0 MB: bundled Adobe CID-to-Unicode CMaps, Standard-14 AFM
    metrics, and the CMYK soft-proof profile.

Added

  • XmpPacket.SetStruct / SetStructArray and XmpField, for authoring nested XMP structs and
    arrays-of-structs (e.g. pdfaExtension:schemas).
  • XmpPacket.Serialize()'s name/value contract is now explicit. An illegal character in a
    property value (a NUL/control character, an unpaired surrogate) is sanitized to U+FFFD rather
    than rejected, so a save is never blocked by garbage data the library did not write. An illegal
    property or struct-field name — only ever caller-supplied, via SetSimple/SetArray/
    SetStruct/SetStructArray — throws ArgumentException instead, since there is nothing to
    repair it into. Callers authoring structs with dynamic field names should validate them first.
  • System font substitution. SystemFontLocator.Resolve(FontRequest) returns a FontMatch
    (bytes plus the face index inside a .ttc); EnumerateFaces() lists what the locator can see as
    SystemFontFace records (family, PostScript name, bold/italic, source path, face index);
    SystemFontLocator.Default scans the platform font directories. ISystemFontProvider gained
    both members with default implementations, so existing implementers keep compiling.
    BundledStandard14Provider wraps any provider with the Standard-14 AFM metrics.
  • Font inventory. FontInventory.Read(PdfDocument) lists every font in a document as a
    FontInventoryEntry (kind, embedding, program holder, used codes); FontInventory.Find locates
    one by object number. FontProgramClassifier, ClassifiedProgram, FontProgramFormat,
    FontDescriptorValues, FontDescriptorMetrics, FontId, FontKind support it.
  • CID-to-Unicode for text extraction: CidCMap and AdobeCidToUnicode (bundled Adobe UCS2
    tables for Japan1, Korea1, GB1, CNS1), ToUnicodeCodespace, and ToUnicodeCMapWriter for
    authoring a ToUnicode CMap.
  • Metadata: PdfMetadata.Language and PdfMetadata.Trapped (PdfTrapped), synced to XMP.
  • Editing: PdfDocumentEditor.SetFileId, ConsolidateOutputIntents, ReplaceOutputIntentProfile,
    PdfPageCollection.SetAnnotationFlags, PdfFormFields.HasXfa, PdfAnnotationInfo.Flags, and
    PdfDocumentEditor.Document.
  • PdfDocumentEditor.PreviewDocumentProof() classifies signature byte ranges and catalog
    permissions without mutating (DocumentProofPreview).
  • Conformance reads: ConformanceClaim.Read (the declared PDF/A profile, with an unreadable-XMP
    flag), OutputIntentProfileValidator.Validate, XmpConformance.ClassifyProperties and
    ModernEquivalentOf (XmpPropertyVerdict, XmpModernEquivalent), and
    Preflighter.Check(document, profile, sourceBytes) for byte-level rules.
  • Render SPI: ImageCommand.ProofCmyk, PdfGraphicsState.ResolvedFillProofCmyk /
    ResolvedStrokeProofCmyk, DeviceCmykConverter.Naive, and
    RecordingRenderTarget.Record(page, scale, fontProvider). The nine-parameter ImageCommand
    constructor and Deconstruct from 2.5.2 are kept.