Files
hcie-rust-v3.05/.kilo/plans/fix-psd-writer-for-photoshop.md
T
2026-07-09 02:59:53 +03:00

4.7 KiB
Raw Blame History

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:

  1. cd0b6b1 — Initial PSD writer (997 lines)
  2. 0a821ea — Added examples, 1-line change to saver
  3. 6616b31 — "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 lfx2 odd-length padding from external to internal
  • Used write_8bim_block helper for iOpa, 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:

  1. Creates a 256×256 canvas
  2. Adds one layer with a red rectangle (no effects)
  3. Calls save_psd() to write _tmp/simple_test.psd
  4. 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:

  1. User creates the same image in Photopea/Photoshop and saves as PSD
  2. Write a Python script to hex-dump both files and diff the binary structure
  3. 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.

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

  1. cargo run --package hcie-io --example test_psd_simple → user opens in Photoshop
  2. If opens → proceed to effects test
  3. If fails → hex dump comparison with Photoshop-generated PSD
  4. Final: 192 PSDs → Photoshop batch export → MAE tuning