use clap::Parser;
use zengif::{EncodeRequest, EncoderConfig, FrameInput, Limits, Repeat, Unstoppable};
use zenwebp::decoder::LoopCount;
use zenwebp::mux::AnimationDecoder;
#[derive(Parser, Debug)]
#[command(about = "Convert a web pee file to a gif", long_about = None)]
struct Args {
#[clap(help = "Webp you want to read")]
source_file: String,
#[clap(help = "Gif you want to write")]
destination_file: String,
#[clap(short, long, help="overwrite destination file if it exists", default_value_t=false)]
force: bool,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let args = Args::parse();
let bytes = std::fs::read(&args.source_file)?;
let decoder = zenwebp::WebPDecoder::new(&bytes)?;
if !args.force && std::fs::exists(&args.destination_file)? {
println!("Destination file already exists, quitting");
return Ok(());
}
let (w, h) = decoder.dimensions();
let anim: bool = decoder.is_animated();
let loop_count = decoder.loop_count();
let loop_duration = decoder.loop_duration();
let frames = decoder.num_frames();
println!("Source file: {}", args.source_file);
println!(" - Dimensions: {}x{}", w, h);
println!(" - Has alpha: {}", decoder.has_alpha());
if !anim {
println!("\n\nNo animation, quitting. todo i guess; use tui-img instead or XnViewMP until then");
return Ok(());
};
println!(" - Animation frames: {frames}");
println!(" - Loop count and total length: {loop_count:?} / {loop_duration}ms");
let gif_loop_count = match loop_count {
LoopCount::Forever => Repeat::Infinite,
LoopCount::Times(n) => Repeat::Count(n.into()),
};
println!("Decoding all frames...");
let frames = AnimationDecoder::new(&bytes)?.decode_all()?;
let config = EncoderConfig::new()
.use_transparency(decoder.has_alpha())
.repeat(gif_loop_count);
let limits = Limits::default().max_dimensions(4096, 4096);
let mut encoder = EncodeRequest::new(&config, w as u16, h as u16)
.limits(&limits)
.stop(&Unstoppable)
.build()?;
print!("Adding frames to GIF: ");
let mut frame_index: u64 = 0;
for frame in frames {
frame_index += 1;
print!("{frame_index} ");
encoder.add_frame(FrameInput::from_bytes(
frame.width as u16, frame.height as u16, (frame.duration_ms as u16).saturating_div(10), &frame.data, ))?;
}
println!("\nTurning it into binary mush");
let output_gif_bytes = encoder.finish()?;
if std::fs::exists(&args.destination_file)? && args.force {
println!("Overwriting existing file in place: {}", args.destination_file)
} else {
println!("Writing to disk: {}", args.destination_file);
}
std::fs::write(&args.destination_file, output_gif_bytes)?;
Ok(())
}