Commit Graph
92 Commits
Author SHA1 Message Date
aiongg 860f437063 Merge part 2 (paint), #265 2026-10-24 07:12:35 +00:00
aiongg 2cbbf81b1d hayro-interpret: a transparent plate paint stays transparent when a stencil drops pattern opacity 2026-10-24 06:57:41 +00:00
aiongg 429258979d hayro-interpret, hayro: port PdfCraft's font and text fixes (ledger P7, 49, 50)
From PdfCraft 0b670caf4:

- P7 (PdfCraft #3109, #3116): text in mode 7 (clip only) installs its
  clip and reaches the device as GlyphDrawMode::Clip, which the hayro
  renderer does not paint, so extraction that leaves out invisible OCR
  text keeps a heading drawn through its clip. Test:
  clipping_only_text_reaches_the_device_apart_from_invisible_text in
  crates/pdf/tests/upstream_text.rs.
- (49) (PdfCraft #2949 and 09668ce88): a TrueType post table version
  1.0, 2.0 or 3.0 written with its 16-bit halves swapped is accepted,
  and a swapped 2.0 table's glyph names are read. Unit test on a
  synthetic sfnt in font::blob::tests.
- (50) (PdfCraft #3958): the CFF glyph-name map is built once on first
  use and shared between clones instead of scanning the charset per
  code. PdfCraft's unit test comes with it.
2026-10-24 06:55:26 +00:00
aiongg f4f0e88985 hayro-interpret, hayro: port PdfCraft's paint fixes (ledger 51, 46, P4, 36)
From PdfCraft 0b670caf4:

- (51): the saved-state accounting (state_bytes, the saved_bytes update,
  num_states) uses saturating sums, so a huge dash array or clip list
  stays over the 64 MiB input bound on 32-bit targets instead of
  wrapping.
- (46) and the hayro stencil paint (PdfCraft #2977): an image XObject's
  group applies the fill opacity, so a stencil mask's paint no longer
  carries it again (a mask at ca 0.5 was drawn at a quarter), a pattern
  paint drops the opacity it captured at scn (Pattern::without_opacity),
  and the mask is painted with the fill paint rather than the stroke
  paint.
- PdfCraft #3246 (unledgered): a shading pattern takes the alpha current
  at paint time (Pattern::set_alpha), so a gs after scn or SCN still
  applies; plate paints take it the same way.
- (36) (PdfCraft #3035): a mesh pixel whose corner no triangle holds
  strictly takes the triangle that covers its center, edges included
  (Triangle::covers), so shared edges leave no seam. Marked
  "PdfCraft patch (#3035)": the plate-mode code already uses (35) and
  (36) for #2770's numbers.

Tests: the PdfCraft raster tests for (46), #3246 and (36), adapted in
crates/pdf/tests/upstream_raster.rs.
2026-10-24 06:39:40 +00:00
aiongg 7895f5ed79 krilla: optional content groups (layers), patch 12 (#258)
Document::add_optional_content_group writes an OCG; Surface::start_optional_content and
end_optional_content mark content with /OC BDC/EMC, registering the group under the stream's
/Properties resources. Marks nest independently of tagging, and misuse returns or records a
KrillaError instead of panicking. The catalog gets /OCProperties (hidden groups in /OFF) and,
opt-in, /PageMode /UseOC. PDF/A-1 reports ValidationError::OptionalContent; below PDF 1.5 the
version requirement is registered too.
2026-10-24 02:13:19 -04:00
aiongg 4238a2dd57 Merge upstream main into print-color
Conflicts: NOTICE, vendor/README.craft-reader.md and the hayro-interpret and
hayro-syntax SOURCE.json keep the ec0a965 provenance and add hayro-cmap
(a2ec27b) and hayro-postscript (crates.io 0.1.0). type0.rs keeps PdfCraft's
flat sample array with its 64-bit largest sample and main's 32-bit test.
Local sha256 values recomputed for the merged files.
2026-10-24 05:46:57 +00:00
aiongg 2eca9b3a53 pdf: vendor hayro-postscript and skip << and >> runs without recursion (#263)
hayro-postscript 0.1.0 is the token scanner hayro-cmap uses for the
CMap streams PDFs embed. Its object reader skipped each `<<` or `>>`
by calling itself again, so a stream holding a long run of `<` or `>`
bytes recursed once per pair and aborted the process with a stack
overflow.

Vendor the crates.io package unchanged and patch `object::read` to
skip those runs in a loop, returning the same next object as before.
Wire it in like the other Hayro crates: workspace exclude,
[patch.crates-io] entry, SOURCE.json with registry and local hashes,
the backend test script, NOTICE, ATTRIBUTION.md and the reader README.

Tests cover a million `<` and a million `>` bytes, `<< /A 1 >>` and
nested `<<<< /X >>>>` runs.
2026-10-23 23:31:35 -04:00
aiongg d2d5a400da pdf: port PdfCraft's reader fixes, part 1 (syntax and text) (#261)
* hayro-syntax: port PdfCraft's syntax fixes (ledger 17, 19, 20, 23, 4-ext, #3565, base_dimensions floor)

From PdfCraft a2ec27b47:

- (17), (19): a CCITT image with /Rows 0, or with fewer /Rows than its
  /Height, decodes to the image height instead of zero or /Rows rows.
- (20): spaces or tabs between the stream keyword and its line break are
  skipped, so the stream data starts after the line break.
- (4) extension: an inline image's EI followed by a delimiter (EI%, EI[)
  ends the image; only a regular character makes it part of a longer token.
- (23): bytes above 0x7F between two EI candidates don't reject the first;
  the operator look-ahead decides.
- #3565: a doubled sign (--280, +-280) is read and skipped as one number.
- Page::base_dimensions keeps a one-point floor after /UserUnit instead of
  one raw unit.

Also a local bound: a CCITT /Columns past u32::MAX is refused instead of
wrapping to a small width that passed ccitt_size_ok.

Tests: content and number unit tests from PdfCraft, a stream unit test, a
synthetic page test for the floor, a CCITT /Columns unit test, and the two CCITT raster tests in
crates/pdf/tests/upstream_raster.rs.

* hayro-interpret: port PdfCraft's text fixes (ledger 30, 44, P2, P6, P8, 26-ext)

From PdfCraft a2ec27b47:

- (30): WinAnsi 0xA0 and 0xAD and MacRoman 0xCA read as an ordinary space
  and hyphen (Annex D.2 gives them those glyph names) unless /Differences
  names nbspace or sfthyphen.
- (44): a /ToUnicode /Identity-H or /Identity-V name reads two-byte codes
  as their Unicode values; controls and lone surrogates give no text.
- P6: glyph names outside the Adobe Glyph List (f_i, hyphen.case,
  uniXXXXXXXX) read by the glyph list specification's full mapping; names
  that only number a glyph (C39, c251) give no text.
- P8: a substitute font whose charmap lacks a spacing character (U+2002 and
  similar) draws its ordinary space instead of .notdef.
- P2: a Type 3 glyph's /FontBBox is transformed to device space before it
  bounds the glyph's clip and shadings, so shaded glyphs draw at every
  position.
- (26) extension: comma-below letters (s, t, k, l, n, r, G with comma) in
  the standard-font stand-ins are the base letter with the font's comma,
  scaled and placed under the baseline.

Tests: crates/pdf/tests/upstream_text.rs for (30), (44) and P6; the Type 3
shading and comma-below raster tests in crates/pdf/tests/upstream_raster.rs.
P8's PdfCraft test needs a Japanese substitute font and is not ported.

* hayro-syntax: refresh SOURCE.json local hashes for Cargo.lock, ascii_85.rs and filter/mod.rs

They changed in #241 and #253 without their local sha256 values.
2026-10-23 23:30:56 -04:00
aiongg ef13696c29 krilla, craft-pdf tests: rustfmt the review fixes 2026-10-24 02:56:03 +00:00
aiongg 4befe2f986 krilla: document that nonzero overprint mode applies to DeviceCMYK only 2026-10-24 02:53:25 +00:00
aiongg dc54ca0e71 krilla: Trapped::Unknown is written to XMP as well as the information dictionary 2026-10-24 02:53:06 +00:00
aiongg 66bc4f0b4c krilla: a PDF/X version fails PDF/A-1 to 3 validation, whose XMP needs an extension schema 2026-10-24 02:46:07 +00:00
aiongg 5d5e0892de krilla: Image::from_custom checks channel lengths in usize and returns an error 2026-10-24 02:43:24 +00:00
aiongg b4de602172 krilla: ImageColorspace stays Copy; DeviceN images take their space from CustomImage::device_n_space 2026-10-24 02:33:10 +00:00
aiongg 2c6b3b5392 hayro-interpret: compute the largest 32-bit Type 0 sample in 64 bits (#257)
PdfCraft ledger hayro-interpret (31), its overflow part: a Type 0 function
with /BitsPerSample 32 computed 2_u32.pow(32), which overflows (a panic with
overflow checks on). The maximum is now ((1u64 << bps) - 1) as f32. The flat
sample array that (31) also brings is a performance change and is not part of
this commit. Test: function::type0::tests::thirty_two_bit_samples_do_not_overflow.

PdfCraft's other reader limits are already covered here: ASCII85 output is
bounded by the decode limit (#253), object-stream indexes are parsed once with
checked offsets, and direct objects nest at most 64 levels (PdfCraft: 128).
2026-10-23 22:32:25 -04:00
aiongg fbda14c62b krilla: soft-mask groups blend in sGrey under ICC CMYK, so the backdrop stays black 2026-10-24 02:30:08 +00:00
aiongg 9f75d3dc19 pdf: keep a CID font's /W2 table past an out-of-range first CID; vendor hayro-cmap from PdfCraft (#254)
* pdf: keep a CID font's /W2 table past an out-of-range first CID; vendor hayro-cmap from PdfCraft

- hayro-interpret: a /W2 run whose first CID is past 65535 is skipped, as in
  /W. A run starting at 4294967295 overflowed the CID counter and discarded
  the whole table. Unit test in font::cid.
- hayro-cmap 0.1.0 is vendored from PdfCraft a2ec27b47 with its malformed-CMap
  patch (PdfCraft #3177): bad bfchar/bfrange entries, an unresolvable usecmap
  and an unparseable tail are skipped instead of failing the whole CMap. The
  crate's tests come with it. Wired up like the other vendored Hayro crates
  (workspace exclude, patch entry, SOURCE.json, backend test script); NOTICE,
  ATTRIBUTION.md and vendor/README.craft-reader.md record the source.

* hayro-syntax: refuse an xref-stream subsection that runs past object number u32::MAX

The object number was start + i in unchecked u32: a subsection starting near
u32::MAX overflowed (a panic in debug builds, a wrong object number in
release). Covered in xref::tests::xref_stream_entries_need_backing_bytes.

* hayro-cmap: a binary usecmap counts against the nesting limit; /W2 checks the CID first

- hayro-cmap: a binary CMap's usecmap passed its own depth to the nested
  parse, so a self-referencing binary CMap recursed until the stack
  overflowed. It now counts like a text usecmap. Test:
  self_referencing_binary_usecmap_stops_at_the_nesting_limit.
- hayro-interpret: the /W2 first-CID check runs before the run's metrics
  are read, so an incomplete run past CID 65535 no longer discards the
  rest of the table.

* hayro-syntax: refuse xref-stream object numbers past i32::MAX

ObjectIdentifier stores an i32; a number between i32::MAX and u32::MAX
was cast to a negative object number.
2026-10-23 22:17:04 -04:00
aiongg c52c6f3ec0 Merge upstream main into print-color
- hayro-syntax ascii_85.rs: main's decode-limit version (same bound as
  the pdfcraft ec0a965 copy, plus its test).
- hayro-interpret and krilla SOURCE.json: source fields from pdfcraft
  ec0a965 / krilla 0.8.2, sha256 recomputed for merged files.
- krilla PNG decode cap from main recorded as patches/11-png-decode-cap.patch
  with its ledger row and README section.
2026-10-24 02:08:42 +00:00
Dylan M. Taylor d6b3fb9671 security: bound vendored hayro ASCII85 output by the stream decode limit (#253)
* security: bound ASCII85 output by the stream decode limit (CodeRabbit)

* fix(ascii85): truncate terminal partial groups to decode limit
2026-10-23 21:54:26 -04:00
Dylan M. Taylor 9def84d7a5 security: fallible bitmap allocation in vendored hayro-jbig2 (#242)
* security: fallible bitmap allocation in vendored hayro-jbig2 (follow-up to #239)

* security: reinitialize allocates before mutating the jbig2 bitmap (CodeRabbit)
2026-10-23 11:16:19 -04:00
Dylan M. Taylor 35d18945a9 fix(hayro-syntax): read full /W[0] xref entry type width (#241)
* fix(hayro-syntax): read full /W[0] width for xref stream entry type (follow-up to #239)

* hayro-syntax: loader-path test for oversized /W[0]; document patch; drop committed build output (CodeRabbit)
2026-10-23 11:14:16 -04:00
Dylan M. Taylor 6cefd467fc security: bound vendored hayro xref/object-stream/JBIG2/graphics-state work and krilla PNG size (CodeRabbit) (#239)
* security: bound vendored hayro xref, object-stream, JBIG2 and graphics-state work; krilla PNG size

hayro-syntax:
- xref-stream subsections must be backed by decoded bytes: zero /W widths and counts
  longer than the data are refused before inserting (CodeRabbit CWE-400, xref.rs:962)
- object-stream offset tables are parsed once per document and cached in Data
  (CodeRabbit CWE-407, xref.rs:1079)
- embedded JBIG2 pages over 2^28 pixels are refused before allocating, with checked,
  fallible reservation (CodeRabbit CWE-789, filter/jbig2.rs:34)
- a JBIG2Globals stream with an image filter is ignored, so globals cannot recurse
  (CodeRabbit CWE-674, filter/jbig2.rs:20)

hayro-interpret:
- at most 4096 saved graphics states / 64 MiB retained; dash arrays over 256 entries stroke
  solid (CodeRabbit CWE-400, context.rs:226)

krilla:
- PNGs implying more than 1 GiB of decoded output are refused at Image::from_png and in
  the deferred decoder; the buffer is reserved fallibly (CodeRabbit CWE-789,
  graphics/image.rs:565)

SOURCE.json local hashes updated; patches recorded in vendor/README.craft-reader.md and
vendor/krilla/README.craft.md.

* vendor: fix SOURCE.json local hashes; reserve krilla's colour/alpha split buffers fallibly

- SOURCE.json: only the local sha256 changes; the source/upstream hashes of the patched
  files are restored (CodeRabbit review)
- krilla handle_u8_image/handle_u16_image reserve their split buffers with try_reserve_exact
  and return an error, so a valid image under the 1 GiB decode cap cannot abort the process
  on the second allocation (CodeRabbit review)
2026-10-23 08:39:26 -04:00
aiongg 4cdf3dece4 hayro-interpret: name the spot alternate helper for its space 2026-10-23 08:25:41 +00:00
aiongg bd5c21682c hayro: DeviceCMYK luminosity masks take their values from the inks
A luminosity soft mask whose group is DeviceCMYK draws the group's four process plates over the backdrop and applies 1 - min(1, 0.3c + 0.59m + 0.11y + k) (ISO 32000-2 §10.4.2.2), so K 100% hides the masked object. Spot colorants on those plates paint through their alternate space (Plate::spots_as_process).
2026-10-23 07:26:21 +00:00
aiongg af39757fea krilla: README states that patch 09 changes every document's XMP 2026-10-23 05:22:24 +00:00
aiongg 7865923aec Merge upstream main into print-color 2026-10-23 05:21:53 +00:00
James ChapmanandClaude Code f20f364d55 hayro-jbig2: cap long-form referred-to segment count (#176)
* hayro-jbig2: cap long-form referred-to-segment count

A crafted JBIG2 segment header can claim a 29-bit referred-to-segment count;
Vec::with_capacity reserved ~2 GiB from that field before a single
referred-to number was read, and the resulting allocation failure aborts
the process in a way catch_unwind cannot contain (fatal on wasm32, where
memory is capped well below 2 GiB). A ~100 KB Flate-compressed PDF was
enough to reach it inside the 256 MiB stream budget.

Real files refer to a handful of segments, so the count is now capped at
u16::MAX; larger claims fail as InvalidReferredCount before any
retention-flag bytes are consumed. Regression test included.

Updates SOURCE.json's local hash for src/segment.rs and records the patch
in vendor/README.craft-reader.md, following the vendored tree's provenance
practice.

Co-Authored-By: Claude Code <noreply@anthropic.com>

* hayro-jbig2: record git-blob sha256 for patched segment.rs

The previous entry hashed the Windows working-tree checkout (CRLF) of
src/segment.rs instead of the LF content git stores, so every other
manifest entry's convention (git-blob content hash) was broken by this
one file. Re-hash against `git show HEAD:vendor/hayro-jbig2/src/segment.rs`
as the vendored manifests' other 30 entries do.

Co-Authored-By: Claude Code <noreply@anthropic.com>

---------

Co-authored-by: Claude Code <noreply@anthropic.com>
2026-10-22 13:10:36 -04:00
aiongg 0fe6156614 krilla: PDF/A ledgers state DeviceN and the print output intent
Patch 06 records that DeviceN fails export under PDF/A-1 to -3 (its tint transform is
PostScript) and is written under PDF/A-4; patch 08 records the second output intent and
the caller's CMYK destination profile.
2026-10-20 04:09:24 +00:00
aiongg 4026931196 Merge craft-prepress into the print color PR 2026-10-20 03:51:59 +00:00
aiongg 60dc2b54ce krilla: write mesh corner colors in one color space
A mesh gradient took its color space and component count from the first
patch's first corner, so a later corner in another space was truncated or
padded with zeros and written as the wrong color. Mesh corner colors now go
through the same rule as gradient stops (`common_color_space`): process
colors alone are DeviceCMYK, one spot alone is Separation, and mixes are
DeviceN with process colorants first, then spots. Colors that rule can't
unify (RGB with CMYK, registration) fail the document with
`KrillaError::MixedMeshColorSpaces`. The opacity soft mask is unchanged, and
a mesh in one space writes the same bytes as before.

patches/10-mesh-gradients.patch holds #184's change and this fix, so
patches 01 to 10 reproduce src; the ledger section 10 and SOURCE.json follow.
2026-10-20 03:41:18 +00:00
fastmikey99 ce31f9d710 krilla: mesh gradients as PDF Type 6 shadings
paint::MeshGradient / MeshPatch: Coons patches with a colour and opacity at each corner, written as
one Type 6 (Coons patch mesh) shading through pdf-writer's StreamShading, so viewers and RIPs blend
them smoothly at device resolution instead of an app cutting each patch into flat-colour pieces.
Same path as the other gradients: a shading pattern fill, and corner opacities below 1 as a
luminosity soft mask of the same mesh in gray. 32-bit coordinates over the mesh bounds, 8-bit
components, Flate. Recorded in vendor/krilla/README.craft.md and SOURCE.json.
2026-10-20 03:41:18 +00:00
aiongg 21154585b5 krilla: record the master-rendition patch (#183) in the patch ledger 2026-10-20 03:41:18 +00:00
Hamza 96c45ccde1 krilla: a written document is the master rendition, not a proof
`chunk_container` wrote `xmpMM:RenditionClass` as `proof` on every PDF krilla
produces. That property says which rendition a file is (XMP Part 2, Media
Management): `default` is the master, `proof` a proof copy. So every export
told a prepress system that a print deliverable was only a proof, and PDF/X
output carries the same claim.

Noticed on storytold/designcraft#1207, where PDF/X-4 output was being checked
against Acrobat's preflight; it is not what fails that check, but it is wrong
and it reaches every app that writes PDF through this tree.

Checked with DesignCraft pointed at this tree: `xmpMM:RenditionClass` reads
`default` for a PDF/X-4 export and for an ordinary one, where both read `proof`
before.
2026-10-20 03:41:18 +00:00
aiongg eedd0246df krilla: CMYK print color in the vendored krilla, and a craft-pdf print preset
Print PDFs written through krilla separated wrongly: transparency groups blended in RGB
(K 50% over C100 separated as C84 M34 Y32 K37 instead of C50 K50), and there was no
overprint, knockout, DeviceN, soft-mask backdrop or print output intent.

Patches in vendor/krilla/patches/, recorded in README.craft.md and SOURCE.json:
- 02 blending color space: GroupColorSpace { Rgb (default, unchanged output), Cmyk }
- 03 overprint: Surface::push_overprint (/op /OP /OPM)
- 04 knockout groups: Surface::push_group(GroupOptions { isolated, knockout })
- 05 soft-mask backdrop and transfer function (/BC /TR)
- 06 DeviceN and NChannel colors for fills and strokes
- 07 DeviceN images and shadings
- 08 print output intent (GTS_PDFX), /Trapped, PDF/X version markers

craft_pdf::write::print::settings(PrintColor) turns them on for print export.
2026-10-20 03:41:13 +00:00
aiongg 2c80b65e98 separations: use US spelling 2026-10-20 03:25:47 +00:00
aionggandmtlcl410 b01d19c716 vendor: port pdfcraft #2974 knockout groups into hayro
Bring storytold/pdfcraft#2974 (source commit
bae69819594a6385a027fec1f67e6b3c36c259b4) onto the vendored
hayro-interpret and hayro. Knockout transparency groups (/K true) knock
out: while one is innermost, fills, strokes, glyph outlines and shadings
are drawn with Compose::Copy, weighted by coverage. An unmasked image's
rectangle and a nested group's shape are cleared before their layer
composites; the nested group's shape comes from an erase pass over its
content. Masked images and stencils composite as before.

Code comments label the change "Knockout patch (pdfcraft #2974)": the
pull request numbers it hayro-interpret patch 39 and hayro patch 19,
which pdfcraft may renumber. The erase pass resolves resources with
Resources::from_scope, as this tree's form drawing does.

crates/pdf/tests/knockout.rs adapts the pull request's test to the
raster path (without its preview case: craft-pdf has no preview mode).
A plate-mode test checks that a knockout group of two 50% squares
separates with only the top square in the overlap. Options documents
that color_replacement also maps plate films. Ledger, NOTICE and the
source manifests are updated.

Co-authored-by: mtlcl410 <2368091+mtlcl410@users.noreply.github.com>
2026-10-20 03:07:22 +00:00
aionggandGuillem Hermida 7764afb2a7 vendor: convert plate-mode CMYK through a CmykConversion trait
CmykSimulation converts process colour to an output intent's CMYK
through a color::CmykConversion: sRGB colours, and CIE XYZ relative to
the D50 PCS white (color::PCS_WHITE) for Lab and ICCBased colours.
CmykSimulation::new keeps the moxcms conversion from pdfcraft #2770,
which takes XYZ on through its ProPhoto hub; with_conversion takes a
caller's, so a crate can separate with its own colour management.

crates/pdf/tests/plates.rs adapts #2770's plate tests to the raster
path: process, spot, DeviceN, All/None, ICC CMYK, gray and RGB colours,
images, shadings, uncoloured patterns, soft masks, OP/op/OPM, the ink
sink, output-intent simulation with #2770's synthetic ICC profiles, and
a caller's conversion. The ledger and NOTICE name the pull request.

Co-authored-by: Guillem Hermida <66697068+guillehr2@users.noreply.github.com>
2026-10-20 02:53:37 +00:00
aionggandGuillem Hermida 2c8c3ad261 vendor: port pdfcraft #2770 plate mode into hayro-interpret
Bring the vendored interpreter part of storytold/pdfcraft#2770 (Output
Preview, source commit 6fcf2a4aca29e943e28cb69017ff8f87d00656c6) onto
the ec0a965 snapshot. It applies without conflicts.

InterpreterSettings::plate draws one ink's separation: every paint
draws that ink's tint as a gray film, by the colour space's ink use and
tint. The graphics state reads OP, op and OPM, and an overprinting
paint that doesn't specify the plate's ink leaves the plate as it is
(ISO 32000-2 8.6.7). InterpreterSettings::ink_sink reports the spot
inks paints use, and color::CmykSimulation converts process colour to
an output intent's CMYK profile.

PdfCraft's separations.rs, Output Preview UI and automation are not
part of this port. The ledger in vendor/README.craft-reader.md names the
pull request, author and source commit.

Co-authored-by: Guillem Hermida <66697068+guillehr2@users.noreply.github.com>
2026-10-20 02:40:50 +00:00
aiongg b6f60f25b1 vendor: re-sync hayro reader trees from pdfcraft ec0a965
Bring vendor/hayro, hayro-interpret, hayro-syntax and hayro-jbig2 to
storytold/pdfcraft ec0a965074f376a5bf610435948e4e5184bf3299 (main,
2026-10-19), from 7437bde. The local patches (per-document decode
limits, incomplete-content diagnostics, Hayro 0.8 resource scopes,
nesting cap, iterative page tree, TJ fill order, transfer rounding,
safety repairs) are carried by a three-way merge without conflicts.

The re-sync includes transparency group /I and /K reading (pdfcraft
#2027), patches 28, 29 and 31-34, and the reader fixes listed in
vendor/README.craft-reader.md. SOURCE.json manifests, NOTICE and the
craft-pdf README name the new source revision.
2026-10-20 02:30:13 +00:00
skylar taylor-barrick ca50d63b77 fix(pdf): preserve upstream reader behavior during migration 2026-10-14 02:26:18 -06:00
skylar taylor-barrick c07b3fada6 feat(pdf): share patched reading and rasterization 2026-10-13 12:52:32 -06:00
skylar taylor-barrick c3487320b2 feat(pdf): add shared guarded writer foundation 2026-10-13 12:29:12 -06:00