28 图层
✅ 已验证
建
n = doc.createNode(name, "paintlayer"); parent.addChildNode(n, above)
g = doc.createGroupLayer(name) # 必须用这个, createNode(..., "grouplayer") 拿不到 setPassThroughMode
v = doc.createVectorLayer(name)
doc.createCloneLayer / createFilterLayer / createFillLayer / createTransformMask / createSelectionMask / createColorizeMask
addChildNode(child, None)放到该 parent 子栈的顶部;above=X插在 X 之上;childNodes()返回底→顶- 这些 layer 可以直接
paintLine,不用先写像素再差分 - 嵌套 4 级实测正常;但 group 是独立合成的,每级多存一份 tile,深度别超过 3–4
- reparent(
removeChildNode+addChildNode)可行
canvas.build(spec) 用 L() / G() 声明式建树,列表顺序 = 底→顶,建完回读 childNodes() 与 spec 比对,重名抛错。s.find("04_Color/Skin/Skin_Shadow") / s.find("Skin_Shadow") / by_role / by_label 寻址。
属性
setBlendingMode / setOpacity / setColorLabel / setVisible / setLocked / setAlphaLocked / setInheritAlpha 生效(后两者实测:锁 alpha 后空白处再画一笔像素数不变;inherit alpha 见第 13 章)。
setBlendingMode 完全不校验:传 "xyzzy" 原样读回,按 normal 合成。读回值相等不能证明模式有效。在 base(128,64,192)+top(100,200,80) 上实测确认改变合成结果的 39 个:
multiply screen overlay soft_light soft_light_svg hard_light hard overlay
dodge burn linear_dodge linear_burn vivid_light pin_light
add subtract divide inverse_subtract exclusion negation
darken lighten darker color
hue saturation color luminize lightness
grain_merge grain_extract allanon parallel geometric_mean
reflect glow freeze heat behind greater erase
darker color / hard overlay 中间是空格。linear_light hard_mix difference lighter color copy dissolve alphadarken 没能确认(合成与 normal 相同)。
group 的两个陷阱
passthrough 让 clip 失效(第 13 章)。
不透传时,组内的 multiply 不跟组下面的画面相乘。 09_Post 里放一个 multiply 暗角,纯黑背景被抬成 (6,6,6)。组内合成是先把兄弟层合到一起再整组盖到下面——暗角在跟同组的透明层相乘,得到一团灰。单层探针查不出来(单独测 multiply 叠纯黑是 (0,0,0))。必须在真实的组结构里量。 修法是给这个组 passthrough=True(它没有 clip 层)。
读
| 方法 | 读什么 |
|---|---|
node.pixelData(x,y,w,h) | 该层自己的像素,BGRA |
node.projectionPixelData(x,y,w,h) | 该 node 含子节点的合成 |
doc.projection / s.composite() | 整个文档的合成 |
- group 的
pixelData是空数组(cannot reshape array of size 0),要projectionPixelData - 矢量层读不到
pixelData,只能看合成 - 大画布多图层时一定传 box:2000×3000 一层 24 MB,上百层几个 GB
矢量层
vl = doc.createVectorLayer("v"); parent.addChildNode(vl, None)
vl.addShapesFromSvg('<svg xmlns="http://www.w3.org/2000/svg"><path d="…" fill="#…"/></svg>')
probes/probe_vector.py 5/5:进 composite(跨度与 SVG 完全一致);贝塞尔 C/Q 能渲染;坐标 1:1 像素,8192×12288 上 (7800,11800) 偏移 (+0,+0);.kra 往返保真;单条跨 7700px 正常。
vl.toSvg() 反向导出。node.save() 对矢量层段错误,进程直接死——不需要它,矢量本来就进 composite。
建完之后还能改:shapes() / setZIndex / setTransformation / createGroupShape /
setAntialiased 全部生效。但几何单位是「点 pt」不是像素(300 DPI 下 1 px = 0.24 pt),
拿像素坐标问 shapeAtPosition 会得到 None。详见第 30 章。
15 个矢量层 / 5000 控制点约 12s;addShapesFromSvg 之后 pump(6, 0.05)。
Node 级变换
move / rotateNode / scaleNode / shearNode / cropNode 在 group 里都生效,
clip(inherit alpha)关系跟着走。非破坏的版本是 TransformMask——读它的出厂
toXML() 骨架再改,手写的 transform_params 会被拒。见第 30 章。
transparency mask
挂在目标图层下才生效,挂 rootNode 是孤儿。mask.setSelection(sel) 后精确裁剪。可编辑,比 inherit alpha 更适合交给画师。
.kra
doc.saveAs("x.kra") 正常(5.x 会段错误)。往返保真:层数、inheritAlpha、blend / opacity / label、矢量层。doc.exportImage(path, InfoObject()) 出 PNG。存盘前 doc.setBatchmode(True)。