Add color debugging feature and improve RGB to ANSI conversion
This commit is contained in:
1 parent
77d0b7659c
commit
28e212e0ac
2 files changed
+72
-35
No files matched your search
+10
-35
@@ -375,47 +375,22 @@ fn rgb_to_ansi256(r: u8, g: u8, b: u8) -> u8 {
|
||||
}
|
||||
|
||||
/// Convert RGB to ANSI 16 color code
|
||||
fn rgb_to_ansi16(r: u8, g: u8, b: u8) -> u8 {
|
||||
// Calculate brightness
|
||||
pub(crate) fn rgb_to_ansi16(r: u8, g: u8, b: u8) -> u8 {
|
||||
// Calculate brightness (perceived luminance)
|
||||
let brightness = (r as f32 * 0.299 + g as f32 * 0.587 + b as f32 * 0.114).round() as u8;
|
||||
|
||||
// Determine if it's bright or dark
|
||||
let is_bright = brightness > 128;
|
||||
|
||||
// Determine base color
|
||||
let base_color = if r > g && r > b {
|
||||
// Red dominant
|
||||
if r > 192 && g < 64 && b < 64 {
|
||||
1 // Red
|
||||
} else if r > g && r > b {
|
||||
3 // Yellow
|
||||
} else {
|
||||
7 // White
|
||||
}
|
||||
} else if g > r && g > b {
|
||||
// Green dominant
|
||||
if g > 192 && r < 64 && b < 64 {
|
||||
2 // Green
|
||||
} else if g > b {
|
||||
3 // Yellow
|
||||
} else {
|
||||
6 // Cyan
|
||||
}
|
||||
} else {
|
||||
// Blue dominant
|
||||
if b > 192 && r < 64 && g < 64 {
|
||||
4 // Blue
|
||||
} else if b > r {
|
||||
6 // Cyan
|
||||
} else {
|
||||
5 // Magenta
|
||||
}
|
||||
};
|
||||
// Determine base color using simple thresholding on each channel, producing an index 0..7
|
||||
let r_on = r > 128;
|
||||
let g_on = g > 128;
|
||||
let b_on = b > 128;
|
||||
let base_idx = (r_on as u8) + (g_on as u8) * 2 + (b_on as u8) * 4; // 0..7
|
||||
|
||||
// SGR color codes: 30..37 for normal, 90..97 for bright
|
||||
if is_bright {
|
||||
base_color + 8 // Bright colors are 8-15
|
||||
90 + base_idx
|
||||
} else {
|
||||
base_color // Normal colors are 0-7
|
||||
30 + base_idx
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+62
@@ -58,6 +58,9 @@ pub struct Args {
|
||||
/// Disable all coloring (respects NO_COLOR environment variable)
|
||||
#[arg(long)]
|
||||
pub no_color: bool,
|
||||
/// Print color detection/debug info and exit
|
||||
#[arg(long)]
|
||||
pub color_debug: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -69,6 +72,8 @@ pub struct ColorConfig {
|
||||
pub single_color: Option<Color>,
|
||||
pub gradient: Option<(Color, Color)>,
|
||||
pub color_cache: Vec<Color>,
|
||||
pub ansi_enabled: bool,
|
||||
pub debug: bool,
|
||||
}
|
||||
|
||||
pub fn parse_color_args(args: &Args) -> Result<ColorConfig, Box<dyn Error>> {
|
||||
@@ -160,6 +165,12 @@ pub fn parse_color_args(args: &Args) -> Result<ColorConfig, Box<dyn Error>> {
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
// Determine if ANSI is enabled (Windows toggle helper) — don't enable if --no-color
|
||||
#[cfg(windows)]
|
||||
let ansi_enabled = !args.no_color && enable_windows_ansi();
|
||||
#[cfg(not(windows))]
|
||||
let ansi_enabled = false;
|
||||
|
||||
Ok(ColorConfig {
|
||||
mode: color_mode,
|
||||
rainbow: args.rainbow,
|
||||
@@ -168,6 +179,8 @@ pub fn parse_color_args(args: &Args) -> Result<ColorConfig, Box<dyn Error>> {
|
||||
single_color,
|
||||
gradient,
|
||||
color_cache: Vec::new(),
|
||||
ansi_enabled,
|
||||
debug: args.color_debug,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -492,6 +505,19 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Parse color-related arguments
|
||||
let mut color_config = parse_color_args(&args)?;
|
||||
|
||||
// If color debug is requested, print information and exit
|
||||
if args.color_debug {
|
||||
eprintln!("Color Debug: mode={:?}, ansi_enabled={}, rainbow={}, saturation={}, brightness={}",
|
||||
color_config.mode, color_config.ansi_enabled, color_config.rainbow, color_config.saturation, color_config.brightness);
|
||||
if let Some(single) = &color_config.single_color {
|
||||
eprintln!("Single color: {:?}", single);
|
||||
}
|
||||
if let Some((start, end)) = &color_config.gradient {
|
||||
eprintln!("Gradient: {:?} -> {:?}", start, end);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
draw_miku_says(&text, style, &mut color_config)?;
|
||||
|
||||
Ok(())
|
||||
@@ -585,6 +611,7 @@ mod tests {
|
||||
color: None,
|
||||
gradient: None,
|
||||
no_color: false,
|
||||
color_debug: false,
|
||||
};
|
||||
|
||||
let config = parse_color_args(&args).unwrap();
|
||||
@@ -609,6 +636,7 @@ mod tests {
|
||||
color: None,
|
||||
gradient: None,
|
||||
no_color: true,
|
||||
color_debug: false,
|
||||
};
|
||||
|
||||
let config = parse_color_args(&args).unwrap();
|
||||
@@ -656,6 +684,8 @@ mod tests {
|
||||
single_color: None,
|
||||
gradient: None,
|
||||
color_cache: vec![Color::Hex("#000000".to_string())], // Pre-filled
|
||||
ansi_enabled: false,
|
||||
debug: false,
|
||||
};
|
||||
|
||||
// Test with 0 characters
|
||||
@@ -677,6 +707,8 @@ mod tests {
|
||||
single_color: None,
|
||||
gradient: None,
|
||||
color_cache: vec![Color::Hex("#000000".to_string())], // Pre-filled
|
||||
ansi_enabled: false,
|
||||
debug: false,
|
||||
};
|
||||
|
||||
let start = Color::Hex("#FF0000".to_string());
|
||||
@@ -701,6 +733,8 @@ mod tests {
|
||||
single_color: None,
|
||||
gradient: None,
|
||||
color_cache: Vec::new(),
|
||||
ansi_enabled: false,
|
||||
debug: false,
|
||||
};
|
||||
|
||||
generate_rainbow_cache(&mut config, 10);
|
||||
@@ -712,6 +746,14 @@ mod tests {
|
||||
assert_ne!(first_color, last_color);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rgb_to_ansi16_mapping() {
|
||||
// Validate mapping for basic colors
|
||||
assert_eq!(crate::color::rgb_to_ansi16(255, 0, 0), 31);
|
||||
assert_eq!(crate::color::rgb_to_ansi16(255, 255, 255), 97);
|
||||
assert_eq!(crate::color::rgb_to_ansi16(0, 0, 0), 30);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generate_gradient_cache() {
|
||||
let mut config = ColorConfig {
|
||||
@@ -722,6 +764,8 @@ mod tests {
|
||||
single_color: None,
|
||||
gradient: None,
|
||||
color_cache: Vec::new(),
|
||||
ansi_enabled: false,
|
||||
debug: false,
|
||||
};
|
||||
|
||||
let start = Color::Hex("#FF0000".to_string()); // Red
|
||||
@@ -736,4 +780,22 @@ mod tests {
|
||||
let last_color = &config.color_cache[9];
|
||||
assert_ne!(first_color, last_color);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_color_debug_flag() {
|
||||
let args = Args {
|
||||
text: Some("test".to_string()),
|
||||
style: None,
|
||||
list: false,
|
||||
rainbow: false,
|
||||
saturation: 100,
|
||||
brightness: 50,
|
||||
color: None,
|
||||
gradient: None,
|
||||
no_color: false,
|
||||
color_debug: true,
|
||||
};
|
||||
let config = parse_color_args(&args).unwrap();
|
||||
assert!(config.debug);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user