Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

22 strokes.jsonl 规范

✅ 已验证 · 代码 code/canvas.py_journal_rec() / _JOURNAL_OPS

Session(journal=True) 把落笔与写像素的方法包一层,每调一次写一行 JSON 到 <作品>/strokes.jsonl。它是「这张画是不是真画出来的」的唯一证据,也是回放的输入。

通用字段

每行都有:

字段类型含义
iint序号,从 1 起,连续
tfloat距会话开始的秒数
opstr操作名,下表之一

坐标一律是画布像素(8x 作业就是 8192×12288 的坐标),y 向下。layer 是节点路径(由 build() 建的树)或节点名(否则)。

落笔类(可精确回放)

op字段说明
strokelayer, pts: [[x,y],…], pressure: [p,…]逐段 paintLinepressurepts 等长,0..1;null = 全程 1.0
pathlayer, pts一次 paintPath,quadTo 平滑,全程压力固定
linelayer, pts, width, segments分段变宽的浮点路径(线稿专用)
dablayer, xy: [x,y], pressure一个点
ellipselayer, rect: [x,y,w,h], fill
polygonlayer, pts自动闭合
{"i": 6, "t": 221.045, "op": "stroke", "layer": "BG_Glow",
 "pts": [[0.0, 0.0], [292.32, 0.0], [584.56, 0.0]], "pressure": [0.55, 1.0, 0.55]}
{"i": 26612, "t": 239.116, "op": "path", "layer": "Marks",
 "pts": [[6448.0, 3976.0], [6406.88, 4000.8]]}

换装类

op字段说明
set_presetpreset, size换 brush preset(带 pump)
set_colorrgb: [r,g,b]前景色(带 pump)
brushrgb / size / opacity / flow / preset快路径,只记真正传了的字段,一条约 40 字节
{"i": 4, "t": 221.043, "op": "brush", "preset": "b) Airbrush Soft"}
{"i": 5, "t": 221.044, "op": "brush", "rgb": [0, 0, 0], "size": 584.95}

落笔的颜色和笔径就是它前面最近一条 brush / set_color / set_preset 设的。size 是传给 setBrushSize 的值,不是画出来的宽度第 21 章的系数)。

写像素类(只记指纹,不记像素)

op字段说明
set_pixelslayer, box: [x,y,w,h], shape, mean: [r,g,b,a], sha1写了什么形状的数组、均值、前 12 位 sha1
groundlayer, box, rgb铺底色
eraselayer, box清 alpha
filterlayer, name, params应用 filter
{"i": 1, "t": 2.426, "op": "set_pixels", "layer": "BG_Base", "box": [],
 "shape": [12288, 8192, 4], "mean": [0.0, 0.0, 0.0, 255.0], "sha1": "6629f2f7f361"}

box: [] 表示整幅。这几类不可精确回放——回放时跳过并报告,调用方要自己把数据部分重跑。

缓冲

逐条 flush 在十万笔量级是纯浪费;但进程挂掉时日志是唯一剩下的东西。折中:每 500 条落一次盘s.flush() / s.stage() / s.final() 时也落盘。进程被 OOM 杀掉时最多丢 500 条。

规模

8 万笔的作业写 209,004 行(每笔约 2.6 行:换装 + 落笔)、18 MB。

一个已知的局限 🧪

layer 字段在没走 build() 的作业里是 node.name()。第五版的树里 73 个色阶组各有一个 Soft 和一个 Marks名字不唯一"layer": "Marks" 无法定位回具体哪一层。回放路由会失败(第 24 章)。修法是让 _node_path()index 为空时递归拼全路径,没做。