* fix(render): sampled functions index a flat sample array (vendored hayro-interpret patch 31) A Type 0 sampled function kept its samples in a HashMap keyed by each point of its /Size grid (two SmallVecs per key, SipHash), and the renderer builds a shading's functions again every time it is painted, so every paint hashed one insert per sample. A 2,097,152-sample ramp painted 30 times took 38 s; the pdf.js corpus's bug1721218 (InDesign) spent most of a 1.5 s page on it. The samples now stay in stream order in one Vec, and a grid point is found by strides (first input fastest). The interpolation keeps the same recursion and arithmetic, so results are bit for bit the same, and a point the stream ended before still gives no value. The repeated-paint page draws in well under a second. The maximum sample value no longer computes 2^32 in a u32 (a panic with overflow checks on at 32 bits per sample). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MoEx9Nj8KC4WKDcf5YaokQ * fix(render): one decode of an image serves every size it is drawn at (vendored hayro-interpret patch 32) The decoded-image cache (patch 24) keyed each decode by the size the image is drawn at, but only the JPX filter decodes a reduced resolution for a size: every other filter decodes the whole image. So a JPEG or Flate scan missed the cache at every zoom step, was decoded again, and was kept once per zoom level. The key now carries the target size only when JPX decodes the image, its /SMask or its /Mask (read from /Filter or /F, erring towards keeping the target). `InterpreterCache::decoded_image_decodes` counts the cache's decodes; the new test draws a Flate image at five sizes and sees one decode, and a copy whose soft mask is JPX-encoded still decodes per size. Both assertions fail with the old keying. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MoEx9Nj8KC4WKDcf5YaokQ * fix(render): patch meshes copy their vertices' colours less (vendored hayro-interpret patch 33) A Coons or tensor-product patch is drawn as 722 triangles over a 20 x 20 grid of points, and every vertex's colours (a SmallVec) were produced or copied up to five times: each grid cell interpolated its four corners itself (1,444 interpolations a patch for 400 points), cloned all six vertices of its two triangles, and the mesh sampler cloned each vertex again to move the triangle into device space. Profiling page 8 of the annual report in #1584 put a quarter of its time in those clones. Each grid point's colours are now interpolated once, a cell's second triangle takes the vertices its first copied, and the sampler moves a patch's freshly made triangles instead of copying them (`TriangleSampler::sample_owned`; a free-form triangle mesh, which the shading keeps, is still copied). The same inputs give the same values: rendering the first three pages of every pdf.js corpus file is byte for byte the same. Release build, Linux: report page 8 773 -> 696 ms, personwithdog.pdf 149 -> 129 ms, issue13520.pdf 104 -> 87 ms. The new test pins the colours near each corner, at the centre and between them for a Coons and a tensor-product patch (taken before the change); swapping two vertices' grid points makes it fail. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MoEx9Nj8KC4WKDcf5YaokQ * docs: roadmap entries for faster sampled functions, image decodes and patch meshes Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MoEx9Nj8KC4WKDcf5YaokQ --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
hayro-interpret
A crate for interpreting PDF files.
This crate provides an abstraction to interpret the content of a PDF file and render them
into an abstract [Device], which clients can implement as needed. This allows you, for
example, to render PDF files to bitmaps (which is what the hayro crate does), or other formats
such as SVG.
It should be noted that this crate is still very much in development. Therefore it currently lacks pretty much any documentation on how to use it. It's current API also only really makes it useful for rendering to PNG or SVG, though this will be improved upon in the future.
Examples
See the examples folder on the GitHub repository. Apart from that, you can also consult
the implementation of hayro and hayro-svg to get an idea on how to use this crate.
Safety
This crate forbids unsafe code via a crate-level attribute.
Cargo features
This crate has one optional feature:
embed-fonts: PDF processors are required to support 14 predefined fonts that do not need to be embedded into a PDF file. If you enable this feature, hayro will embed a (permissively-licensed) substitute for each font, so that you don't have to implement your custom font loading logic. This will add around ~240KB to your binary.
License
Licensed under either of
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
PdfCraft function limits
The PdfCraft patch rejects function construction after 64 nested functions or 10,000 total
function nodes, including repeated references, and detects cycles on the current path. Shared
children in different branches remain valid. Stitching functions reject empty or unresolved
child lists instead of silently truncating them. Calculator functions have a shared limit of 64
procedure levels and 10,000 parsed tokens (operators and procedure openings); evaluation has
its own 10,000-operator limit across selected branches. These are implementation resource
limits rather than PDF format limits. Rejection returns the existing None, and the optional
logging feature reports the reason and limit; no new interface warning is introduced.
Calculator integer division without an integer result is also rejected. Bit shifting discards bits beyond the 32-bit word and fills with zeroes, including logical right shifts of negative words; rotation accepts the full signed shift range without negating the minimum integer. Fixed-size operand and procedure-stack overflow errors propagate instead of truncating work. Normal function signatures and supported color/transfer-function behavior remain unchanged.