| 271 | } |
| 272 | |
| 273 | fn write_composite( |
| 274 | reference_img: &RgbImage, |
| 275 | candidate_img: &RgbImage, |
| 276 | heatmap: &RgbImage, |
| 277 | path: &Path, |
| 278 | ) -> Result<(), String> { |
| 279 | let w = reference_img.width(); |
| 280 | let h = reference_img.height(); |
| 281 | // Three panels side by side with a 1-pixel divider. |
| 282 | let pad = 1u32; |
| 283 | let total_w = w * 3 + pad * 2; |
| 284 | let mut out: RgbImage = ImageBuffer::from_pixel(total_w, h, Rgb([80, 80, 80])); |
| 285 | |
| 286 | for y in 0..h { |
| 287 | for x in 0..w { |
| 288 | out.put_pixel(x, y, *reference_img.get_pixel(x, y)); |
| 289 | out.put_pixel(w + pad + x, y, *candidate_img.get_pixel(x, y)); |
| 290 | out.put_pixel(2 * (w + pad) + x, y, *heatmap.get_pixel(x, y)); |
| 291 | } |
| 292 | } |
| 293 | out.save(path).map_err(|e| format!("save {:?}: {e}", path)) |
| 294 | } |
| 295 | |
| 296 | // ============================================================ |
| 297 | // CLI |