Fix text fill within clip: true blocks in PNG export (#5502)

This commit is contained in:
PgBiel 2024-12-04 07:00:04 -03:00 committed by GitHub
parent cda94ab405
commit 884c02872c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 55 additions and 12 deletions

View File

@ -164,30 +164,42 @@ fn write_bitmap<S: PaintSampler>(
// If we have a clip mask we first render to a pixmap that we then blend
// with our canvas
if state.mask.is_some() {
let cw = canvas.width() as i32;
let ch = canvas.height() as i32;
let mw = bitmap.width;
let mh = bitmap.height;
let left = bitmap.left;
let top = bitmap.top;
// Pad the pixmap with 1 pixel in each dimension so that we do
// not get any problem with floating point errors along their border
let mut pixmap = sk::Pixmap::new(mw + 2, mh + 2)?;
let pixels = bytemuck::cast_slice_mut::<u8, u32>(pixmap.data_mut());
for x in 0..mw {
for y in 0..mh {
let alpha = bitmap.coverage[(y * mw + x) as usize];
let color = sampler.sample((x, y));
pixmap.pixels_mut()[((y + 1) * (mw + 2) + (x + 1)) as usize] =
sk::ColorU8::from_rgba(
color.red(),
color.green(),
color.blue(),
alpha,
)
.premultiply();
// To sample at the correct position, we need to convert each
// pixel's position in the bitmap (x and y) to its final
// expected position in the canvas. Due to padding, this
// pixel's position in the pixmap will be (x + 1, y + 1).
// Then, when drawing the pixmap to the canvas, we place its
// top-left corner at position (left - 1, top - 1). Therefore,
// the final position of this pixel in the canvas is given by
// (left - 1 + x + 1, top - 1 + y + 1) = (left + x, top + y).
let sample_pos = (
(left + x as i32).clamp(0, cw) as u32,
(top + y as i32).clamp(0, ch) as u32,
);
let color = sampler.sample(sample_pos);
let color = bytemuck::cast(color);
let applied = alpha_mul(color, alpha as u32);
pixels[((y + 1) * (mw + 2) + (x + 1)) as usize] = applied;
}
}
let left = bitmap.left;
let top = bitmap.top;
canvas.draw_pixmap(
left - 1,
top - 1,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 908 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -81,3 +81,34 @@ I
// Warning: 17-34 Typst's default font has changed from Linux Libertine to its successor Libertinus Serif
// Hint: 17-34 please set the font to `"Libertinus Serif"` instead
#set text(font: "Linux Libertine")
--- issue-5499-text-fill-in-clip-block ---
#let pat = pattern(
size: (30pt, 30pt),
relative: "parent",
square(
size: 30pt,
fill: gradient
.conic(..color.map.rainbow),
)
)
#block(clip: false, height: 2em, {
text(fill: blue, "Hello")
[ ]
text(fill: blue.darken(20%).transparentize(50%), "Hello")
[ ]
text(fill: gradient.linear(..color.map.rainbow), "Hello")
[ ]
text(fill: pat, "Hello")
})
#block(clip: true, height: 2em, {
text(fill: blue, "Hello")
[ ]
text(fill: blue.darken(20%).transparentize(50%), "Hello")
[ ]
text(fill: gradient.linear(..color.map.rainbow), "Hello")
[ ]
text(fill: pat, "Hello")
})