leafer-x-psd 0.0.1-beta.0 → 0.0.1-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +84 -15
- package/dist/psd.mjs +310 -232
- package/dist/psd.mjs.map +1 -1
- package/dist/psd.umd.cjs +5 -5
- package/dist/psd.umd.cjs.map +1 -1
- package/package.json +2 -1
- package/types/adapter/vector.d.ts +27 -0
- package/types/types.d.ts +2 -0
package/README.md
CHANGED
|
@@ -327,6 +327,7 @@ for (const { key, kind, layer, width, height } of getResources(frame)) {
|
|
|
327
327
|
| `semantic-fallback` | 语义化适配器失败,已降级到下一个适配器(通常是位图) |
|
|
328
328
|
| `text-unsupported` | 文字图层的某项属性尚无对应能力(字符级样式、文字变形、水平缩放、段间距) |
|
|
329
329
|
| `text-leading-suspect` | 文字图层的 `leading` 数值不可信,已退回自动行高 |
|
|
330
|
+
| `vector-unsupported` | 形状图层的填充/描边样式尚无对应能力(图案、噪声渐变、angle 类渐变、反相形状等) |
|
|
330
331
|
| `mask-skipped` | 蒙版的部分参数(如羽化、反相)未映射 |
|
|
331
332
|
| `empty-layer` | 图层没有可渲染内容,已跳过 |
|
|
332
333
|
| `filtered` | 被你自己的 `filter` 跳过 |
|
|
@@ -390,24 +391,43 @@ setCanvasLimits({ maxSide: 30000 }) // 确实要处理 30000px
|
|
|
390
391
|
| 文字图层 | `Text`(默认 `text: 'editable'`) | ✅ 亚像素级贴合(见下) |
|
|
391
392
|
| 文字图层(竖排/旋转) | 竖排模拟;旋转来自 `transform` | ✅ |
|
|
392
393
|
| 字体名 | 内置 PS 全名 → 字体族名映射 | ✅ 见下 |
|
|
393
|
-
| 形状图层 |
|
|
394
|
+
| 形状图层 | `vmsk` 几何 + `vectorFill`/`vectorStroke` → **`Path`** | ✅ 矢量;样式映射不了时退回位图,见下 |
|
|
394
395
|
| 智能对象 | 烘焙成位图 | ❌ 不展开原始内容 |
|
|
395
396
|
| 调整图层 | — | ❌ 跳过并报 `effect-unsupported`(见下) |
|
|
396
397
|
|
|
397
398
|
> **当前进度**:M0 ~ M6 均已完成,三个真实样例的还原度都进入个位数误差并锁定为回归基线。
|
|
398
|
-
> 剩余的已知缺口只有 ag-psd
|
|
399
|
-
>
|
|
399
|
+
> 剩余的已知缺口只有 ag-psd 本身不提供数据的部分(智能对象内容、CMYK),
|
|
400
|
+
> Leafer 没有等价能力的效果(斜面浮雕/光泽/图案叠加),
|
|
401
|
+
> 以及形状图层里那几类样式(图案填充、噪声渐变、angle 类渐变、反相形状)。
|
|
400
402
|
|
|
401
|
-
###
|
|
403
|
+
### 形状图层的几何在 `vmsk` 里
|
|
402
404
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
+
`LayerAdditionalInfo.pathList` 至今仍是 `// TODO: ...`,但**那条路不是唯一的路**:
|
|
406
|
+
PSD 里形状图层的几何就存在**矢量蒙版的槽位**(`vmsk` + `vscg` / `vstk`),
|
|
407
|
+
ag-psd 把它报成 `layer.vectorMask`,填充与描边样式报成 `vectorFill` / `vectorStroke`。
|
|
405
408
|
|
|
406
|
-
|
|
407
|
-
|
|
409
|
+
所以形状图层会直接还原成一个 **Leafer `Path`**(`adapter/vector.ts`):几何来自
|
|
410
|
+
`vectorMask.paths`,填充来自 `vectorFill`,形状自己的描边来自 `vectorStroke`。
|
|
411
|
+
`vmsk` 的锚点是**文档绝对坐标**(与真矢量蒙版同源),因此 `Path` 的原点落在文档 `(0, 0)`。
|
|
408
412
|
|
|
409
|
-
|
|
410
|
-
|
|
413
|
+
三条实测事实(`test-1.psd` 的「多边形 1」,采样自 `regions.test.ts` 的同一套比对):
|
|
414
|
+
|
|
415
|
+
1. **形状层的 `canvas` 已经按形状光栅化过**(四角 alpha 全 0),
|
|
416
|
+
所以以前"位图 + 矢量蒙版再裁一次"是**重复裁剪**:二次抗锯齿让该层区域差从
|
|
417
|
+
**0.937 劣化到 1.316**(整图 1.020 → 1.039);
|
|
418
|
+
2. 改成矢量 `Path` 之后比"只用位图"还要准:该层区域差 0.937(位图)→ 矢量渲染后
|
|
419
|
+
整图从 1.039 降到 **1.006**(`text: 'editable'` 下 0.990 → **0.957**);
|
|
420
|
+
3. 因此 `decorator/mask.ts` 对形状图层**不再套那层矢量蒙版** —— 那个 `vmsk` 是几何本身,
|
|
421
|
+
不是裁剪。
|
|
422
|
+
|
|
423
|
+
**映射不了就退回位图,不硬撑**:图案填充、噪声渐变、`angle`/`reflected`/`diamond`
|
|
424
|
+
渐变、反相形状(`invert`)都会报 `vector-unsupported` 并交给位图适配器
|
|
425
|
+
(PS 自己光栅化的像素),因为"画一个错的矢量"比"用一张对的位图"更糟。
|
|
426
|
+
形状层自己的描边与**图层效果里的描边**是两回事:前者映射到 `Path` 的 `stroke`,
|
|
427
|
+
后者走效果路径(两者同时启用时的叠加顺序见 [TODO.md](../../TODO.md))。
|
|
428
|
+
|
|
429
|
+
出于历史原因说明一句:`content: 'editable'` 目前仍然做不到任何事(形状层已经改走
|
|
430
|
+
`Path` 适配器,不再依赖这个选项),本插件不会假装它生效,而是给出 `semantic-fallback` 诊断。
|
|
411
431
|
|
|
412
432
|
### 为什么不烘焙调整图层
|
|
413
433
|
|
|
@@ -619,17 +639,20 @@ npm test
|
|
|
619
639
|
|
|
620
640
|
| 样例 | 内容 | `text: 'raster'` | `text: 'editable'` |
|
|
621
641
|
| --- | --- | --- | --- |
|
|
622
|
-
| `test-1.psd` |
|
|
642
|
+
| `test-1.psd` | 像素层、位图+矢量双蒙版、横排/竖排文字、图层组、**形状层**、负坐标超界 | 1.006 | **0.957** |
|
|
623
643
|
| `test-2.psd` | 剪贴蒙版、正片叠底/变亮、投影、双描边、内阴影、内发光、双蒙版 | 3.022 | 3.022 |
|
|
624
644
|
| `test-text.psd` | 横排、旋转 45°、旋转 -31.79°、竖排、微软雅黑、楷体、三行段落 | **1.200** | 1.773 |
|
|
625
645
|
|
|
626
646
|
**全部样例最优位移都是 (0,0)** —— 任何 1px 平移都会让差异明显劣化,说明不存在
|
|
627
647
|
系统性偏移。位移诊断很关键:整体偏移也会让差异只出现在边缘上,从统计数字里看不出来。
|
|
628
648
|
|
|
629
|
-
注意 `test-1` 上**语义化文字模式比烘焙模式更准**(0.
|
|
649
|
+
注意 `test-1` 上**语义化文字模式比烘焙模式更准**(0.957 vs 1.006):用真字体清晰渲染,
|
|
630
650
|
比复用 PS 烘焙的位图更贴合参考图。`test-text` 反过来(1.773 vs 1.200),因为它是纯文字
|
|
631
651
|
样例,烘焙模式直接复用了 PS 自己的文字位图,而语义化模式要重排一遍。
|
|
632
652
|
|
|
653
|
+
> `test-1` 的数字在形状图层改成矢量 `Path` 之后有所改善(1.039 → 1.006 / 0.990 → 0.957),
|
|
654
|
+
> 原因见「形状图层的几何在 `vmsk` 里」。
|
|
655
|
+
|
|
633
656
|
### 文字逐层精度
|
|
634
657
|
|
|
635
658
|
```
|
|
@@ -691,7 +714,7 @@ ag-psd 解码 : 34 ms (91%)
|
|
|
691
714
|
|
|
692
715
|
```sh
|
|
693
716
|
npm run dev # 启动调试台(http://localhost:5173)
|
|
694
|
-
npm test #
|
|
717
|
+
npm test # 197 个测试(含跑构建产物的冒烟测试)
|
|
695
718
|
npm run typecheck
|
|
696
719
|
npm run build # 打包 ESM + UMD,并生成 types/
|
|
697
720
|
npm run verify:artifact # 构建 + 校验产物(npm publish 前会自动跑)
|
|
@@ -699,10 +722,41 @@ npm run pack # 构建 + 校验 + npm pack,检查会发布哪些文
|
|
|
699
722
|
|
|
700
723
|
# 命令行查看一个 PSD 的图层结构(排查偏差的第一手段)
|
|
701
724
|
node packages/psd/scripts/inspect-psd.mjs samples/test-1.psd
|
|
725
|
+
|
|
726
|
+
# 把每个图层的 canvas 导出成图片 + manifest(要看像素时用它)
|
|
727
|
+
node packages/psd/scripts/export-layers.mjs samples/test-1.psd --composite --with-masks
|
|
702
728
|
```
|
|
703
729
|
|
|
704
730
|
只在插件包内工作的话,也可以 `cd packages/psd` 后直接跑上述命令(去掉 `-w` 相关的部分)。
|
|
705
731
|
|
|
732
|
+
### 两个命令行工具
|
|
733
|
+
|
|
734
|
+
排查"某个区域和 PS 不一致"时的顺序是:先用 `inspect-psd` 看**结构**(谁是谁、蒙版/矢量/
|
|
735
|
+
效果的原始数据),再用 `export-layers` 看**像素**(PS 自己给每一层的画布长什么样)。
|
|
736
|
+
|
|
737
|
+
| 工具 | 作用 |
|
|
738
|
+
| --- | --- |
|
|
739
|
+
| `scripts/inspect-psd.mjs` | 打印图层树:盒子、混合模式、蒙版框、`realMask`、矢量路径与首个锚点、`vectorFill`、文字 `transform`、启用中的效果 |
|
|
740
|
+
| `scripts/export-layers.mjs` | 把每个图层的 canvas 导出成图片(默认 PNG,可 `webp`/`jpeg`),目录结构 = 图层树,并写一份 `manifest.json` |
|
|
741
|
+
|
|
742
|
+
```sh
|
|
743
|
+
node scripts/export-layers.mjs design.psd # → ./psd-layers/design/
|
|
744
|
+
node scripts/export-layers.mjs design.psd --flat --format webp --quality 0.9
|
|
745
|
+
node scripts/export-layers.mjs design.psd --with-masks --composite --skip-hidden
|
|
746
|
+
```
|
|
747
|
+
|
|
748
|
+
导出的 `manifest.json` 里带着每个图层的名字、盒子、混合模式、不透明度、隐藏/剪贴标记、
|
|
749
|
+
启用中的效果、蒙版与矢量信息,可以直接和插件的解析结果逐项对照。
|
|
750
|
+
|
|
751
|
+
> ⚠️ 导出的 `layer.canvas` 是**图层自身的像素通道,不包含图层效果** ——
|
|
752
|
+
> 效果在 PSD 里只是 `lfx2` 参数,ag-psd 不做渲染(要带效果的参考图,
|
|
753
|
+
> 那是 `--composite` 导出的整幅合成图,Photoshop 自己烘焙的)。
|
|
754
|
+
> 这也解释了为什么插件对位图图层必须自己烘焙效果:
|
|
755
|
+
> 实测拿未烘焙的 canvas 直接顶替,`test-2.psd` 该层区域差会从 3.31 变成 14.81。
|
|
756
|
+
>
|
|
757
|
+
> 文件名会做净化(图层名是文件内容,可能带 `../`、控制字符、Windows 非法字符),
|
|
758
|
+
> 并会断言不会写到输出目录之外。
|
|
759
|
+
|
|
706
760
|
> **`dist/` 与 `types/` 不提交进 git**,它们是 `npm run build` 的产物。
|
|
707
761
|
> 因此发布前必须先构建 —— 这件事由包里的 `prepublishOnly` 钩子自动完成,
|
|
708
762
|
> 并且会顺带跑一遍 `test:artifact`(校验 `main`/`module`/`types`/`unpkg`/`exports`
|
|
@@ -742,6 +796,7 @@ import { psdToFrame } from 'leafer-x-psd'
|
|
|
742
796
|
| `__tests__/regions.test.ts` | 分图层区域比对,输出「参考 \| 渲染 \| 差异」并排图 |
|
|
743
797
|
| `__tests__/runtime.test.ts` | 分批切片、规模基准、耗时拆解、取消、资源回收、蒙版裁剪收益 |
|
|
744
798
|
| `__tests__/limits.test.ts` | 配额与不可信输入:画布上限、效果参数钳制、超限降级、URL 来源已移除 |
|
|
799
|
+
| `__tests__/vector.test.ts` | 形状图层 → `Path`:几何/填充/描边、组内坐标、无像素不再丢失、退回位图、真矢量蒙版不回归 |
|
|
745
800
|
| `__tests__/package.test.ts` | **消费 `dist/` 构建产物**:ESM 导入、UMD 的 `LeaferX.psd` 全局、包元信息 |
|
|
746
801
|
|
|
747
802
|
`package.test.ts` 刻意与源码测试分开:只有真正去用发布出去的东西,才会暴露
|
|
@@ -785,10 +840,24 @@ import { psdToFrame } from 'leafer-x-psd'
|
|
|
785
840
|
- **文字的水平缩放与文字变形**(`horizontalScale` / `warp`)尚未映射,会报 `text-unsupported`。
|
|
786
841
|
- **斜面浮雕 / 光泽 / 图案叠加**在 Leafer 中没有对应能力,会报 `effect-unsupported` 并丢弃。
|
|
787
842
|
- **效果烘焙的近似之处**:膨胀/腐蚀是用「沿圆周多次绘制」逼近的(最多 24 次),
|
|
788
|
-
|
|
789
|
-
|
|
843
|
+
大半径下有轻微多边形锯齿;`shadowBlurScale` 是**全局**一个系数,而投影/外发光/内阴影/
|
|
844
|
+
内发光在 canvas 上走的是三条不同实现路径;PS 的 `contour` 等高线 / `noise` / `jitter` /
|
|
845
|
+
`technique` 完全没有表达(用自定义等高线的文件会有系统性偏差)。这些都记在
|
|
846
|
+
[TODO.md](../../TODO.md) 的 B 节。
|
|
847
|
+
- **形状图层的样式覆盖不完整**:几何与纯色/linear·radial 渐变填充可以矢量化,
|
|
848
|
+
但图案填充、噪声渐变、`angle`/`reflected`/`diamond` 渐变、反相形状(`invert`)
|
|
849
|
+
会报 `vector-unsupported` 并退回位图;形状自己的描边与图层效果里的描边同时启用时,
|
|
850
|
+
叠加顺序尚未处理。
|
|
851
|
+
- **位图图层的效果必须由插件自己烘焙**:`layer.canvas` **不含**图层效果
|
|
852
|
+
(效果只是 PSD 里的参数),所以"直接用 ag-psd 的画布"等于丢掉效果
|
|
853
|
+
(实测 `test-2.psd` 该层区域差 3.31 → 14.81)。
|
|
790
854
|
- **智能对象不展开**:只烘焙外观,不解析内嵌的原始文档。
|
|
791
855
|
|
|
856
|
+
## 待办
|
|
857
|
+
|
|
858
|
+
已知但尚未做的事(保真度优化、合成图模式、CI 等)统一记在
|
|
859
|
+
[`TODO.md`](../../TODO.md),`CODE_REVIEW.md` 里是评审结论与当前状态。
|
|
860
|
+
|
|
792
861
|
## License
|
|
793
862
|
|
|
794
863
|
MIT
|