4.7 KiB
PSD Writer: Regression Fix for Photoshop Compatibility
Problem
The PSD files generated by hcie-psd/src/psd_saver.rs can be parsed by Psd::from_bytes (our internal parser) but cannot be opened in Adobe Photoshop. The user says PSD writing was working earlier in the project's git history and has regressed.
Git History
There are 3 commits touching hcie-psd/src/psd_saver.rs:
cd0b6b1— Initial PSD writer (997 lines)0a821ea— Added examples, 1-line change to saver6616b31— "Fix layer extra data and merged image layout" (our recent changes)
Key Differences: cd0b6b1 vs 6616b31 (HEAD)
Change 1: Merged Image Row Length Order (SUSPECT)
Original (cd0b6b1): Interleaved — [R0, G0, B0, A0, R1, G1, B1, A1, ...]
for y in 0..h {
for ch_idx in 0..4 {
buf.extend_from_slice(&row_lengths[ch_idx][y]);
}
}
Current (6616b31): Per-channel — [R0, R1, ..., Rn, G0, G1, ..., Gn, ...]
for ch_idx in 0..4 {
for y in 0..h {
buf.extend_from_slice(&row_lengths[ch_idx][y]);
}
}
PSD Spec says: "byte counts for all the scan lines (rows × channels)" — ambiguous ordering, but data is planar (RRR GGG BBB). Both orderings produce the same total count. The question is which order Photoshop expects.
CRITICAL: The original code has a mismatch — byte counts are interleaved but compressed data is per-channel. This would cause Photoshop to read wrong row lengths → corrupted data. The current code is internally consistent (both per-channel). But maybe Photoshop expects interleaved for both.
Change 2: Layer Count Sign (SUSPECT)
Both versions always write negative layer count:
layer_records_buf.extend_from_slice(&(-layer_count.abs()).to_be_bytes());
Per PSD spec: "If the count is negative, the first layer in the following record is a group." For a simple document with no groups, Photoshop may reject negative count.
Change 3: Extra Data Blocks (6616b31 additions)
- Added
luni(Unicode layer name) block - Added
lyid(layer ID) block - Moved
lfx2odd-length padding from external to internal - Used
write_8bim_blockhelper foriOpa,brst,shmd
Change 4: PassThrough blend mode added
BlendMode::PassThrough => b"pass",
Debugging Plan
Step 1: Create Minimal Test PSD (no effects)
Write a Rust example examples/test_psd_simple.rs that:
- Creates a 256×256 canvas
- Adds one layer with a red rectangle (no effects)
- Calls
save_psd()to write_tmp/simple_test.psd - The user opens this in Photoshop
This isolates the PSD structural issues from effects serialization.
Step 2: Binary Comparison with Reference PSD
If Step 1 PSD doesn't open:
- User creates the same image in Photopea/Photoshop and saves as PSD
- Write a Python script to hex-dump both files and diff the binary structure
- Identify exact byte offset where the format diverges
Step 3: Fix Identified Issues
Based on the debugging results, fix the PSD writer. Most likely fixes:
Fix A — Merged Image Row Lengths: Try interleaved order (matching original) for BOTH byte counts AND data. This is the most common PSD layout in practice.
Fix B — Layer Count: Write positive count when there are no groups:
let count = if layers.iter().any(|l| l.layer_type == LayerType::Group) {
-(layers.len() as i16)
} else {
layers.len() as i16
};
Fix C — lfx2/shmd descriptor correctness: Verify the ActionDescriptor binary format matches what Photoshop writes. Cross-reference with the spec's descriptor format section.
Step 4: Test with Effects
Once the basic PSD opens, add inner shadow effects and test again.
Step 5: Batch Generate 192 Inner Shadow PSDs
Write examples/generate_inner_shadow_psd_set.rs using the fixed save_psd().
Step 6: Batch Export PNGs in Photoshop
User runs _tools/photoshop/export_psd_folder_to_png.jsx in Photoshop to batch-export all 192 PSDs as transparent PNGs.
Step 7: Run MAE Grid Search
cargo run --package hcie-io --example tune_mae_inner_shadow_grid
Files to Modify/Create
| File | Action |
|---|---|
hcie-psd/src/psd_saver.rs |
Fix merged image row order, layer count, possibly effects format |
hcie-io/examples/test_psd_simple.rs |
Create — minimal PSD for Photoshop validation |
hcie-io/examples/generate_inner_shadow_psd_set.rs |
Create — batch inner shadow PSD generator |
hcie-io/examples/tune_mae_inner_shadow_grid.rs |
Already created, ready to use |
Verification
cargo run --package hcie-io --example test_psd_simple→ user opens in Photoshop- If opens → proceed to effects test
- If fails → hex dump comparison with Photoshop-generated PSD
- Final: 192 PSDs → Photoshop batch export → MAE tuning