Files
hcie-rust-v3.05/hcie-io/examples/debug_effects_detail.rs
2026-07-09 02:59:53 +03:00

156 lines
6.6 KiB
Rust

fn main() {
let orig_bytes = std::fs::read("_images/_psd_stil_test/inner_shadow/black_triangle_green_inner_shadow_normal_blend.psd").unwrap();
let saved_bytes = std::fs::read("_tmp/roundtrip_output.psd").unwrap();
// Parse effects from both files
println!("=== ORIGINAL PSD EFFECTS ===");
let orig_layers = hcie_psd::import_psd(std::path::Path::new("_images/_psd_stil_test/inner_shadow/black_triangle_green_inner_shadow_normal_blend.psd")).unwrap();
for (i, layer) in orig_layers.iter().enumerate() {
println!("Layer {}: '{}' effects={}", i, layer.name, layer.effects.len());
for (j, fx) in layer.effects.iter().enumerate() {
print_effect(j, fx);
}
}
println!("\n=== SAVED PSD EFFECTS ===");
let saved_layers = hcie_psd::import_psd(std::path::Path::new("_tmp/roundtrip_output.psd")).unwrap();
for (i, layer) in saved_layers.iter().enumerate() {
println!("Layer {}: '{}' effects={}", i, layer.name, layer.effects.len());
for (j, fx) in layer.effects.iter().enumerate() {
print_effect(j, fx);
}
}
// Compare lfx2 raw bytes more carefully
println!("\n=== LFX2 RAW DEEP DIVE ===");
let orig_lfx2 = extract_lfx2_from_layer1(&orig_bytes);
let saved_lfx2 = extract_lfx2_from_layer1(&saved_bytes);
if let (Some(o), Some(s)) = (&orig_lfx2, &saved_lfx2) {
println!("ORIG lfx2: {} bytes", o.len());
println!("SAVED lfx2: {} bytes", s.len());
// Find ALL differences
let min_len = o.len().min(s.len());
let mut diffs = Vec::new();
for i in 0..min_len {
if o[i] != s[i] {
diffs.push(i);
}
}
println!("Total differing bytes: {} (in shared {} bytes)", diffs.len(), min_len);
// Show context around each diff region
let mut i = 0;
while i < diffs.len() {
let start = diffs[i];
let mut end = start;
while i < diffs.len() && diffs[i] - end < 4 {
end = diffs[i];
i += 1;
}
let ctx_start = start.saturating_sub(8);
let ctx_end = (end + 24).min(min_len);
println!("\n Diff region @{}..{}:", start, end);
println!(" ORIG : {}", hex_dump_range(&o[ctx_start..ctx_end], start - ctx_start));
println!(" SAVED: {}", hex_dump_range(&s[ctx_start..ctx_end], start - ctx_start));
}
// Show extra bytes in ORIG
if o.len() > s.len() {
println!("\n ORIG extra tail ({} bytes):", o.len() - s.len());
println!(" {}", hex_dump(&o[s.len()..]));
}
}
}
fn print_effect(idx: usize, fx: &hcie_protocol::effects::LayerEffect) {
use hcie_protocol::effects::LayerEffect::*;
let name = match fx {
DropShadow { .. } => "DropShadow",
InnerShadow { .. } => "InnerShadow",
OuterGlow { .. } => "OuterGlow",
InnerGlow { .. } => "InnerGlow",
BevelEmboss { .. } => "BevelEmboss",
Satin { .. } => "Satin",
ColorOverlay { .. } => "ColorOverlay",
GradientOverlay { .. } => "GradientOverlay",
PatternOverlay { .. } => "PatternOverlay",
Stroke { .. } => "Stroke",
};
match fx {
InnerShadow { enabled, blend_mode, color, opacity, angle, distance, choke, size, noise, .. } => {
println!(" [{}] {} enabled={} blend={:?} color={:?} op={:.2} angle={:.1} dist={:.1} choke={:.1} size={:.1} noise={:.1}",
idx, name, enabled, blend_mode, color, opacity, angle, distance, choke, size, noise);
}
BevelEmboss { enabled, style, technique, depth, direction, size, soften, angle, altitude, .. } => {
println!(" [{}] {} enabled={:?} style={:?} technique={:?} depth={:.1} dir={:?} size={:.1} soften={:.1} angle={:.1} alt={:.1}",
idx, name, enabled, style, technique, depth, direction, size, soften, angle, altitude);
}
_ => {
println!(" [{}] {}", idx, name);
}
}
}
fn extract_lfx2_from_layer1(bytes: &[u8]) -> Option<Vec<u8>> {
let cmd_len = u32::from_be_bytes([bytes[26], bytes[27], bytes[28], bytes[29]]) as usize;
let ir_start = 30 + cmd_len;
let ir_len = u32::from_be_bytes([bytes[ir_start], bytes[ir_start+1], bytes[ir_start+2], bytes[ir_start+3]]) as usize;
let lmi_start = ir_start + 4 + ir_len;
let lmi_len = u32::from_be_bytes([bytes[lmi_start], bytes[lmi_start+1], bytes[lmi_start+2], bytes[lmi_start+3]]) as usize;
let lmi = &bytes[lmi_start+4..lmi_start+4+lmi_len];
let li_len = u32::from_be_bytes([lmi[0], lmi[1], lmi[2], lmi[3]]) as usize;
let li = &lmi[4..4+li_len];
let layer_count = i16::from_be_bytes([li[0], li[1]]).unsigned_abs() as usize;
let mut pos = 2;
for _ in 0..layer_count {
if pos + 18 > li.len() { return None; }
let ch_count = u16::from_be_bytes([li[pos+16], li[pos+17]]) as usize;
pos += 18;
pos += ch_count * 6;
if pos + 12 > li.len() { return None; }
pos += 12;
let extra_len = u32::from_be_bytes([li[pos], li[pos+1], li[pos+2], li[pos+3]]) as usize;
pos += 4;
let extra_end = pos + extra_len;
// Skip mask + blend + name
if pos + 4 > extra_end { return None; }
let mask_len = u32::from_be_bytes([li[pos], li[pos+1], li[pos+2], li[pos+3]]) as usize;
pos += 4 + mask_len;
if pos + 4 > extra_end { return None; }
let blend_len = u32::from_be_bytes([li[pos], li[pos+1], li[pos+2], li[pos+3]]) as usize;
pos += 4 + blend_len;
if pos >= extra_end { return None; }
let name_len = li[pos] as usize;
pos += 1 + name_len;
pos += (4 - ((name_len + 1) % 4)) % 4;
while pos + 8 <= extra_end {
let sig = &li[pos..pos+4];
if sig != b"8BIM" && sig != b"8B64" { break; }
let key = &li[pos+4..pos+8];
let block_len = u32::from_be_bytes([li[pos+8], li[pos+9], li[pos+10], li[pos+11]]) as usize;
if key == b"lfx2" {
return Some(li[pos+12..pos+12+block_len].to_vec());
}
pos += 12 + block_len;
if block_len % 2 != 0 { pos += 1; }
}
pos = extra_end;
}
None
}
fn hex_dump(data: &[u8]) -> String {
data.iter().take(64).map(|b| format!("{:02X}", b)).collect::<Vec<_>>().join(" ")
}
fn hex_dump_range(data: &[u8], highlight_offset: usize) -> String {
data.iter().enumerate().map(|(i, b)| {
let s = format!("{:02X}", b);
if i == highlight_offset { format!("[{}]", s) } else { s }
}).collect::<Vec<_>>().join(" ")
}