fn test_file(psd_path: &str, ref_path: &str, out_path: &str) { println!("\n=== {} ===", psd_path); let layers = match hcie_psd::import_psd(std::path::Path::new(psd_path)) { Ok(l) => l, Err(e) => { println!("import_psd failed: {}", e); return; } }; if layers.is_empty() { println!("No layers imported."); return; } for (i, layer) in layers.iter().enumerate() { let effs = if layer.effects.is_empty() { "no effects".to_string() } else { format!("{} effects: {}", layer.effects.len(), layer.effects.iter().map(|e| format!("{}({})", e.effect_name(), if e.is_enabled() {"on"} else {"off"})).collect::>().join(", ")) }; println!("Layer {}: '{}' {}x{} visible={} {}", i, layer.name, layer.width, layer.height, layer.visible, effs); } let comp_layers: Vec = layers.iter().map(|l| hcie_composite::Layer { name: l.name.clone(), layer_type: l.layer_type.clone(), data: l.data.clone(), pixels: l.pixels.clone(), width: l.width, height: l.height, visible: l.visible, opacity: l.opacity, blend_mode: l.blend_mode.clone(), locked: l.locked, dirty: l.dirty, id: l.id, parent_id: l.parent_id, styles: l.styles.clone(), clipping_mask: l.clipping_mask, collapsed: l.collapsed, adjustment: l.adjustment.clone(), mask_pixels: l.mask_pixels.clone(), mask_bounds: l.mask_bounds, mask_default_color: l.mask_default_color, curve_points: l.curve_points.clone(), fill_opacity: l.fill_opacity, effects: l.effects.clone(), effects_dirty: std::sync::atomic::AtomicBool::new(false), effects_cache: std::sync::Mutex::new(None), adjustment_raw: None, is_section_divider: false, image_resources_raw: None, }).collect(); let canvas_w = comp_layers[0].width; let canvas_h = comp_layers[0].height; let output = hcie_composite::composite_layers(&comp_layers, canvas_w, canvas_h); { let img = image::RgbaImage::from_raw(canvas_w, canvas_h, output.clone()) .expect("Failed to create image from buffer"); img.save(out_path).expect("Failed to save output image"); } println!("Saved composite to {}", out_path); if std::path::Path::new(ref_path).exists() { let ref_img = image::open(ref_path).unwrap().to_rgba8(); if ref_img.width() == canvas_w && ref_img.height() == canvas_h { let mut diff_sum = 0.0f64; let mut max_diff = 0u32; let comp_img = image::open(out_path).unwrap().to_rgba8(); for (p1, p2) in comp_img.pixels().zip(ref_img.pixels()) { let d = p1.0.iter().zip(p2.0.iter()) .map(|(a, b)| (*a as i32 - *b as i32).abs() as f64) .sum::(); diff_sum += d; max_diff = max_diff.max(d as u32); } let px_cnt = (canvas_w * canvas_h) as f64; println!("Avg diff per channel: {:.2}", diff_sum / px_cnt); println!("Max diff per pixel: {}", max_diff); } else { println!("Reference image dimensions differ."); } } else { println!("Reference not found: {}", ref_path); } } fn main() { test_file( "_images/_psd_stil_test/test_2/test_2.psd", "_images/_psd_stil_test/test_2/test_2.png", "/tmp/test_2_out.png", ); let tests = [ ("drop shadow", "drop shadow"), ("inner shadow", "inner shadow"), ("inner bevel", "inner bevel"), ("Emboss", "Emboss"), ("inner glow", "inner glow"), ("stroke", "stroke"), ]; for (_label, sub) in &tests { let psd = format!("_images/_psd_stil_test/test_2/{}.psd", sub); let ref_path = format!("_images/_psd_stil_test/test_2/{}.png", sub); test_file(&psd, &ref_path, &format!("/tmp/test2_{}.png", sub.replace(' ', "_"))); } }