From ed247797ac17e0975d6663d65b0976ab92130d80 Mon Sep 17 00:00:00 2001 From: Eric Biedert Date: Mon, 5 Aug 2024 12:24:22 +0200 Subject: [PATCH] Fix alignment of gradients and patterns on strokes in PNG (#4634) --- crates/typst-render/src/paint.rs | 16 +++++++++++- ...gradient-linear-stroke-relative-parent.png | Bin 0 -> 139 bytes tests/ref/pattern-stroke-relative-parent.png | Bin 0 -> 757 bytes tests/ref/pattern-stroke.png | Bin 248 -> 383 bytes tests/suite/visualize/gradient.typ | 16 ++++++++++++ tests/suite/visualize/pattern.typ | 24 +++++++++++++++++- 6 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 tests/ref/gradient-linear-stroke-relative-parent.png create mode 100644 tests/ref/pattern-stroke-relative-parent.png diff --git a/crates/typst-render/src/paint.rs b/crates/typst-render/src/paint.rs index 2b5c19c9..3a507ca4 100644 --- a/crates/typst-render/src/paint.rs +++ b/crates/typst-render/src/paint.rs @@ -185,6 +185,12 @@ pub fn to_sk_paint<'a>( .container_transform .post_concat(state.transform.invert().unwrap()), }; + + let gradient_map = match relative { + RelativeTo::Self_ => gradient_map, + RelativeTo::Parent => None, + }; + let width = (container_size.x.to_f32().abs() * state.pixel_per_pt).ceil() as u32; let height = @@ -225,6 +231,13 @@ pub fn to_sk_paint<'a>( let canvas = render_pattern_frame(&state, pattern); *pixmap = Some(Arc::new(canvas)); + let offset = match relative { + RelativeTo::Self_ => { + gradient_map.map(|(offset, _)| -offset).unwrap_or_default() + } + RelativeTo::Parent => Point::zero(), + }; + // Create the shader sk_paint.shader = sk::Pattern::new( pixmap.as_ref().unwrap().as_ref().as_ref(), @@ -232,7 +245,8 @@ pub fn to_sk_paint<'a>( sk::FilterQuality::Nearest, 1.0, fill_transform - .pre_scale(1.0 / state.pixel_per_pt, 1.0 / state.pixel_per_pt), + .pre_scale(1.0 / state.pixel_per_pt, 1.0 / state.pixel_per_pt) + .pre_translate(offset.x.to_f32(), offset.y.to_f32()), ); } } diff --git a/tests/ref/gradient-linear-stroke-relative-parent.png b/tests/ref/gradient-linear-stroke-relative-parent.png new file mode 100644 index 0000000000000000000000000000000000000000..60da4ee89b09a87c7223c1df94258b65db41f6e8 GIT binary patch literal 139 zcmeAS@N?(olHy`uVBq!ia0vp^6+rC9!3-n~PA#wnQv3lvA+G=b|392j-B`NjzoQvL z$<6e{4_ZJeb59q?kcwMx&l(Cc7;vy`5c{xx=2z2#&PJPt$yR?u5}P7)#JZ0rZA76O Zvc;A?kg(jeW;w`o22WQ%mvv4FO#r#AFhBqR literal 0 HcmV?d00001 diff --git a/tests/ref/pattern-stroke-relative-parent.png b/tests/ref/pattern-stroke-relative-parent.png new file mode 100644 index 0000000000000000000000000000000000000000..fe9b1174fb5647f47d1757e72827def585a53d9b GIT binary patch literal 757 zcmVbCaTKiKA1;G?7m3T6g_tCqIR)XmA0Sq5F;k*- z5xDBLDpqS+sk7sPUafYG*9WBsyttr=)f+@ZX#yuMXyVZ{ff3hJmXy1lxLIb8EVy)6 z;}z_l!OGW!ap3AFn(pEhQhb*P>oegR>>){lMBpS+L-OEqkRpW^i4=zgmn2AEpwB`0 zAz>a1u8<7HhjTC{VIc>u4jCGo=AcjNIt;i1REAcjIrxgI8!+H%pb7{>fSL^kT#~+5 z=1uEcbv*`LTlIn3nwG4z%YbX6_-u4nf4dC0q~a5r*Z8^Wdgp{Ipy{_V;d(&T4H$5> zY5MslTt3alHpf_WY5K*7xMG@@F3VWlPrnz?alwM-rN=uKBcUbY9gE^)zh6a=#RU;k zLo)4L>tusp#Hp)zk*xM>u7$pyZt#8=cF&;er_btq3;lC;jh}C(^UP0NaxU~OJen48 zo))1+kPb=sRgz`DmlO>#PvTAeEIzT``-_5KmMOPz*!-^&u6v-rn@y)?^^i@=&_S zm8DZdLVl_5`}(PQ3z=;lSF`=!a{ghB@~7j4_S=`e|Ns4OlZiIJx=u_~{SI%9bH5Io z?h@F=x-wku-a_7wUD-Nb85@g#T;XTfso}1WD|ubG!na(|@F{DGdW>Q6s#T8c!D>%l zv}dnbHF=(oWNhKdg0Rfc;3J~bS5!Xg@^0&1HB0G;YYcX@RW#=PN3-*rHQ&Gg(b<*L zuf0y@?Z?BSw=P*cv|3~meeCLz5cx|@CN(-w>hk1M7V$sT(X~1V^dy6)tDnm{r-UW| Ds|~fU delta 232 zcmey*^n-DNL_G^L0|UcXD_(r#)gQxmjE*dl#s9lBbJfNX4zU(+&9?0t8%Q9S^cvFq#X9Sao`-2R`8Fd%*GP z>(P0aSj&v3IvK5>k!E!A{OW&hPqwEl^=3SNch$oXW0t<#6^XMiB^={9?rZbyWa_bo z`Fk@guJ9a8uFaYp%-SFRky|I{8xVis*75nn#Qpi0h+858eOtR>x5>@WAD7KfWKZvE df1F>*xa{hqCUd!uIY8$zc)I$ztaD0e0syYmX|4bO diff --git a/tests/suite/visualize/gradient.typ b/tests/suite/visualize/gradient.typ index c3794150..61f6b6d0 100644 --- a/tests/suite/visualize/gradient.typ +++ b/tests/suite/visualize/gradient.typ @@ -175,6 +175,22 @@ ) ) +--- gradient-linear-stroke-relative-parent --- +// The image should look as if there is a single gradient that is being used for +// both the circle stroke and the block fill. +#align( + center + horizon, + block( + width: 50pt, + height: 50pt, + fill: gradient.linear(red, blue).sharp(4), + circle( + radius: 18pt, + stroke: 5pt + gradient.linear(red, blue, relative: "parent").sharp(4), + ) + ) +) + --- gradient-linear-line --- // Test gradient on lines #set page(width: 100pt, height: 100pt) diff --git a/tests/suite/visualize/pattern.typ b/tests/suite/visualize/pattern.typ index b0c92efa..b87b7755 100644 --- a/tests/suite/visualize/pattern.typ +++ b/tests/suite/visualize/pattern.typ @@ -101,13 +101,35 @@ center + top, square( size: 50pt, - stroke: 5pt + pattern( + fill: pattern( size: (5pt, 5pt), align(horizon + center, circle(fill: blue, radius: 2.5pt)) + ), + stroke: 7.5pt + pattern( + size: (5pt, 5pt), + align(horizon + center, circle(fill: red, radius: 2.5pt)) ) ) ) +--- pattern-stroke-relative-parent --- +// Test pattern on strokes with relative set to `"parent"` +// The pattern on the circle should align with the pattern on the square. +#align( + center + top, + block( + width: 50pt, + height: 50pt, + fill: pattern(size: (5pt, 5pt), circle(radius: 2.5pt, fill: blue)), + align(center + horizon, circle( + radius: 15pt, + stroke: 7.5pt + pattern( + size: (5pt, 5pt), circle(radius: 2.5pt, fill: red), relative: "parent" + ), + )) + ) +) + --- pattern-text --- // Test a pattern on some text // You shouldn't be able to see the text, if you can then