Coloured pixel art for the canvas, read from the SVG files themselves.
The three LLM logos are shuqikhor's pixel icons (MIT), vendored unchanged
in third-party/pixel-icons. They are included here with include_str!
and are the one source of the logos: the page embeds the very same text
(lmjtfy::meatproxy uses CLAUDE, CHATGPT and GEMINI), and the card
rasterises it with Icon::parse, which reads exactly what they use:
<rect>s, and <path>s of absolute M, H, V and z, so every edge
is axis-aligned and a pixel is in or out by its centre. A file that uses
anything else is refused, not drawn wrong.
One filled pixel: its column and row, and its colour.
An icon as the pixels it fills, later shapes over earlier.
32impl Icon {
The icon in svg, or why it cannot be read.
34 pub fn parse(svg: &str) -> Result<Icon, String> { 35 let size = attribute(svg, "viewBox") 36 .and_then(|view| view.split_whitespace().nth(2).and_then(|side| side.parse::<usize>().ok())) 37 .ok_or("no square viewBox")?; 38 let mut grid: Vec<Option<[u8; 3]>> = vec![None; size * size]; 39 let mut rest = svg; 40 while let Some(open) = rest.find('<') { 41 rest = &rest[open + 1..]; 42 let end = rest.find('>').ok_or("an unclosed tag")?; 43 let tag = &rest[..end]; 44 rest = &rest[end..]; 45 let name = tag.split_whitespace().next().unwrap_or_default(); 46 if name != "rect" && name != "path" { 47 continue; 48 } 49 let rgb = colour(attribute(tag, "fill").ok_or("a shape without a fill")?)?; 50 let covers: Box<dyn Fn(usize, usize) -> bool> = if name == "rect" { 51 let number = |key: &str| attribute(tag, key).and_then(|value| value.parse::<f64>().ok()).ok_or(format!("a rect without {key}")); 52 let (x, y, w, h) = (number("x")?, number("y")?, number("width")?, number("height")?); 53 Box::new(move |column, row| { 54 let (cx, cy) = (column as f64 + 0.5, row as f64 + 0.5); 55 cx > x && cx < x + w && cy > y && cy < y + h 56 }) 57 } else { 58 let edges = edges(attribute(tag, "d").ok_or("a path without d")?)?; 59 Box::new(move |column, row| winding(&edges, column as f64 + 0.5, row as f64 + 0.5) != 0) 60 }; 61 for row in 0..size { 62 for column in 0..size { 63 if covers(column, row) { 64 grid[row * size + column] = Some(rgb); 65 } 66 } 67 } 68 } 69 let cells: Vec<Cell> = grid.iter().enumerate().filter_map(|(at, rgb)| rgb.map(|rgb| Cell { x: at % size, y: at / size, rgb })).collect(); 70 if cells.is_empty() { 71 return Err("nothing is drawn".into()); 72 } 73 Ok(Icon { size, cells }) 74 }
Every colour it uses, in the order first met.
The value of key="..." in text.
#rrggbb.
95fn colour(text: &str) -> Result<[u8; 3], String> { 96 let hex = text.strip_prefix('#').filter(|hex| hex.len() == 6).ok_or_else(|| format!("fill {text} is not #rrggbb"))?; 97 let byte = |at: usize| u8::from_str_radix(&hex[at..at + 2], 16).map_err(|_| format!("fill {text} is not #rrggbb")); 98 Ok([byte(0)?, byte(2)?, byte(4)?]) 99}
A vertical edge, x from from to to: the only edges that cross a
horizontal ray.
103type Edge = (f64, f64, f64);
The vertical edges of a path of M, H, V and z.
106fn edges(d: &str) -> Result<Vec<Edge>, String> { 107 let mut edges = Vec::new(); 108 let (mut start, mut at) = ((0.0, 0.0), (0.0, 0.0)); 109 let mut chars = d.chars().peekable(); 110 let mut open = false; 111 let mut close = |edges: &mut Vec<Edge>, at: (f64, f64), start: (f64, f64)| -> Result<(), String> { 112 if at.0 != start.0 && at.1 != start.1 { 113 return Err("a path closes on a diagonal".into()); 114 } 115 if at.0 == start.0 && at.1 != start.1 { 116 edges.push((at.0, at.1, start.1)); 117 } 118 Ok(()) 119 }; 120 while let Some(command) = chars.next() { 121 if command.is_whitespace() || command == ',' { 122 continue; 123 } 124 let mut numbers = Vec::new(); 125 loop { 126 while chars.peek().is_some_and(|c| c.is_whitespace() || *c == ',') { 127 chars.next(); 128 } 129 let mut text = String::new(); 130 while chars.peek().is_some_and(|c| c.is_ascii_digit() || *c == '.' || *c == '-') { 131 text.push(chars.next().expect("peeked")); 132 } 133 if text.is_empty() { 134 break; 135 } 136 numbers.push(text.parse::<f64>().map_err(|_| format!("{text} is not a number"))?); 137 } 138 match (command, numbers.as_slice()) { 139 ('M', [x, y]) => { 140 if open { 141 close(&mut edges, at, start)?; 142 } 143 (start, at, open) = ((*x, *y), (*x, *y), true); 144 } 145 ('H', [x]) => at.0 = *x, 146 ('V', [y]) => { 147 edges.push((at.0, at.1, *y)); 148 at.1 = *y; 149 } 150 ('z' | 'Z', []) => { 151 close(&mut edges, at, start)?; 152 at = start; 153 open = false; 154 } 155 _ => return Err(format!("the path command {command} {numbers:?} is not M, H, V or z")), 156 } 157 } 158 if open { 159 close(&mut edges, at, start)?; 160 } 161 Ok(edges) 162}
The winding number of the path around (px, py): edges to its right that
cross its row, up counting one way and down the other. Non-zero is
inside, which is SVG's default fill rule.