Repository: linebender/resvg (language: rust)

Issue:
Switch to zune-jpeg
Apparently `jpeg-decoder` is somewhat deprecated.

Additionally:

- [x] try to decode JPEG directly to `tiny_skia::Pixmap` to avoid needless allocations
- [ ] ~~try to use JPEG-native resizing when possible #781~~


Discussion / hints:
I can work on this.

Fix patch:
diff --git a/Cargo.lock b/Cargo.lock
index da7bf245f..989aa3619 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -135,12 +135,6 @@ version = "0.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "029d73f573d8e8d63e6d5020011d3255b28c3ba85d6cf870a07184ed23de9284"
 
-[[package]]
-name = "jpeg-decoder"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0"
-
 [[package]]
 name = "kurbo"
 version = "0.11.0"
@@ -212,7 +206,6 @@ name = "resvg"
 version = "0.42.0"
 dependencies = [
  "gif",
- "jpeg-decoder",
  "log",
  "once_cell",
  "pico-args",
@@ -221,6 +214,7 @@ dependencies = [
  "svgtypes",
  "tiny-skia",
  "usvg",
+ "zune-jpeg",
 ]
 
 [[package]]
@@ -449,3 +443,18 @@ name = "xmlwriter"
 version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9"
+
+[[package]]
+name = "zune-core"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a"
+
+[[package]]
+name = "zune-jpeg"
+version = "0.4.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec866b44a2a1fd6133d363f073ca1b179f438f99e7e5bfb1e33f7181facfe448"
+dependencies = [
+ "zune-core",
+]
diff --git a/crates/resvg/Cargo.toml b/crates/resvg/Cargo.toml
index d4a6d0327..85ec077da 100644
--- a/crates/resvg/Cargo.toml
+++ b/crates/resvg/Cargo.toml
@@ -16,13 +16,13 @@ required-features = ["text", "system-fonts", "memmap-fonts"]
 
 [dependencies]
 gif = { version = "0.13", optional = true }
-jpeg-decoder = { version = "0.3", default-features = false, features = ["platform_independent"], optional = true }
 log = "0.4"
 pico-args = { version = "0.5", features = ["eq-separator"] }
 rgb = "0.8"
 svgtypes = "0.15.1"
 tiny-skia = "0.11.4"
 usvg = { path = "../usvg", version = "0.42.0", default-features = false }
+zune-jpeg = { version = "0.4", optional = true }
 
 [dev-dependencies]
 once_cell = "1.5"
@@ -40,4 +40,4 @@ memmap-fonts = ["usvg/memmap-fonts"]
 # Enables decoding and rendering of raster images.
 # When disabled, `image` elements with SVG data will still be rendered.
 # Adds around 200KiB to your binary.
-raster-images = ["gif", "jpeg-decoder"]
+raster-images = ["gif", "dep:zune-jpeg"]
diff --git a/crates/resvg/src/image.rs b/crates/resvg/src/image.rs
index 68ac72ce6..e63e0a079 100644
--- a/crates/resvg/src/image.rs
+++ b/crates/resvg/src/image.rs
@@ -78,31 +78,16 @@ mod raster_images {
     }
 
     fn decode_jpeg(data: &[u8]) -> Option<tiny_skia::Pixmap> {
-        let mut decoder = jpeg_decoder::Decoder::new(data);
+        use zune_jpeg::zune_core::colorspace::ColorSpace;
+        use zune_jpeg::zune_core::options::DecoderOptions;
+
+        let options = DecoderOptions::default().jpeg_set_out_colorspace(ColorSpace::RGBA);
+        let mut decoder = zune_jpeg::JpegDecoder::new_with_options(data, options);
         let img_data = decoder.decode().ok()?;
         let info = decoder.info()?;
 
         let size = tiny_skia::IntSize::from_wh(info.width as u32, info.height as u32)?;
-
-        let data = match info.pixel_format {
-            jpeg_decoder::PixelFormat::RGB24 => img_data,
-            jpeg_decoder::PixelFormat::L8 => {
-                let mut rgb_data: Vec<u8> = Vec::with_capacity(img_data.len() * 3);
-                for gray in img_data {
-                    rgb_data.push(gray);
-                    rgb_data.push(gray);
-                    rgb_data.push(gray);
-                }
-
-                rgb_data
-            }
-            _ => return None,
-        };
-
-        let (w, h) = size.dimensions();
-        let mut pixmap = tiny_skia::Pixmap::new(w, h)?;
-        rgb_to_pixmap(&data, &mut pixmap);
-        Some(pixmap)
+        tiny_skia::Pixmap::from_vec(img_data, size)
     }
 
     fn decode_gif(data: &[u8]) -> Option<tiny_skia::Pixmap> {
@@ -122,21 +107,6 @@ mod raster_images {
         Some(pixmap)
     }
 
-    fn rgb_to_pixmap(data: &[u8], pixmap: &mut tiny_skia::Pixmap) {
-        use rgb::FromSlice;
-
-        let mut i = 0;
-        let dst = pixmap.data_mut();
-        for p in data.as_rgb() {
-            dst[i + 0] = p.r;
-            dst[i + 1] = p.g;
-            dst[i + 2] = p.b;
-            dst[i + 3] = 255;
-
-            i += tiny_skia::BYTES_PER_PIXEL;
-        }
-    }
-
     fn rgba_to_pixmap(data: &[u8], pixmap: &mut tiny_skia::Pixmap) {
         use rgb::FromSlice;
 


Test patch:
diff --git a/crates/resvg/tests/tests/structure/image/embedded-jpeg-as-image-jpeg.png b/crates/resvg/tests/tests/structure/image/embedded-jpeg-as-image-jpeg.png
index f878674a3..c1b60c2ac 100644
Binary files a/crates/resvg/tests/tests/structure/image/embedded-jpeg-as-image-jpeg.png and b/crates/resvg/tests/tests/structure/image/embedded-jpeg-as-image-jpeg.png differ
diff --git a/crates/resvg/tests/tests/structure/image/embedded-jpeg-as-image-jpg.png b/crates/resvg/tests/tests/structure/image/embedded-jpeg-as-image-jpg.png
index f878674a3..c1b60c2ac 100644
Binary files a/crates/resvg/tests/tests/structure/image/embedded-jpeg-as-image-jpg.png and b/crates/resvg/tests/tests/structure/image/embedded-jpeg-as-image-jpg.png differ
diff --git a/crates/resvg/tests/tests/structure/image/embedded-jpeg-without-mime.png b/crates/resvg/tests/tests/structure/image/embedded-jpeg-without-mime.png
index f878674a3..c1b60c2ac 100644
Binary files a/crates/resvg/tests/tests/structure/image/embedded-jpeg-without-mime.png and b/crates/resvg/tests/tests/structure/image/embedded-jpeg-without-mime.png differ
diff --git a/crates/resvg/tests/tests/structure/image/external-jpeg.png b/crates/resvg/tests/tests/structure/image/external-jpeg.png
index f878674a3..c1b60c2ac 100644
Binary files a/crates/resvg/tests/tests/structure/image/external-jpeg.png and b/crates/resvg/tests/tests/structure/image/external-jpeg.png differ
diff --git a/crates/resvg/tests/tests/structure/image/float-size.png b/crates/resvg/tests/tests/structure/image/float-size.png
index 5b8cb9250..1adc77ceb 100644
Binary files a/crates/resvg/tests/tests/structure/image/float-size.png and b/crates/resvg/tests/tests/structure/image/float-size.png differ
diff --git a/crates/resvg/tests/tests/structure/image/no-height.png b/crates/resvg/tests/tests/structure/image/no-height.png
index 5dd2f458c..cbfc4f0e9 100644
Binary files a/crates/resvg/tests/tests/structure/image/no-height.png and b/crates/resvg/tests/tests/structure/image/no-height.png differ
diff --git a/crates/resvg/tests/tests/structure/image/no-width-and-height.png b/crates/resvg/tests/tests/structure/image/no-width-and-height.png
index 7e65130e9..c1b60c2ac 100644
Binary files a/crates/resvg/tests/tests/structure/image/no-width-and-height.png and b/crates/resvg/tests/tests/structure/image/no-width-and-height.png differ
diff --git a/crates/resvg/tests/tests/structure/image/no-width.png b/crates/resvg/tests/tests/structure/image/no-width.png
index 5dd2f458c..cbfc4f0e9 100644
Binary files a/crates/resvg/tests/tests/structure/image/no-width.png and b/crates/resvg/tests/tests/structure/image/no-width.png differ
diff --git a/crates/resvg/tests/tests/structure/image/width-and-height-set-to-auto.png b/crates/resvg/tests/tests/structure/image/width-and-height-set-to-auto.png
index 7e65130e9..c1b60c2ac 100644
Binary files a/crates/resvg/tests/tests/structure/image/width-and-height-set-to-auto.png and b/crates/resvg/tests/tests/structure/image/width-and-height-set-to-auto.png differ