Files
2026-07-09 02:59:53 +03:00

111 lines
5.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# PSD Layer Style (fx) Test Files — Handoff
## Goal
Otomatik PSD layer style test pipeline: her efekt tipi için doğru formatta PSD dosyası → Photopea referans render → engine çıktısı ile karşılaştırma.
## Output
16 test PSD dosyası `/home/hc/Pictures/_psd_stil_test/` altında:
- `fx_baseline.psd` — efektsiz base
- `fx_drop_shadow.psd`, `fx_inner_shadow.psd`, `fx_outer_glow.psd`, `fx_inner_glow.psd`
- `fx_bevel_inner.psd`, `fx_bevel_outer.psd`, `fx_emboss.psd`, `fx_pillow_emboss.psd`
- `fx_satin.psd`, `fx_color_overlay.psd`, `fx_gradient_overlay.psd`, `fx_pattern_overlay.psd`
- `fx_stroke_inside.psd`, `fx_stroke_center.psd`, `fx_stroke_outside.psd`
## Changes Made
### `src/psd_saver.rs` — lfx2 descriptor writer (replaces lrFX)
- **Tag**: `"lrFX"``"lfx2"` (line 188)
- **`write_lfx2_block()`**: Writes lfx2 descriptor format matching Photopea output:
- Header: `[ver=0 u32][dver=16 u32]`
- `_read_body`: name(U+0000), classID('null'), count(2+n_effects)
- Fixed items: `Scl`(UntF #Prc 100), `masterFXSwitch`(bool true)
- Per-effect: Objc with effect-specific fields (see effect field lists below)
- **Effect descriptors** (`write_fx_descriptor`):
- `DrSh` (DropShadow): 14 fields — enab, Md, Opct, Clr, uglg, lagl, Dstn, Ckmt, blur, Nose, AntA, TrnS, layerConceals, Cntn
- `IrSh` (InnerShadow): 14 fields (same as DrSh)
- `OrGl` (OuterGlow): 10 fields — enab, Md, Opct, Clr, GlwT, blur, Ckmt, AntA, TrnS, Nose
- `IrGl` (InnerGlow): 10 fields — enab, Md, Opct, Clr, GlwS, blur, Ckmt, AntA, TrnS, Nose
- `ebbl` (BevelEmboss): 29 fields — enab, hglM, hglC, hglO, sdwM, sdwC, sdwO, bvlT, bvlS, uglg, lagl, Lald, srgR, blur, bvlD, TrnS, antialiasGloss, Sftn, useShape, MpgS, AntA, Inpr, useTexture, InvT, Algn, Scl, textureDepth, Ptrn, phase
- `lagl` (Satin): 10 fields — enab, Md, Opct, Clr, lagl, Dstn, blur, MpgS, Invr, AntA
- `sofi` (ColorOverlay): 5 fields — enab, Md, Opct, Clr, Cntn
- `GrFl` (GradientOverlay): 10 fields — enab, Md, Opct, Angl, Type, Rvrs, Algn, Scl, Ofst, Grad(Grdn)
- `PtFl` (PatternOverlay): 5 fields + Ptrn Objc with Nm, Idnt, phase
- `FrFX` (Stroke): 8 fields — enab, Styl, PntT, Md, Opct, Sz, Clr (+ TrnS if not Color fill)
### Descriptor helper functions
- `w_key4(buf, &[u8; 4])` — 4-byte OSType key (length prefix = 0)
- `w_key_var(buf, &[u8])` — variable-length key (length prefix = N)
- `w_ustr_null(buf)` — Unicode name: length=1, U+0000
- `w_ustr(buf, &str)` — Unicode name: length=N, UTF-16BE bytes
- `w_class_id(buf, &[u8; 4])` — classID with length=0 prefix
- `w_bool(buf, bool)`, `w_enum(buf, type, val)`, `w_untf(buf, unit, f64)`, `w_doub(buf, f64)`, `w_long(buf, i32)`
- `w_objc_start(buf)` — writes "Objc" tag
- `w_objc_body_start(buf, class_id, count)` — _read_body: name(U+0000) + classID + count
- `w_rgbc_color(buf, &[u8; 4])` — writes RGBC Objc with Rd/Grn/Bl doub
- `w_default_contour(buf)` — standard linear contour (TrnS/MpgS)
- `w_contour_with_key(buf, key)` — key + default contour
### `write_shmd_block()` — Photopea sheet metadata
- Structure: `[ver=1][8BIMcmls][sub_size=0][desc_size][descriptor...]`
- Descriptor items:
- `LyrI`: long 0
- `layerSettings`: VlLs → Objc null with 6 items:
- `compList`: VlLs[long 0]
- `enab`: bool true
- `Ofst`: Objc {Hrzn long 0, Vrtc long 0}
- `FXRefPoint`: Objc {Hrzn long 0, Vrtc long 0}
- `blendOptions`: Objc {Md enum Nrml, Opct UntF 100, fillOpacity UntF 100}
- `Lefx`: Objc — FULL effect descriptor copy (same as lfx2: Scl + masterFXSwitch + effects)
- Total: ~1038 bytes per single-effect layer
### Layer extra data additions
- **Blending ranges**: 40 bytes → 10 pairs of (u16=0, u16=65535)
- **iOpa block**: `8BIMiOpa` size=4, data=`[0xff, 0x00, 0x00, 0x00]`
- **brst block**: `8BIMbrst` size=0
- **lfx2 block**: `8BIMlfx2` size=N, descriptor data
- **shmd block**: `8BIMshmd` size=M, Photopea metadata
### `examples/generate_style_tests.rs`
- Generates all 16 PSD files: 15 single-effect + 1 baseline
- 512×512 canvas, asymmetric trapezoidal shape per layer
- Baseline has no effects; all others have exactly 1 effect
### Imports
- Added `GradientDef` to `use hcie_fx::types::{..., GradientDef}`
- Uses `hcie_blend::BlendMode` for blend mode mapping
## Key Format Decisions
### Objc format
Photopea Objc descriptor: NO outer wrapper. Direct `_read_body`:
```
"Objc" + name_len(u32) + name(u16×N) + classID_len(u32) + classID + count(u32) + items...
```
where name is always `U+0000` (len=1), and classID is length-prefixed (len=0 → 4-byte key).
### enum format
```"enum" + classID_len(u32=0) + type_id(4B) + classID_len(u32=0) + value(4B)```
### Nested Objc
Contour (TrnS/MpgS), Color (RGBC), Pattern (Ptrn), Gradient (Grdn) all use the same format recursively.
## How to Regenerate
```bash
cd /home/hc/Documents/00_PROJECTS/hcie-rust-v4
cargo run -p hcie-io --example generate_style_tests
```
Files go to `/home/hc/Pictures/_psd_stil_test/fx_*.psd`.
## Verification
- All 15 effect files have: lfx2 + shmd + iOpa + brst blocks
- fx_baseline.psd has no effect blocks (baseline reference)
- lfx2 binary format byte-identical in structure to working `hc_drop_shadow.psd`
- shmd mirrors the lfx2 descriptor inside `Lefx` section
## Remaining / Known Issues
- lfx2 format verified against Photopea output (`hc_drop_shadow.psd`)
- Files open in Photopea — effects should render based on shmd+lfx2 metadata
- GradientOverlay and PatternOverlay use minimal default gradient/pattern data
- BevelEmboss texture (Ptrn) uses hardcoded default UUID
- Contour names use ASCII "Linear" (Photopea uses localized names like "Lineární")