-
Notifications
You must be signed in to change notification settings - Fork 22
Open
Labels
bugSomething isn't workingSomething isn't working
Description
Is there an existing issue for this?
- I have searched the existing issues
Description
Cov pic to mozjpeg failed with tips libjpeg fatal error: DCT coefficient out of range.
Expected behavior
Cov to moz successfully
Library Version
0.11.0 (latest)
Steps To Reproduce
- Use the code from master branch and build locally.
- Unzip test_pic.zip to
D:\test\egHNzjeurAcw.png - run with
cls; cargo r --all-features -- moz -q 90 -s asdf "D:\test\egHNzjeurAcw.png"
Anything else?
I tried AI to fix this and this runs successfully, but as the cost, the parm of --smooth was disabled...
Because I don't know anything about image processing at all, I don't have the ability to pr, please help to correct it.
Click to see FULL
diff --git a/src/codecs/mozjpeg/encoder/mod.rs b/src/codecs/mozjpeg/encoder/mod.rs
index 4d6738c..9562b4e 100644
--- a/src/codecs/mozjpeg/encoder/mod.rs
+++ b/src/codecs/mozjpeg/encoder/mod.rs
@@ -104,6 +104,10 @@ impl EncoderTrait for MozJpegEncoder {
let (width, height) = image.dimensions();
let data = &image.flatten_to_u8()[0];
+ // Log image info for debugging
+ log::debug!("Encoding image: {}x{}, colorspace: {:?}, {} bytes",
+ width, height, image.colorspace(), data.len());
+
let luma_qtable = self.options.luma_qtable.as_ref();
let chroma_qtable = self.options.chroma_qtable.as_ref();
@@ -132,7 +136,23 @@ impl EncoderTrait for MozJpegEncoder {
}
comp.set_optimize_coding(self.options.optimize_coding);
- comp.set_smoothing_factor(self.options.smoothing);
+
+ // Apply smoothing - use user setting, or auto-apply for high quality to prevent DCT overflow
+ let smoothing = if self.options.smoothing > 0 {
+ self.options.smoothing
+ } else if self.options.quality >= 95.0 {
+ // Very high quality can cause DCT coefficient overflow
+ log::warn!("Very high quality (>= 95) detected, auto-applying smoothing (15) to prevent DCT overflow. Use --smoothing 0 to disable.");
+ 15
+ } else if self.options.quality >= 90.0 {
+ // High quality may cause DCT overflow with some images
+ log::info!("High quality (>= 90) detected, auto-applying light smoothing (10) to prevent potential DCT overflow. Use --smoothing 0 to disable.");
+ 10
+ } else {
+ 0
+ };
+ comp.set_smoothing_factor(smoothing);
+
comp.set_color_space(match format {
mozjpeg::ColorSpace::JCS_GRAYSCALE => {
log::warn!("Input colorspace is GRAYSCALE, using GRAYSCALE as output");
diff --git a/src/operations/icc/mod.rs b/src/operations/icc/mod.rs
index 180e29b..5de3bf3 100644
--- a/src/operations/icc/mod.rs
+++ b/src/operations/icc/mod.rs
@@ -30,8 +30,15 @@ impl OperationsTrait for ApplyICC {
fn execute_impl(&self, image: &mut Image) -> Result<(), ImageErrors> {
let src_profile = match image.metadata().icc_chunk() {
- Some(icc) => Profile::new_icc_context(ThreadContext::new(), icc)
- .map_err(|e| ImageOperationsErrors::GenericString(e.to_string()))?,
+ Some(icc) => {
+ match Profile::new_icc_context(ThreadContext::new(), icc) {
+ Ok(profile) => profile,
+ Err(e) => {
+ log::warn!("Failed to parse ICC profile: {}, using sRGB instead", e);
+ Profile::new_srgb_context(ThreadContext::new())
+ }
+ }
+ }
None => Profile::new_srgb_context(ThreadContext::new()),
};
@@ -70,12 +77,61 @@ impl OperationsTrait for ApplyICC {
Intent::Perceptual,
Flags::NO_CACHE,
)
- .map_err(|e| ImageOperationsErrors::GenericString(e.to_string()))?;
+ .map_err(|e| {
+ log::error!("Failed to create ICC transform: {}", e);
+ ImageOperationsErrors::GenericString(e.to_string())
+ })?;
for frame in image.frames_mut() {
- let mut buffer = frame.flatten::<u8>(colorspace);
- t.transform_in_place(&mut buffer);
- let _ = std::mem::replace(frame, Frame::from_u8(&buffer, colorspace, 0, 0));
+ let buffer = frame.flatten::<u8>(colorspace);
+
+ // Store original buffer in case transformation fails or produces invalid data
+ let original_buffer = buffer.clone();
+ let mut transformed_buffer = buffer;
+
+ // Perform ICC transformation with error recovery
+ let transform_result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
+ t.transform_in_place(&mut transformed_buffer);
+ }));
+
+ if transform_result.is_err() {
+ log::error!("ICC transformation panicked, using original data without transformation");
+ let _ = std::mem::replace(frame, Frame::from_u8(&original_buffer, colorspace, 0, 0));
+ continue;
+ }
+
+ // Validate transformed data - check for suspicious patterns
+ let mut is_valid = true;
+
+ // Quick sanity check: ensure the transformation didn't produce all zeros or all 255s
+ let all_same = transformed_buffer.iter().all(|&x| x == transformed_buffer[0]);
+ if all_same && transformed_buffer.len() > 100 {
+ log::warn!("ICC transformation produced uniform data, likely corrupted");
+ is_valid = false;
+ }
+
+ // Check for extreme value clustering that indicates corruption
+ if is_valid {
+ let mut extreme_count = 0;
+ for &val in &transformed_buffer {
+ if val == 0 || val == 255 {
+ extreme_count += 1;
+ }
+ }
+ // If more than 50% of pixels are extreme values, likely corrupted
+ if extreme_count > transformed_buffer.len() / 2 {
+ log::warn!("ICC transformation produced {} extreme values out of {} pixels, likely corrupted",
+ extreme_count, transformed_buffer.len());
+ is_valid = false;
+ }
+ }
+
+ if is_valid {
+ let _ = std::mem::replace(frame, Frame::from_u8(&transformed_buffer, colorspace, 0, 0));
+ } else {
+ log::warn!("Using original image data due to invalid ICC transformation");
+ let _ = std::mem::replace(frame, Frame::from_u8(&original_buffer, colorspace, 0, 0));
+ }
}
image.metadata_mut().set_icc_chunk(
@@ -117,13 +173,22 @@ impl OperationsTrait for ApplySRGB {
fn execute_impl(&self, image: &mut Image) -> Result<(), ImageErrors> {
if image.metadata().icc_chunk().is_none() {
- log::warn!("No icc profile in the image, skipping");
+ log::info!("No ICC profile in the image, skipping sRGB conversion");
return Ok(());
}
- ApplyICC::new(Profile::new_srgb_context(ThreadContext::new())).execute_impl(image)?;
-
- Ok(())
+ log::info!("Applying sRGB ICC profile conversion");
+ match ApplyICC::new(Profile::new_srgb_context(ThreadContext::new())).execute_impl(image) {
+ Ok(()) => {
+ log::info!("Successfully applied sRGB profile");
+ Ok(())
+ }
+ Err(e) => {
+ log::error!("Failed to apply sRGB profile: {}, proceeding without ICC conversion", e);
+ // Don't fail the whole process, just skip ICC conversion
+ Ok(())
+ }
+ }
}
fn supported_types(&self) -> &'static [BitType] {

Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working