Cykooz / fast_image_resize

Rust library for fast image resizing with using of SIMD instructions.
Apache License 2.0
284 stars 25 forks source link

Preparation of a large number of images in a loop #20

Closed yunusbayraktaroglu closed 7 months ago

yunusbayraktaroglu commented 7 months ago

Hello, I want to prepare a large number of images in a loop using your library. I have an application as below for performance optimization, but I am encountering errors. Which path should we follow?

pub struct Variation {
    pub id: String,
    pub size: (u32, u32),
}
pub struct VariationResult {
    pub id: String,
    pub buffer: Vec<u8>,
}

fn bulk_process( src_image: &fr::Image, variations: &Vec<Variation> ) -> Result<Vec<VariationResult>, Box<dyn Error>> 
{
    let mut image_variations: Vec<VariationResult> = Vec::new();

    let mut result_buffer: Vec<u8> = Vec::new();
    let mut buf_writer = BufWriter::new( &mut result_buffer );
    let mut encoder = JpegEncoder::new_with_quality( &mut buf_writer, 100 );

    let mut resizer = fr::Resizer::new( fr::ResizeAlg::Nearest );

    for variation in variations {

        let dst_width = NonZeroU32::new( variation.size.0 ).unwrap();
        let dst_height = NonZeroU32::new( variation.size.1 ).unwrap();
        let mut dst_image = fr::Image::new(
            dst_width,
            dst_height,
            src_image.pixel_type(),
        );

        resizer.resize( &src_image.view(), &mut dst_image.view_mut() ).unwrap();

        encoder.encode( 
            dst_image.buffer(), 
            dst_width.get(), 
            dst_height.get(), 
            ColorType::Rgb8 
        ).unwrap();

        let image = VariationResult { 
            id: variation.id.to_string(), 
            buffer: result_buffer, // ??
        };

        image_variations.push( image );
    }

    Ok( image_variations )

}
Cykooz commented 7 months ago

Move these lines inside of for-loop:

    let mut result_buffer: Vec<u8> = Vec::new();
    let mut buf_writer = BufWriter::new( &mut result_buffer );
    let mut encoder = JpegEncoder::new_with_quality( &mut buf_writer, 100 );
yunusbayraktaroglu commented 7 months ago

Is there a way to avoid creating new instances in the loop?

Cykooz commented 7 months ago

Your question is irrelevant to the fast_image_resize crate. It is more related to the Rust language and how computer's memory works. Value of the result_buffer variable can't be used after it is moved into image_variations vector. How do you want to use the same buffer to store different images at the same time? It is impossible. You must create a new buffer to store each image.

yunusbayraktaroglu commented 7 months ago

Thank you, let me modify my question, if the encoder and the resizer holds the logic of how to process images: Is there a way to create only one instance of these two, to use in +100 resize & encode ops. in loop?

Cykooz commented 7 months ago

You can reuse the memory buffer that is used for dst_image.

let mut dst_buffer: Vec<u8> = Vec:new();
for variation in variations {
    ...
    let dst_buf_size = ...;
    dst_buffer.resize(dst_buf_size, 0);
    let mut dst_image = fr::Image::from_slice_u8(
       dst_width,
       dst_height,
       &mut dst_buffer,
       src_image.pixel_type(),
   ).unwrap();
   ...
}

I think that creating an instance of JpegEncoder is a fairly easy operation. But you may look at the image crate documentation. May be you can find something about how to reuse exists JpegEncoder instance to encode different images.

But, in any case, to store 100+ result images you must create 100+ vectors.

yunusbayraktaroglu commented 7 months ago

Thank you!