126 lines
4.5 KiB
Rust
126 lines
4.5 KiB
Rust
/// Generate a systematic set of stroke PSDs for ground-truth MAE tuning.
|
||
///
|
||
/// Each PSD: 256×256 black rectangle (25% margin) on transparent background
|
||
/// + stroke effect.
|
||
/// Output: `_tmp/stroke_psd_set/`
|
||
use hcie_protocol::{Layer, LayerType, LayerData, BlendMode, effects::{LayerEffect, StrokePosition}};
|
||
use std::sync::atomic::{AtomicBool};
|
||
use std::sync::Mutex;
|
||
|
||
fn main() {
|
||
let out_dir = std::path::Path::new("_tmp/stroke_psd_set");
|
||
std::fs::create_dir_all(out_dir).expect("create output dir");
|
||
|
||
let canvas: u32 = 256;
|
||
let margin: u32 = 96; // larger margin so outside stroke fits
|
||
|
||
let positions: &[(StrokePosition, &str)] = &[
|
||
(StrokePosition::Inside, "inside"),
|
||
(StrokePosition::Center, "center"),
|
||
(StrokePosition::Outside, "outside"),
|
||
];
|
||
let sizes: &[f32] = &[5.0, 15.0];
|
||
let fx_opacities: &[f32] = &[0.75, 1.0];
|
||
let stroke_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 = positions.len() * sizes.len() * fx_opacities.len() * stroke_colors.len();
|
||
println!("Generating {} stroke PSDs...", total);
|
||
|
||
let mut count = 0usize;
|
||
let mut errors = 0usize;
|
||
|
||
for &(position, pos_name) in positions {
|
||
for &size in sizes {
|
||
for &opacity in fx_opacities {
|
||
for &(color, color_name) in stroke_colors {
|
||
count += 1;
|
||
let filename = format!(
|
||
"st_{}_sz{}_op{}_{}.psd",
|
||
pos_name, size as u32,
|
||
(opacity * 100.0) as u32, 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::Stroke {
|
||
enabled: true,
|
||
position,
|
||
blend_mode: "normal".to_string(),
|
||
color,
|
||
opacity,
|
||
size,
|
||
fill_type: hcie_protocol::effects::StrokeFillType::Color,
|
||
};
|
||
|
||
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 % 10 == 0 {
|
||
println!(" [{}/{}] errors={}", count, total, errors);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
println!("Done. {} PSDs generated, {} errors.", count - errors, errors);
|
||
}
|