diff --git a/Cargo.lock b/Cargo.lock index ddb04ea..54fbfb9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1990,7 +1990,7 @@ dependencies = [ "iced", "image", "jxl-oxide", - "misc-image-integration", + "kra-image-integration", "resvg", "rfd", "size", @@ -2327,6 +2327,16 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" +[[package]] +name = "kra-image-integration" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ab1db0e6caced9f4b26057c10ea190c447a8be4fcac03afd7213e35168ad700" +dependencies = [ + "image", + "zip", +] + [[package]] name = "kurbo" version = "0.10.4" @@ -2545,17 +2555,6 @@ dependencies = [ "simd-adler32", ] -[[package]] -name = "misc-image-integration" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8021bf53776c68684f91b0eea6317b518d6b113db09fc929f51f1c01a760ca8f" -dependencies = [ - "image", - "resvg", - "zip", -] - [[package]] name = "moxcms" version = "0.8.1" diff --git a/Cargo.toml b/Cargo.toml index c1c42bf..a957ad4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ license = "AGPL-3.0-or-later" [dependencies] dirs = "6.0.0" -misc-image-integration = "0.1.0" +kra-image-integration = "0.1.0" resvg = "0.48.1" rfd = "0.17.2" size = "0.5.0" diff --git a/src/main.rs b/src/main.rs index 2b7bad5..d8a3e7e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,6 +15,7 @@ use iced::{ use image::{EncodableLayout, RgbaImage, imageops}; use size::Size; +mod svg; mod utils; #[derive(Clone, Debug)] @@ -301,7 +302,8 @@ impl State { fn main() -> Result<(), iced::Error> { jxl_oxide::integration::register_image_decoding_hook(); - misc_image_integration::register(); + kra_image_integration::register(); + svg::register(); iced::application(State::new, State::update, State::view) .subscription(State::subscription) diff --git a/src/svg.rs b/src/svg.rs new file mode 100644 index 0000000..f77fafe --- /dev/null +++ b/src/svg.rs @@ -0,0 +1,59 @@ +use std::io::Read; + +use image::{ + ImageDecoder, ImageError, ImageResult, + error::DecodingError, + hooks::{self, GenericReader}, +}; +use resvg::usvg::{Options, Transform, Tree}; + +pub fn register() -> bool { + hooks::register_decoding_hook("svg".into(), Box::new(hook)) + && hooks::register_decoding_hook("svgz".into(), Box::new(hook)) +} + +fn hook<'a>(mut reader: GenericReader<'a>) -> ImageResult> { + let mut buf = Vec::new(); + reader.read_to_end(&mut buf)?; + let tree = Tree::from_data(&buf, &Options::default()).map_err(to_image_error)?; + Ok(Box::new(SvgDecoder::new(tree))) +} + +struct SvgDecoder { + tree: Tree, +} +impl SvgDecoder { + fn new(tree: Tree) -> Self { + Self { tree } + } +} +impl ImageDecoder for SvgDecoder { + fn color_type(&self) -> image::ColorType { + image::ColorType::Rgba8 + } + fn dimensions(&self) -> (u32, u32) { + self.tree.size().to_int_size().dimensions() + } + fn read_image(self, buf: &mut [u8]) -> ImageResult<()> + where + Self: Sized, + { + let (width, height) = self.dimensions(); + let mut pixmap = resvg::tiny_skia::PixmapMut::from_bytes(buf, width, height).unwrap(); + resvg::render(&self.tree, Transform::default(), &mut pixmap); + + Ok(()) + } + fn read_image_boxed(self: Box, buf: &mut [u8]) -> ImageResult<()> { + (*self).read_image(buf) + } +} + +fn to_image_error( + e: impl Into>, +) -> ImageError { + ImageError::Decoding(DecodingError::new( + image::error::ImageFormatHint::PathExtension("svg".into()), + e, + )) +}