kornelski / mozjpeg-sys

Rust bindings for mozjpeg
https://lib.rs/crates/mozjpeg-sys
Other
33 stars 17 forks source link

panic "Texture data size mismatch" when loading jpeg with mozjpeg instead of image crate #7

Closed Boscop closed 6 years ago

Boscop commented 6 years ago

I was trying out this example of rendering cubemaps with glium: http://onagat.hatenablog.com/entry/2017/03/24/235635

And I noticed that in debug mode, it takes a minute to load the jpeg files, so I wanted to do it with mozjpeg instead.

As a first step, I rewrote the image loading code to use this load_jpeg function:

fn load_jpeg(path: &str) -> io::Result<(Vec<u8>, u32, u32)> {
    let r = BufReader::new(File::open(path)?);
    let image = image::load(r, image::JPEG).unwrap().to_rgba();
    let (w, h) = image.dimensions();
    Ok((image.into_raw(), w, h))
}

// ...
    let (image, w, h) = load_jpeg("images/posx.jpg").unwrap();
    let image = glium::texture::RawImage2d::from_raw_rgba/*_reversed*/(image, (w, h));
    let tex_posx = glium::Texture2d::new(&display, image).unwrap();

    let (image, w, h) = load_jpeg("images/negx.jpg").unwrap();
    let image = glium::texture::RawImage2d::from_raw_rgba/*_reversed*/(image, (w, h));
    let tex_negx = glium::Texture2d::new(&display, image).unwrap();

    let (image, w, h) = load_jpeg("images/posy.jpg").unwrap();
    let image = glium::texture::RawImage2d::from_raw_rgba/*_reversed*/(image, (w, h));
    let tex_posy = glium::Texture2d::new(&display, image).unwrap();

    let (image, w, h) = load_jpeg("images/negy.jpg").unwrap();
    let image = glium::texture::RawImage2d::from_raw_rgba/*_reversed*/(image, (w, h));
    let tex_negy = glium::Texture2d::new(&display, image).unwrap();

    let (image, w, h) = load_jpeg("images/posz.jpg").unwrap();
    let image = glium::texture::RawImage2d::from_raw_rgba/*_reversed*/(image, (w, h));
    let tex_posz = glium::Texture2d::new(&display, image).unwrap();

    let (image, w, h) = load_jpeg("images/negz.jpg").unwrap();
    let image = glium::texture::RawImage2d::from_raw_rgba/*_reversed*/(image, (w, h));
    let tex_negz = glium::Texture2d::new(&display, image).unwrap();

Then I replaced the calls to load_jpeg with calls to load_jpeg_fast, using mozjpeg:

fn load_jpeg_fast(path: &str) -> io::Result<(Vec<u8>, u32, u32)> {
    use std::mem;
    use std::ffi::CString;
    use libc;
    use mozjpeg_sys::*;
    unsafe {
        let mut err: jpeg_error_mgr = mem::zeroed();
        let mut dinfo: jpeg_decompress_struct = mem::zeroed();
        dinfo.common.err = jpeg_std_error(&mut err);
        jpeg_create_decompress(&mut dinfo);

        let path = CString::new(path.as_bytes()).unwrap();
        let mode = CString::new("rb").unwrap();
        let fh = libc::fopen(path.as_ptr(), mode.as_ptr());
        jpeg_stdio_src(&mut dinfo, fh);
        jpeg_read_header(&mut dinfo, true as boolean);

        let width = dinfo.image_width;
        let height = dinfo.image_height;
        println!("Image size {}x{}", width, height);

        dinfo.out_color_space = J_COLOR_SPACE::JCS_RGB;
        jpeg_start_decompress(&mut dinfo);
        let row_stride = dinfo.image_width as usize * dinfo.output_components as usize;
        let buffer_size = row_stride * dinfo.image_height as usize;
        let mut buffer = vec![0u8; buffer_size];

        while dinfo.output_scanline < dinfo.output_height {
            let offset = dinfo.output_scanline as usize * row_stride;
            let mut jsamparray = [buffer[offset..].as_mut_ptr()];
            jpeg_read_scanlines(&mut dinfo, jsamparray.as_mut_ptr(), 1);
        }

        println!("Decoded into {} raw pixel bytes", buffer.len());

        jpeg_finish_decompress(&mut dinfo);
        jpeg_destroy_decompress(&mut dinfo);
        libc::fclose(fh);

        Ok((buffer, width, height))
    }
}

But it's not working, now the program crashes with:

Image size 2048x2048
Decoded into 12582912 raw pixel bytes
thread 'main' panicked at 'Texture data size mismatch', C:\Users\me\.cargo\regis
try\src\github.com-1ecc6299db9ec823\glium-0.16.0\src\texture\any.rs:147:13
stack backtrace:
   0: std::sys::windows::backtrace::unwind_backtrace
             at C:\projects\rust\src\libstd\sys\windows\backtrace\mod.rs:65
   1: std::sys_common::backtrace::_print
             at C:\projects\rust\src\libstd\sys_common\backtrace.rs:71
   2: std::sys_common::backtrace::print
             at C:\projects\rust\src\libstd\sys_common\backtrace.rs:59
   3: std::panicking::default_hook::{{closure}}
             at C:\projects\rust\src\libstd\panicking.rs:207
   4: std::panicking::default_hook
             at C:\projects\rust\src\libstd\panicking.rs:223
   5: std::panicking::rust_panic_with_hook
             at C:\projects\rust\src\libstd\panicking.rs:402
   6: std::panicking::begin_panic<str*>
             at C:\projects\rust\src\libstd\panicking.rs:365
   7: glium::texture::any::new_texture<glium::backend::glutin_backend::GlutinFac
ade,u8>
             at \<panic macros>:3
   8: glium::texture::texture2d::Texture2d::new_impl<glium::backend::glutin_back
end::GlutinFacade,glium::texture::RawImage2d<u8>>
             at .\target\debug\build\glium-fc3f792f7cd57a36\out\textures.rs:2899

   9: glium::texture::texture2d::Texture2d::new<glium::backend::glutin_backend::
GlutinFacade,glium::texture::RawImage2d<u8>>
             at .\target\debug\build\glium-fc3f792f7cd57a36\out\textures.rs:2862

  10: glium_cubemap::main
             at .\src\main.rs:128
  11: std::rt::lang_start::{{closure}}<()>
             at C:\projects\rust\src\libstd\rt.rs:74
  12: std::rt::lang_start_internal::{{closure}}
             at C:\projects\rust\src\libstd\rt.rs:59
  13: std::panicking::try::do_call<closure,i32>
             at C:\projects\rust\src\libstd\panicking.rs:306
  14: panic_unwind::__rust_maybe_catch_panic
             at C:\projects\rust\src\libpanic_unwind\lib.rs:102
  15: std::panicking::try
             at C:\projects\rust\src\libstd\panicking.rs:285
  16: std::panic::catch_unwind
             at C:\projects\rust\src\libstd\panic.rs:361
  17: std::rt::lang_start_internal
             at C:\projects\rust\src\libstd\rt.rs:58
  18: std::rt::lang_start<()>
             at C:\projects\rust\src\libstd\rt.rs:74
  19: main
  20: invoke_main
             at f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl:64
  21: __scrt_common_main_seh
             at f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl:253
  22: BaseThreadInitThunk
  23: RtlUserThreadStart
error: process didn't exit successfully: `target\debug\glium-cubemap.exe` (exit
code: 101)

Any idea what I'm doing wrong? :)

Boscop commented 6 years ago

Ah nvm, I figured out I was using to_rgba() and RawImage2d::from_raw_rgba(), now it works with from_raw_rgb().