Commit Graph
8 Commits
Author SHA1 Message Date
AskaEth c6a24a4fdb Add --type-layer: convert text layers to editable TypeLayers (TySh)
Reuses a reference TySh block from a PS-generated PSD as a template and
mutates its engine data (Text/FontSize/FillColor/FontSet/transform) per
ppl text layer. Rasterized pixels are kept as channel data so the layer
always displays, and Photoshop treats it as an editable text layer.
Font PostScript names are read from the font files via fontTools.
Verified: 54 TypeLayers, psd_tools reads correct text/engine data.
2026-08-27 10:31:36 +08:00
AskaEth edef8799ce Fix blending ranges: zero composite range made PS skip layer blending
PS reads layer blending ranges to decide if a layer participates in
compositing. psd_tools wrote all-zero ranges (composite 0..0), which tells
Photoshop the layer has an empty blend range -> the canvas renders empty
even though layer pixels are correct (Ctrl+C/V shows content, export PNG is
transparent, save-as by PS keeps the bad ranges). Now writes full-range
(0..65535) composite + channel ranges like PS-generated files, verified
against the reference PSD.
2026-08-27 10:02:17 +08:00
AskaEth 8af857d45a Fix luni block: missing 4-byte character count field
The unicode layer name block must be [char_count(4B)][utf-16-be chars].
We wrote raw utf-16 without the count, so Photoshop read the first
characters as the length, shifted the entire extra-data parse, and every
layer's pixels came out empty (all layers transparent). Fixed: name now
reads back correctly and 167/167 layers match the rendered originals
(mean diff 0.000).
2026-08-27 09:25:18 +08:00
AskaEth 00f2cbe71a Write standard tagged blocks (lnsr/lyid/clbl/infx/knko/lspf/lclr/fxrp) per layer
Photoshop reads a layer's tagged blocks until it sees a non-8BIM
signature. With only 'luni' the next bytes are the channel data, which PS
mis-parses and the layer pixels come out empty. PS writes the standard
block set, so we now mirror it (verified: blocks list now matches the
reference PSD).
2026-08-27 09:06:03 +08:00
AskaEth e07ef4acaa Set layer flags bit3 (Photoshop 5.0+) so PS reads tagged blocks correctly
PS-generated PSDs always set flags bit 3 (0x08) to signal Photoshop 5.0+
format where the layer extra data contains tagged blocks. Our layers had
flags=0x00, so Photoshop treated them as pre-5.0 records and failed to
read the extra data / layer pixels, showing every layer as transparent
(only ape_2 happened to render). Verified against the reference PSD.
2026-08-27 08:59:35 +08:00
AskaEth b76a26c11c Fix merged image data: single compression field + RAW for compatibility
Per Adobe PSD spec, the Image Data Section has ONE 2-byte compression
field followed by all planes in planar order (RRR GGG BBB). The previous
code wrote a compression marker per channel (4 extra bytes) and used RLE,
which third-party viewers parse incorrectly (stretching) and Photoshop
rejected. Now writes RAW data with a single compression marker, verified
by pytoshop (decompresses to 3x4882x9764).
2026-08-27 08:37:59 +08:00
AskaEth a5757d1f07 Fix PSD structure: add missing LayerInfo length field and correct channel order
- Layer info section was missing its 4-byte length field, causing all
  subsequent offsets to shift and Photoshop to fail with 'unexpected end
  of file'
- Layer channel data was ordered [R,G,B,A] with ids [-1,0,1,2], shifting
  every channel by one (alpha held red, red held green, ...) - fixed to
  [A,R,G,B] so id -1 is the alpha mask
- Verified: psd_tools opens the PSD, per-layer pixels match the rendered
  originals with 0.000 mean difference
2026-08-27 08:27:05 +08:00
AskaEth 60624f01c2 Add ppl<->psd conversion tools (ppl2psd, psd2ppl) 2026-08-27 08:16:44 +08:00