fosslife / devtools-x

Collection of offline first developer utilities available as non-electron desktop application. all in one place, cross-platform, 10MB app!
https://devtools.fosslife.com/
MIT License
1.11k stars 53 forks source link

Image Compression Crashing App #128

Open oleteacher opened 1 day ago

oleteacher commented 1 day ago

Great job on app! Learning Tauri, this helps me a lot and the tools you have compiled are awesome.

When adding certain images the compressor tool, app simply crashes. Closes without any warning or message.

Running Windows 10 and tried the latest release version of devtools-x.

Example image that crashes app:

lips

Built locally and running dev mode, see this error in dev tools (maybe help you):

IPC custom protocol failed, Tauri will now use the postMessage interface instead TypeError: Failed to fetch
    at Object.sendIpcMessage (<anonymous>:73:7)
    at Object.<anonymous> (<anonymous>:132:38)
    at action (<anonymous>:269:38)
    at <anonymous>:278:11
    at new Promise (<anonymous>)
    at Object.value (<anonymous>:254:14)
    at invoke (core.js:134:39)
    at resize (Image.tsx:70:5)
    at Image.tsx:112:5
    at commitHookEffectListMount (react-dom.development.js:23150:26)
oleteacher commented 1 day ago

Did a push for your inspection.

Think I also made a change to Image.tsx but not sure I added to my fork. In any case, here is what I purposed:

Hardcoded:

const blob = new Blob([new Uint8Array(buff)], {
  type: "image/jpeg", // This is hardcoded
});

My fix:

const blob = new Blob([new Uint8Array(buff)], {
  type: `image/${imageType.toLowerCase()}`,
});
Sparkenstein commented 1 day ago

So the error was ipc failing on tauri, it's fixed as well but I didn't release it. let me release a draft can you try that and let me know. changing type here won't change because this blob is only fetched to calculate sizes.

Sparkenstein commented 1 day ago

Check latest release I accidentally forgot to bump version but 3.3.3 should have fix for this

your pr looks good anyway, I will merge it in 3.3.5 (current is 3.3.4, forgot to bump version)

oleteacher commented 19 hours ago

Odd. I am trying your 3.3.3 64 for windows. It will not load any image into compression area. None.

I tried a build from you 3.3.3 and still cannot get iamges to load correctly. The image above will not load.

I am traveling for next 7 days and not near my dev desktop files.

I am not sure your image_compressor.rs was updated. But I am on a small screen and maybe missing something, old eyes :)

My image_compressor.rs:

pub mod images {
  use std::path::Path;

  use image::{
    codecs::{
      jpeg::JpegEncoder,
      png::{CompressionType, PngEncoder},
    },
    ColorType, ImageEncoder,
  };
  use serde::{Deserialize, Serialize};

  #[derive(Debug, Deserialize, Serialize)]
  pub enum ImageFormat {
    Jpeg,
    Png,
    Webp,
  }

  #[tauri::command]
  pub async fn compress_images_to_buffer(
    image_path: String,
    quality: u8,
    format: ImageFormat,
  ) -> Result<Vec<u8>, String> {
    let time = std::time::Instant::now();
    let path = Path::new(&image_path);

    let img = image::open(path).map_err(|e| e.to_string())?;

    match format {
      ImageFormat::Jpeg => {
        let rgb_img = img.into_rgb8();
        let mut writer = Vec::new();
        let mut encoder = JpegEncoder::new_with_quality(&mut writer, quality);
        encoder
          .encode(
            rgb_img.as_raw(),
            rgb_img.width(),
            rgb_img.height(),
            ColorType::Rgb8
          )
          .map_err(|e| e.to_string())?;
        println!("Time: {:?}", time.elapsed());
        Ok(writer)
      }
      ImageFormat::Png => {
        let rgb_img = img.into_rgb8();
        let mut writer = Vec::new();
        let compression_level = match quality {
          0..=33 => CompressionType::Best,
          34..=66 => CompressionType::Default,
          67..=100 => CompressionType::Fast,
          _ => CompressionType::Default,
        };
        let encoder = PngEncoder::new_with_quality(
          &mut writer,
          compression_level,
          image::codecs::png::FilterType::Sub,
        );
        encoder
          .write_image(
            rgb_img.as_raw(),
            rgb_img.width(),
            rgb_img.height(),
            ColorType::Rgb8
          )
          .map_err(|e| e.to_string())?;
        println!("Time: {:?}", time.elapsed());
        Ok(writer)
      }
      ImageFormat::Webp => {
        // For WebP, we use the original image since webp::Encoder handles the conversion
        let x = webp::Encoder::from_image(&img)
          .map_err(|e| e.to_string())?
          .encode(quality as f32);
        println!("Time: {:?}", time.elapsed());
        Ok(x.to_vec())
      }
    }
  }
}