2026-07-13 20:33:39 +03:00
|
|
|
use std::fs;
|
|
|
|
|
use std::path::Path;
|
|
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
|
let base_dir = "_tmp/psd_tunes/bevel_emboss_png_set";
|
|
|
|
|
let mut samples = vec![];
|
|
|
|
|
for entry in fs::read_dir(base_dir).unwrap() {
|
|
|
|
|
let entry = entry.unwrap();
|
|
|
|
|
let path = entry.path();
|
|
|
|
|
if path.extension().unwrap() == "png" {
|
|
|
|
|
let name = path.file_stem().unwrap().to_str().unwrap().to_string();
|
|
|
|
|
samples.push((name, path));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-14 00:36:09 +03:00
|
|
|
let mut inner_mae = 0.0f64;
|
|
|
|
|
let mut inner_count = 0usize;
|
|
|
|
|
let mut outer_mae = 0.0f64;
|
|
|
|
|
let mut outer_count = 0usize;
|
|
|
|
|
let mut emboss_mae = 0.0f64;
|
|
|
|
|
let mut emboss_count = 0usize;
|
2026-07-13 20:33:39 +03:00
|
|
|
|
2026-07-14 00:36:09 +03:00
|
|
|
let lb = 5;
|
|
|
|
|
let hl = 0.05;
|
|
|
|
|
let sh = 2.5;
|
|
|
|
|
let tilt = 0.05;
|
2026-07-13 20:33:39 +03:00
|
|
|
|
|
|
|
|
println!("Evaluating {} samples", samples.len());
|
|
|
|
|
for (name, png_path) in samples {
|
2026-07-14 00:36:09 +03:00
|
|
|
let psd_name = name.split('_').next().unwrap().to_string() + ".psd";
|
2026-07-13 20:33:39 +03:00
|
|
|
let psd_path = format!("_tmp/psd_tunes/{}", psd_name);
|
2026-07-14 00:36:09 +03:00
|
|
|
if !Path::new(&psd_path).exists() {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-13 20:33:39 +03:00
|
|
|
let target = image::open(&png_path).unwrap().to_rgba8();
|
2026-07-14 00:36:09 +03:00
|
|
|
let layers = hcie_psd::import_psd(std::path::Path::new(&psd_path)).unwrap();
|
|
|
|
|
|
2026-07-13 20:33:39 +03:00
|
|
|
let mut layer = None;
|
2026-07-14 00:36:09 +03:00
|
|
|
for l in &layers {
|
|
|
|
|
for e in &l.effects {
|
|
|
|
|
if let hcie_protocol::effects::LayerEffect::BevelEmboss {
|
|
|
|
|
enabled: true, ..
|
|
|
|
|
} = e
|
|
|
|
|
{
|
|
|
|
|
layer = Some(l);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if layer.is_some() {
|
2026-07-13 20:33:39 +03:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-07-14 00:36:09 +03:00
|
|
|
if layer.is_none() {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2026-07-13 20:33:39 +03:00
|
|
|
let layer = layer.unwrap();
|
|
|
|
|
|
2026-07-14 00:36:09 +03:00
|
|
|
let (depth, size, soften, angle, altitude, direction, technique, style) = {
|
|
|
|
|
let mut d = 0.0f32;
|
|
|
|
|
let mut sz = 0.0f32;
|
|
|
|
|
let mut sof = 0.0f32;
|
|
|
|
|
let mut ang = 0.0f32;
|
|
|
|
|
let mut alt = 0.0f32;
|
|
|
|
|
let mut dir = hcie_protocol::effects::Direction::Up;
|
|
|
|
|
let mut tech = hcie_protocol::effects::Technique::Smooth;
|
|
|
|
|
let mut sty = hcie_protocol::effects::BevelStyle::InnerBevel;
|
|
|
|
|
for e in &layer.effects {
|
|
|
|
|
if let hcie_protocol::effects::LayerEffect::BevelEmboss {
|
|
|
|
|
enabled: true,
|
|
|
|
|
depth,
|
|
|
|
|
size,
|
|
|
|
|
soften,
|
|
|
|
|
angle,
|
|
|
|
|
altitude,
|
|
|
|
|
direction,
|
|
|
|
|
technique,
|
|
|
|
|
style,
|
|
|
|
|
..
|
|
|
|
|
} = e
|
|
|
|
|
{
|
|
|
|
|
d = *depth;
|
|
|
|
|
sz = *size;
|
|
|
|
|
sof = *soften;
|
|
|
|
|
ang = *angle;
|
|
|
|
|
alt = *altitude;
|
|
|
|
|
dir = direction.clone();
|
|
|
|
|
tech = technique.clone();
|
|
|
|
|
sty = style.clone();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
(
|
|
|
|
|
d,
|
|
|
|
|
sz,
|
|
|
|
|
sof,
|
|
|
|
|
ang,
|
|
|
|
|
alt,
|
|
|
|
|
match dir {
|
|
|
|
|
hcie_protocol::effects::Direction::Up => hcie_fx::types::Direction::Up,
|
|
|
|
|
_ => hcie_fx::types::Direction::Down,
|
|
|
|
|
},
|
|
|
|
|
match tech {
|
|
|
|
|
hcie_protocol::effects::Technique::Smooth => hcie_fx::types::Technique::Smooth,
|
|
|
|
|
hcie_protocol::effects::Technique::ChiselHard => {
|
|
|
|
|
hcie_fx::types::Technique::ChiselHard
|
|
|
|
|
}
|
|
|
|
|
_ => hcie_fx::types::Technique::ChiselSoft,
|
|
|
|
|
},
|
|
|
|
|
match sty {
|
|
|
|
|
hcie_protocol::effects::BevelStyle::InnerBevel => {
|
|
|
|
|
hcie_fx::types::BevelStyle::InnerBevel
|
|
|
|
|
}
|
|
|
|
|
hcie_protocol::effects::BevelStyle::OuterBevel => {
|
|
|
|
|
hcie_fx::types::BevelStyle::OuterBevel
|
|
|
|
|
}
|
|
|
|
|
hcie_protocol::effects::BevelStyle::Emboss => hcie_fx::types::BevelStyle::Emboss,
|
|
|
|
|
hcie_protocol::effects::BevelStyle::PillowEmboss => {
|
|
|
|
|
hcie_fx::types::BevelStyle::PillowEmboss
|
|
|
|
|
}
|
|
|
|
|
_ => hcie_fx::types::BevelStyle::StrokeEmboss,
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
};
|
2026-07-13 20:33:39 +03:00
|
|
|
|
2026-07-14 00:36:09 +03:00
|
|
|
let w = layer.width;
|
|
|
|
|
let h = layer.height;
|
|
|
|
|
let px = (w * h) as usize;
|
|
|
|
|
|
|
|
|
|
let alpha: Vec<u8> = layer.pixels.iter().skip(3).step_by(4).copied().collect();
|
|
|
|
|
|
|
|
|
|
let (hl_buf, sh_buf) = hcie_fx::tuned::generate_bevel_tuned(
|
|
|
|
|
&alpha,
|
|
|
|
|
w,
|
|
|
|
|
h,
|
|
|
|
|
depth,
|
|
|
|
|
size,
|
|
|
|
|
soften,
|
|
|
|
|
angle,
|
|
|
|
|
altitude,
|
|
|
|
|
&direction,
|
|
|
|
|
&technique,
|
|
|
|
|
&style,
|
|
|
|
|
lb,
|
|
|
|
|
hl,
|
|
|
|
|
sh,
|
|
|
|
|
1.0,
|
|
|
|
|
tilt,
|
2026-07-13 20:33:39 +03:00
|
|
|
);
|
|
|
|
|
|
2026-07-14 00:36:09 +03:00
|
|
|
let mut out = layer.pixels.clone();
|
|
|
|
|
for i in 0..px {
|
|
|
|
|
let dst = [out[i * 4], out[i * 4 + 1], out[i * 4 + 2], out[i * 4 + 3]];
|
|
|
|
|
let hl_src = [hl_buf[i * 4], hl_buf[i * 4 + 1], hl_buf[i * 4 + 2], hl_buf[i * 4 + 3]];
|
|
|
|
|
let sh_src = [sh_buf[i * 4], sh_buf[i * 4 + 1], sh_buf[i * 4 + 2], sh_buf[i * 4 + 3]];
|
|
|
|
|
let blended = hcie_blend::blend_pixels(dst, hl_src, hcie_blend::BlendMode::Screen, 0.75);
|
|
|
|
|
let blended =
|
|
|
|
|
hcie_blend::blend_pixels(blended, sh_src, hcie_blend::BlendMode::Multiply, 0.75);
|
|
|
|
|
out[i * 4..i * 4 + 4].copy_from_slice(&blended);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut diff_sum = 0.0f64;
|
|
|
|
|
let mut px_count = 0usize;
|
|
|
|
|
let target_raw = target.as_raw();
|
|
|
|
|
|
|
|
|
|
let offset_x = (w as i32 - target.width() as i32) / 2;
|
|
|
|
|
let offset_y = (h as i32 - target.height() as i32) / 2;
|
2026-07-13 20:33:39 +03:00
|
|
|
|
|
|
|
|
for y in 0..target.height() {
|
|
|
|
|
for x in 0..target.width() {
|
|
|
|
|
let sx = x as i32 + offset_x;
|
|
|
|
|
let sy = y as i32 + offset_y;
|
2026-07-14 00:36:09 +03:00
|
|
|
if sx >= 0 && sx < w as i32 && sy >= 0 && sy < h as i32 {
|
|
|
|
|
let s_idx = ((sy as usize) * w as usize + (sx as usize)) * 4;
|
|
|
|
|
let t_idx =
|
|
|
|
|
((y as usize) * target.width() as usize + (x as usize)) * 4;
|
|
|
|
|
|
|
|
|
|
let src_a = layer.pixels[s_idx + 3];
|
2026-07-13 20:33:39 +03:00
|
|
|
if src_a > 0 {
|
2026-07-14 00:36:09 +03:00
|
|
|
diff_sum += (out[s_idx] as f64 - target_raw[t_idx] as f64).abs();
|
|
|
|
|
diff_sum += (out[s_idx + 1] as f64 - target_raw[t_idx + 1] as f64).abs();
|
|
|
|
|
diff_sum += (out[s_idx + 2] as f64 - target_raw[t_idx + 2] as f64).abs();
|
|
|
|
|
px_count += 3;
|
2026-07-13 20:33:39 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-07-14 00:36:09 +03:00
|
|
|
|
2026-07-13 20:33:39 +03:00
|
|
|
if px_count > 0 {
|
2026-07-14 00:36:09 +03:00
|
|
|
let mae = diff_sum / px_count as f64;
|
|
|
|
|
if name.contains("InnerBevel") {
|
|
|
|
|
inner_mae += mae;
|
|
|
|
|
inner_count += 1;
|
|
|
|
|
}
|
|
|
|
|
if name.contains("OuterBevel") {
|
|
|
|
|
outer_mae += mae;
|
|
|
|
|
outer_count += 1;
|
|
|
|
|
}
|
|
|
|
|
if name.contains("Emboss") {
|
|
|
|
|
emboss_mae += mae;
|
|
|
|
|
emboss_count += 1;
|
|
|
|
|
}
|
2026-07-13 20:33:39 +03:00
|
|
|
}
|
|
|
|
|
}
|
2026-07-14 00:36:09 +03:00
|
|
|
|
|
|
|
|
if inner_count > 0 {
|
|
|
|
|
println!(
|
|
|
|
|
"Inner Bevel MAE: {:.4} ({} samples)",
|
|
|
|
|
inner_mae / inner_count as f64,
|
|
|
|
|
inner_count
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
if outer_count > 0 {
|
|
|
|
|
println!(
|
|
|
|
|
"Outer Bevel MAE: {:.4} ({} samples)",
|
|
|
|
|
outer_mae / outer_count as f64,
|
|
|
|
|
outer_count
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
if emboss_count > 0 {
|
|
|
|
|
println!(
|
|
|
|
|
"Emboss MAE: {:.4} ({} samples)",
|
|
|
|
|
emboss_mae / emboss_count as f64,
|
|
|
|
|
emboss_count
|
|
|
|
|
);
|
|
|
|
|
}
|
2026-07-13 20:33:39 +03:00
|
|
|
}
|