@pixerate/editor 0.115.0 → 0.116.0

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.
Files changed (117) hide show
  1. package/THIRD_PARTY_NOTICES.md +3 -0
  2. package/dist/animation-editor/index.cjs +54 -54
  3. package/dist/animation-editor/index.d.cts +2 -2
  4. package/dist/animation-editor/index.d.ts +2 -2
  5. package/dist/animation-editor/index.js +2 -2
  6. package/dist/{chunk-DFQEX3AM.cjs → chunk-2UT4GXYA.cjs} +133 -8
  7. package/dist/chunk-2UT4GXYA.cjs.map +1 -0
  8. package/dist/{chunk-VXR7XWMF.js → chunk-7LNZAWSJ.js} +437 -41
  9. package/dist/chunk-7LNZAWSJ.js.map +1 -0
  10. package/dist/{chunk-LKCYANMW.js → chunk-ARQ7PQ6Q.js} +129 -4
  11. package/dist/chunk-ARQ7PQ6Q.js.map +1 -0
  12. package/dist/chunk-COAMRKVI.cjs +159 -0
  13. package/dist/chunk-COAMRKVI.cjs.map +1 -0
  14. package/dist/{chunk-C6C5PDKU.js → chunk-D53KSJUV.js} +3 -322
  15. package/dist/chunk-D53KSJUV.js.map +1 -0
  16. package/dist/chunk-D53VQGEJ.js +3262 -0
  17. package/dist/chunk-D53VQGEJ.js.map +1 -0
  18. package/dist/chunk-EJVDBITD.cjs +501 -0
  19. package/dist/chunk-EJVDBITD.cjs.map +1 -0
  20. package/dist/{chunk-LPLCWZTM.cjs → chunk-FODKPD44.cjs} +555 -159
  21. package/dist/chunk-FODKPD44.cjs.map +1 -0
  22. package/dist/chunk-HOCPSFGA.cjs +3262 -0
  23. package/dist/chunk-HOCPSFGA.cjs.map +1 -0
  24. package/dist/chunk-IPFRWILU.js +1908 -0
  25. package/dist/chunk-IPFRWILU.js.map +1 -0
  26. package/dist/{chunk-FV5AXTSF.cjs → chunk-JSSBHMMU.cjs} +36 -188
  27. package/dist/chunk-JSSBHMMU.cjs.map +1 -0
  28. package/dist/chunk-LF4WOZXZ.js +159 -0
  29. package/dist/chunk-LF4WOZXZ.js.map +1 -0
  30. package/dist/{chunk-26PGXHY7.cjs → chunk-M7O4BJRH.cjs} +36 -36
  31. package/dist/{chunk-26PGXHY7.cjs.map → chunk-M7O4BJRH.cjs.map} +1 -1
  32. package/dist/chunk-N3467VD6.js +501 -0
  33. package/dist/chunk-N3467VD6.js.map +1 -0
  34. package/dist/{chunk-ST7E3NEE.cjs → chunk-PAOWHJ5O.cjs} +18 -337
  35. package/dist/chunk-PAOWHJ5O.cjs.map +1 -0
  36. package/dist/{chunk-XICA4PVO.js → chunk-SEBYNBHW.js} +10 -10
  37. package/dist/chunk-SMJGE7HM.cjs +1908 -0
  38. package/dist/chunk-SMJGE7HM.cjs.map +1 -0
  39. package/dist/{chunk-MMVHBKMM.js → chunk-T2P5TIZ6.js} +2 -2
  40. package/dist/{chunk-FGW5OWJ4.js → chunk-VJUML33I.js} +4 -156
  41. package/dist/chunk-VJUML33I.js.map +1 -0
  42. package/dist/{chunk-I7FQBWMQ.cjs → chunk-ZYZGEILO.cjs} +239 -239
  43. package/dist/{chunk-I7FQBWMQ.cjs.map → chunk-ZYZGEILO.cjs.map} +1 -1
  44. package/dist/export/index.cjs +4 -2
  45. package/dist/export/index.cjs.map +1 -1
  46. package/dist/export/index.js +5 -3
  47. package/dist/{export-BJE8T0YA.d.cts → export-BXxSGBCq.d.cts} +2 -2
  48. package/dist/{export-Con3UKkm.d.ts → export-Dm44YUvS.d.ts} +2 -2
  49. package/dist/export-Dv0-ZVrV.d.cts +501 -0
  50. package/dist/export-Dv0-ZVrV.d.ts +501 -0
  51. package/dist/{retouch-Do6tBs2H.d.ts → flow-BMtHAmg4.d.ts} +561 -2
  52. package/dist/{retouch-Bxkuc0KH.d.cts → flow-COCB42TP.d.cts} +561 -2
  53. package/dist/image-editor/index.cjs +957 -795
  54. package/dist/image-editor/index.cjs.map +1 -1
  55. package/dist/image-editor/index.d.cts +6 -6
  56. package/dist/image-editor/index.d.ts +6 -6
  57. package/dist/image-editor/index.js +180 -18
  58. package/dist/image-editor/index.js.map +1 -1
  59. package/dist/index.cjs +4 -2
  60. package/dist/index.cjs.map +1 -1
  61. package/dist/index.js +5 -3
  62. package/dist/index.js.map +1 -1
  63. package/dist/kernel-wasm-WYCGNZR4.js +10 -0
  64. package/dist/kernel-wasm-WYCGNZR4.js.map +1 -0
  65. package/dist/kernel-wasm-YPVAEMVN.cjs +10 -0
  66. package/dist/kernel-wasm-YPVAEMVN.cjs.map +1 -0
  67. package/dist/paint/index.cjs +165 -3
  68. package/dist/paint/index.cjs.map +1 -1
  69. package/dist/paint/index.d.cts +225 -3
  70. package/dist/paint/index.d.ts +225 -3
  71. package/dist/paint/index.js +166 -4
  72. package/dist/paint-editor/index.cjs +4690 -845
  73. package/dist/paint-editor/index.cjs.map +1 -1
  74. package/dist/paint-editor/index.d.cts +1525 -277
  75. package/dist/paint-editor/index.d.ts +1525 -277
  76. package/dist/paint-editor/index.js +4560 -715
  77. package/dist/paint-editor/index.js.map +1 -1
  78. package/dist/raster/index.cjs +4 -3
  79. package/dist/raster/index.cjs.map +1 -1
  80. package/dist/raster/index.js +10 -9
  81. package/dist/{svg-BnRj0q8i.d.cts → svg-CVdFc80-.d.cts} +2 -2
  82. package/dist/{svg-CmmBFfGT.d.ts → svg-DlEuhwoX.d.ts} +2 -2
  83. package/dist/{types-1SUQKDAw.d.ts → types-CDLGhAZp.d.ts} +40 -2
  84. package/dist/{types-yINF17Ta.d.cts → types-Tfly4Aya.d.cts} +40 -2
  85. package/dist/vector/index.cjs +1897 -975
  86. package/dist/vector/index.cjs.map +1 -1
  87. package/dist/vector/index.d.cts +292 -32
  88. package/dist/vector/index.d.ts +292 -32
  89. package/dist/vector/index.js +928 -6
  90. package/dist/vector/index.js.map +1 -1
  91. package/dist/video-editor/index.cjs +502 -2165
  92. package/dist/video-editor/index.cjs.map +1 -1
  93. package/dist/video-editor/index.d.cts +3 -501
  94. package/dist/video-editor/index.d.ts +3 -501
  95. package/dist/video-editor/index.js +151 -1814
  96. package/dist/video-editor/index.js.map +1 -1
  97. package/package.json +1 -1
  98. package/skills/pixerate-image-editor/references/photoshop-files.md +7 -3
  99. package/skills/pixerate-vector/SKILL.md +3 -0
  100. package/dist/chunk-C6C5PDKU.js.map +0 -1
  101. package/dist/chunk-DFQEX3AM.cjs.map +0 -1
  102. package/dist/chunk-FGW5OWJ4.js.map +0 -1
  103. package/dist/chunk-FV5AXTSF.cjs.map +0 -1
  104. package/dist/chunk-GX332W2C.js +0 -181
  105. package/dist/chunk-GX332W2C.js.map +0 -1
  106. package/dist/chunk-LKCYANMW.js.map +0 -1
  107. package/dist/chunk-LPLCWZTM.cjs.map +0 -1
  108. package/dist/chunk-MUUXNRU4.cjs +0 -181
  109. package/dist/chunk-MUUXNRU4.cjs.map +0 -1
  110. package/dist/chunk-ST7E3NEE.cjs.map +0 -1
  111. package/dist/chunk-TCKIXI46.cjs +0 -1136
  112. package/dist/chunk-TCKIXI46.cjs.map +0 -1
  113. package/dist/chunk-UBIXVXPR.js +0 -1136
  114. package/dist/chunk-UBIXVXPR.js.map +0 -1
  115. package/dist/chunk-VXR7XWMF.js.map +0 -1
  116. /package/dist/{chunk-XICA4PVO.js.map → chunk-SEBYNBHW.js.map} +0 -0
  117. /package/dist/{chunk-MMVHBKMM.js.map → chunk-T2P5TIZ6.js.map} +0 -0
@@ -1,1136 +0,0 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4; var _class5; var _class6; var _class7;
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
- var _chunkTFOPHZ3Ucjs = require('./chunk-TFOPHZ3U.cjs');
14
-
15
- // src/paint/brush.ts
16
- var DEFAULT_BRUSH = {
17
- size: 20,
18
- hardness: 1,
19
- spacing: 0.1,
20
- angle: 0,
21
- roundness: 1,
22
- opacity: 1,
23
- flow: 1,
24
- smoothing: 0,
25
- pressureSize: true,
26
- pressureOpacity: false,
27
- blend: "normal"
28
- };
29
- var MAX_BRUSH_SIZE = 2500;
30
- function normalizeBrush(raw = {}) {
31
- const num = (v, lo, hi, d) => typeof v === "number" && Number.isFinite(v) ? Math.min(hi, Math.max(lo, v)) : d;
32
- return {
33
- size: num(raw.size, 1, MAX_BRUSH_SIZE, DEFAULT_BRUSH.size),
34
- hardness: num(raw.hardness, 0, 1, DEFAULT_BRUSH.hardness),
35
- spacing: num(raw.spacing, 0.01, 10, DEFAULT_BRUSH.spacing),
36
- angle: num(raw.angle, -360, 360, DEFAULT_BRUSH.angle),
37
- roundness: num(raw.roundness, 0.01, 1, DEFAULT_BRUSH.roundness),
38
- opacity: num(raw.opacity, 0, 1, DEFAULT_BRUSH.opacity),
39
- flow: num(raw.flow, 0, 1, DEFAULT_BRUSH.flow),
40
- smoothing: num(raw.smoothing, 0, 0.95, DEFAULT_BRUSH.smoothing),
41
- pressureSize: typeof raw.pressureSize === "boolean" ? raw.pressureSize : DEFAULT_BRUSH.pressureSize,
42
- pressureOpacity: typeof raw.pressureOpacity === "boolean" ? raw.pressureOpacity : DEFAULT_BRUSH.pressureOpacity,
43
- blend: _nullishCoalesce(raw.blend, () => ( "normal"))
44
- };
45
- }
46
- var TIP_SHAPE = [
47
- [0, 0.664],
48
- [0.14, 0.58],
49
- [0.28, 0.5],
50
- [0.4, 0.44],
51
- [0.52, 0.36],
52
- [0.63, 0.29],
53
- [0.7, 0.24],
54
- [0.78, 0.19],
55
- [0.84, 0.15],
56
- [0.89, 0.11],
57
- [1, 0]
58
- ];
59
- var TIP_EDGE_PX = 1.2;
60
- var SMALL_TIP_RADIUS = 3;
61
- var SUBPIXEL = [-0.375, -0.125, 0.125, 0.375];
62
- function tipShape(radius, hardness) {
63
- const h = (Number.isNaN(hardness) ? 0 : Math.min(1, Math.max(0, hardness))) * 10;
64
- const i = Math.min(9, Math.floor(h));
65
- const t = h - i;
66
- const a = TIP_SHAPE[i];
67
- const b = TIP_SHAPE[i + 1];
68
- const r0 = a[0] + (b[0] - a[0]) * t;
69
- const s = a[1] + (b[1] - a[1]) * t;
70
- const r = Number.isFinite(radius) ? Math.max(0, radius) : 0;
71
- const edge = Math.max(0.25, Math.min(TIP_EDGE_PX, 0.3 * r));
72
- return [Math.max(0, Math.min(r0 * r, r - edge)), Math.max(1e-3, s * r, edge)];
73
- }
74
- function softExp(u) {
75
- let g = Math.min(1, Math.max(0, 1 - u / 64));
76
- for (let k = 0; k < 6; k++) g *= g;
77
- return g;
78
- }
79
- function tipFalloff(d, radius, hardness) {
80
- const [r0, s] = tipShape(radius, hardness);
81
- if (d <= r0) return 1;
82
- const x = (d - r0) / s;
83
- return softExp(x * x);
84
- }
85
- function tipReach(radius, hardness) {
86
- const [r0, s] = tipShape(radius, hardness);
87
- return r0 + 2.6 * s;
88
- }
89
- function dabCoverage(d, radius, hardness) {
90
- if (Number.isNaN(d) || d >= tipReach(radius, hardness) + 0.5) return 0;
91
- return tipFalloff(d, radius, hardness);
92
- }
93
- function smoothPoints(points, amount) {
94
- const a = 1 - Math.min(0.95, Math.max(0, amount));
95
- if (a >= 1 || points.length < 3) return points.slice();
96
- const out = [];
97
- let cur = null;
98
- for (const p of points) {
99
- const n = cur ? { ...p, x: cur.x + (p.x - cur.x) * a, y: cur.y + (p.y - cur.y) * a } : p;
100
- out.push(n);
101
- cur = n;
102
- }
103
- out[out.length - 1] = points[points.length - 1];
104
- return out;
105
- }
106
- var pressureOf = (p) => typeof p.pressure === "number" && Number.isFinite(p.pressure) ? Math.min(1, Math.max(0, p.pressure)) : 1;
107
- var DabWalker = (_class = class {
108
- constructor(brush) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this);
109
- this.brush = brush;
110
- }
111
-
112
- __init() {this.last = null}
113
- __init2() {this.nextAt = 0}
114
- __init3() {this.pendingFirst = null}
115
- diameter(p) {
116
- return this.brush.pressureSize ? this.brush.size * pressureOf(p) : this.brush.size;
117
- }
118
- stepLen(p) {
119
- return Math.max(0.5, Math.max(1, this.diameter(p)) * Math.max(0.01, this.brush.spacing));
120
- }
121
- dab(p) {
122
- const b = this.brush;
123
- return {
124
- x: p.x,
125
- y: p.y,
126
- radius: Math.max(0.5, this.diameter(p) / 2),
127
- alpha: Math.min(1, Math.max(0, b.flow)),
128
- opacity: b.pressureOpacity ? pressureOf(p) : 1,
129
- angle: b.angle * Math.PI / 180,
130
- roundness: Math.min(1, Math.max(0.01, b.roundness))
131
- };
132
- }
133
- push(p, out) {
134
- const a = this.last;
135
- if (!a) {
136
- this.last = p;
137
- this.pendingFirst = p;
138
- this.nextAt = this.stepLen(p);
139
- return;
140
- }
141
- if (this.pendingFirst) {
142
- out.push(this.dab(this.pendingFirst));
143
- this.pendingFirst = null;
144
- }
145
- const dx = p.x - a.x;
146
- const dy = p.y - a.y;
147
- const len = Math.hypot(dx, dy);
148
- if (len > 1e-9) {
149
- while (this.nextAt <= len + 1e-9) {
150
- const f = Math.min(1, this.nextAt / len);
151
- const q = {
152
- x: a.x + dx * f,
153
- y: a.y + dy * f,
154
- pressure: pressureOf(a) + (pressureOf(p) - pressureOf(a)) * f
155
- };
156
- out.push(this.dab(q));
157
- this.nextAt += this.stepLen(q);
158
- }
159
- this.nextAt -= len;
160
- }
161
- this.last = p;
162
- }
163
- finish(out) {
164
- if (this.pendingFirst) {
165
- out.push(this.dab(this.pendingFirst));
166
- this.pendingFirst = null;
167
- }
168
- }
169
- }, _class);
170
- function walkDabs(points, brush) {
171
- const w = new DabWalker(brush);
172
- const out = [];
173
- for (const p of smoothPoints(points, brush.smoothing)) w.push(p, out);
174
- w.finish(out);
175
- return out;
176
- }
177
- function dabRect(d, hardness) {
178
- const ro = Math.min(1, Math.max(0.5 / d.radius, d.roundness));
179
- const rm = Math.max(0.5, d.radius * ro);
180
- const r = Math.max(rm, tipReach(rm, hardness)) / ro + 1.5;
181
- const x0 = Math.floor(d.x - r);
182
- const y0 = Math.floor(d.y - r);
183
- return { x: x0, y: y0, width: Math.ceil(d.x + r) - x0, height: Math.ceil(d.y + r) - y0 };
184
- }
185
- function rasterizeDab(d, hardness, rect, out) {
186
- const w = rect.width;
187
- const h = rect.height;
188
- out.fill(0, 0, w * h);
189
- const r = d.radius;
190
- const ro = Math.min(1, Math.max(0.5 / r, d.roundness));
191
- const rm = Math.max(0.5, r * ro);
192
- const reach = Math.max(rm, tipReach(rm, hardness));
193
- const sn = Math.sin(d.angle);
194
- const cs = Math.cos(d.angle);
195
- const toTip = (dx, dy) => {
196
- const ux = dx;
197
- const uy = -dy;
198
- return [ux * cs + uy * sn, -ux * sn + uy * cs];
199
- };
200
- const small = rm < SMALL_TIP_RADIUS;
201
- const reach2 = (reach + (small ? 0.75 : 0.5)) ** 2;
202
- for (let yy = 0; yy < h; yy++) {
203
- const dy = rect.y + yy + 0.5 - d.y;
204
- for (let xx = 0; xx < w; xx++) {
205
- const dx = rect.x + xx + 0.5 - d.x;
206
- const [u, v] = toTip(dx, dy);
207
- const d2 = (u * ro) ** 2 + v * v;
208
- if (d2 >= reach2) continue;
209
- let val;
210
- if (small) {
211
- let sum = 0;
212
- for (const sy of SUBPIXEL) {
213
- for (const sx of SUBPIXEL) {
214
- const [su, sv] = toTip(dx + sx, dy + sy);
215
- sum += tipFalloff(Math.sqrt((su * ro) ** 2 + sv * sv), rm, hardness);
216
- }
217
- }
218
- val = sum / 16;
219
- } else {
220
- val = dabCoverage(Math.sqrt(d2), rm, hardness);
221
- }
222
- if (val > 0) out[yy * w + xx] = val * d.alpha;
223
- }
224
- }
225
- }
226
- var TILE_PIXELS = _chunkTFOPHZ3Ucjs.TILE * _chunkTFOPHZ3Ucjs.TILE;
227
- var CoverageMap = (_class2 = class {constructor() { _class2.prototype.__init4.call(this);_class2.prototype.__init5.call(this);_class2.prototype.__init6.call(this); }
228
- __init4() {this.tiles = /* @__PURE__ */ new Map()}
229
- __init5() {this.bounds = null}
230
- __init6() {this.dirty = /* @__PURE__ */ new Set()}
231
- get(x, y) {
232
- const tx = Math.floor(x / _chunkTFOPHZ3Ucjs.TILE);
233
- const ty = Math.floor(y / _chunkTFOPHZ3Ucjs.TILE);
234
- const t = this.tiles.get(_chunkTFOPHZ3Ucjs.tileKey.call(void 0, tx, ty));
235
- return t ? t[(y - ty * _chunkTFOPHZ3Ucjs.TILE) * _chunkTFOPHZ3Ucjs.TILE + (x - tx * _chunkTFOPHZ3Ucjs.TILE)] : 0;
236
- }
237
- /** Builds up `vals` (over `rect`) with flow towards `ceil`: `c ← c + v·(ceil − c)`. */
238
- accumulate(rect, vals, ceil) {
239
- if (rect.width <= 0 || rect.height <= 0) return;
240
- const w = rect.width;
241
- const tx0 = Math.floor(rect.x / _chunkTFOPHZ3Ucjs.TILE);
242
- const ty0 = Math.floor(rect.y / _chunkTFOPHZ3Ucjs.TILE);
243
- const tx1 = Math.floor((rect.x + rect.width - 1) / _chunkTFOPHZ3Ucjs.TILE);
244
- const ty1 = Math.floor((rect.y + rect.height - 1) / _chunkTFOPHZ3Ucjs.TILE);
245
- let touched = false;
246
- for (let ty = ty0; ty <= ty1; ty++) {
247
- for (let tx = tx0; tx <= tx1; tx++) {
248
- const x0 = Math.max(rect.x, tx * _chunkTFOPHZ3Ucjs.TILE);
249
- const y0 = Math.max(rect.y, ty * _chunkTFOPHZ3Ucjs.TILE);
250
- const x1 = Math.min(rect.x + rect.width, tx * _chunkTFOPHZ3Ucjs.TILE + _chunkTFOPHZ3Ucjs.TILE);
251
- const y1 = Math.min(rect.y + rect.height, ty * _chunkTFOPHZ3Ucjs.TILE + _chunkTFOPHZ3Ucjs.TILE);
252
- let tile;
253
- for (let y = y0; y < y1; y++) {
254
- const row = (y - rect.y) * w;
255
- const trow = (y - ty * _chunkTFOPHZ3Ucjs.TILE) * _chunkTFOPHZ3Ucjs.TILE;
256
- for (let x = x0; x < x1; x++) {
257
- const v = vals[row + (x - rect.x)];
258
- if (v <= 0) continue;
259
- if (!tile) {
260
- const key = _chunkTFOPHZ3Ucjs.tileKey.call(void 0, tx, ty);
261
- tile = this.tiles.get(key);
262
- if (!tile) {
263
- tile = new Float32Array(TILE_PIXELS);
264
- this.tiles.set(key, tile);
265
- }
266
- this.dirty.add(key);
267
- touched = true;
268
- }
269
- const ti = trow + (x - tx * _chunkTFOPHZ3Ucjs.TILE);
270
- const c = tile[ti];
271
- if (ceil > c) tile[ti] = c + v * (ceil - c);
272
- }
273
- }
274
- }
275
- }
276
- if (touched) this.bounds = unionRect(this.bounds, rect);
277
- }
278
- /** Tiles changed since the last call. */
279
- takeDirty() {
280
- const out = [...this.dirty];
281
- this.dirty.clear();
282
- return out;
283
- }
284
- }, _class2);
285
- function unionRect(a, b) {
286
- if (!a) return { ...b };
287
- const x = Math.min(a.x, b.x);
288
- const y = Math.min(a.y, b.y);
289
- return { x, y, width: Math.max(a.x + a.width, b.x + b.width) - x, height: Math.max(a.y + a.height, b.y + b.height) - y };
290
- }
291
- var StrokeCoverage = (_class3 = class {
292
- constructor(brush) {;_class3.prototype.__init7.call(this);_class3.prototype.__init8.call(this);_class3.prototype.__init9.call(this);_class3.prototype.__init10.call(this);
293
- this.brush = brush;
294
- this.walker = new DabWalker(brush);
295
- this.smoothing = brush.smoothing;
296
- }
297
-
298
- __init7() {this.coverage = new CoverageMap()}
299
-
300
-
301
- __init8() {this.smoothPos = null}
302
- __init9() {this.buf = new Float32Array(0)}
303
- __init10() {this.dabCount = 0}
304
- /** Feeds input points; returns the document rectangles the new dabs touched. */
305
- push(points) {
306
- const dabs = [];
307
- for (const p of points) this.walker.push(this.smooth(p), dabs);
308
- return this.paint(dabs);
309
- }
310
- /** Ends the stroke (a single click still paints one dab). */
311
- finish(last) {
312
- const dabs = [];
313
- if (last && this.smoothPos && (this.smoothPos.x !== last.x || this.smoothPos.y !== last.y)) this.walker.push(last, dabs);
314
- this.walker.finish(dabs);
315
- return this.paint(dabs);
316
- }
317
- smooth(p) {
318
- const a = 1 - Math.min(0.95, Math.max(0, this.smoothing));
319
- const cur = this.smoothPos;
320
- const n = cur && a < 1 ? { ...p, x: cur.x + (p.x - cur.x) * a, y: cur.y + (p.y - cur.y) * a } : p;
321
- this.smoothPos = n;
322
- return n;
323
- }
324
- paint(dabs) {
325
- const rects = [];
326
- for (const d of dabs) {
327
- const rect = dabRect(d, this.brush.hardness);
328
- const n = rect.width * rect.height;
329
- if (this.buf.length < n) this.buf = new Float32Array(n);
330
- const vals = this.buf.subarray(0, n);
331
- rasterizeDab(d, this.brush.hardness, rect, vals);
332
- this.coverage.accumulate(rect, vals, d.opacity);
333
- rects.push(rect);
334
- this.dabCount++;
335
- }
336
- return rects;
337
- }
338
- }, _class3);
339
- function applyStrokeToTile(coverage, tileData, channels, tx, ty, s, options = {}) {
340
- const out = options.into ? new Uint8ClampedArray(options.into) : new Uint8ClampedArray(tileData);
341
- const ox = tx * _chunkTFOPHZ3Ucjs.TILE + s.offset.x;
342
- const oy = ty * _chunkTFOPHZ3Ucjs.TILE + s.offset.y;
343
- let x0 = 0;
344
- let y0 = 0;
345
- let x1 = _chunkTFOPHZ3Ucjs.TILE;
346
- let y1 = _chunkTFOPHZ3Ucjs.TILE;
347
- if (options.region) {
348
- const r = options.region;
349
- x0 = Math.max(0, Math.floor(r.x) - ox);
350
- y0 = Math.max(0, Math.floor(r.y) - oy);
351
- x1 = Math.min(_chunkTFOPHZ3Ucjs.TILE, Math.ceil(r.x + r.width) - ox);
352
- y1 = Math.min(_chunkTFOPHZ3Ucjs.TILE, Math.ceil(r.y + r.height) - oy);
353
- if (x1 <= x0 || y1 <= y0) return out;
354
- if (options.into) {
355
- for (let y = y0; y < y1; y++) out.set(tileData.subarray((y * _chunkTFOPHZ3Ucjs.TILE + x0) * channels, (y * _chunkTFOPHZ3Ucjs.TILE + x1) * channels), (y * _chunkTFOPHZ3Ucjs.TILE + x0) * channels);
356
- }
357
- }
358
- const sel = s.selection;
359
- const cb = [0, 0, 0, 0];
360
- const cs = [s.color[0] / 255, s.color[1] / 255, s.color[2] / 255, s.color[3] / 255];
361
- const bg = [s.background[0] / 255, s.background[1] / 255, s.background[2] / 255, s.background[3] / 255];
362
- const aligned = s.offset.x % _chunkTFOPHZ3Ucjs.TILE === 0 && s.offset.y % _chunkTFOPHZ3Ucjs.TILE === 0;
363
- const covTile = aligned ? coverage.tiles.get(_chunkTFOPHZ3Ucjs.tileKey.call(void 0, Math.floor(ox / _chunkTFOPHZ3Ucjs.TILE), Math.floor(oy / _chunkTFOPHZ3Ucjs.TILE))) : void 0;
364
- if (aligned && !covTile) return out;
365
- for (let y = y0; y < y1; y++) {
366
- const dy = oy + y;
367
- for (let x = x0; x < x1; x++) {
368
- const dx = ox + x;
369
- const c = covTile ? covTile[y * _chunkTFOPHZ3Ucjs.TILE + x] : coverage.get(dx, dy);
370
- if (c <= 0) continue;
371
- let k = c * s.opacity;
372
- if (sel) {
373
- if (dx < 0 || dy < 0 || dx >= sel.width || dy >= sel.height) continue;
374
- k *= sel.data[dy * sel.width + dx] / 255;
375
- }
376
- if (k > 1) k = 1;
377
- if (k <= 0) continue;
378
- const p = y * _chunkTFOPHZ3Ucjs.TILE + x;
379
- if (channels === 1) {
380
- const target = s.mode === "erase" ? s.background[0] : s.color[0];
381
- out[p] = Math.round(out[p] + (target - out[p]) * k);
382
- continue;
383
- }
384
- const i = p * 4;
385
- if (s.mode === "erase" && !s.lockTransparency) {
386
- out[i + 3] = Math.round(out[i + 3] * (1 - k));
387
- continue;
388
- }
389
- if (s.lockTransparency && out[i + 3] === 0) continue;
390
- const src = s.mode === "erase" ? bg : cs;
391
- if (s.blend === "pigment") {
392
- const bytes = s.mode === "erase" ? s.background : s.color;
393
- const as = src[3] * k;
394
- if (!(as > 0)) continue;
395
- const ao = as + out[i + 3] / 255 * (1 - as);
396
- _chunkTFOPHZ3Ucjs.mixPigment8.call(void 0, out[i], out[i + 1], out[i + 2], bytes[0], bytes[1], bytes[2], as / ao, cb);
397
- out[i] = Math.round(cb[0] * 255);
398
- out[i + 1] = Math.round(cb[1] * 255);
399
- out[i + 2] = Math.round(cb[2] * 255);
400
- if (!s.lockTransparency) out[i + 3] = Math.round(ao * 255);
401
- continue;
402
- }
403
- for (let ch = 0; ch < 4; ch++) cb[ch] = out[i + ch] / 255;
404
- const o = _chunkTFOPHZ3Ucjs.blendPixel.call(void 0, s.blend, cb, src, k);
405
- out[i] = Math.round(o[0] * 255);
406
- out[i + 1] = Math.round(o[1] * 255);
407
- out[i + 2] = Math.round(o[2] * 255);
408
- if (!s.lockTransparency) out[i + 3] = Math.round(o[3] * 255);
409
- }
410
- }
411
- return out;
412
- }
413
- function coverageTileCoord(key) {
414
- return _chunkTFOPHZ3Ucjs.tileCoord.call(void 0, key);
415
- }
416
-
417
- // src/paint/exchange.ts
418
- var MIXING_MODELS = ["rgb", "pigment"];
419
- var EMPTY_MIXER_LOAD = { reservoir: null, amount: 0, pickup: null };
420
- var MIXER_PICKUP_RATE = 0.25;
421
- var MIXER_DRAIN = 0.08;
422
- function exchangeRates(pickup, mix, load, mixing) {
423
- return { pickup: MIXER_PICKUP_RATE * pickup, mix: mix * pickup, drain: MIXER_DRAIN * (1 - load), mixing };
424
- }
425
- var PaintExchange = (_class4 = class {
426
- constructor(rates, load) {;_class4.prototype.__init11.call(this);
427
- this.rates = rates;
428
- this.reservoir = load.reservoir ? [load.reservoir[0], load.reservoir[1], load.reservoir[2]] : null;
429
- this.amount = this.reservoir ? Math.min(1, Math.max(0, load.amount)) : 0;
430
- this.well = load.pickup ? [load.pickup[0], load.pickup[1], load.pickup[2]] : null;
431
- this.pig = rates.mixing === "pigment" ? { res: _chunkTFOPHZ3Ucjs.createPigment.call(void 0, _nullishCoalesce(this.reservoir, () => ( [0, 0, 0]))), well: _chunkTFOPHZ3Ucjs.createPigment.call(void 0, _nullishCoalesce(this.well, () => ( [0, 0, 0]))), paint: _chunkTFOPHZ3Ucjs.createPigment.call(void 0, [0, 0, 0]), canvas: _chunkTFOPHZ3Ucjs.createPigment.call(void 0, [0, 0, 0]) } : null;
432
- }
433
-
434
-
435
-
436
-
437
-
438
- __init11() {this.out = [0, 0, 0]}
439
- /** What the brush carries now. */
440
- get load() {
441
- return { reservoir: this.reservoir ? [...this.reservoir] : null, amount: this.amount, pickup: this.well ? [...this.well] : null };
442
- }
443
- /** The colour picked up so far, or `null`. */
444
- get pickup() {
445
- return this.well;
446
- }
447
- /** The prepared pigment of the last `paint` colour (pigment mixing only), for `deposit`. */
448
- get paintPigment() {
449
- return _nullishCoalesce(_optionalChain([this, 'access', _ => _.pig, 'optionalAccess', _2 => _2.paint]), () => ( null));
450
- }
451
- /** Recolours the reservoir without refilling it (a multi-coloured brush, per dab). */
452
- setReservoirColor(r, g, b) {
453
- if (!this.reservoir) {
454
- this.reservoir = [r, g, b];
455
- this.amount = 1;
456
- } else {
457
- this.reservoir[0] = r;
458
- this.reservoir[1] = g;
459
- this.reservoir[2] = b;
460
- }
461
- if (this.pig) _chunkTFOPHZ3Ucjs.setPigmentColor.call(void 0, this.pig.res, r, g, b);
462
- }
463
- /** `a` mixed `t` of the way to `b` into `this.out`, by the mixing model. */
464
- mix(a, pa, b, pb, t) {
465
- const o = this.out;
466
- if (pa && pb) _chunkTFOPHZ3Ucjs.lerpPigmentInto.call(void 0, pa, pb, t, o, 0);
467
- else for (let c = 0; c < 3; c++) o[c] = a[c] + (b[c] - a[c]) * t;
468
- return o;
469
- }
470
- /** `a` mixed `t` of the way to `b` (sRGB 0..1) by the mixing model, into `out`. */
471
- mixColors(a, b, t, out) {
472
- if (this.pig) {
473
- _chunkTFOPHZ3Ucjs.setPigmentColor.call(void 0, this.pig.canvas, a[0], a[1], a[2]);
474
- _chunkTFOPHZ3Ucjs.setPigmentColor.call(void 0, this.pig.paint, b[0], b[1], b[2]);
475
- _chunkTFOPHZ3Ucjs.lerpPigmentInto.call(void 0, this.pig.canvas, this.pig.paint, t, out, 0);
476
- } else for (let c = 0; c < 3; c++) out[c] = a[c] + (b[c] - a[c]) * t;
477
- return out;
478
- }
479
- /** 1. Pick-up: the well moves towards the sampled colour (or takes it, when clean). */
480
- pickUp(sample) {
481
- if (!sample || !(this.rates.pickup > 0)) return;
482
- const pig = this.pig;
483
- if (!this.well) this.well = [sample.rgb[0], sample.rgb[1], sample.rgb[2]];
484
- else {
485
- if (pig) _chunkTFOPHZ3Ucjs.setPigmentColor.call(void 0, pig.canvas, sample.rgb[0], sample.rgb[1], sample.rgb[2]);
486
- const o = this.mix(this.well, _nullishCoalesce(_optionalChain([pig, 'optionalAccess', _3 => _3.well]), () => ( null)), sample.rgb, _nullishCoalesce(_optionalChain([pig, 'optionalAccess', _4 => _4.canvas]), () => ( null)), this.rates.pickup * sample.contact);
487
- this.well = [o[0], o[1], o[2]];
488
- }
489
- if (pig) _chunkTFOPHZ3Ucjs.setPigmentColor.call(void 0, pig.well, this.well[0], this.well[1], this.well[2]);
490
- }
491
- /**
492
- * 2. The dab's paint: the reservoir mixed with the well, written to `out`. Returns the total
493
- * weight (≤ 0: nothing to lay down); deposit `min(1, weight)` of it. With pigment mixing,
494
- * `paintPigment` is the result's pigment afterwards.
495
- */
496
- paint(out) {
497
- const res = this.reservoir;
498
- const wr = res ? this.amount * (1 - this.rates.mix) : 0;
499
- const wp = this.well ? this.rates.mix : 0;
500
- const total = wr + wp;
501
- if (!(total > 1e-6)) return 0;
502
- const pig = this.pig;
503
- if (res && this.well) {
504
- const m = this.mix(res, _nullishCoalesce(_optionalChain([pig, 'optionalAccess', _5 => _5.res]), () => ( null)), this.well, _nullishCoalesce(_optionalChain([pig, 'optionalAccess', _6 => _6.well]), () => ( null)), wp / total);
505
- out[0] = m[0];
506
- out[1] = m[1];
507
- out[2] = m[2];
508
- } else {
509
- const c = _nullishCoalesce(res, () => ( this.well));
510
- out[0] = c[0];
511
- out[1] = c[1];
512
- out[2] = c[2];
513
- }
514
- if (pig) _chunkTFOPHZ3Ucjs.setPigmentColor.call(void 0, pig.paint, out[0], out[1], out[2]);
515
- return total;
516
- }
517
- /** 3. The reservoir drains. */
518
- drain() {
519
- this.amount *= 1 - this.rates.drain;
520
- }
521
- }, _class4);
522
- var TileMedium = (_class5 = class {
523
- constructor(target, options = {}) {;_class5.prototype.__init12.call(this);_class5.prototype.__init13.call(this);_class5.prototype.__init14.call(this);_class5.prototype.__init15.call(this);_class5.prototype.__init16.call(this);_class5.prototype.__init17.call(this);_class5.prototype.__init18.call(this);_class5.prototype.__init19.call(this);_class5.prototype.__init20.call(this);_class5.prototype.__init21.call(this);
524
- this.target = target;
525
- this.options = options;
526
- }
527
-
528
-
529
- // The tile last looked up by `locate` (and whether it came from `writeTile`).
530
- __init12() {this.tx = NaN}
531
- __init13() {this.ty = NaN}
532
- __init14() {this.tile = null}
533
- __init15() {this.writable = false}
534
- __init16() {this.canvasPig = _chunkTFOPHZ3Ucjs.createPigment.call(void 0, [0, 0, 0])}
535
- __init17() {this.paintPig = _chunkTFOPHZ3Ucjs.createPigment.call(void 0, [0, 0, 0])}
536
- __init18() {this.paintKey = -1}
537
- __init19() {this.cb = [0, 0, 0, 0]}
538
- __init20() {this.src = [0, 0, 0, 1]}
539
- __init21() {this.o = [0, 0, 0]}
540
- /** Forgets the cached tile (call when another writer may have replaced tiles). */
541
- reset() {
542
- this.tx = NaN;
543
- }
544
- /**
545
- * The tile holding document pixel (dx, dy) (`pixels`) and the pixel's byte index in it, or -1
546
- * when reading an empty tile.
547
- */
548
- locate(dx, dy, write) {
549
- const t = this.target;
550
- const lx = dx - t.offset.x;
551
- const ly = dy - t.offset.y;
552
- const tx = Math.floor(lx / _chunkTFOPHZ3Ucjs.TILE);
553
- const ty = Math.floor(ly / _chunkTFOPHZ3Ucjs.TILE);
554
- if (tx !== this.tx || ty !== this.ty || write && !this.writable) {
555
- this.tx = tx;
556
- this.ty = ty;
557
- this.tile = write ? t.writeTile(tx, ty) : t.readTile(tx, ty);
558
- this.writable = write;
559
- }
560
- return this.tile ? ((ly - ty * _chunkTFOPHZ3Ucjs.TILE) * _chunkTFOPHZ3Ucjs.TILE + (lx - tx * _chunkTFOPHZ3Ucjs.TILE)) * 4 : -1;
561
- }
562
- /** The tile `locate` last found. */
563
- get pixels() {
564
- return this.tile;
565
- }
566
- /** Selection coverage at a document pixel, 0..1 (1 without a selection). */
567
- selectionAt(dx, dy) {
568
- const sel = this.target.selection;
569
- if (!sel) return 1;
570
- if (dx < 0 || dy < 0 || dx >= sel.width || dy >= sel.height) return 0;
571
- return sel.data[dy * sel.width + dx] / 255;
572
- }
573
- sample(rect, cov) {
574
- const w = rect.width;
575
- this.tx = NaN;
576
- let ar = 0;
577
- let ag = 0;
578
- let ab = 0;
579
- let wsum = 0;
580
- let asum = 0;
581
- for (let yy = 0; yy < rect.height; yy++) {
582
- for (let xx = 0; xx < w; xx++) {
583
- const k = cov[yy * w + xx];
584
- if (k <= 0) continue;
585
- wsum += k;
586
- const i = this.locate(rect.x + xx, rect.y + yy, false);
587
- if (i < 0) continue;
588
- const px = this.tile;
589
- const al = px[i + 3] / 255;
590
- if (al <= 0) continue;
591
- const ka = k * al;
592
- ar += px[i] / 255 * ka;
593
- ag += px[i + 1] / 255 * ka;
594
- ab += px[i + 2] / 255 * ka;
595
- asum += ka;
596
- }
597
- }
598
- if (!(asum > 1e-6)) return null;
599
- return { rgb: [ar / asum, ag / asum, ab / asum], contact: asum / Math.max(1e-6, wsum) };
600
- }
601
- deposit(rect, cov, dep, paint, paintPigment, field = null) {
602
- const t = this.target;
603
- const sel = t.selection;
604
- const w = rect.width;
605
- const o = this.o;
606
- const blend = this.options.blend;
607
- const pigment = blend === void 0 ? paintPigment !== null : blend === "pigment";
608
- const general = blend !== void 0 && blend !== "normal" && blend !== "pigment";
609
- let lastKey = -1;
610
- this.tx = NaN;
611
- for (let yy = 0; yy < rect.height; yy++) {
612
- const dy = rect.y + yy;
613
- for (let xx = 0; xx < w; xx++) {
614
- const p = yy * w + xx;
615
- let k = cov[p] * dep;
616
- if (k <= 0) continue;
617
- const dx = rect.x + xx;
618
- if (sel) {
619
- if (dx < 0 || dy < 0 || dx >= sel.width || dy >= sel.height) continue;
620
- k *= sel.data[dy * sel.width + dx] / 255;
621
- if (k <= 0) continue;
622
- }
623
- if (k > 1) k = 1;
624
- if (t.lockTransparency) {
625
- const ri = this.locate(dx, dy, false);
626
- if (ri < 0 || this.tile[ri + 3] === 0) continue;
627
- }
628
- const i = this.locate(dx, dy, true);
629
- const px = this.tile;
630
- const pr = field ? field[p * 3] : paint[0];
631
- const pg = field ? field[p * 3 + 1] : paint[1];
632
- const pb = field ? field[p * 3 + 2] : paint[2];
633
- if (general) {
634
- const cb = this.cb;
635
- for (let c = 0; c < 4; c++) cb[c] = px[i + c] / 255;
636
- const src = this.src;
637
- src[0] = pr;
638
- src[1] = pg;
639
- src[2] = pb;
640
- const r = _chunkTFOPHZ3Ucjs.blendPixel.call(void 0, blend, cb, src, k);
641
- px[i] = Math.round(r[0] * 255);
642
- px[i + 1] = Math.round(r[1] * 255);
643
- px[i + 2] = Math.round(r[2] * 255);
644
- if (!t.lockTransparency) px[i + 3] = Math.round(r[3] * 255);
645
- continue;
646
- }
647
- const a = px[i + 3] / 255;
648
- const na = t.lockTransparency ? a : a + (1 - a) * k;
649
- const share = t.lockTransparency ? k : na > 0 ? k / na : 1;
650
- if (a <= 0 || share >= 1) {
651
- o[0] = pr;
652
- o[1] = pg;
653
- o[2] = pb;
654
- } else if (pigment && field) {
655
- _chunkTFOPHZ3Ucjs.mixPigment8.call(void 0, px[i], px[i + 1], px[i + 2], Math.round(pr * 255), Math.round(pg * 255), Math.round(pb * 255), share, o);
656
- } else if (pigment) {
657
- const key = px[i] << 16 | px[i + 1] << 8 | px[i + 2];
658
- if (key !== lastKey) {
659
- _chunkTFOPHZ3Ucjs.setPigmentColor.call(void 0, this.canvasPig, px[i] / 255, px[i + 1] / 255, px[i + 2] / 255);
660
- lastKey = key;
661
- }
662
- let pp = paintPigment;
663
- if (!pp) {
664
- const pkey = Math.round(pr * 255) << 16 | Math.round(pg * 255) << 8 | Math.round(pb * 255);
665
- if (pkey !== this.paintKey) {
666
- _chunkTFOPHZ3Ucjs.setPigmentColor.call(void 0, this.paintPig, pr, pg, pb);
667
- this.paintKey = pkey;
668
- }
669
- pp = this.paintPig;
670
- }
671
- _chunkTFOPHZ3Ucjs.lerpPigmentInto.call(void 0, this.canvasPig, pp, share, o, 0);
672
- } else {
673
- o[0] = px[i] / 255 + (pr - px[i] / 255) * share;
674
- o[1] = px[i + 1] / 255 + (pg - px[i + 1] / 255) * share;
675
- o[2] = px[i + 2] / 255 + (pb - px[i + 2] / 255) * share;
676
- }
677
- px[i] = Math.round(o[0] * 255);
678
- px[i + 1] = Math.round(o[1] * 255);
679
- px[i + 2] = Math.round(o[2] * 255);
680
- px[i + 3] = Math.round(na * 255);
681
- }
682
- }
683
- }
684
- }, _class5);
685
-
686
- // src/paint/mixer.ts
687
- var DEFAULT_MIXER = {
688
- wet: 0.5,
689
- load: 0.5,
690
- mix: 0.5,
691
- loadEachStroke: true,
692
- cleanEachStroke: true,
693
- mixing: "rgb"
694
- };
695
- function normalizeMixer(raw = {}) {
696
- const unit2 = (v, d) => typeof v === "number" && Number.isFinite(v) ? Math.min(1, Math.max(0, v)) : d;
697
- const bool = (v, d) => typeof v === "boolean" ? v : d;
698
- return {
699
- wet: unit2(raw.wet, DEFAULT_MIXER.wet),
700
- load: unit2(raw.load, DEFAULT_MIXER.load),
701
- mix: unit2(raw.mix, DEFAULT_MIXER.mix),
702
- loadEachStroke: bool(raw.loadEachStroke, DEFAULT_MIXER.loadEachStroke),
703
- cleanEachStroke: bool(raw.cleanEachStroke, DEFAULT_MIXER.cleanEachStroke),
704
- mixing: raw.mixing === "pigment" ? "pigment" : "rgb"
705
- };
706
- }
707
- function mixerRates(settings) {
708
- return exchangeRates(settings.wet, settings.mix, settings.load, settings.mixing);
709
- }
710
- function loadMixer(load, color) {
711
- const c = (v) => Math.min(1, Math.max(0, Number.isFinite(v) ? v : 0));
712
- return { reservoir: [c(color[0]), c(color[1]), c(color[2])], amount: 1, pickup: load.pickup };
713
- }
714
- function cleanMixer(load) {
715
- return { reservoir: load.reservoir, amount: load.amount, pickup: null };
716
- }
717
- var MixerStroke = (_class6 = class {
718
- constructor(brush, settings, load, target) {;_class6.prototype.__init22.call(this);_class6.prototype.__init23.call(this);_class6.prototype.__init24.call(this);_class6.prototype.__init25.call(this);_class6.prototype.__init26.call(this);
719
- this.brush = brush;
720
- this.walker = new DabWalker(brush);
721
- this.exchange = new PaintExchange(mixerRates(normalizeMixer(settings)), load);
722
- this.medium = new TileMedium(target);
723
- }
724
-
725
- __init22() {this.dabCount = 0}
726
- __init23() {this.bounds = null}
727
-
728
- __init24() {this.smoothPos = null}
729
- __init25() {this.buf = new Float32Array(0)}
730
-
731
-
732
- __init26() {this.paintColor = [0, 0, 0]}
733
- /** The brush load after the dabs so far. */
734
- get load() {
735
- return this.exchange.load;
736
- }
737
- push(points) {
738
- const dabs = [];
739
- for (const p of points) this.walker.push(this.smooth(p), dabs);
740
- return this.paint(dabs);
741
- }
742
- finish(last) {
743
- const dabs = [];
744
- if (last && this.smoothPos && (this.smoothPos.x !== last.x || this.smoothPos.y !== last.y)) this.walker.push(last, dabs);
745
- this.walker.finish(dabs);
746
- return this.paint(dabs);
747
- }
748
- smooth(p) {
749
- const a = 1 - Math.min(0.95, Math.max(0, this.brush.smoothing));
750
- const cur = this.smoothPos;
751
- const n = cur && a < 1 ? { ...p, x: cur.x + (p.x - cur.x) * a, y: cur.y + (p.y - cur.y) * a } : p;
752
- this.smoothPos = n;
753
- return n;
754
- }
755
- paint(dabs) {
756
- const rects = [];
757
- for (const d of dabs) {
758
- const rect = dabRect(d, this.brush.hardness);
759
- const n = rect.width * rect.height;
760
- if (this.buf.length < n) this.buf = new Float32Array(n);
761
- const cov = this.buf.subarray(0, n);
762
- rasterizeDab({ ...d, alpha: 1 }, this.brush.hardness, rect, cov);
763
- this.dab(d, rect, cov);
764
- rects.push(rect);
765
- this.bounds = union(this.bounds, rect);
766
- this.dabCount++;
767
- }
768
- return rects;
769
- }
770
- dab(d, rect, cov) {
771
- const ex = this.exchange;
772
- ex.pickUp(this.medium.sample(rect, cov));
773
- const total = ex.paint(this.paintColor);
774
- if (total > 0) {
775
- const dep = Math.min(1, total) * this.brush.flow * this.brush.opacity * d.opacity;
776
- if (dep > 0) this.medium.deposit(rect, cov, dep, this.paintColor, ex.paintPigment);
777
- }
778
- ex.drain();
779
- }
780
- }, _class6);
781
- function union(a, b) {
782
- if (!a) return { ...b };
783
- const x = Math.min(a.x, b.x);
784
- const y = Math.min(a.y, b.y);
785
- return { x, y, width: Math.max(a.x + a.width, b.x + b.width) - x, height: Math.max(a.y + a.height, b.y + b.height) - y };
786
- }
787
-
788
- // src/paint/blending.ts
789
- var DEFAULT_BLENDER = { strength: 0.5, distance: 0.35, mixing: "pigment" };
790
- var DEFAULT_SMUDGE = { strength: 0.7, length: 0.85, mixing: "rgb" };
791
- var unit = (v, d) => typeof v === "number" && Number.isFinite(v) ? Math.min(1, Math.max(0, v)) : d;
792
- function normalizeBlender(raw = {}, base = DEFAULT_BLENDER) {
793
- return { strength: unit(raw.strength, base.strength), distance: unit(raw.distance, base.distance), mixing: raw.mixing === "rgb" || raw.mixing === "pigment" ? raw.mixing : base.mixing };
794
- }
795
- function normalizeSmudge(raw = {}, base = DEFAULT_SMUDGE) {
796
- return { strength: unit(raw.strength, base.strength), length: unit(raw.length, base.length), mixing: raw.mixing === "rgb" || raw.mixing === "pigment" ? raw.mixing : base.mixing };
797
- }
798
- function blendRadius(settings, radius) {
799
- return Math.max(1, Math.round(settings.distance * 2 * radius));
800
- }
801
- function createBlenderScratch() {
802
- return { sums: new Float64Array(0), mix: { rgb: [0, 0, 0], strength: 1, ks: new Float32Array(_chunkTFOPHZ3Ucjs.PIGMENT_BANDS), scatter: 1 }, out: [0, 0, 0] };
803
- }
804
- var N = _chunkTFOPHZ3Ucjs.PIGMENT_BANDS;
805
- function blenderDab(medium, rect, cov, opacity, radius, settings, scratch) {
806
- const R = blendRadius(settings, radius);
807
- const W = rect.width + 2 * R;
808
- const H = rect.height + 2 * R;
809
- const pigment = settings.mixing === "pigment";
810
- const C = pigment ? N + 2 : 4;
811
- const stride = (W + 1) * C;
812
- const size = stride * (H + 1);
813
- if (scratch.sums.length < size) scratch.sums = new Float64Array(size);
814
- const I = scratch.sums;
815
- I.fill(0, 0, size);
816
- medium.reset();
817
- const row = new Float64Array(C);
818
- for (let y = 0; y < H; y++) {
819
- row.fill(0);
820
- const dy = rect.y - R + y;
821
- for (let x = 0; x < W; x++) {
822
- const dx = rect.x - R + x;
823
- const i = medium.locate(dx, dy, false);
824
- if (i >= 0) {
825
- const px = medium.pixels;
826
- const a = px[i + 3] / 255;
827
- if (a > 0) {
828
- if (pigment) {
829
- const p = _chunkTFOPHZ3Ucjs.pigment8.call(void 0, px[i], px[i + 1], px[i + 2]);
830
- const sa = p.scatter * p.strength * a;
831
- for (let k = 0; k < N; k++) row[k] += sa * p.ks[k];
832
- row[N] += sa;
833
- row[N + 1] += a;
834
- } else {
835
- row[0] += px[i] / 255 * a;
836
- row[1] += px[i + 1] / 255 * a;
837
- row[2] += px[i + 2] / 255 * a;
838
- row[3] += a;
839
- }
840
- }
841
- }
842
- const o = (y + 1) * stride + (x + 1) * C;
843
- const up = y * stride + (x + 1) * C;
844
- for (let c = 0; c < C; c++) I[o + c] = I[up + c] + row[c];
845
- }
846
- }
847
- const area = (2 * R + 1) * (2 * R + 1);
848
- const strength = settings.strength * opacity;
849
- const lock = medium.target.lockTransparency;
850
- const mixPig = scratch.mix;
851
- const out = scratch.out;
852
- const sum = (c, x1, y1, x2, y2) => I[y2 * stride + x2 * C + c] - I[y1 * stride + x2 * C + c] - I[y2 * stride + x1 * C + c] + I[y1 * stride + x1 * C + c];
853
- const w = rect.width;
854
- medium.reset();
855
- for (let yy = 0; yy < rect.height; yy++) {
856
- for (let xx = 0; xx < w; xx++) {
857
- const k = cov[yy * w + xx];
858
- if (k <= 0) continue;
859
- const dx = rect.x + xx;
860
- const dy = rect.y + yy;
861
- let t = strength * k * medium.selectionAt(dx, dy);
862
- if (t <= 0) continue;
863
- if (t > 1) t = 1;
864
- const x1 = xx;
865
- const y1 = yy;
866
- const x2 = xx + 2 * R + 1;
867
- const y2 = yy + 2 * R + 1;
868
- const asum = sum(pigment ? N + 1 : 3, x1, y1, x2, y2);
869
- const ri = medium.locate(dx, dy, false);
870
- const a = ri < 0 ? 0 : medium.pixels[ri + 3] / 255;
871
- if (lock && a <= 0) continue;
872
- const avgA = asum / area;
873
- const na = lock ? a : (1 - t) * a + t * avgA;
874
- if (asum <= 1e-9) {
875
- if (lock || a <= 0) continue;
876
- const i2 = medium.locate(dx, dy, true);
877
- medium.pixels[i2 + 3] = Math.round(na * 255);
878
- continue;
879
- }
880
- const share = lock ? t : na > 0 ? t * avgA / na : 1;
881
- const i = medium.locate(dx, dy, true);
882
- const px = medium.pixels;
883
- if (pigment) {
884
- const sa = sum(N, x1, y1, x2, y2);
885
- for (let c = 0; c < N; c++) mixPig.ks[c] = sum(c, x1, y1, x2, y2) / sa;
886
- mixPig.scatter = sa / asum;
887
- if (a <= 0 || share >= 1) _chunkTFOPHZ3Ucjs.lerpPigmentInto.call(void 0, mixPig, mixPig, 0, out, 0);
888
- else _chunkTFOPHZ3Ucjs.lerpPigmentInto.call(void 0, _chunkTFOPHZ3Ucjs.pigment8.call(void 0, px[i], px[i + 1], px[i + 2]), mixPig, share, out, 0);
889
- } else {
890
- for (let c = 0; c < 3; c++) {
891
- const m = sum(c, x1, y1, x2, y2) / asum;
892
- out[c] = a <= 0 || share >= 1 ? m : px[i + c] / 255 + (m - px[i + c] / 255) * share;
893
- }
894
- }
895
- px[i] = Math.round(out[0] * 255);
896
- px[i + 1] = Math.round(out[1] * 255);
897
- px[i + 2] = Math.round(out[2] * 255);
898
- if (!lock) px[i + 3] = Math.round(na * 255);
899
- }
900
- }
901
- }
902
- var SmudgeTip = (_class7 = class {
903
- constructor(settings, diameter) {;_class7.prototype.__init27.call(this);_class7.prototype.__init28.call(this);
904
- this.settings = settings;
905
- this.size = Math.max(2, Math.min(512, Math.ceil(diameter)));
906
- this.patch = new Float32Array(this.size * this.size * 4);
907
- }
908
-
909
-
910
-
911
- __init27() {this.loaded = false}
912
- __init28() {this.out = [0, 0, 0]}
913
- cell(d, px, py) {
914
- const s = this.size;
915
- const r = Math.max(0.5, d.radius);
916
- const bx = Math.min(s - 1, Math.max(0, Math.floor(((px - d.x) / r + 1) / 2 * s)));
917
- const by = Math.min(s - 1, Math.max(0, Math.floor(((py - d.y) / r + 1) / 2 * s)));
918
- return (by * s + bx) * 4;
919
- }
920
- /** Fills the patch from the pixels under the dab. */
921
- load(medium, d) {
922
- const s = this.size;
923
- const r = Math.max(0.5, d.radius);
924
- medium.reset();
925
- for (let by = 0; by < s; by++) {
926
- for (let bx = 0; bx < s; bx++) {
927
- const dx = Math.floor(d.x + ((bx + 0.5) / s * 2 - 1) * r);
928
- const dy = Math.floor(d.y + ((by + 0.5) / s * 2 - 1) * r);
929
- const i = medium.locate(dx, dy, false);
930
- const c = (by * s + bx) * 4;
931
- if (i < 0) {
932
- this.patch.fill(0, c, c + 4);
933
- continue;
934
- }
935
- const px = medium.pixels;
936
- this.patch[c] = px[i] / 255;
937
- this.patch[c + 1] = px[i + 1] / 255;
938
- this.patch[c + 2] = px[i + 2] / 255;
939
- this.patch[c + 3] = px[i + 3] / 255;
940
- }
941
- }
942
- this.loaded = true;
943
- }
944
- /** `a` mixed `t` of the way to `b` (both 0..1) into `out`. */
945
- mix(a0, a1, a2, b0, b1, b2, t) {
946
- const o = this.out;
947
- if (this.settings.mixing === "pigment") {
948
- _chunkTFOPHZ3Ucjs.mixPigment8.call(void 0, Math.round(a0 * 255), Math.round(a1 * 255), Math.round(a2 * 255), Math.round(b0 * 255), Math.round(b1 * 255), Math.round(b2 * 255), t, o);
949
- } else {
950
- o[0] = a0 + (b0 - a0) * t;
951
- o[1] = a1 + (b1 - a1) * t;
952
- o[2] = a2 + (b2 - a2) * t;
953
- }
954
- return o;
955
- }
956
- /** One dab: lays the carried patch over the tip's footprint (`cov` over `rect`), then picks up. */
957
- dab(medium, d, rect, cov) {
958
- if (!this.loaded) {
959
- this.load(medium, d);
960
- return;
961
- }
962
- const { strength, length } = this.settings;
963
- const lock = medium.target.lockTransparency;
964
- const patch = this.patch;
965
- const w = rect.width;
966
- medium.reset();
967
- for (let yy = 0; yy < rect.height; yy++) {
968
- for (let xx = 0; xx < w; xx++) {
969
- const cv = cov[yy * w + xx];
970
- if (cv <= 0) continue;
971
- const dx = rect.x + xx;
972
- const dy = rect.y + yy;
973
- let k = strength * cv * d.opacity * medium.selectionAt(dx, dy);
974
- if (k <= 0) continue;
975
- if (k > 1) k = 1;
976
- const c = this.cell(d, dx + 0.5, dy + 0.5);
977
- const ba = patch[c + 3];
978
- const ri = medium.locate(dx, dy, false);
979
- const a = ri < 0 ? 0 : medium.pixels[ri + 3] / 255;
980
- if (lock && a <= 0) continue;
981
- const px0 = ri >= 0 ? medium.pixels : null;
982
- const o0 = px0 ? px0[ri] / 255 : 0;
983
- const o1 = px0 ? px0[ri + 1] / 255 : 0;
984
- const o2 = px0 ? px0[ri + 2] / 255 : 0;
985
- if (a > 0 || ba > 0) {
986
- const na = lock ? a : a + (ba - a) * k;
987
- const share = lock ? k * ba : na > 0 ? k * ba / na : 0;
988
- let r = o0;
989
- let g = o1;
990
- let b = o2;
991
- if (a <= 0 || share >= 1) {
992
- r = patch[c];
993
- g = patch[c + 1];
994
- b = patch[c + 2];
995
- } else if (share > 0) {
996
- const m = this.mix(o0, o1, o2, patch[c], patch[c + 1], patch[c + 2], share);
997
- r = m[0];
998
- g = m[1];
999
- b = m[2];
1000
- }
1001
- const i = medium.locate(dx, dy, true);
1002
- const out = medium.pixels;
1003
- out[i] = Math.round(r * 255);
1004
- out[i + 1] = Math.round(g * 255);
1005
- out[i + 2] = Math.round(b * 255);
1006
- out[i + 3] = Math.round(na * 255);
1007
- }
1008
- const pick = (1 - length) * Math.min(1, cv * d.opacity);
1009
- if (pick > 0) {
1010
- const pa = ba + (a - ba) * pick;
1011
- const s = pa > 0 ? a * pick / pa : 0;
1012
- if (s > 0) {
1013
- const m = ba <= 0 || s >= 1 ? [o0, o1, o2] : this.mix(patch[c], patch[c + 1], patch[c + 2], o0, o1, o2, s);
1014
- patch[c] = m[0];
1015
- patch[c + 1] = m[1];
1016
- patch[c + 2] = m[2];
1017
- }
1018
- patch[c + 3] = pa;
1019
- }
1020
- }
1021
- }
1022
- }
1023
- }, _class7);
1024
-
1025
- // src/paint/pigment-tools.ts
1026
- var HEX = /^#?([0-9a-f]{6})$/i;
1027
- function parseHex(value, index) {
1028
- const m = typeof value === "string" ? HEX.exec(value.trim()) : null;
1029
- if (!m) throw new Error(`colors[${index}].color is ${JSON.stringify(value)}; use #rrggbb, e.g. "#1e40af".`);
1030
- const n = parseInt(m[1], 16);
1031
- return [(n >> 16 & 255) / 255, (n >> 8 & 255) / 255, (n & 255) / 255];
1032
- }
1033
- function toHex(rgb) {
1034
- return "#" + rgb.map((v) => Math.round(Math.min(1, Math.max(0, v)) * 255).toString(16).padStart(2, "0")).join("");
1035
- }
1036
- function createPigmentTools() {
1037
- const mixColors = {
1038
- name: "mix_colors",
1039
- title: "Mix colours like paint",
1040
- description: "Mixes colours as paint would (model pigment, the default: Kubelka-Munk mixing over reflectance spectra, so blue and yellow make green and white lightens a colour into a tint instead of greying it), or as light on screen (model rgb: the weighted RGB average). Changes nothing. Returns mixed (#rrggbb, by the chosen model), the other model's result for comparison (rgbLerp and pigment), the normalised weights and the model.",
1041
- inputSchema: {
1042
- type: "object",
1043
- properties: {
1044
- colors: {
1045
- type: "array",
1046
- minItems: 1,
1047
- maxItems: 16,
1048
- description: "The paints to mix (1 to 16).",
1049
- items: {
1050
- type: "object",
1051
- properties: {
1052
- color: { type: "string", description: "Paint colour #rrggbb." },
1053
- weight: { type: "number", minimum: 0, description: "Parts of this paint, any scale (e.g. 1 and 3 for a 1:3 mix). At least one weight must be above 0." },
1054
- strength: {
1055
- type: "number",
1056
- exclusiveMinimum: 0,
1057
- maximum: 100,
1058
- description: "Tinting strength (default 1): each part counts as this many, so a strong dark paint (e.g. 4) tints a lot of white."
1059
- }
1060
- },
1061
- required: ["color", "weight"],
1062
- additionalProperties: false
1063
- }
1064
- },
1065
- model: {
1066
- type: "string",
1067
- enum: ["pigment", "rgb"],
1068
- description: "pigment (default): mix like paint (Kubelka-Munk), as the pigment blend mode, Mixer Brush and mixing pad do; rgb: average the RGB values, as normal blending and rgb mixing brushes do (strength is ignored)."
1069
- }
1070
- },
1071
- required: ["colors"],
1072
- additionalProperties: false
1073
- },
1074
- annotations: { title: "Mix colours like paint", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
1075
- handler: (args) => {
1076
- const items = args.colors;
1077
- const rgbs = items.map((item, i) => parseHex(item.color, i));
1078
- const total = items.reduce((sum, item) => sum + item.weight, 0);
1079
- if (!(total > 0)) throw new Error("Every weight is 0; give at least one colour a weight above 0.");
1080
- const pigments = rgbs.map((rgb2, i) => _chunkTFOPHZ3Ucjs.createPigment.call(void 0, rgb2, { strength: items[i].strength }));
1081
- const mixed = _chunkTFOPHZ3Ucjs.mixPigments.call(void 0, pigments, items.map((item) => item.weight));
1082
- const lerp = [0, 1, 2].map((c) => rgbs.reduce((sum, rgb2, i) => sum + rgb2[c] * items[i].weight, 0) / total);
1083
- const rgb = args.model === "rgb";
1084
- return {
1085
- mixed: toHex(rgb ? lerp : mixed),
1086
- rgbLerp: toHex(lerp),
1087
- pigment: toHex(mixed),
1088
- weights: items.map((item) => item.weight / total),
1089
- model: rgb ? "rgb" : "kubelka-munk"
1090
- };
1091
- }
1092
- };
1093
- return [mixColors];
1094
- }
1095
-
1096
-
1097
-
1098
-
1099
-
1100
-
1101
-
1102
-
1103
-
1104
-
1105
-
1106
-
1107
-
1108
-
1109
-
1110
-
1111
-
1112
-
1113
-
1114
-
1115
-
1116
-
1117
-
1118
-
1119
-
1120
-
1121
-
1122
-
1123
-
1124
-
1125
-
1126
-
1127
-
1128
-
1129
-
1130
-
1131
-
1132
-
1133
-
1134
-
1135
- exports.DEFAULT_BRUSH = DEFAULT_BRUSH; exports.MAX_BRUSH_SIZE = MAX_BRUSH_SIZE; exports.normalizeBrush = normalizeBrush; exports.tipShape = tipShape; exports.tipFalloff = tipFalloff; exports.tipReach = tipReach; exports.dabCoverage = dabCoverage; exports.smoothPoints = smoothPoints; exports.DabWalker = DabWalker; exports.walkDabs = walkDabs; exports.dabRect = dabRect; exports.rasterizeDab = rasterizeDab; exports.CoverageMap = CoverageMap; exports.StrokeCoverage = StrokeCoverage; exports.applyStrokeToTile = applyStrokeToTile; exports.coverageTileCoord = coverageTileCoord; exports.MIXING_MODELS = MIXING_MODELS; exports.EMPTY_MIXER_LOAD = EMPTY_MIXER_LOAD; exports.MIXER_PICKUP_RATE = MIXER_PICKUP_RATE; exports.MIXER_DRAIN = MIXER_DRAIN; exports.exchangeRates = exchangeRates; exports.PaintExchange = PaintExchange; exports.TileMedium = TileMedium; exports.DEFAULT_MIXER = DEFAULT_MIXER; exports.normalizeMixer = normalizeMixer; exports.mixerRates = mixerRates; exports.loadMixer = loadMixer; exports.cleanMixer = cleanMixer; exports.MixerStroke = MixerStroke; exports.DEFAULT_BLENDER = DEFAULT_BLENDER; exports.DEFAULT_SMUDGE = DEFAULT_SMUDGE; exports.normalizeBlender = normalizeBlender; exports.normalizeSmudge = normalizeSmudge; exports.blendRadius = blendRadius; exports.createBlenderScratch = createBlenderScratch; exports.blenderDab = blenderDab; exports.SmudgeTip = SmudgeTip; exports.createPigmentTools = createPigmentTools;
1136
- //# sourceMappingURL=chunk-TCKIXI46.cjs.map