Skip to content

stet 0.2.0 — ⚠ breaking release

Choose a tag to compare

@AndyCappDev AndyCappDev released this 01 May 18:18
· 141 commits to main since this release

[0.2.0] — 2026-05-01

This release lands a substantial expansion of the stet-pdf-reader
structural API, the PDF imaging-extension operators (transparency,
soft masks, optional content), and the pdfmark PostScript-to-PDF
authoring bridge. Several public match-surface enums are now
#[non_exhaustive] to lock in additive evolution — the breaking
changes are deliberate and documented per-crate below.

⚠ Breaking changes

This is a breaking release. Cargo treats the 0.1 → 0.2 bump as
incompatible (per the SemVer rules for 0.x), so existing users
pinned at stet = "0.1" won't be auto-upgraded.

The breaking surface is concentrated in two places:

  1. #[non_exhaustive] markers were added to ~40 public
    match-surface enums across stet-graphics, stet-core, and
    stet-pdf-reader. Any downstream match over DisplayElement,
    PsError, Destination, AnnotationKind, the various pdfmark
    record enums, etc. now requires a _ => { ... } wildcard arm.
    See the "Changed — public API breaking changes" subsection below
    for the complete list.

  2. stet-pdf no longer emits PDF/X-3 OutputIntents. PDF output
    is now plain PDF 1.7. PdfDevice::set_output_profile() is
    #[deprecated] as a no-op; existing call sites compile but stop
    producing the (previously broken) PDF/X-3 conformance label.

For a typical downstream renderer that pattern-matches on
DisplayElement, the migration is one wildcard arm per match
site:

 match element {
     DisplayElement::Fill { .. } => { /* … */ }
     DisplayElement::Stroke { .. } => { /* … */ }
     DisplayElement::Image { .. } => { /* … */ }
+    _ => { /* fall through; new variants in 0.2.x are additive */ }
 }

The #[non_exhaustive] ratchet is intentional: it makes future
variant additions non-breaking, so 0.2.x → 0.3.x will be smaller.

Added — stet-pdf-reader structural API

A read-only structural-content API for PDF inspection and tooling.
Every accessor parses lazily on first call and caches its result.

  • metadata()/Info dict (title, author, dates, …) and the
    catalog's /Metadata XMP stream.
  • viewer_preferences() — page layout, page mode, print preferences,
    and reading direction hints.
  • outline() — bookmark tree as OutlineItems with
    destination/action resolution.
  • destinations(), resolve_named_destination(name) — named
    destination table merged from /Catalog /Dests (legacy) and the
    /Names /Dests name tree.
  • page_annotations(page) — typed Annotation list with
    destination/action resolution.
  • form(), form_fields() — AcroForm field tree (text, choice,
    button, signature) with widget cross-references.
  • page_boxes(page) — MediaBox / CropBox / BleedBox / TrimBox /
    ArtBox.
  • embedded_files(), embedded_file_bytes(name)/EmbeddedFiles
    name-tree walker.
  • layers(), layer(ocg_id), configurations(),
    default_configuration(), layer_tree(), layer_set_for(intent)
    — Optional Content Group (OCG) metadata, hierarchy, render-intent
    rules, and a runtime LayerSet for visibility overrides.
  • parse_warnings() — diagnostic sink for non-fatal parse issues
    (broken outlines, bad name trees, malformed /VE expressions, …).
  • New stet inspect <file.pdf> CLI subcommand surfaces the structural
    API at the command line.

See docs/PDF-READER-API.md and docs/PDF-LAYERS.md for full
references.

Added — PDF imaging extensions

Display-list-level support for the PDF transparency and optional-content
imaging models, layered on top of the PostScript interpreter.

  • Alpha and blend modes: setblendmode, setfillalpha,
    setstrokealpha, setalphaisshape. All 16 PDF blend modes.
  • Transparency groups: begintransparencygroup /
    endtransparencygroup with Knockout, Isolated, and group
    colour space (DeviceGray / DeviceRGB / DeviceCMYK / ICC).
  • Soft masks: begintransparencymaskgroup /
    endtransparencymaskgroup with Alpha and Luminosity subtypes,
    transfer functions, and backdrop-colour handling.
  • Optional Content (OCG): setocg / endocg operators wrap
    display-list content in OcgGroup elements with
    OcgVisibility::Single / Membership / Expression predicates.
    LayerSet (in stet-graphics) is the consumer's per-render override
    map; render_page_to_rgba_with_layers honours it.
  • Filters: JBIG2Decode and JPXDecode for embedded image
    streams.

See docs/PDF-EXTENSIONS.md for the full reference and
docs/PDF-LAYERS.md for the runtime layer-visibility model.

Added — pdfmark PostScript-to-PDF authoring

pdfmark operator dispatch in stet-ops (gated behind
register_pdf_authoring_ops so it's only visible to systemdict on the
PDF output path) plus matching emitters in stet-pdf. Five phases of
authoring support:

  • /DOCINFO — document info dictionary (title, author, subject,
    keywords, creator, producer, dates, trapped).
  • /OUT — outline (bookmark) tree authoring with destination /
    action targets.
  • /ANN — Link, Text, FreeText annotations.
  • /DEST, /PAGE, /PAGES — named destinations and per-page-box
    overrides.
  • /VIEWERPREFERENCES, /Metadata — viewer preferences and
    document-level XMP metadata.
  • /Widget and /FORM — AcroForm widget annotations and field-tree
    emission.
  • /EMBED, JavaScript / Named actions, page-level /AA triggers.

See docs/PDFMARK-AUTHORING.md for the full reference.

Added — colour management

  • Hand-rolled colorimetric A2B1 CLUT sampler
    (stet-graphics::icc::perceptual). moxcms 0.8's create_transform
    pipeline over-saturates CMYK→sRGB output relative to lcms2 / Acrobat
    / Ghostscript on midtone colours; this module bypasses it for v2
    lut16Type CMYK profiles and matches lcms2 RelCol output to ±1 RGB
    level on a 17⁴ sweep against ISO Coated v2 300% (ECI). Out-of-gamut
    colours clip to the sRGB boundary (matching lcms2 / GS) so pure
    process primaries remain saturated. BPC is calibrated against the
    sampler's own (1, 1, 1, 1) output so K-heavy CMYK lands at the
    correct darkness. Profiles whose tables are mAB / mft1 fall back
    to the moxcms-driven bake.
  • Soft-mask CMYK-domain blend gate widened to accept Group-wrapped
    flat CMYK fills (GWG 16.11 "Gradient Feather"). The GWG 16.10
    outer-glow protection still rejects on the inner Fill's blend-mode
    check.

Changed — public API breaking changes

These match-surface enums are now #[non_exhaustive] so adding
variants is non-breaking for any consumer that includes a _ => arm.
Existing consumers must add wildcard arms (or update their match
expressions) to keep building.

  • stet-graphics: DisplayElement, ImageColorSpace,
    ShadingColorSpace, SpotColorSpace, LineCap, LineJoin,
    FillRule.
  • stet-core: PsError, FilterKind, RleState.
  • stet-core::pdfmark: PdfMarkRecord, AnnotationSubtype,
    AnnotationTarget, OutlineDestination, OutlineAction,
    GoToTarget, ViewSpec, FieldType, FieldValue, DocDate,
    TrappedState, TzSign, LinkHighlight, TextAnnotationIcon,
    PageOverrideScope.
  • stet-pdf-reader: PdfError, Destination, ViewSpec, Action,
    AnnotationDate, AnnotationKind, AnnotationColor,
    AnnotationKindData, FieldKind, ButtonType, FieldValue,
    TrappedFlag, PageLayout, PageMode, ReadingDirection,
    PrintScaling, Duplex, AfRelationship, ParsePhase,
    LocationHint, Severity, RenderIntent, LayerIntent,
    UsageState, PageElementSubtype, LayerTreeNode, BaseState,
    ListMode, AutoStateEvent.

Param structs (FillParams, StrokeParams, ImageParams, the
pdfmark record structs, Annotation, FormField, Layer, etc.) are
not marked #[non_exhaustive] — adding fields lands additively
and consumers should pattern-match with .. for forward
compatibility.

A scripts/check-non-exhaustive.sh audit runs in the local pre-push
hook; new public enums in the listed files must either carry the
marker or be allow-listed with a one-line justification. See the
"Stable extension points" section of CLAUDE.md and the per-doc
"Stability" sections of docs/DISPLAY-LIST.md,
docs/PDF-READER-API.md, and docs/PDFMARK-AUTHORING.md.

Changed — other

  • stet-pdf: removed the PDF/X-3 OutputIntent emission. The writer
    was emitting soft-mask transparency (prohibited by PDF/X-3) while
    labelling output as PDF/X-3:2003 — a conformance conflict any
    preflight tool would flag. PDF output is now plain PDF 1.7 with no
    PDF/X conformance claim. A correct PDF/X-4 implementation is
    planned.
  • stet-pdf: PdfDevice::set_output_profile() is #[deprecated]
    as a no-op. Retained for forward API compatibility with the planned
    PDF/X-4 work.
  • stet-cli: --width / --height flags for PDF input override
    the page's MediaBox at render time.

Added — documentation

  • docs/PDF-READER-API.md — full reference for the structural API.
  • docs/PDF-LAYERS.md — full reference for the OCG / layer API.
  • docs/PDF-EXTENSIONS.md — full reference for the imaging extension
    operators and the JBIG2 / JPX filters.
  • docs/PDFMARK-AUTHORING.md — full reference for the pdfmark
    authoring bridge.
  • New Rendering Correctness section in the root README covering
    seam-free rendering on adjacent clipped regions and full overprint
    simulation.