summaryrefslogtreecommitdiff
path: root/crates/typst-render/src
diff options
context:
space:
mode:
authorfrozolotl <44589151+frozolotl@users.noreply.github.com>2025-01-31 10:56:25 +0100
committerGitHub <noreply@github.com>2025-01-31 09:56:25 +0000
commit3eb6e87af1d8870a38cc5914e345d07373e1e8c1 (patch)
tree800de2bc1ed9a5c7f8efc21e2741c0cd5c4728f6 /crates/typst-render/src
parentbe1fa91a00a9bff6c5eb9744266f252b8cc23fe4 (diff)
Include images from raw pixmaps and more (#5632)
Co-authored-by: PgBiel <9021226+PgBiel@users.noreply.github.com> Co-authored-by: Laurenz <laurmaedje@gmail.com>
Diffstat (limited to 'crates/typst-render/src')
-rw-r--r--crates/typst-render/src/image.rs40
1 files changed, 27 insertions, 13 deletions
diff --git a/crates/typst-render/src/image.rs b/crates/typst-render/src/image.rs
index 27b03911..7425bdd2 100644
--- a/crates/typst-render/src/image.rs
+++ b/crates/typst-render/src/image.rs
@@ -3,8 +3,9 @@ use std::sync::Arc;
use image::imageops::FilterType;
use image::{GenericImageView, Rgba};
use tiny_skia as sk;
+use typst_library::foundations::Smart;
use typst_library::layout::Size;
-use typst_library::visualize::{Image, ImageKind};
+use typst_library::visualize::{Image, ImageKind, ImageScaling};
use crate::{AbsExt, State};
@@ -34,7 +35,7 @@ pub fn render_image(
let w = (scale_x * view_width.max(aspect * view_height)).ceil() as u32;
let h = ((w as f32) / aspect).ceil() as u32;
- let pixmap = scaled_texture(image, w, h)?;
+ let pixmap = build_texture(image, w, h)?;
let paint_scale_x = view_width / pixmap.width() as f32;
let paint_scale_y = view_height / pixmap.height() as f32;
@@ -57,29 +58,42 @@ pub fn render_image(
/// Prepare a texture for an image at a scaled size.
#[comemo::memoize]
-fn scaled_texture(image: &Image, w: u32, h: u32) -> Option<Arc<sk::Pixmap>> {
- let mut pixmap = sk::Pixmap::new(w, h)?;
+fn build_texture(image: &Image, w: u32, h: u32) -> Option<Arc<sk::Pixmap>> {
+ let mut texture = sk::Pixmap::new(w, h)?;
match image.kind() {
ImageKind::Raster(raster) => {
- let downscale = w < raster.width();
- let filter =
- if downscale { FilterType::Lanczos3 } else { FilterType::CatmullRom };
- let buf = raster.dynamic().resize(w, h, filter);
- for ((_, _, src), dest) in buf.pixels().zip(pixmap.pixels_mut()) {
+ let w = texture.width();
+ let h = texture.height();
+
+ let buf;
+ let dynamic = raster.dynamic();
+ let resized = if (w, h) == (dynamic.width(), dynamic.height()) {
+ // Small optimization to not allocate in case image is not resized.
+ dynamic
+ } else {
+ let upscale = w > dynamic.width();
+ let filter = match image.scaling() {
+ Smart::Custom(ImageScaling::Pixelated) => FilterType::Nearest,
+ _ if upscale => FilterType::CatmullRom,
+ _ => FilterType::Lanczos3, // downscale
+ };
+ buf = dynamic.resize_exact(w, h, filter);
+ &buf
+ };
+
+ for ((_, _, src), dest) in resized.pixels().zip(texture.pixels_mut()) {
let Rgba([r, g, b, a]) = src;
*dest = sk::ColorU8::from_rgba(r, g, b, a).premultiply();
}
}
- // Safety: We do not keep any references to tree nodes beyond the scope
- // of `with`.
ImageKind::Svg(svg) => {
let tree = svg.tree();
let ts = tiny_skia::Transform::from_scale(
w as f32 / tree.size().width(),
h as f32 / tree.size().height(),
);
- resvg::render(tree, ts, &mut pixmap.as_mut())
+ resvg::render(tree, ts, &mut texture.as_mut());
}
}
- Some(Arc::new(pixmap))
+ Some(Arc::new(texture))
}