etemesi254 / zune-image

A fast and memory efficient image library in Rust
Other
327 stars 30 forks source link

Encoder ignores width & height #158

Closed kkettinger closed 9 months ago

kkettinger commented 9 months ago

When using EncoderOptions and setting width and height, they are ignored in the resulting image. Setting the quality is not ignored.

Here a minimal example:

use std::fs::File;
use std::io::Read;
use std::path::Path;
use zune_image::codecs::bmp::zune_core::options::{DecoderOptions, EncoderOptions};
use zune_image::codecs::ImageFormat;
use zune_image::image::Image;

fn main() {
    let file_path = "test.jpg";
    let file_path_output = "output.jpg";

    // Read file
    let mut file = File::open(file_path).unwrap();
    let mut data = Vec::new();
    file.read_to_end(&mut data).unwrap();

    // Convert to Image type
    let image = Image::read(data, DecoderOptions::default()).unwrap();

    // Encoder options
    let encoder_options = EncoderOptions::default()
        .set_width(100)
        .set_height(100)
        .set_quality(70);

    println!("encoder options: {:?}", encoder_options);

    // Encoder
    let ext = Path::new(file_path_output).extension().unwrap();
    let (_, mut encoder) = ImageFormat::get_encoder_for_extension(ext.to_str().unwrap()).unwrap();
    encoder.set_options(encoder_options);

    // Encode
    let result = encoder.encode(&image).unwrap();

    // Write file
    std::fs::write(file_path_output, &result).unwrap();

    // Display width & height for input & output
    let image_output = Image::read(&result, DecoderOptions::default()).unwrap();

    println!("input dimensions: {:?}", image.dimensions());
    println!("output dimensions: {:?}", image_output.dimensions());
}

Output:

encoder options: EncoderOptions { width: 100, height: 100, colorspace: RGB, quality: 70, depth: Eight, num_threads: 4, effort: 4, flags: EncoderFlags { jpeg_encode_progressive: false, jpeg_optimize_huffman: false, image_strip_metadata: false } }
input dimensions: (3648, 2736)
output dimensions: (3648, 2736)

cargo.toml

zune-image = "0.4.14"

Hope you can help me out why the encoder ignores my dimensions. Thank you in advance.

kkettinger commented 9 months ago

Just found out the dimensions seem to be maximum dimensions for encoding/decoding, not for resizing the image. There is a zune-imageprocs crate that does resizing.

Here is a complete example for everyone interested:

use std::fs::File;
use std::io::Read;
use std::path::Path;

use zune_image::codecs::bmp::zune_core::options::{DecoderOptions, EncoderOptions};
use zune_image::codecs::ImageFormat;
use zune_image::image::Image;
use zune_image::traits::OperationsTrait;
use zune_imageprocs::resize::{Resize, ResizeMethod};

fn main() {
    let file_path = "test.jpg";
    let file_path_output = "output.jpg";

    // Read file
    let mut file = File::open(file_path).unwrap();
    let mut data = Vec::new();
    file.read_to_end(&mut data).unwrap();

    // Image format
    let (image_format, _) = ImageFormat::guess_format(&data).unwrap();

    // Decoder options
    let decoder_options = DecoderOptions::default();

    // Decode
    let mut decoder = image_format.get_decoder_with_options(&data, decoder_options).unwrap();
    let mut image = decoder.decode().unwrap();

    println!("input dimensions: {:?}", image.dimensions());

    // Resize
    Resize::new(1024, 1024, ResizeMethod::Bilinear).execute(&mut image).unwrap();

    // Encoder options
    let encoder_options = EncoderOptions::default()
        .set_quality(70);

    println!("encoder options: {:?}", encoder_options);

    // Encoder
    let ext = Path::new(file_path_output).extension().unwrap();
    let (_, mut encoder) = ImageFormat::get_encoder_for_extension(ext.to_str().unwrap()).unwrap();
    encoder.set_options(encoder_options);

    // Encode
    let result = encoder.encode(&image).unwrap();

    // Write file
    std::fs::write(file_path_output, &result).unwrap();

    // Display output dimensions
    let image_output = Image::read(&result, DecoderOptions::default()).unwrap();
    println!("output dimensions: {:?}", image_output.dimensions());
}
etemesi254 commented 9 months ago

Yes, sorry the encoder fills basic image information from the image itself.

The reason we still have it to set up additional parameters such as threading e.g if you have specific requirements for how many threads to be used for jxl encoding.