Commit Graph
436 Commits
Author SHA1 Message Date
skylartaylor b282cb2d29 egui037: Reconcile shared UI pins with reviewed PDF updates 2026-10-25 01:29:13 +02:00
aiongg 2ab6049d90 krilla: link annotations and page boxes refuse non-finite geometry (patch 13) (#283)
* krilla: link annotations refuse non-finite or degenerate geometry (patch 13)

Link quad points that are empty or non-finite, link rects and page boxes
that overflow when flipped into PDF coordinates, and XYZ destinations with
a missing page or a non-finite point made krilla panic, which aborts a
WASM app. Document::finish returns InvalidAnnotationGeometry,
InvalidPageBox or InvalidDestination instead. Constructor signatures are
unchanged.

* krilla: error messages format page indices without overflow (patch 13)
2026-10-24 09:38:24 -04:00
aiongg e179d42418 craft-pdf: write URI links only for http(s) with a host and mailto (#282)
* craft-pdf: write URI links only for http(s) with a host and mailto

A document from someone else can carry any link target, and an export
that turns every hyperlink into a PDF URI action hands those targets to
whoever opens the file: script and data URIs, OS protocol handlers,
UNC paths, //host/share, file:// and smb:// links to a host, and
Windows Search links naming a share.

safe_url allows only http and https URLs with a host and mailto with an
address, after trimming whitespace and comparing the scheme
case-insensitively. It is the rule DeckCraft uses for its slide show
and export, and is available without any feature.

write::uri_target returns the Krilla link target for an allowed URL and
None otherwise, so an app that builds its URI links with it writes no
link annotation for a refused target and leaves the page content as
drawn.

* craft-pdf: safe_url needs a real http(s) host and a mailto recipient
2026-10-24 08:47:54 -04:00
aiongg 734eb11826 Merge pull request #279 from aiongg/pdf-reader-sync
pdf: reader-sync batch, PdfCraft's reader fixes parts 2–5
2026-10-24 08:23:26 -04:00
aiongg fcbf08de14 Merge remote-tracking branch 'upstream/main' into pdf-reader-sync
# Conflicts:
#	vendor/hayro-syntax/SOURCE.json
2026-10-24 12:11:27 +00:00
skylartaylor 25da1314d4 Preserve fractional ink endpoints in aligned text bounds 2026-10-24 12:01:36 +02:00
skylartaylor a415e404d6 fix(ui): preserve bounds and paint origins for aligned text 2026-10-24 10:51:20 +02:00
Dylan M. TaylorandClaude Opus 5.5 13d766e074 security: bound vendored hayro CCITT rows of unknown height and JPEG 2000 codestream size (#255)
* security: bound vendored hayro CCITT rows of unknown height and JPEG 2000 codestream size

- CCITT: `/Rows 0` decoded to the end of the data; a bit of 2D code can repeat a whole row,
  so a small stream produced gigabytes. Rows are now capped by the output limit (in the
  stream's 1-bit rows) and 2^28 pixels.
- JPEG 2000: the decoder allocated its output from the codestream's own dimensions,
  infallibly. Over 2^28 pixels or the output limit (at least 64 MiB) is refused before
  decoding, and the buffer is reserved fallibly.
- SOURCE.json local hashes updated (ascii_85.rs's had not been after #253).

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

* fix(ccitt): pass the output limit in the columns test

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 04:29:32 -04:00
aiongg d0f4ab75a8 hayro-interpret, hayro-syntax: review fixes for the reader-sync batch
- Patch-mesh triangles are rebuilt after inflation, so the stored dot products match
  the vertices.
- A stencil image restores the fill alpha itself when the saved-state bound skipped
  its save.
- A resolved JP2 palette decodes to 8 bits whatever /BitsPerComponent says.
2026-10-24 08:07:16 +00:00
skylartaylor 8c05070a63 MIG-037: integrate current shared-library main and clarify performance reports
Preserve the reviewed current-main print/vendor changes, render the benchmark
font path as readable JSON, and document the implemented example harness.
2026-10-24 09:48:06 +02:00
aiongg 4bd8b167da Merge part 5: ICC profile cache key 2026-10-24 07:46:44 +00:00
aiongg 89a5b2cf2e hayro-interpret: port PdfCraft's ICC profile cache key (#3020)
Cache the color space of an /ICCBased profile by its stream object, and on
a miss by its dictionary key and raw bytes, instead of the dictionary's
bytes alone, so two profiles with the same /N and /Length each draw through
their own profile. InterpreterCache::icc_profile_reads counts profile reads.
PdfCraft's two raster tests are adapted in tests/upstream_raster.rs.
2026-10-24 07:46:17 +00:00
aiongg 3648e60159 pdf: keep both sides' upstream_raster tests from the /Default color spaces merge 2026-10-24 07:43:00 +00:00
aiongg f8cbf0e1c2 pdf: keep both sides' upstream_raster tests from the /Default color spaces merge 2026-10-24 07:42:37 +00:00
aiongg d2b25a0dc1 Merge part 5: mesh shading extent
# Conflicts:
#	vendor/README.craft-reader.md
#	vendor/hayro/SOURCE.json
2026-10-24 07:40:58 +00:00
aiongg 197e5137fa Merge part 5: /Default color spaces
# Conflicts:
#	crates/pdf/tests/upstream_raster.rs
#	vendor/README.craft-reader.md
2026-10-24 07:40:52 +00:00
aiongg 4952238c66 hayro-interpret: port PdfCraft's /Default color spaces (#3018)
A resource dictionary's /DefaultGray, /DefaultRGB and /DefaultCMYK
replace the device spaces that color operators, cs/CS, images and
shadings select (ISO 32000-2 8.6.5.6). Decoded images and shadings are
cached per default.

Defaults follow this tree's resource scoping (a form with /Resources
sees only its own), and they do not apply on a plate, so device color
separates onto the same inks as before. PdfCraft's raster tests are
adapted in upstream_raster.rs, with a plate test in plates.rs.
2026-10-24 07:39:43 +00:00
aiongg a672020a96 Merge part 5: /VE expressions and page transparency group
# Conflicts:
#	vendor/README.craft-reader.md
2026-10-24 07:39:41 +00:00
aiongg 5ff42f2642 hayro-interpret, hayro: port PdfCraft's mesh shading extent (#3296)
EncodedShadingPattern::extent records the device pixels a mesh's triangles
touched when it was encoded. set_paint returns PaintSetup: the mesh texture
covers that extent with Extend::Pad instead of the whole path, and a mesh with
no triangle on the canvas paints nothing. Output is unchanged; the knockout
erase pass and plate drawing are untouched. Adds hayro's mesh_extent_tests.
2026-10-24 07:38:33 +00:00
aiongg 30ee2f832f hayro: port PdfCraft's page transparency group (#2972)
The page group composites over a transparent backdrop and is then put on the background, so a blend mode over an empty part of the page keeps its color. With a color replacement, and on a plate render, the background stays inside the group as its backdrop, so plate films are as before. Ledger hayro (18); the PdfCraft raster test is adapted in upstream_raster.rs.
2026-10-24 07:38:08 +00:00
aiongg 7c7ec9c8ca hayro-interpret: port PdfCraft's optional-content /VE expressions (#2987)
An optional content membership dictionary with a visibility expression (/And, /Or, /Not over listed groups) shows its content when the expression is true, ahead of /OCGs and /P. Malformed expressions, or ones nested deeper than 32 levels, fall back to /OCGs and /P. Ledger hayro-interpret (40); the PdfCraft raster test is adapted in upstream_raster.rs.
2026-10-24 07:36:15 +00:00
aiongg c45caf2cd1 Merge part 4 (syntax)
# Conflicts:
#	vendor/README.craft-reader.md
2026-10-24 07:33:56 +00:00
aiongg d118f471b8 hayro-syntax: port PdfCraft's unfiltered inline-image length (#3107)
From PdfCraft #3438 with its look-ahead bound (01af6cba3): an inline
image without a filter ends at the byte length its /W, /H, /CS, /BPC
and /IM give when white space and EI follow there, so an EI inside its
samples does not end it. Anything else keeps the EI look-ahead. A
computed end past the content window waits for more data only while it
fits within MAX_DECODED_STREAM.

Tests: PdfCraft's six content::tests unit tests.
2026-10-24 07:33:40 +00:00
aiongg d2ffefcddf hayro-syntax: port PdfCraft's JP2 palette without /ColorSpace (ledger P5)
A JPX image whose dictionary has no /ColorSpace, or one that does not resolve, takes its colors from the JP2 palette instead of drawing its raw indices as gray. Resolved palette colors are 8-bit samples whatever the index precision. From PdfCraft #3184, with its three jpx unit tests.
2026-10-24 07:32:06 +00:00
aiongg d9d02c42be hayro-syntax: port PdfCraft's trailer /Prev reference (ledger 24)
A trailer /Prev written as N G R is followed: it is the offset the referenced object holds when the section's own entries place it, and otherwise offset N. Each section's entries are read before its Prev is followed. From PdfCraft #2400, with its two xref unit tests; the local xref-stream bounds are kept.
2026-10-24 07:26:55 +00:00
aiongg 647156d354 Merge part 3 (fonts and text), #266
# Conflicts:
#	vendor/README.craft-reader.md
#	vendor/hayro/SOURCE.json
2026-10-24 07:12:51 +00:00
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 e95a9c8127 Merge pull request #190 from aiongg/print-color
pdf: CMYK print color in the vendored krilla, plate tests and craft-prepress
2026-10-24 01:58:00 -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
skylartaylor 0f46902e32 Reconcile egui 0.37 with current shared libraries
Preserve the reviewed shared UI tree and the frozen app dependency commit while
bringing in current main. Port the new keymap UI APIs and use verified central
fonts in its strict UI tests and snapshots.
2026-10-24 07:20:20 +02: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
skylartaylor c488caa9fb egui037: add shared screenshot and text helpers 2026-10-24 05:25:10 +02:00
aiongg ed368e819e ci: keep craft-cms changes in the PDF workflow's triggers
craft-cms has no workflow of its own, and craft-prepress and craft-plate-test
depend on it, so the PDF workflow is the only place its changes are tested.
2026-10-24 03:04:40 +00:00
aiongg 7069ebf368 Merge branch 'print-color-prepress-fixes' into print-color 2026-10-24 03:04:33 +00:00
aiongg 0073927bf4 Merge pull request #260 from aiongg/keymap-batch
keymap batch: craft-keymap, keyboard layouts, the Keyboard Shortcuts dialog
2026-10-23 22:59:20 -04:00
aiongg ef13696c29 krilla, craft-pdf tests: rustfmt the review fixes 2026-10-24 02:56:03 +00:00
aiongg 830985971f ci: plate-test job provisions the test font, and text scenes fail on CI without it 2026-10-24 02:54:41 +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 f2b26db319 ci: PDF workflow skips craft-cms changes and pins the plate-test actions 2026-10-24 02:44:09 +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 bdace448d9 prepress: non_exhaustive public enums, and checked plate sizes for hand-made Plates 2026-10-24 02:42:36 +00:00
aiongg 558f8ce2fc Merge upstream main into keymap-batch 2026-10-24 02:42:28 +00:00
aiongg 53837472d6 Merge pull request #259 from aiongg/i18n-batch
i18n batch: isolation, region, sizes, folding and sorting, ICU4X numbers, number parsing, craft-fonts-build
2026-10-23 22:42:02 -04:00