mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-10 18:31:10 -06:00
fix(render): a stencil mask is drawn at the fill opacity once (#2975)
hayro-interpret draws every image XObject inside a transparency group that applies the fill opacity (ca). A stencil mask (/ImageMask true) also takes the fill colour, with that same alpha, as its paint, so the opacity was applied twice: at ca 0.5 a mask was drawn at 25 %, at ca 0.25 at about 6 %. Rectangles and raster images were right. Vendored hayro-interpret patch (36) resets the fill alpha to 1 once the image's group is pushed, before the stencil's paint is taken; the saved state is restored after the image. Type 3 glyph and pattern stencils take their paint from the glyph or pattern and are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
dab3149110
commit
1cf6ca5579
@@ -5822,6 +5822,44 @@ trailer << /Root 1 0 R >>
|
||||
assert_eq!(pixel(&on, 150, 55), &[255, 255, 255, 255], "the image's white quadrant stays white");
|
||||
}
|
||||
|
||||
/// #2975: a stencil mask (`/ImageMask true`) is painted in the fill colour at the fill
|
||||
/// opacity, once: at `ca 0.5` it is as opaque as a rectangle filled at `ca 0.5` beside it
|
||||
/// (it was a quarter as opaque, the opacity applied by both the image's group and its paint).
|
||||
#[test]
|
||||
fn stencil_masks_are_drawn_at_the_fill_opacity_once() {
|
||||
let px = |p: &RenderedPage, x: u32, y: u32| p.rgba[((y * p.width + x) * 4) as usize..][..3].to_vec();
|
||||
for alpha in ["1", "0.5", "0.25"] {
|
||||
let content = "/A gs 0 0 1 rg q 100 0 0 100 20 50 cm /Msk Do Q 160 50 100 100 re f";
|
||||
let pdf = format!(
|
||||
"%PDF-1.7
|
||||
1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj
|
||||
2 0 obj << /Type /Pages /Kids [3 0 R] /Count 1 >> endobj
|
||||
3 0 obj << /Type /Page /Parent 2 0 R /MediaBox [0 0 300 200] /Contents 4 0 R /Resources << /ExtGState << /A << /ca {alpha} >> >> /XObject << /Msk 5 0 R >> >> >> endobj
|
||||
4 0 obj << /Length {} >> stream
|
||||
{content}
|
||||
endstream endobj
|
||||
5 0 obj << /Type /XObject /Subtype /Image /Width 2 /Height 2 /ImageMask true /Length 2 >> stream
|
||||
| ||||