Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JpegEncoder is very slow! #2240

Closed
lanyeeee opened this issue May 20, 2024 · 2 comments
Closed

JpegEncoder is very slow! #2240

lanyeeee opened this issue May 20, 2024 · 2 comments

Comments

@lanyeeee
Copy link

I needed to set the quality before save the jpg image, and I found the solution here #1842 (comment) (use image::codecs::jpeg::JpegEncoder), but I found it very slow, saving a jpg image with it took almost 10 times as long as ImageBuffer::save.

I also tried jpeg-encoder. In my test, it takes 1/2 the time of ImageBuffer::save to encode an image, here's my test code.

main.rs

use anyhow::{Ok, Result};
use image::codecs::jpeg::JpegEncoder;
use std::fs;

fn main() -> Result<()> {
    let in_img = image::open("1.jpg")
        .expect("Failed to open output image")
        .to_rgb8();

    // save with image::codecs::jpeg::JpegEncoder
    let timer = std::time::Instant::now();
    let mut writer = fs::File::create("encoder_save_out.jpg")?;
    let encoder = JpegEncoder::new_with_quality(&mut writer, 95);
    in_img.write_with_encoder(encoder)?;
    println!("write_with_encoder: {:?}", timer.elapsed());

    // save with ImageBuffer::save
    let timer = std::time::Instant::now();
    in_img.save("save_out.jpg")?;
    println!("ImageBuffer::save: {:?}", timer.elapsed());

    // save with jpeg_encoder
    let timer = std::time::Instant::now();
    let encoder = jpeg_encoder::Encoder::new_file("jpeg_encoder_out.jpg", 95)?;
    encoder.encode(
        &in_img.as_raw(),
        in_img.width() as u16,
        in_img.height() as u16,
        jpeg_encoder::ColorType::Rgb,
    )?;
    println!("jpeg_encoder: {:?}", timer.elapsed());

    Ok(())
}

Cargo.toml

[dependencies]
image = "0.25.1"
anyhow = "1.0"
jpeg-encoder = "0.6.0"

output

write_with_encoder: 8.3307498s
ImageBuffer::save: 706.4297ms
jpeg_encoder: 280.8474ms

So why is using image::codecs::jpeg::JpegEncoder so much slower than ImageBuffer::save, is there some bug?

@fintelia
Copy link
Contributor

fintelia commented May 20, 2024

Save internally uses a BufWriter which performs better than a raw File object:

let buffered_file_write = &mut BufWriter::new(File::create(path)?); // always seekable

It then internally creates a JpegEncoder, so that part is the same:

jpeg::JpegEncoder::new(buffered_write).write_image(buf, width, height, color)

@lanyeeee
Copy link
Author

I'm really sorry for didn't consider the File is not buffered.
Without buffering, each write is a system call, so it's very slow.
Now I've changed the code like this, it works like a charm.

let file = fs::File::create("encoder_save_out.jpg")?;
let mut buffered_file_writer = &mut BufWriter::new(file);
let encoder = JpegEncoder::new_with_quality(&mut buffered_file_writer, 95);
in_img.write_with_encoder(encoder)?;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants