recolor outlines
This commit is contained in:
93
src/main.rs
93
src/main.rs
@@ -7,25 +7,40 @@ use std::process;
|
|||||||
fn main() {
|
fn main() {
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
|
|
||||||
if args.len() < 4 {
|
if args.len() < 5 {
|
||||||
print_usage(&args[0]);
|
print_usage(&args[0]);
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
let input_path = &args[1];
|
let input_path = &args[1];
|
||||||
let output_path = &args[2];
|
let output_path = &args[2];
|
||||||
let color_input = &args[3];
|
let white_color_input = &args[3];
|
||||||
let apply_texture = args.len() > 4 && args[4].to_lowercase() == "true";
|
let black_color_input = &args[4];
|
||||||
|
let apply_texture = args.len() > 5 && args[5].to_lowercase() == "true";
|
||||||
|
|
||||||
let target_color = match parse_hex_color(color_input) {
|
let white_color = match parse_hex_color(white_color_input) {
|
||||||
Ok(color) => color,
|
Ok(color) => color,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Error: {}", e);
|
eprintln!("Error parsing white color: {}", e);
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match recolor_gif(input_path, output_path, target_color, apply_texture) {
|
let black_color = match parse_hex_color(black_color_input) {
|
||||||
|
Ok(color) => color,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Error parsing black color: {}", e);
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match recolor_gif(
|
||||||
|
input_path,
|
||||||
|
output_path,
|
||||||
|
white_color,
|
||||||
|
black_color,
|
||||||
|
apply_texture,
|
||||||
|
) {
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Error: {}", e);
|
eprintln!("Error: {}", e);
|
||||||
@@ -36,19 +51,24 @@ fn main() {
|
|||||||
|
|
||||||
fn print_usage(program: &str) {
|
fn print_usage(program: &str) {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"Usage: {} <input.gif> <output.gif> <color> [texture]",
|
"Usage: {} <input.gif> <output.gif> <white_color> <black_color> [texture]",
|
||||||
program
|
program
|
||||||
);
|
);
|
||||||
eprintln!();
|
eprintln!();
|
||||||
eprintln!("Arguments:");
|
eprintln!("Arguments:");
|
||||||
eprintln!(" <input.gif> Path to input GIF file");
|
eprintln!(" <input.gif> Path to input GIF file");
|
||||||
eprintln!(" <output.gif> Path to output GIF file");
|
eprintln!(" <output.gif> Path to output GIF file");
|
||||||
eprintln!(" <color> Target color in hex format (e.g., FF5733 or #FF5733)");
|
eprintln!(
|
||||||
eprintln!(" [texture] Optional: 'true' to apply texture/noise (default: false)");
|
" <white_color> Target color for white pixels in hex format (e.g., FF5733 or #FF5733)"
|
||||||
|
);
|
||||||
|
eprintln!(
|
||||||
|
" <black_color> Target color for black pixels in hex format (e.g., 000000 or #000000)"
|
||||||
|
);
|
||||||
|
eprintln!(" [texture] Optional: 'true' to apply texture/noise (default: false)");
|
||||||
eprintln!();
|
eprintln!();
|
||||||
eprintln!("Examples:");
|
eprintln!("Examples:");
|
||||||
eprintln!(" {} neko.gif neko_red.gif FF0000", program);
|
eprintln!(" {} neko.gif neko_red.gif FF0000 000000", program);
|
||||||
eprintln!(" {} neko.gif neko_blue.gif 0066FF true", program);
|
eprintln!(" {} neko.gif neko_blue.gif 0066FF 330000 true", program);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_hex_color(hex: &str) -> Result<Rgba<u8>, String> {
|
fn parse_hex_color(hex: &str) -> Result<Rgba<u8>, String> {
|
||||||
@@ -67,7 +87,8 @@ fn parse_hex_color(hex: &str) -> Result<Rgba<u8>, String> {
|
|||||||
fn recolor_gif(
|
fn recolor_gif(
|
||||||
input_path: &str,
|
input_path: &str,
|
||||||
output_path: &str,
|
output_path: &str,
|
||||||
target_color: Rgba<u8>,
|
white_color: Rgba<u8>,
|
||||||
|
black_color: Rgba<u8>,
|
||||||
apply_texture: bool,
|
apply_texture: bool,
|
||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
// Open and decode input GIF
|
// Open and decode input GIF
|
||||||
@@ -94,7 +115,7 @@ fn recolor_gif(
|
|||||||
.ok_or("Failed to create image from frame")?;
|
.ok_or("Failed to create image from frame")?;
|
||||||
|
|
||||||
// Recolor the image
|
// Recolor the image
|
||||||
recolor_image(&mut img, target_color, apply_texture);
|
recolor_image(&mut img, white_color, black_color, apply_texture);
|
||||||
|
|
||||||
// Create output frame with same timing
|
// Create output frame with same timing
|
||||||
let mut pixel_data = img.into_raw();
|
let mut pixel_data = img.into_raw();
|
||||||
@@ -107,12 +128,23 @@ fn recolor_gif(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recolor_image(img: &mut RgbaImage, target_color: Rgba<u8>, apply_texture: bool) {
|
fn recolor_image(
|
||||||
// Generate color palette with variations if texture is enabled
|
img: &mut RgbaImage,
|
||||||
let color_palette = if apply_texture {
|
white_color: Rgba<u8>,
|
||||||
generate_color_palette(target_color, 7)
|
black_color: Rgba<u8>,
|
||||||
|
apply_texture: bool,
|
||||||
|
) {
|
||||||
|
// Generate color palettes with variations if texture is enabled
|
||||||
|
let white_palette = if apply_texture {
|
||||||
|
generate_color_palette(white_color, 7)
|
||||||
} else {
|
} else {
|
||||||
vec![target_color]
|
vec![white_color]
|
||||||
|
};
|
||||||
|
|
||||||
|
let black_palette = if apply_texture {
|
||||||
|
generate_color_palette(black_color, 7)
|
||||||
|
} else {
|
||||||
|
vec![black_color]
|
||||||
};
|
};
|
||||||
|
|
||||||
for (x, y, pixel) in img.enumerate_pixels_mut() {
|
for (x, y, pixel) in img.enumerate_pixels_mut() {
|
||||||
@@ -128,14 +160,19 @@ fn recolor_image(img: &mut RgbaImage, target_color: Rgba<u8>, apply_texture: boo
|
|||||||
|
|
||||||
// Determine pixel type based on brightness
|
// Determine pixel type based on brightness
|
||||||
if brightness < 64 {
|
if brightness < 64 {
|
||||||
// Very dark pixels (outlines) - keep original
|
// Very dark pixels (outlines) - apply black target color
|
||||||
continue;
|
|
||||||
} else if brightness > 200 {
|
|
||||||
// White/light pixels (body) - apply target color
|
|
||||||
let chosen_color = if apply_texture {
|
let chosen_color = if apply_texture {
|
||||||
pick_color_from_palette(&color_palette, x, y)
|
pick_color_from_palette(&black_palette, x, y)
|
||||||
} else {
|
} else {
|
||||||
target_color
|
black_color
|
||||||
|
};
|
||||||
|
*pixel = chosen_color;
|
||||||
|
} else if brightness > 200 {
|
||||||
|
// White/light pixels (body) - apply white target color
|
||||||
|
let chosen_color = if apply_texture {
|
||||||
|
pick_color_from_palette(&white_palette, x, y)
|
||||||
|
} else {
|
||||||
|
white_color
|
||||||
};
|
};
|
||||||
*pixel = chosen_color;
|
*pixel = chosen_color;
|
||||||
} else {
|
} else {
|
||||||
@@ -145,9 +182,9 @@ fn recolor_image(img: &mut RgbaImage, target_color: Rgba<u8>, apply_texture: boo
|
|||||||
let blend_factor = blend_factor.clamp(0.0, 1.0);
|
let blend_factor = blend_factor.clamp(0.0, 1.0);
|
||||||
|
|
||||||
let chosen_color = if apply_texture {
|
let chosen_color = if apply_texture {
|
||||||
pick_color_from_palette(&color_palette, x, y)
|
pick_color_from_palette(&white_palette, x, y)
|
||||||
} else {
|
} else {
|
||||||
target_color
|
white_color
|
||||||
};
|
};
|
||||||
|
|
||||||
let new_r =
|
let new_r =
|
||||||
|
|||||||
Reference in New Issue
Block a user