* M2: a shrunk image on a turned or mirrored page snaps to whole pixels (#5530) hayro patch 14 (`snap_minified_image`) shrinks an interpolated image once to its whole-pixel device rectangle and draws that 1:1, instead of shrinking to a rounded-up size and resampling again at a fractional scale and offset. It only accepted an upright transform (a > 0, d > 0, b = c = 0), so every image on a page under /Rotate 90, 180 or 270 -- and any image placed turned or mirrored by its own matrix -- still took the double resample. That is #5530: a scanned page that matches PDFium upright drifts and softens when the same page is rotated. The snap now accepts every transform whose axes lie along the device's (the eight quarter-turns and mirrors) and returns the 1:1 transform that draws the shrunk raster from the snapped corner, one source-axis step a whole device pixel, in whichever direction that axis runs. Skewed and freely rotated images keep the old path. On a synthetic page (crop box and scale on whole pixels, image at fractional coordinates), /Rotate 90, 180 and 270 renders turned back differed from the upright render in 72% of pixels, by up to 200 grey levels; now they are identical. Non-interpolated images were already identical and stay so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * M2: snap only when the dropped skew is invisible, and only a resize that succeeded Review of #5640: - The snap judged an image axis-aligned by a tolerance on its coefficients (1e-4 of the scale). For a very wide image a skew that small still moves the far edge by more than a pixel (40 000 samples at 4e-5: 1.6 px), and the snap flattened it. It now measures what it drops: how far each off-axis term moves the far edges, at most a hundredth of a device pixel (SNAP_SKEW). Upright and turned alike. - A resize that fails hands back the source raster at source size; the 1:1 snapped transform then drew it at that size. The snapped transform is now used only when the shrink produced the snapped size; otherwise the full transform, as before. - The mirrored case of the edge test drew a uniform image, which looks the same mirrored; it now also mirrors a half-black image and checks which side the black lands on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * M2: the turned-page test draws every kind of image the snap reaches The /Rotate oracle test drew one 8-bit grey image. Stencil masks (CCITT scans often are one), 1-bit images and images with a soft mask reach the snap through other paths, so it now draws all five: 8-bit and 1-bit grey, a stencil mask, a soft mask of the image's size and one of another size. On main, every interpolated kind is off by 113-217 levels over 63-73% of the image when turned, and so is a non-interpolated image with a smaller soft mask (110 levels, 16%): hayro patch 15 filters such a mask whatever /Interpolate says, so it is snapped upright and was not when turned. All are identical with the fix; the other non-interpolated kinds were already identical and stay as guards. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com>
hayro
A crate for rendering PDF files.
This crate allows you to render pages of a PDF file into bitmaps. It is supposed to be relatively lightweight, since we do not have any dependencies on the GPU. All the rendering happens on the CPU.
The ultimate goal of this crate is to be a feature-complete and performant PDF rasterizer.
With that said, we are currently still very far away from reaching that goal: So far, no effort
has been put into performance optimizations, as we are still working on implementing missing features.
However, this crate is currently the most comprehensive and feature-complete
implementation of a PDF rasterizer in pure Rust. This claim is supported by the fact that we currently
include over 1000 PDF files in our regression test suite. The majority of those have been scraped
from the pdf.js and PDFBOX test suites and therefore represent a very large and diverse sample
of PDF files.
As mentioned, there are still some serious limitations, including lack of support for encrypted/password-protected PDF files, blending and isolation, knockout groups as well as a range of smaller features such as color key masking. But you should be able to render the vast majority of PDF files without too many issues.
Safety
This crate forbids unsafe code via a crate-level attribute.
Examples
For usage examples, see the example in the GitHub repository.
Cargo features
This crate has one optional feature:
embed-fonts: See the description ofhayro-interpretfor more information.
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.