Refined for CLI & automated usage

This commit is contained in:
2025-12-19 14:03:58 +08:00
parent d48c04d2b2
commit 3ea4e6166e

View File

@@ -1,42 +1,54 @@
use image::{Rgba, RgbaImage};
use std::env;
use std::fs::File;
use std::io::{self, BufReader, BufWriter, Write};
use std::io::{BufReader, BufWriter};
use std::process;
fn main() {
println!("=== Neko Sprite Recolor Tool ===\n");
let args: Vec<String> = env::args().collect();
// Get input path
println!("Enter input GIF path:");
let input_path = read_line();
if args.len() < 4 {
print_usage(&args[0]);
process::exit(1);
}
// Get output path
println!("Enter output GIF path:");
let output_path = read_line();
let input_path = &args[1];
let output_path = &args[2];
let color_input = &args[3];
let apply_texture = args.len() > 4 && args[4].to_lowercase() == "true";
// Get target color
println!("Enter target color (hex, e.g., FF5733):");
let color_input = read_line();
let target_color = parse_hex_color(&color_input).expect("Invalid hex color");
let target_color = match parse_hex_color(color_input) {
Ok(color) => color,
Err(e) => {
eprintln!("Error: {}", e);
process::exit(1);
}
};
// Ask about texture
println!("Apply texture/noise? (y/n):");
let texture_input = read_line();
let apply_texture = texture_input.to_lowercase().starts_with('y');
println!("\nProcessing...");
match recolor_gif(&input_path, &output_path, target_color, apply_texture) {
Ok(_) => println!("✓ Successfully created: {}", output_path),
Err(e) => eprintln!("✗ Error: {}", e),
match recolor_gif(input_path, output_path, target_color, apply_texture) {
Ok(_) => (),
Err(e) => {
eprintln!("Error: {}", e);
process::exit(1);
}
}
}
fn read_line() -> String {
let mut input = String::new();
io::stdin()
.read_line(&mut input)
.expect("Failed to read line");
input.trim().to_string()
fn print_usage(program: &str) {
eprintln!(
"Usage: {} <input.gif> <output.gif> <color> [texture]",
program
);
eprintln!();
eprintln!("Arguments:");
eprintln!(" <input.gif> Path to input GIF file");
eprintln!(" <output.gif> Path to output GIF file");
eprintln!(" <color> Target color in hex format (e.g., FF5733 or #FF5733)");
eprintln!(" [texture] Optional: 'true' to apply texture/noise (default: false)");
eprintln!();
eprintln!("Examples:");
eprintln!(" {} neko.gif neko_red.gif FF0000", program);
eprintln!(" {} neko.gif neko_blue.gif 0066FF true", program);
}
fn parse_hex_color(hex: &str) -> Result<Rgba<u8>, String> {
@@ -75,14 +87,8 @@ fn recolor_gif(
let mut encoder = gif::Encoder::new(writer, width, height, &[])?;
encoder.set_repeat(gif::Repeat::Infinite)?;
let mut frame_count = 0;
// Process each frame
while let Some(frame) = decoder.read_next_frame()? {
frame_count += 1;
print!("\rProcessing frame {}...", frame_count);
io::stdout().flush()?;
// Convert frame buffer to RgbaImage
let mut img = RgbaImage::from_raw(width as u32, height as u32, frame.buffer.to_vec())
.ok_or("Failed to create image from frame")?;
@@ -98,8 +104,6 @@ fn recolor_gif(
encoder.write_frame(&output_frame)?;
}
println!("\n✓ Processed {} frames", frame_count);
Ok(())
}