From ecc3b8238595ac5c26355fe196dc74f577edaf23 Mon Sep 17 00:00:00 2001 From: Janne Mareike Koschinski <janne@kuschku.de> Date: Mon, 9 Mar 2020 23:10:33 +0100 Subject: [PATCH] add more configurable image formats --- src/ingest/extract.rs | 3 +- src/ingest/spritesheet.rs | 60 ++++++++++++++++++++++++++------------- src/main.rs | 14 +++++++-- 3 files changed, 54 insertions(+), 23 deletions(-) diff --git a/src/ingest/extract.rs b/src/ingest/extract.rs index 658cf09..a633087 100644 --- a/src/ingest/extract.rs +++ b/src/ingest/extract.rs @@ -1,6 +1,7 @@ use std::path::Path; use failure::{format_err, Error}; +use image::ImageOutputFormat; use crate::ffmpeg_api::api::*; use crate::ffmpeg_api::enums::*; @@ -15,7 +16,7 @@ pub fn extract( frame_interval: MediaTime, input_file: &Path, output_folder: &Path, - format: impl AsRef<str>, + format: ImageOutputFormat, scaler: SwsScaler, flags: SwsFlags, ) -> Result<(), Error> { diff --git a/src/ingest/spritesheet.rs b/src/ingest/spritesheet.rs index 6fa2853..de26266 100644 --- a/src/ingest/spritesheet.rs +++ b/src/ingest/spritesheet.rs @@ -1,11 +1,18 @@ +use std::fs::File; +use std::io::BufWriter; use std::path::PathBuf; use failure::{bail, format_err, Error}; -use image::{ImageBuffer, RgbImage}; +use image::{DynamicImage, ImageOutputFormat, RgbImage}; use crate::util::media_time::MediaTime; use crate::util::webvtt::{WebVTTCue, WebVTTFile}; +pub enum ImageFormat { + Jpeg(i32), + Png, +} + pub struct SpritesheetManager { num_horizontal: u32, num_vertical: u32, @@ -19,7 +26,7 @@ pub struct SpritesheetManager { metadata: WebVTTFile, output_path: PathBuf, name: String, - format: String, + format: ImageOutputFormat, initialized: bool, } @@ -31,7 +38,7 @@ impl SpritesheetManager { frame_interval: MediaTime, output_path: impl Into<PathBuf>, name: impl AsRef<str>, - format: impl AsRef<str>, + format: ImageOutputFormat, ) -> SpritesheetManager { SpritesheetManager { num_horizontal, @@ -39,14 +46,14 @@ impl SpritesheetManager { max_side, sprite_width: 0, sprite_height: 0, - spritesheet: ImageBuffer::new(0, 0), + spritesheet: RgbImage::new(0, 0), current_image: 0, last_timestamp: MediaTime::from_millis(0), frame_interval, metadata: WebVTTFile::new(), output_path: output_path.into(), name: String::from(name.as_ref()), - format: String::from(format.as_ref()), + format, initialized: false, } } @@ -59,15 +66,15 @@ impl SpritesheetManager { self.sprite_height = self.max_side; self.sprite_width = self.sprite_height * width / height; } - self.reinit_buffer(); + self.spritesheet = self.reinit_buffer(); self.initialized = true; } - fn reinit_buffer(&mut self) { - self.spritesheet = ImageBuffer::new( + fn reinit_buffer(&self) -> RgbImage { + RgbImage::new( self.sprite_width * self.num_horizontal, self.sprite_height * self.num_vertical, - ); + ) } pub fn initialized(&self) -> bool { @@ -95,6 +102,15 @@ impl SpritesheetManager { index * self.sprite_width } + fn ending(&self) -> String { + String::from(match self.format { + ImageOutputFormat::Png => "png", + ImageOutputFormat::Jpeg(_) => "jpeg", + ImageOutputFormat::Bmp => "bmp", + _ => panic!("Invalid image format: {:?}", self.format), + }) + } + fn y(&self, current: u32) -> u32 { let index = (current / self.num_horizontal) % self.num_vertical; index * self.sprite_height @@ -141,7 +157,7 @@ impl SpritesheetManager { "{}_{}.{}#xywh={},{},{},{}", self.name, self.spritesheet_index(self.current_image - 1), - self.format, + self.ending(), self.x(self.current_image - 1), self.y(self.current_image - 1), self.sprite_width, @@ -151,15 +167,21 @@ impl SpritesheetManager { } fn save_spritesheet(&mut self) -> Result<(), Error> { - self.spritesheet - .save(self.output_path.join(format!( - "{}_{}.{}", - self.name, - self.spritesheet_index(self.current_image), - self.format - ))) - .map_err(|error| format_err!("Could not write spritesheet: {}", error))?; - self.reinit_buffer(); + let name = format!( + "{}_{}.{}", + self.name, + self.spritesheet_index(self.current_image), + self.ending(), + ); + + let file = File::create(self.output_path.join(&name)) + .map_err(|err| format_err!("Could not create spritesheet {}: {}", &name, err))?; + + let new_buffer = self.reinit_buffer(); + DynamicImage::ImageRgb8(std::mem::replace(&mut self.spritesheet, new_buffer)) + .write_to(&mut BufWriter::new(file), self.format.clone()) + .map_err(|err| format_err!("Could not write spritesheet {}: {}", &name, err))?; + Ok(()) } diff --git a/src/main.rs b/src/main.rs index 39a2214..3c99314 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,7 @@ use structopt::StructOpt; use crate::ffmpeg_api::enums::{SwsFlags, SwsScaler}; use crate::util::media_time::MediaTime; +use image::ImageOutputFormat; fn parse_scaler(src: &str) -> Result<SwsScaler, String> { match src { @@ -40,10 +41,12 @@ struct Options { num_horizontal: u32, #[structopt(long = "num-vertical", default_value = "5")] num_vertical: u32, - #[structopt(long = "max-size", default_value = "160")] + #[structopt(long = "max-size", default_value = "240")] max_size: u32, - #[structopt(long = "format", default_value = "png")] + #[structopt(long = "format", default_value = "jpg")] format: String, + #[structopt(long = "quality", default_value = "90")] + quality: u8, #[structopt(long = "scaler", default_value = "area", parse(try_from_str = parse_scaler))] scaler: SwsScaler, #[structopt(long = "fast-chroma")] @@ -75,7 +78,12 @@ fn main() -> Result<(), Error> { MediaTime::from_seconds(options.frame_interval), Path::new(&options.input), Path::new(&options.output), - options.format, + match options.format.as_str() { + "jpeg" | "jpg" => ImageOutputFormat::Jpeg(options.quality), + "png" => ImageOutputFormat::Png, + "bmp" => ImageOutputFormat::Bmp, + _ => panic!("Unsupported image format: {}", options.format), + }, options.scaler, flags, )?; -- GitLab