From 2db68a3dc1fdabfff98a540b25c589142bd48a18 Mon Sep 17 00:00:00 2001 From: Piyush Mishra Date: Sat, 26 Mar 2022 01:11:16 +0530 Subject: [PATCH] Using mozjpeg for jpeg image converisons. New export image naming format --- Cargo.lock | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 1 + Cross.toml | 2 ++ src/utils.rs | 57 ++++++++++++++++++++++++---------- 4 files changed, 128 insertions(+), 18 deletions(-) create mode 100644 Cross.toml diff --git a/Cargo.lock b/Cargo.lock index ea70ae2..f0e930c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,6 +20,17 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom 0.2.3", + "once_cell", + "version_check", +] + [[package]] name = "aho-corasick" version = "0.7.18" @@ -38,6 +49,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + [[package]] name = "atty" version = "0.2.14" @@ -283,6 +300,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "dunce" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453440c271cf5577fd2a40e4942540cb7d0d2f85e27c8d07dd0023c925a67541" + [[package]] name = "either" version = "1.6.1" @@ -305,6 +328,15 @@ dependencies = [ "threadpool", ] +[[package]] +name = "fallible_collections" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52db5973b6a19247baf19b30f41c23a1bfffc2e9ce0a5db2f60e3cd5dc8895f7" +dependencies = [ + "hashbrown", +] + [[package]] name = "flate2" version = "1.0.22" @@ -420,6 +452,9 @@ name = "hashbrown" version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash", +] [[package]] name = "heck" @@ -563,9 +598,9 @@ checksum = "7efd1d698db0759e6ef11a7cd44407407399a910c774dd804c64c032da7826ff" [[package]] name = "libc" -version = "0.2.112" +version = "0.2.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" +checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" [[package]] name = "libwebp-sys" @@ -637,6 +672,31 @@ dependencies = [ "adler", ] +[[package]] +name = "mozjpeg" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75fce8c02d82d7dc473d6c156c52cc9f161e9eef0bca5145d87ad6c62a20ac3f" +dependencies = [ + "arrayvec", + "fallible_collections", + "libc", + "mozjpeg-sys", + "rgb", +] + +[[package]] +name = "mozjpeg-sys" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "215a592d91abceb187028dfc6d9c07811bdfc5584d4ada50a4d387d82ed0aedc" +dependencies = [ + "cc", + "dunce", + "libc", + "nasm-rs", +] + [[package]] name = "nalgebra" version = "0.30.1" @@ -661,6 +721,12 @@ dependencies = [ "getrandom 0.2.3", ] +[[package]] +name = "nasm-rs" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce095842aee9aa3ecbda7a5d2a4df680375fd128a8596b6b56f8e497e231f483" + [[package]] name = "num" version = "0.4.0" @@ -747,6 +813,12 @@ dependencies = [ "libc", ] +[[package]] +name = "once_cell" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" + [[package]] name = "os_str_bytes" version = "6.0.0" @@ -816,6 +888,7 @@ dependencies = [ "infer", "lazy_static", "log", + "mozjpeg", "rusttype", "serde", "serde_json", @@ -990,6 +1063,15 @@ version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +[[package]] +name = "rgb" +version = "0.8.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e74fdc210d8f24a7dbfedc13b04ba5764f5232754ccebfdf5fff1bad791ccbc6" +dependencies = [ + "bytemuck", +] + [[package]] name = "rusttype" version = "0.9.2" diff --git a/Cargo.toml b/Cargo.toml index bece8e6..1e07858 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,3 +33,4 @@ dirs = "4.0" infer = "0.7.0" textwrap = "0.14" webbrowser = "0.5" +mozjpeg = "0.9.2" \ No newline at end of file diff --git a/Cross.toml b/Cross.toml new file mode 100644 index 0000000..4d25551 --- /dev/null +++ b/Cross.toml @@ -0,0 +1,2 @@ +[target.x86_64-pc-windows-gnu] +image = "rustembedded/cross:x86_64-pc-windows-gnu" \ No newline at end of file diff --git a/src/utils.rs b/src/utils.rs index 2dd1156..fc62075 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -64,6 +64,13 @@ impl Into<(i32, i32)> for Coord { } } + +impl Into<(usize, usize)> for Coord { + fn into(self) -> (usize, usize) { + (self.0 as usize, self.1 as usize) + } +} + #[derive(Serialize, Deserialize, Debug, Clone)] pub(crate) struct ImageInfo { pub(crate) path: PathBuf, @@ -217,14 +224,10 @@ impl ImageContainer { }; let config = globals::CONFIG.read().unwrap(); let export_format = &config.image_format; - let export = path_original.parent().unwrap().join("export").join( - path_original - .with_extension(export_format.as_extension()) - .file_name() - .unwrap() - .to_str() - .unwrap(), - ); + let mut export = path_original.parent().unwrap().join("export") + .join(format!("{}-{}", path_original.file_stem().unwrap_or_default().to_string_lossy(), + path_original.extension().unwrap_or_default().to_string_lossy())); + export.set_extension(export_format.as_extension()); let mut prop = prop.clone(); prop.image_info = None; @@ -276,11 +279,25 @@ impl ImageContainer { encoder.write_image(&img.into_rgba8(), w, h, image::ColorType::Rgba8).warn_log("Failed to export Image!"); } ImageType::Jpeg => { - let mut encoder = - image::codecs::jpeg::JpegEncoder::new_with_quality(&mut output, 100); - encoder.set_pixel_density(image::codecs::jpeg::PixelDensity::dpi(300)); + let (width, height) = Coord::from(img.dimensions()).into(); + let buf = img.into_rgb8(); + + let mut comp = mozjpeg::Compress::new(mozjpeg::ColorSpace::JCS_RGB); - encoder.encode_image(&img).warn_log("Failed to export Image!"); + comp.set_size(width, height); + comp.set_quality(100.0); + comp.set_smoothing_factor(1); + comp.set_mem_dest(); + comp.start_compress(); + + comp.write_scanlines(&buf); + + comp.finish_compress(); + + match comp.data_to_vec() { + Ok(data) => std::fs::write(&export, data).warn_log("Failed to export Image!"), + Err(e) => Result::<(), _>::Err(e).warn_log("Failed to encode image!") + } } _ => (), } @@ -479,13 +496,21 @@ fn load_image(image_info: &ImageInfo) -> DynamicImage { ImageType::Webp => { let mut f = File::open(&image_info.path).expect_log("Failed to open image!"); let mut buf = vec![]; - f.read_to_end(&mut buf).unwrap(); - let a = webp::Decoder::new(&buf).decode().unwrap(); + f.read_to_end(&mut buf).expect_log("Failed to read image!"); + let a = webp::Decoder::new(&buf).decode().ok_or("").expect_log("Failed to decode image!"); a.to_image() } ImageType::Jpeg => { - let dec = image::codecs::jpeg::JpegDecoder::new(File::open(&image_info.path).expect_log("Failed to open image!")).expect_log("Failed to decode image!"); - DynamicImage::from_decoder(dec).expect_log("Failed to open image!") + let mut f = File::open(&image_info.path).expect_log("Failed to open image!"); + let mut buf = vec![]; + f.read_to_end(&mut buf).expect_log("Failed to read image!"); + + let d = mozjpeg::Decompress::with_markers(mozjpeg::ALL_MARKERS).from_mem(&buf) + .expect_log("Failed to decompress image!"); + let mut image = d.rgb().expect_log("Failed to covert to rgb image!"); + let pixels = image.read_scanlines_flat().unwrap(); + let image = ImageBuffer::from_raw(image.width() as u32, image.height() as u32, pixels).unwrap(); + DynamicImage::ImageRgb8(image) } ImageType::Png => { let dec = image::codecs::png::PngDecoder::new(File::open(&image_info.path).expect_log("Failed to open image!")).expect_log("Failed to decode image!");