/// Generate a systematic set of inner shadow PSDs for ground-truth MAE tuning. /// /// Each PSD: 256×256 black rectangle (25% margin) + inner shadow effect. /// Output: `_tmp/inner_shadow_psd_set/` use hcie_protocol::{Layer, LayerType, LayerData, BlendMode, effects::LayerEffect}; use std::sync::atomic::{AtomicBool}; use std::sync::Mutex; fn main() { let out_dir = std::path::Path::new("_tmp/inner_shadow_psd_set"); std::fs::create_dir_all(out_dir).expect("create output dir"); let canvas: u32 = 256; let margin: u32 = 64; let angles: &[f32] = &[0.0, 90.0, 180.0, 270.0]; let distances: &[f32] = &[5.0, 15.0, 30.0]; let sizes: &[f32] = &[10.0, 30.0]; let chokes: &[f32] = &[0.0, 20.0]; let fx_opacities: &[f32] = &[0.75, 1.0]; let noises: &[f32] = &[0.0, 15.0]; let fx_blend_modes: &[(BlendMode, &str)] = &[ (BlendMode::Normal, "normal"), (BlendMode::Multiply, "multiply"), ]; let shadow_colors: &[([u8; 4], &str)] = &[ ([220, 30, 30, 255], "red"), ([30, 180, 30, 255], "green"), ([30, 60, 220, 255], "blue"), ([220, 220, 220, 255], "white"), ]; let total = angles.len() * distances.len() * sizes.len() * chokes.len() * fx_opacities.len() * fx_blend_modes.len() * shadow_colors.len() * noises.len(); println!("Generating {} inner shadow PSDs...", total); let mut count = 0usize; let mut errors = 0usize; for &angle in angles { for &distance in distances { for &size in sizes { for &choke in chokes { for &opacity in fx_opacities { for &(_bm, bm_name) in fx_blend_modes { for &(color, color_name) in shadow_colors { for &noise in noises { count += 1; let filename = format!( "is_a{}_d{}_s{}_c{}_op{}_n{}_{}_{}.psd", angle as u32, distance as u32, size as u32, choke as u32, (opacity * 100.0) as u32, noise as u32, bm_name, color_name ); let path = out_dir.join(&filename); if path.exists() { continue; } let mut pixels = vec![0u8; (canvas * canvas * 4) as usize]; for y in 0..canvas { for x in 0..canvas { let i = (y * canvas + x) as usize * 4; if x >= margin && x < canvas - margin && y >= margin && y < canvas - margin { pixels[i] = 0; pixels[i + 1] = 0; pixels[i + 2] = 0; pixels[i + 3] = 255; } } } let effect = LayerEffect::InnerShadow { enabled: true, blend_mode: bm_name.to_string(), color, opacity, angle, distance, choke, size, noise, contour: None, }; let layer = Layer { name: "shape".to_string(), layer_type: LayerType::Raster, data: LayerData::Raster, pixels: pixels.clone(), width: canvas, height: canvas, visible: true, opacity: 1.0, blend_mode: BlendMode::Normal, locked: false, dirty: false, id: 1, parent_id: None, styles: vec![], clipping_mask: false, collapsed: false, adjustment: None, mask_pixels: None, mask_bounds: None, mask_default_color: 0, curve_points: vec![], fill_opacity: 1.0, effects: vec![effect], effects_dirty: AtomicBool::new(false), effects_cache: Mutex::new(None), adjustment_raw: None, is_section_divider: false, image_resources_raw: None, }; match hcie_psd::save_psd(&[layer], canvas, canvas, &pixels, &path) { Ok(()) => {} Err(e) => { eprintln!(" ERROR {}: {}", filename, e); errors += 1; } } if count % 20 == 0 { println!(" [{}/{}] errors={}", count, total, errors); } } } } } } } } } println!("Done. {} PSDs generated, {} errors.", count - errors, errors); }