1use ass_core::parser::ast::{Section, SectionType};
4use ass_core::Script;
5
6pub struct ColorDiagnostic;
8
9impl ColorDiagnostic {
10 pub fn analyze_script(script: &Script) -> ColorReport {
12 let mut report = ColorReport::default();
13
14 if let Some(Section::Styles(styles)) = script.find_section(SectionType::Styles) {
16 for style in styles {
17 let name = style.name;
18 let primary = style.primary_colour;
19 let secondary = style.secondary_colour;
20 let outline = style.outline_colour;
21 let back = style.back_colour;
22
23 report.styles.push(StyleColors {
24 name: name.to_string(),
25 primary_raw: primary.to_string(),
26 primary_parsed: parse_color_debug(primary),
27 secondary_raw: secondary.to_string(),
28 outline_raw: outline.to_string(),
29 back_raw: back.to_string(),
30 });
31 }
32 }
33
34 if let Some(Section::Events(events)) = script.find_section(SectionType::Events) {
36 for event in events {
37 if event.text.contains("\\c") || event.text.contains("\\1c") {
38 report.has_color_overrides = true;
39 }
40 }
41 }
42
43 report
44 }
45
46 pub fn create_white_text_test() -> String {
48 r#"[Script Info]
49Title: White Text Test
50PlayResX: 640
51PlayResY: 480
52
53[V4+ Styles]
54Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
55Style: WhiteText,Arial,50,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,2,0,2,10,10,10,1
56
57[Events]
58Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
59Dialogue: 0,0:00:00.00,0:00:05.00,WhiteText,,0,0,0,,This should be WHITE text"#.to_string()
60 }
61
62 pub fn create_color_reference_test() -> String {
64 r#"[Script Info]
65Title: Color Reference Test
66PlayResX: 640
67PlayResY: 480
68
69[V4+ Styles]
70Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
71Style: White,Arial,40,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,2,10,10,10,1
72Style: Red,Arial,40,&H000000FF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,2,10,10,10,1
73Style: Green,Arial,40,&H0000FF00,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,2,10,10,10,1
74Style: Blue,Arial,40,&H00FF0000,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,2,10,10,10,1
75Style: Yellow,Arial,40,&H0000FFFF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,2,10,10,10,1
76Style: Cyan,Arial,40,&H00FFFF00,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,2,10,10,10,1
77Style: Magenta,Arial,40,&H00FF00FF,&H000000FF,&H00000000,&H00000000,-1,0,0,0,100,100,0,0,1,2,0,2,10,10,10,1
78
79[Events]
80Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
81Dialogue: 0,0:00:00.00,0:00:10.00,White,,0,0,0,,WHITE
82Dialogue: 0,0:00:00.00,0:00:10.00,Red,,0,0,60,,RED
83Dialogue: 0,0:00:00.00,0:00:10.00,Green,,0,0,120,,GREEN
84Dialogue: 0,0:00:00.00,0:00:10.00,Blue,,0,0,180,,BLUE
85Dialogue: 0,0:00:00.00,0:00:10.00,Yellow,,0,0,240,,YELLOW
86Dialogue: 0,0:00:00.00,0:00:10.00,Cyan,,0,0,300,,CYAN
87Dialogue: 0,0:00:00.00,0:00:10.00,Magenta,,0,0,360,,MAGENTA"#.to_string()
88 }
89}
90
91#[derive(Debug, Default)]
92pub struct ColorReport {
93 pub styles: Vec<StyleColors>,
94 pub has_color_overrides: bool,
95}
96
97#[derive(Debug)]
98pub struct StyleColors {
99 pub name: String,
100 pub primary_raw: String,
101 pub primary_parsed: ColorDebugInfo,
102 pub secondary_raw: String,
103 pub outline_raw: String,
104 pub back_raw: String,
105}
106
107#[derive(Debug)]
108pub struct ColorDebugInfo {
109 pub hex_value: String,
110 pub has_alpha: bool,
111 pub alpha: u8,
112 pub red: u8,
113 pub green: u8,
114 pub blue: u8,
115 pub expected_color: String,
116}
117
118fn parse_color_debug(color: &str) -> ColorDebugInfo {
119 let color_trimmed = color.trim_end_matches('&');
120
121 if let Some(hex) = color_trimmed.strip_prefix("&H") {
122 let has_alpha = hex.len() >= 8;
123
124 if let Ok(value) = u32::from_str_radix(hex, 16) {
125 let (alpha, bgr_value) = if has_alpha {
126 let alpha = ((value >> 24) & 0xFF) as u8;
127 (alpha, value & 0xFFFFFF)
128 } else {
129 (0x00, value) };
131
132 let r = (bgr_value & 0xFF) as u8;
133 let g = ((bgr_value >> 8) & 0xFF) as u8;
134 let b = ((bgr_value >> 16) & 0xFF) as u8;
135
136 let expected = match (r, g, b) {
137 (255, 255, 255) => "WHITE",
138 (255, 0, 0) => "RED",
139 (0, 255, 0) => "GREEN",
140 (0, 0, 255) => "BLUE",
141 (255, 255, 0) => "YELLOW",
142 (0, 255, 255) => "CYAN",
143 (255, 0, 255) => "MAGENTA",
144 (0, 0, 0) => "BLACK",
145 _ => "CUSTOM",
146 };
147
148 return ColorDebugInfo {
149 hex_value: hex.to_string(),
150 has_alpha,
151 alpha,
152 red: r,
153 green: g,
154 blue: b,
155 expected_color: expected.to_string(),
156 };
157 }
158 }
159
160 ColorDebugInfo {
161 hex_value: "INVALID".to_string(),
162 has_alpha: false,
163 alpha: 0,
164 red: 0,
165 green: 0,
166 blue: 0,
167 expected_color: "ERROR".to_string(),
168 }
169}
170
171impl ColorReport {
172 pub fn print_diagnostic(&self) {
173 println!("=== ASS Color Diagnostic Report ===\n");
174
175 for style in &self.styles {
176 println!("Style: {}", style.name);
177 println!(" Primary Color: {}", style.primary_raw);
178 println!(" Hex: {}", style.primary_parsed.hex_value);
179 println!(
180 " RGBA: ({}, {}, {}, {})",
181 style.primary_parsed.red,
182 style.primary_parsed.green,
183 style.primary_parsed.blue,
184 if style.primary_parsed.has_alpha {
185 format!("{}", 255 - style.primary_parsed.alpha) } else {
187 "255".to_string()
188 }
189 );
190 println!(" Expected: {}", style.primary_parsed.expected_color);
191
192 if style.primary_parsed.expected_color == "YELLOW" && style.name.contains("White") {
194 println!(
195 " ⚠️ WARNING: Style named '{}' is YELLOW but should probably be WHITE!",
196 style.name
197 );
198 println!(" Correct white: &H00FFFFFF");
199 println!(" Current value might be: &H0000FFFF (yellow)");
200 }
201 println!();
202 }
203
204 if self.has_color_overrides {
205 println!("Note: Script contains color override tags (\\c or \\1c) in events");
206 }
207 }
208}