diff options
| author | PgBiel <9021226+PgBiel@users.noreply.github.com> | 2024-12-04 07:00:04 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-12-04 10:00:04 +0000 |
| commit | 884c02872ce9d7432c3b67a920011cf385ce70b2 (patch) | |
| tree | b5e2e28510780135cc492575f63727a096d1f98e /crates/typst-render | |
| parent | cda94ab40505a2d812c3a743a8d916bcfe4484c3 (diff) | |
Fix text fill within `clip: true` blocks in PNG export (#5502)
Diffstat (limited to 'crates/typst-render')
| -rw-r--r-- | crates/typst-render/src/text.rs | 36 |
1 files changed, 24 insertions, 12 deletions
diff --git a/crates/typst-render/src/text.rs b/crates/typst-render/src/text.rs index c017b1ce..b47659cb 100644 --- a/crates/typst-render/src/text.rs +++ b/crates/typst-render/src/text.rs @@ -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, |
