Skip to content

Commit

Permalink
Restore streaming output writes
Browse files Browse the repository at this point in the history
During the upgrade from image 0.23 to 0.24, `ImageBuffer::write_to()`
was changed to require a seekable writer.
This doesn't work when writing to stdout, so we were forced to buffer
the output before writing it out in one go.

It turns out that most individual encoders don't actually require
seeking, and neither of the two we use does.
Restore streaming behavior by invoking encoders directly.

See: image-rs/image#1922
  • Loading branch information
9ary committed May 16, 2023
1 parent 15df71a commit 7694466
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 14 deletions.
35 changes: 21 additions & 14 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@
use std::env;
use std::ffi::CString;
use std::fs::File;
use std::io::{self, Write};
use std::io;
use std::path::Path;
use std::process;
use std::time;

use getopts::Options;
use image::codecs;
use image::GenericImage;
use image::GenericImageView;
use image::ImageOutputFormat;
use image::Rgba;
use image::RgbaImage;
use x11::xlib;
Expand Down Expand Up @@ -96,8 +98,8 @@ fn run() -> i32 {
.unwrap_or_else(|| "png".to_string())
.to_lowercase();
let output_format = match output_ext.as_ref() {
"png" => image::ImageOutputFormat::Png,
"pam" => image::ImageOutputFormat::Pnm(image::codecs::pnm::PnmSubtype::ArbitraryMap),
"png" => ImageOutputFormat::Png,
"pam" => ImageOutputFormat::Pnm(codecs::pnm::PnmSubtype::ArbitraryMap),
_ => {
eprintln!("Invalid image format specified");
return 1;
Expand Down Expand Up @@ -233,25 +235,30 @@ fn run() -> i32 {
}
};

if path == "-" {
let mut buf = Vec::new();
image
.write_to(&mut io::Cursor::new(&mut buf), output_format)
.expect("Encoding failed");
io::stdout()
.write_all(buf.as_slice())
.expect("Writing to stdout failed");
let writer: Box<dyn io::Write> = if path == "-" {
Box::new(io::stdout())
} else {
match File::create(Path::new(&path)) {
Ok(mut f) => image
.write_to(&mut f, output_format)
.expect("Writing to file failed"),
Ok(f) => Box::new(f),
Err(e) => {
eprintln!("Failed to create {path}: {e}");
return 1;
}
}
};

match output_format {
ImageOutputFormat::Png => {
let encoder = codecs::png::PngEncoder::new(writer);
util::write_image_buffer_with_encoder(&image, encoder)
}
ImageOutputFormat::Pnm(subtype) => {
let encoder = codecs::pnm::PnmEncoder::new(writer).with_subtype(subtype);
util::write_image_buffer_with_encoder(&image, encoder)
}
_ => unreachable!(),
}
.expect("Failed to write output");

0
}
Expand Down
18 changes: 18 additions & 0 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,21 @@ pub fn parse_int<T: num_traits::Num>(string: &str) -> Result<T, T::FromStrRadixE
_ => T::from_str_radix(string, 10),
}
}

use image::EncodableLayout;
pub fn write_image_buffer_with_encoder<P, Container>(
image: &image::ImageBuffer<P, Container>,
encoder: impl image::ImageEncoder,
) -> image::ImageResult<()>
where
P: image::PixelWithColorType,
[P::Subpixel]: image::EncodableLayout,
Container: core::ops::Deref<Target = [P::Subpixel]>,
{
encoder.write_image(
image.as_raw().as_bytes(),
image.width(),
image.height(),
P::COLOR_TYPE,
)
}

0 comments on commit 7694466

Please sign in to comment.