Image: `load_from_memory*` functions don't work with data returned from `DynamicImage.to_bytes()`

Created on 25 Jul 2020  路  4Comments  路  Source: image-rs/image

The load_from_memory and load_from_memory_with_format functions are failing with bytes returned from DynamicImage#to_bytes().

There are two tests that show this:

Test one:

#[test]
fn from_load_from_memory() {
    let img = open("features/fixtures/img01.jpg")
        .expect("File should load");

    let img = load_from_memory(&img.to_bytes())
        .expect("File should load from its own data");

    assert!(true);
}

Fails with this:

---- from_load_from_memory stdout ----
thread 'from_load_from_memory' panicked at 'File should load from its own data: Unsupported(UnsupportedError { format: Unknown, kind: Format(Unknown) })', tests/transformers_test.rs:50:15

Test two:

#[test]
fn from_load_from_memory_with_format() {
    let img = open("features/fixtures/img01.jpg")
        .expect("File should load");

    let img = load_from_memory_with_format(&img.to_bytes(), ImageFormat::Jpeg)
        .expect("File should load from its own data and format hint");

    assert!(true);
}

Fails with this:

---- from_load_from_memory_with_format stdout ----
thread 'from_load_from_memory_with_format' panicked at 'File should load from its own data and format hint: Decoding(DecodingError { format: Exact(Jpeg), underlying: Some(Format("first two bytes is not a SOI marker")) })', tests/transformers_test.rs:61:15

As best as I can tell, I'm reading Vec<u8> data from a successfully opened DynamicImage back into two functions that take a Vec<u8> and return a DynamicImage. But it's failing.
There's obviously some nuance I'm missing!

If anybody could point me in the right direction to accomplish what I'm trying to achieve, here, it would be really appreciated.
Thanks,
Doug.

question

All 4 comments

The to_bytes method does not encode the image, it returns to you the bytes making up the pixels. You shouldn't decode those bytes but you can use ImageBuffer::from_raw to restore an image. This requires you to save all the metadata separately. If you don't want to do that manually, i.e. for process-to-process communication or very temporary storage, then you may consider using one of the pnm formats which takes care of prepending the the image size and color type to the (basically) raw bytes with without any of the computation overhead (compression, quantization, ..) of jpeg and png.

Thanks @HeroicKatora !
What I need to do is:

  • to load a DynamicImage (no problem with that)
  • run some processing on it (I'm guessing is simple, from the docs)
  • then output the Vec<u8> of bytes of processed image in correct Jpeg format

The resulting Vec<u8> should be readable by clients as an image -- this is for an image service that modifies images on-the-fly.
It's the third step there I'm struggling with. I'll keep digging but if you could point me at the method I need to get the Jpeg-formatted Vec<u8> I'd be really grateful!
Thanks again,
Doug.

In that case, you're going to want to use JPEGEncoder. The resulting code should be something like:

let mut output = Vec::new();
JPEGEncoder::new(&mut output).encode_image(&img).unwrap();

@fintelia thank you!
That would have taken me ages to trip over!
Thanks so much!

Was this page helpful?
0 / 5 - 0 ratings