156 lines
6.6 KiB
Rust
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(" ")
|
|
}
|