Skip to content

Snap solid filled rectangles to whole pixels - #637

Merged
Velli20 merged 3 commits into
mainfrom
snap-filled-rects-to-pixels
Oct 31, 2026
Merged

Velli20 merged 3 commits into
mainfrom
snap-filled-rects-to-pixels

Conversation

@Velli20

@Velli20 Velli20 commented Oct 31, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Barcode bars drawn as solid re f rectangles rendered thin and grey: each bar was filled at its exact fractional position with anti-aliasing.
  • Adds CanvasPath::axis_aligned_rect, which detects a single four-corner subpath that stays axis-aligned under a given pixel mapping. It is backend-agnostic so the web and FemtoVG backends can reuse it.
  • Adds Rect::snapped_to_pixels, which moves each edge to the nearest pixel boundary and keeps at least one pixel per axis.
  • The Skia backend's fill_path uses both for solid fills (no shader): the rectangle is snapped in the canvas's current pixel grid (so tiling-pattern tiles snap in their own backing pixels) and drawn without anti-aliasing. Pattern and shading fills are unchanged.
  • Nearest-edge snapping (rather than rounding out to every touched pixel) keeps bars and the ~1 px gaps between them separate at low zoom; rounding out merged narrow barcodes into solid blocks.

Notes

  • Snapped edges can differ from PDFium's by a pixel; the conformance README now says so.
  • The web canvas and FemtoVG backends still anti-alias these rectangles.
  • With B (fill and stroke), the fill part also snaps.

Test plan

  • cargo clippy --workspace --all-targets -- -D warnings, cargo fmt --check
  • cargo conformance render of the TCPDF barcode example at 1x and 2x: Code 39, Standard 2 of 5, and Code 128/EAN bars are solid and separate
  • cargo test (not run locally: the test configuration needs a fresh Skia build that the sandbox blocked)
  • Conformance workflow on this PR for regressions in other documents

🤖 Generated with Claude Code

Velli20 and others added 3 commits October 31, 2026 15:15
A solid fill of a single rectangle that stays axis-aligned in device space
now covers every pixel it touches, at least one pixel wide and tall, without
anti-aliasing. Thin barcode bars drawn with `re f` stay solid instead of
turning grey and narrow, matching PDFium.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rounding a rectangle out to every pixel it touches can make a 1.13 px bar
3 px wide and close the gap next to it, so narrow barcodes filled in as
solid blocks. When the outer pixel span is a full pixel wider than the
rectangle's rounded-up size, drop the pixel on the side with more slack,
as PDFium does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Rounding a rectangle out can only grow it, so bars separated by gaps of
about one pixel still merged into solid blocks at low zoom. Move each edge
to the nearest pixel boundary instead, keeping at least one pixel per axis:
bars stay solid and the gaps between them stay open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Velli20 Velli20 changed the title Fill pixel-aligned rectangles over whole pixels without anti-aliasing Snap solid filled rectangles to whole pixels Oct 31, 2026
@Velli20
Velli20 merged commit 1285e55 into main Oct 31, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant