@pixerate/editor 0.250.0 → 0.251.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.
- package/dist/agent/index.cjs +40 -41
- package/dist/agent/index.js +9 -10
- package/dist/animation/index.cjs +6 -7
- package/dist/animation/index.js +5 -6
- package/dist/animation-editor/index.cjs +70 -70
- package/dist/animation-editor/index.js +12 -12
- package/dist/brushes/index.cjs +1406 -0
- package/dist/brushes/index.d.cts +12 -0
- package/dist/brushes/index.d.ts +12 -0
- package/dist/brushes/index.js +1406 -0
- package/dist/brushes/migrate.d.cts +17 -0
- package/dist/brushes/migrate.d.ts +17 -0
- package/dist/brushes/normalize.d.cts +15 -0
- package/dist/brushes/normalize.d.ts +15 -0
- package/dist/brushes/presets.d.cts +12 -0
- package/dist/brushes/presets.d.ts +12 -0
- package/dist/brushes/resolve.d.cts +56 -0
- package/dist/brushes/resolve.d.ts +56 -0
- package/dist/brushes/schema.d.cts +29 -0
- package/dist/brushes/schema.d.ts +29 -0
- package/dist/brushes/types.d.cts +323 -0
- package/dist/brushes/types.d.ts +323 -0
- package/dist/{brushstrokeRender-2FHFLSEG.js → brushstrokeRender-5PYSKZIJ.js} +8 -8
- package/dist/{brushstrokeRender-QGRXOKDA.cjs → brushstrokeRender-7FLLSQEC.cjs} +14 -14
- package/dist/canvas/index.cjs +57 -58
- package/dist/canvas/index.js +31 -32
- package/dist/chart/index.cjs +159 -160
- package/dist/chart/index.js +9 -10
- package/dist/{chunk-NOHJP5TK.js → chunk-2ZJ4DT3M.js} +1 -1
- package/dist/{chunk-XZNU4DUX.cjs → chunk-3NS5C7FB.cjs} +76 -76
- package/dist/{chunk-UTI5IITZ.cjs → chunk-4ZC5QJE2.cjs} +3 -3
- package/dist/{chunk-SMSGP2HQ.js → chunk-5JNA6LLY.js} +1 -1
- package/dist/{chunk-RD7RX52G.cjs → chunk-5UEFBM2M.cjs} +207 -18
- package/dist/{chunk-WA44NKPF.js → chunk-62Z5WLRA.js} +1 -1
- package/dist/{chunk-BVRRIW7F.js → chunk-6GRUVGKU.js} +3 -3
- package/dist/{chunk-QARCM66V.js → chunk-6ZZKRH7R.js} +3 -3
- package/dist/{chunk-BP6KSGVD.js → chunk-7272D3K2.js} +4 -6
- package/dist/{chunk-NTRAVM2I.js → chunk-7P6VF3FG.js} +2 -2
- package/dist/chunk-APX63ILU.js +173 -0
- package/dist/{chunk-W7L4HUT2.cjs → chunk-CJ6TBL2N.cjs} +16 -16
- package/dist/{chunk-7PT4RJL5.cjs → chunk-EUIDTZNQ.cjs} +111 -113
- package/dist/{chunk-CXXXAZ7H.js → chunk-F6R67I3A.js} +1 -1
- package/dist/{chunk-I7NJPHWV.cjs → chunk-FQPUF2W2.cjs} +35 -606
- package/dist/{chunk-D5KGAO4Z.js → chunk-GCVFEPJG.js} +2 -573
- package/dist/{chunk-LEQKZGQI.js → chunk-GOBOCZZI.js} +1 -1
- package/dist/{chunk-KDLBJ6QR.js → chunk-GYMMNCFT.js} +3 -3
- package/dist/{chunk-NUTMINJZ.cjs → chunk-H7ET2ISK.cjs} +52 -52
- package/dist/chunk-HS6QDWDF.cjs +1029 -0
- package/dist/{chunk-T7KQEMAE.cjs → chunk-HUAISCUX.cjs} +18 -18
- package/dist/{chunk-YGQVCQTG.js → chunk-ILP77UD6.js} +1 -1
- package/dist/{chunk-S6OT6CTS.cjs → chunk-IWEVV63O.cjs} +31 -33
- package/dist/{chunk-M2VKFE5L.cjs → chunk-JFHBXNR2.cjs} +88 -88
- package/dist/{chunk-WPUXGDH4.cjs → chunk-JPEHXIB5.cjs} +10 -10
- package/dist/chunk-JSDND7DF.cjs +173 -0
- package/dist/{chunk-36ZTV7WO.js → chunk-L6Y7TSQ4.js} +1 -1
- package/dist/{chunk-YW43M56C.cjs → chunk-LFMKWGFL.cjs} +1 -1
- package/dist/{chunk-V6DT2CDH.js → chunk-M2TPMYJE.js} +1 -1
- package/dist/{chunk-LJZRHVZV.cjs → chunk-M5GLQQWG.cjs} +2 -2
- package/dist/{chunk-JEGJP4OW.js → chunk-MHLU6GRJ.js} +196 -7
- package/dist/{chunk-KMPM5JM5.js → chunk-MONXNVZK.js} +4 -6
- package/dist/chunk-MTKY6K3Q.js +1029 -0
- package/dist/{chunk-MOW3JMNG.cjs → chunk-N76AMOKE.cjs} +42 -42
- package/dist/{chunk-75K3W4D6.cjs → chunk-NKGB64CW.cjs} +16 -16
- package/dist/{chunk-SGPIVHJB.js → chunk-P3K2JCJA.js} +3 -3
- package/dist/chunk-PXDIAYB6.cjs +594 -0
- package/dist/{chunk-3TWOCSCY.js → chunk-QC3OXRE4.js} +9 -9
- package/dist/{chunk-YM6ZBTXG.cjs → chunk-QLSGTCYT.cjs} +23 -23
- package/dist/{chunk-7YW7T5TJ.js → chunk-RHPSE2YR.js} +2 -2
- package/dist/{chunk-44BMJJVA.cjs → chunk-RUONPPMC.cjs} +8 -8
- package/dist/{chunk-ATK6ABN3.cjs → chunk-SABJMH6M.cjs} +145 -12
- package/dist/{chunk-XWOLPNBW.cjs → chunk-SOSBOS5T.cjs} +22 -22
- package/dist/{chunk-PPFJHTW5.cjs → chunk-TFF2GTGN.cjs} +22 -24
- package/dist/{chunk-X7WRL5ZZ.cjs → chunk-TLOGFIIV.cjs} +37 -37
- package/dist/chunk-TXFWZ5ZJ.js +594 -0
- package/dist/{chunk-GXAK6Q5J.js → chunk-UFEDHACQ.js} +2 -2
- package/dist/{chunk-GA4EU4P3.cjs → chunk-UXETV2NC.cjs} +4 -4
- package/dist/{chunk-N4DFDI73.js → chunk-WKMUBATU.js} +1 -1
- package/dist/{chunk-3R5P3DVY.cjs → chunk-WRZ6C4TU.cjs} +6 -6
- package/dist/{chunk-U4NUOKBT.js → chunk-WZOGDKCQ.js} +134 -1
- package/dist/{chunk-6ADHGQ73.js → chunk-YBAPT7NL.js} +2 -4
- package/dist/color/index.cjs +4 -6
- package/dist/color/index.js +7 -9
- package/dist/export/index.cjs +7 -8
- package/dist/export/index.js +6 -7
- package/dist/extensions/index.cjs +10 -11
- package/dist/extensions/index.js +9 -10
- package/dist/gradient/index.cjs +33 -34
- package/dist/gradient/index.js +4 -5
- package/dist/image-editor/index.cjs +845 -844
- package/dist/image-editor/index.js +39 -38
- package/dist/index.cjs +16 -17
- package/dist/index.js +10 -11
- package/dist/paint/index.cjs +6 -4
- package/dist/paint/index.js +21 -19
- package/dist/paint-editor/brushes.d.cts +1 -2
- package/dist/paint-editor/brushes.d.ts +1 -2
- package/dist/paint-editor/index.cjs +2193 -694
- package/dist/paint-editor/index.js +1575 -76
- package/dist/paint-editor/mark-settings.d.cts +104 -0
- package/dist/paint-editor/mark-settings.d.ts +104 -0
- package/dist/paint-editor/procedural.d.cts +2 -75
- package/dist/paint-editor/procedural.d.ts +2 -75
- package/dist/paint-editor/stickers.d.cts +1 -22
- package/dist/paint-editor/stickers.d.ts +1 -22
- package/dist/raster/index.cjs +2 -2
- package/dist/raster/index.js +9 -9
- package/dist/stickers/index.cjs +10 -10
- package/dist/stickers/index.js +9 -9
- package/dist/tokens/index.cjs +3 -4
- package/dist/tokens/index.js +2 -3
- package/dist/typography/index.cjs +7 -8
- package/dist/typography/index.js +2 -3
- package/dist/vector/index.cjs +974 -974
- package/dist/vector/index.js +12 -12
- package/dist/video-editor/index.cjs +6 -7
- package/dist/video-editor/index.js +5 -6
- package/package.json +11 -1
- package/dist/chunk-4JNWA3VT.cjs +0 -302
- package/dist/chunk-7AHBW2CQ.cjs +0 -200
- package/dist/chunk-F67XMVDI.js +0 -200
- package/dist/chunk-GT77U7QG.cjs +0 -2637
- package/dist/chunk-OTEPAQJX.js +0 -2637
- package/dist/chunk-WKH5ZAUA.js +0 -302
|
@@ -0,0 +1,594 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CoverageMap,
|
|
3
|
+
PaintGradientSampler,
|
|
4
|
+
TIP_GRADIENT_STEPS,
|
|
5
|
+
applyStrokeToTile,
|
|
6
|
+
dabRect,
|
|
7
|
+
gradientDabColor,
|
|
8
|
+
hexToPaintRgb,
|
|
9
|
+
normalizeBrush,
|
|
10
|
+
rasterizeDab,
|
|
11
|
+
resolvePaintGradient,
|
|
12
|
+
scalePaintGradient
|
|
13
|
+
} from "./chunk-GCVFEPJG.js";
|
|
14
|
+
import {
|
|
15
|
+
TileableNoise,
|
|
16
|
+
hash2,
|
|
17
|
+
randSigned
|
|
18
|
+
} from "./chunk-4D6KP5BV.js";
|
|
19
|
+
import {
|
|
20
|
+
BRUSHSTROKE_MAX_SCALE,
|
|
21
|
+
BRUSHSTROKE_MIN_SCALE
|
|
22
|
+
} from "./chunk-ODBT55Q7.js";
|
|
23
|
+
import {
|
|
24
|
+
pngDataUrl
|
|
25
|
+
} from "./chunk-OTTT5N3K.js";
|
|
26
|
+
import {
|
|
27
|
+
TILE,
|
|
28
|
+
TiledSurface,
|
|
29
|
+
emptySurface,
|
|
30
|
+
finishTile,
|
|
31
|
+
readRegion,
|
|
32
|
+
tileCoord,
|
|
33
|
+
tileKey,
|
|
34
|
+
tilesInRect
|
|
35
|
+
} from "./chunk-HVVR5PZW.js";
|
|
36
|
+
|
|
37
|
+
// src/paint/grain.ts
|
|
38
|
+
var GRAIN_PATTERNS = ["smooth", "cold-pressed", "hot-pressed", "rough", "vellum", "laid", "ingres", "sanded", "canvas", "linen", "gesso"];
|
|
39
|
+
var GRAIN_TILE = 256;
|
|
40
|
+
var clamp01 = (v) => v < 0 ? 0 : v > 1 ? 1 : v;
|
|
41
|
+
function patternHeights(pattern, n, seed) {
|
|
42
|
+
const out = new Float32Array(n * n);
|
|
43
|
+
const salt = Math.imul(seed | 0, 2654435761) + 17;
|
|
44
|
+
if (pattern === "smooth") return out.fill(1);
|
|
45
|
+
const noise = (cx, cy, oct, s = 0) => new TileableNoise(n, cx, cy, oct, salt + s);
|
|
46
|
+
const k = n / GRAIN_TILE;
|
|
47
|
+
switch (pattern) {
|
|
48
|
+
case "cold-pressed": {
|
|
49
|
+
const base = noise(20 * k, 20 * k, 4);
|
|
50
|
+
const fine = noise(64 * k, 64 * k, 2, 3);
|
|
51
|
+
for (let y = 0; y < n; y++)
|
|
52
|
+
for (let x = 0; x < n; x++) out[y * n + x] = clamp01((base.at(x, y) - 0.5) * 1.8 + 0.5 + (fine.at(x, y) - 0.5) * 0.5 + (hash2(x, y, salt) - 0.5) * 0.12);
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
case "hot-pressed": {
|
|
56
|
+
const base = noise(40 * k, 40 * k, 3);
|
|
57
|
+
for (let y = 0; y < n; y++) for (let x = 0; x < n; x++) out[y * n + x] = clamp01((base.at(x, y) - 0.5) * 1.1 + 0.6 + (hash2(x, y, salt) - 0.5) * 0.08);
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
case "rough": {
|
|
61
|
+
const base = noise(10 * k, 10 * k, 5);
|
|
62
|
+
const blot = noise(28 * k, 28 * k, 2, 5);
|
|
63
|
+
for (let y = 0; y < n; y++)
|
|
64
|
+
for (let x = 0; x < n; x++) out[y * n + x] = clamp01((base.at(x, y) - 0.5) * 2.4 + 0.5 + (blot.at(x, y) - 0.5) * 0.7 + (hash2(x, y, salt) - 0.5) * 0.15);
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
case "vellum": {
|
|
68
|
+
const base = noise(40 * k, 40 * k, 3);
|
|
69
|
+
for (let y = 0; y < n; y++) for (let x = 0; x < n; x++) out[y * n + x] = clamp01((base.at(x, y) - 0.5) * 1.6 + 0.55 + (hash2(x, y, salt) - 0.5) * 0.2);
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
case "laid": {
|
|
73
|
+
const pulp = noise(32 * k, 32 * k, 3);
|
|
74
|
+
const chain = n / 8;
|
|
75
|
+
for (let y = 0; y < n; y++) {
|
|
76
|
+
const laid = 0.5 + 0.5 * Math.cos(2 * Math.PI * y / 4);
|
|
77
|
+
for (let x = 0; x < n; x++) {
|
|
78
|
+
const c = Math.abs((x + 0.5) % chain - chain / 2) / (chain / 2);
|
|
79
|
+
const chainLine = c > 0.94 ? -0.35 : 0;
|
|
80
|
+
out[y * n + x] = clamp01(0.3 + 0.5 * laid + chainLine + (pulp.at(x, y) - 0.5) * 0.6);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
case "ingres": {
|
|
86
|
+
const fibres = noise(64 * k, 12 * k, 3);
|
|
87
|
+
const base = noise(16 * k, 16 * k, 3, 7);
|
|
88
|
+
for (let y = 0; y < n; y++)
|
|
89
|
+
for (let x = 0; x < n; x++) {
|
|
90
|
+
const g = hash2(x, y, salt ^ 85);
|
|
91
|
+
out[y * n + x] = clamp01((fibres.at(x, y) - 0.5) * 1.5 + (base.at(x, y) - 0.5) * 0.7 + 0.55 + (g < 0.1 ? -0.3 : 0));
|
|
92
|
+
}
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
case "sanded": {
|
|
96
|
+
const grit = noise(96 * k, 96 * k, 2);
|
|
97
|
+
for (let y = 0; y < n; y++)
|
|
98
|
+
for (let x = 0; x < n; x++) {
|
|
99
|
+
const h = hash2(x, y, salt);
|
|
100
|
+
out[y * n + x] = clamp01((grit.at(x, y) - 0.5) * 2.4 + 0.5 + (h - 0.5) * 0.7);
|
|
101
|
+
}
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
case "canvas":
|
|
105
|
+
case "linen": {
|
|
106
|
+
const period = (pattern === "canvas" ? 8 : 5) * k;
|
|
107
|
+
const threads = Math.max(2, 2 * Math.round(n / period / 2));
|
|
108
|
+
const p = n / threads;
|
|
109
|
+
const slub = noise(threads, threads, 2, 11);
|
|
110
|
+
for (let y = 0; y < n; y++)
|
|
111
|
+
for (let x = 0; x < n; x++) {
|
|
112
|
+
const fx = (x + 0.5) / p;
|
|
113
|
+
const fy = (y + 0.5) / p;
|
|
114
|
+
const cx = Math.floor(fx);
|
|
115
|
+
const cy = Math.floor(fy);
|
|
116
|
+
const warp = Math.sin(Math.PI * (fx - cx));
|
|
117
|
+
const weft = Math.sin(Math.PI * (fy - cy));
|
|
118
|
+
const top = (cx + cy) % 2 === 0 ? warp : weft;
|
|
119
|
+
const irregular = pattern === "linen" ? (slub.at(x, y) - 0.5) * 0.5 : 0;
|
|
120
|
+
out[y * n + x] = clamp01(0.2 + 0.7 * top + irregular + (hash2(x, y, salt) - 0.5) * 0.15);
|
|
121
|
+
}
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
case "gesso": {
|
|
125
|
+
const streaks = noise(2 * k, 28 * k, 3);
|
|
126
|
+
const tooth = noise(64 * k, 64 * k, 2, 13);
|
|
127
|
+
for (let y = 0; y < n; y++)
|
|
128
|
+
for (let x = 0; x < n; x++) out[y * n + x] = clamp01((streaks.at(x, y) - 0.5) * 1.8 + (tooth.at(x, y) - 0.5) * 0.9 + 0.55);
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return out;
|
|
133
|
+
}
|
|
134
|
+
var rawCache = /* @__PURE__ */ new Map();
|
|
135
|
+
function grainHeights(pattern, seed, size = GRAIN_TILE) {
|
|
136
|
+
const key = `${pattern}:${seed}:${size}`;
|
|
137
|
+
let h = rawCache.get(key);
|
|
138
|
+
if (!h) {
|
|
139
|
+
h = patternHeights(pattern, size, seed);
|
|
140
|
+
if (rawCache.size > 32) rawCache.delete(rawCache.keys().next().value);
|
|
141
|
+
rawCache.set(key, h);
|
|
142
|
+
}
|
|
143
|
+
return h;
|
|
144
|
+
}
|
|
145
|
+
var PaperGrain = class {
|
|
146
|
+
size = GRAIN_TILE;
|
|
147
|
+
heights;
|
|
148
|
+
scale;
|
|
149
|
+
mirror;
|
|
150
|
+
ox;
|
|
151
|
+
oy;
|
|
152
|
+
flat;
|
|
153
|
+
constructor(paper, media = "dry") {
|
|
154
|
+
const raw = grainHeights(paper.pattern, paper.seed);
|
|
155
|
+
const t = paper[media];
|
|
156
|
+
this.flat = paper.pattern === "smooth";
|
|
157
|
+
if (t.contrast === 1 && !t.invert) this.heights = raw;
|
|
158
|
+
else {
|
|
159
|
+
const out = new Float32Array(raw.length);
|
|
160
|
+
for (let i = 0; i < raw.length; i++) {
|
|
161
|
+
const v = clamp01((raw[i] - 0.5) * t.contrast + 0.5);
|
|
162
|
+
out[i] = t.invert ? 1 - v : v;
|
|
163
|
+
}
|
|
164
|
+
this.heights = out;
|
|
165
|
+
}
|
|
166
|
+
this.scale = paper.scale;
|
|
167
|
+
this.mirror = paper.tiling === "mirror";
|
|
168
|
+
this.ox = paper.offset?.x ?? 0;
|
|
169
|
+
this.oy = paper.offset?.y ?? 0;
|
|
170
|
+
}
|
|
171
|
+
/** Tile cell index for a coordinate in grain pixels (mirrored on odd tiles when mirroring). */
|
|
172
|
+
wrap(v) {
|
|
173
|
+
const n = this.size;
|
|
174
|
+
if (!this.mirror) return (v % n + n) % n;
|
|
175
|
+
const p = (v % (2 * n) + 2 * n) % (2 * n);
|
|
176
|
+
return p < n ? p : 2 * n - 1 - p;
|
|
177
|
+
}
|
|
178
|
+
/** Height 0..1 at document position (x, y). */
|
|
179
|
+
at(x, y) {
|
|
180
|
+
const u = (x - this.ox) / this.scale - 0.5;
|
|
181
|
+
const v = (y - this.oy) / this.scale - 0.5;
|
|
182
|
+
const x0 = Math.floor(u);
|
|
183
|
+
const y0 = Math.floor(v);
|
|
184
|
+
const fx = u - x0;
|
|
185
|
+
const fy = v - y0;
|
|
186
|
+
const n = this.size;
|
|
187
|
+
const h = this.heights;
|
|
188
|
+
const a = this.wrap(x0);
|
|
189
|
+
const b = this.wrap(x0 + 1);
|
|
190
|
+
const c = this.wrap(y0) * n;
|
|
191
|
+
const d = this.wrap(y0 + 1) * n;
|
|
192
|
+
const top = h[c + a] + (h[c + b] - h[c + a]) * fx;
|
|
193
|
+
const bot = h[d + a] + (h[d + b] - h[d + a]) * fx;
|
|
194
|
+
return top + (bot - top) * fy;
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
function grainCatch(h, depth, pressure) {
|
|
198
|
+
if (depth <= 0) return 1;
|
|
199
|
+
const t = depth * (0.75 - 0.65 * Math.min(1, Math.max(0, pressure)));
|
|
200
|
+
const u = clamp01((h - t + 0.18) / 0.36);
|
|
201
|
+
return 1 - depth + depth * u * u * (3 - 2 * u);
|
|
202
|
+
}
|
|
203
|
+
function strokeGrainCatch(h, depth, pressure) {
|
|
204
|
+
if (depth <= 0) return 1;
|
|
205
|
+
const p = Math.min(1, Math.max(0, pressure));
|
|
206
|
+
const amount = Math.min(1, depth * (1.4 - 0.6 * p));
|
|
207
|
+
const u = clamp01((h - 0.2 - 0.25 * (1 - p)) / 0.5);
|
|
208
|
+
return 1 - amount + amount * u * u * (3 - 2 * u);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// src/paint/path-stroke.ts
|
|
212
|
+
var JITTER_SIZE = 1;
|
|
213
|
+
var JITTER_ANGLE = 2;
|
|
214
|
+
var JITTER_OPACITY = 3;
|
|
215
|
+
var JITTER_SCATTER = 4;
|
|
216
|
+
function lean(s) {
|
|
217
|
+
if (typeof s.altitude === "number" && Number.isFinite(s.altitude)) {
|
|
218
|
+
return { amount: 1 - Math.min(1, Math.max(0, s.altitude / (Math.PI / 2))), azimuth: s.azimuth ?? 0 };
|
|
219
|
+
}
|
|
220
|
+
if (typeof s.tiltX === "number" || typeof s.tiltY === "number") {
|
|
221
|
+
const tx = (s.tiltX ?? 0) * Math.PI / 180;
|
|
222
|
+
const ty = (s.tiltY ?? 0) * Math.PI / 180;
|
|
223
|
+
if (tx === 0 && ty === 0) return { amount: 0, azimuth: 0 };
|
|
224
|
+
const az = Math.atan2(Math.tan(ty), Math.tan(tx));
|
|
225
|
+
const alt = Math.atan(1 / Math.hypot(Math.tan(tx), Math.tan(ty)));
|
|
226
|
+
return { amount: 1 - alt / (Math.PI / 2), azimuth: az };
|
|
227
|
+
}
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
function pathStrokeDabs(samples, options) {
|
|
231
|
+
const brush = normalizeBrush(options.brush);
|
|
232
|
+
const pts = options.closed && samples.length > 2 ? [...samples, samples[0]] : [...samples];
|
|
233
|
+
if (!pts.length) return [];
|
|
234
|
+
const tilt = options.tilt ?? {};
|
|
235
|
+
const minSize = Math.min(1, Math.max(0, options.minSize ?? 0));
|
|
236
|
+
let index = 0;
|
|
237
|
+
const t0 = pts.find((s) => typeof s.t === "number" && Number.isFinite(s.t))?.t ?? null;
|
|
238
|
+
const dab = (x, y, p, l, dir, travel = 0, time = null, speed = null) => {
|
|
239
|
+
const pr = Math.min(1, Math.max(0, p));
|
|
240
|
+
const lean0 = l?.amount ?? 0;
|
|
241
|
+
const size = brush.size * (brush.pressureSize ? minSize + (1 - minSize) * pr : 1) * (1 + 1.5 * (tilt.size ?? 0) * lean0);
|
|
242
|
+
let angle = brush.angle * Math.PI / 180;
|
|
243
|
+
if (options.followPath) angle += dir;
|
|
244
|
+
if (tilt.followAzimuth && l) angle = -l.azimuth;
|
|
245
|
+
const roundness = Math.max(0.05, brush.roundness * (1 - 0.85 * (tilt.roundness ?? 0) * lean0));
|
|
246
|
+
const op = brush.pressureOpacity ? pr : 1;
|
|
247
|
+
const i = index++;
|
|
248
|
+
const params = { travel, index: i, pressure: pr, lean: lean0, speed, direction: dir, time: time === null || t0 === null ? null : time - t0 };
|
|
249
|
+
let diameter = size;
|
|
250
|
+
let opacity = brush.opacity * op;
|
|
251
|
+
const j = options.jitter;
|
|
252
|
+
if (j) {
|
|
253
|
+
if (j.size) diameter *= Math.max(0.05, 1 + j.size * randSigned(j.seed, i, JITTER_SIZE));
|
|
254
|
+
if (j.angle) angle += j.angle * Math.PI * randSigned(j.seed, i, JITTER_ANGLE);
|
|
255
|
+
if (j.opacity) opacity *= 1 - j.opacity * (randSigned(j.seed, i, JITTER_OPACITY) * 0.5 + 0.5);
|
|
256
|
+
if (j.scatter) {
|
|
257
|
+
const off = j.scatter * diameter * randSigned(j.seed, i, JITTER_SCATTER);
|
|
258
|
+
x += Math.sin(dir) * off;
|
|
259
|
+
y += Math.cos(dir) * off;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return { x, y, radius: Math.max(0.5, diameter / 2), alpha: brush.flow, opacity, angle, roundness, params };
|
|
263
|
+
};
|
|
264
|
+
const out = [];
|
|
265
|
+
const pressure = (s) => typeof s.pressure === "number" && Number.isFinite(s.pressure) ? s.pressure : 1;
|
|
266
|
+
if (pts.length === 1) {
|
|
267
|
+
out.push(dab(pts[0].x, pts[0].y, pressure(pts[0]), lean(pts[0]), 0));
|
|
268
|
+
return out;
|
|
269
|
+
}
|
|
270
|
+
let carry = 0;
|
|
271
|
+
let along = 0;
|
|
272
|
+
const timeOf = (s) => typeof s.t === "number" && Number.isFinite(s.t) ? s.t : null;
|
|
273
|
+
out.push(dab(pts[0].x, pts[0].y, pressure(pts[0]), lean(pts[0]), Math.atan2(-(pts[1].y - pts[0].y), pts[1].x - pts[0].x), 0, timeOf(pts[0])));
|
|
274
|
+
for (let i = 0; i + 1 < pts.length; i++) {
|
|
275
|
+
const a = pts[i];
|
|
276
|
+
const b = pts[i + 1];
|
|
277
|
+
const dx = b.x - a.x;
|
|
278
|
+
const dy = b.y - a.y;
|
|
279
|
+
const len = Math.hypot(dx, dy);
|
|
280
|
+
if (len === 0) continue;
|
|
281
|
+
const dir = Math.atan2(-dy, dx);
|
|
282
|
+
const la = lean(a);
|
|
283
|
+
const lb = lean(b);
|
|
284
|
+
const ta = timeOf(a);
|
|
285
|
+
const tb = timeOf(b);
|
|
286
|
+
const speed = ta !== null && tb !== null && tb > ta ? len / (tb - ta) : null;
|
|
287
|
+
let t = carry;
|
|
288
|
+
for (; ; ) {
|
|
289
|
+
const f = t / len;
|
|
290
|
+
if (f > 1) break;
|
|
291
|
+
const p = pressure(a) + (pressure(b) - pressure(a)) * f;
|
|
292
|
+
const l = la && lb ? { amount: la.amount + (lb.amount - la.amount) * f, azimuth: la.azimuth + (lb.azimuth - la.azimuth) * f } : la ?? lb;
|
|
293
|
+
const size = brush.size * (brush.pressureSize ? minSize + (1 - minSize) * p : 1);
|
|
294
|
+
const step = Math.max(0.5, size * brush.spacing);
|
|
295
|
+
if (t > 0 || i > 0) out.push(dab(a.x + dx * f, a.y + dy * f, p, l, dir, along + t, ta !== null && tb !== null ? ta + (tb - ta) * f : null, speed));
|
|
296
|
+
t += step;
|
|
297
|
+
}
|
|
298
|
+
carry = t - len;
|
|
299
|
+
along += len;
|
|
300
|
+
}
|
|
301
|
+
return out;
|
|
302
|
+
}
|
|
303
|
+
function pathStrokeCoverage(samples, options) {
|
|
304
|
+
const brush = normalizeBrush(options.brush);
|
|
305
|
+
const coverage = new CoverageMap();
|
|
306
|
+
const dabs = pathStrokeDabs(samples, options);
|
|
307
|
+
const g = options.gradient?.paint.type === "gradient" ? options.gradient : null;
|
|
308
|
+
const sampler = g ? new PaintGradientSampler(resolvePaintGradient(g.paint, g.colors ?? { paint: "#000000", secondary: "#ffffff" }), g.seed ?? 0) : null;
|
|
309
|
+
const tipTable = sampler?.acrossTip ? sampler.tipTable(TIP_GRADIENT_STEPS) : null;
|
|
310
|
+
const scratch = { field: new Float32Array(0), sample: { rgb: [0, 0, 0], alpha: 1 } };
|
|
311
|
+
let buf = new Float32Array(0);
|
|
312
|
+
let bounds = null;
|
|
313
|
+
for (const d of dabs) {
|
|
314
|
+
const rect = dabRect(d, brush.hardness);
|
|
315
|
+
const n = rect.width * rect.height;
|
|
316
|
+
if (n <= 0) continue;
|
|
317
|
+
if (buf.length < n) buf = new Float32Array(n);
|
|
318
|
+
const vals = buf.subarray(0, n);
|
|
319
|
+
rasterizeDab(d, brush.hardness, rect, vals);
|
|
320
|
+
if (sampler) {
|
|
321
|
+
const { color, field } = gradientDabColor(sampler, tipTable, d, d.params, rect, vals, scratch);
|
|
322
|
+
coverage.accumulate(rect, vals, d.opacity, color, field);
|
|
323
|
+
} else coverage.accumulate(rect, vals, d.opacity);
|
|
324
|
+
if (!bounds) bounds = { ...rect };
|
|
325
|
+
else {
|
|
326
|
+
const x = Math.min(bounds.x, rect.x);
|
|
327
|
+
const y = Math.min(bounds.y, rect.y);
|
|
328
|
+
bounds = { x, y, width: Math.max(bounds.x + bounds.width, rect.x + rect.width) - x, height: Math.max(bounds.y + bounds.height, rect.y + rect.height) - y };
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
const grain = options.grain;
|
|
332
|
+
if (grain && grain.depth > 0 && dabs.length) {
|
|
333
|
+
const pressure = dabs.reduce((sum, d) => sum + (d.params?.pressure ?? 1), 0) / dabs.length;
|
|
334
|
+
for (const [key, t] of coverage.tiles) {
|
|
335
|
+
const { tx, ty } = tileCoord(key);
|
|
336
|
+
for (let y = 0, k = 0; y < TILE; y++) {
|
|
337
|
+
const gy = ty * TILE + y + 0.5;
|
|
338
|
+
for (let x = 0; x < TILE; x++, k++) if (t[k] > 0) t[k] *= strokeGrainCatch(grain.at(tx * TILE + x + 0.5, gy), grain.depth, pressure);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
return { coverage, bounds, dabs: dabs.length };
|
|
343
|
+
}
|
|
344
|
+
function paintPathStroke(surface, samples, options) {
|
|
345
|
+
if (surface.channels !== 4) throw new Error("paintPathStroke paints RGBA surfaces (4 channels).");
|
|
346
|
+
const brush = normalizeBrush(options.brush);
|
|
347
|
+
const hex = (c) => "#" + [0, 1, 2].map((i) => Math.round(Math.min(255, Math.max(0, c[i]))).toString(16).padStart(2, "0")).join("");
|
|
348
|
+
let color = options.color;
|
|
349
|
+
if (options.paint?.paint.type === "color") {
|
|
350
|
+
const rgb = hexToPaintRgb(options.paint.paint.color).map((v) => Math.round(v * 255));
|
|
351
|
+
color = [rgb[0], rgb[1], rgb[2], color[3]];
|
|
352
|
+
}
|
|
353
|
+
const gradient = options.paint?.paint.type === "gradient" ? { ...options.paint, colors: options.paint.colors ?? { paint: hex(color), secondary: "#ffffff" } } : null;
|
|
354
|
+
const { coverage, bounds, dabs } = pathStrokeCoverage(samples, { ...options, gradient });
|
|
355
|
+
if (!bounds) return { surface, bounds: null, dabs };
|
|
356
|
+
const offset = options.offset ?? { x: 0, y: 0 };
|
|
357
|
+
const apply = {
|
|
358
|
+
mode: options.mode ?? "paint",
|
|
359
|
+
color,
|
|
360
|
+
background: [0, 0, 0, 0],
|
|
361
|
+
opacity: brush.opacity,
|
|
362
|
+
blend: options.blend ?? brush.blend,
|
|
363
|
+
lockTransparency: options.lockTransparency ?? false,
|
|
364
|
+
selection: options.selection ?? null,
|
|
365
|
+
offset
|
|
366
|
+
};
|
|
367
|
+
const tiles = new Map(surface.tiles);
|
|
368
|
+
for (const { tx, ty } of tilesInRect({ x: bounds.x - offset.x, y: bounds.y - offset.y, width: bounds.width, height: bounds.height })) {
|
|
369
|
+
const key = tileKey(tx, ty);
|
|
370
|
+
const src = surface.tiles.get(key)?.data;
|
|
371
|
+
const base = src && src.length === TILE * TILE * 4 ? src : new Uint8ClampedArray(TILE * TILE * 4);
|
|
372
|
+
const t = finishTile(applyStrokeToTile(coverage, base, 4, tx, ty, apply), 4, surface.defaultValue);
|
|
373
|
+
if (t) tiles.set(key, t);
|
|
374
|
+
else tiles.delete(key);
|
|
375
|
+
}
|
|
376
|
+
return { surface: new TiledSurface(4, tiles, surface.defaultValue), bounds, dabs };
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// src/paint/brushstroke.ts
|
|
380
|
+
var DEFAULT_MAX_PIXELS = 4096 * 4096;
|
|
381
|
+
var isProfilePath = (input) => !Array.isArray(input) && typeof input === "object" && input !== null && "points" in input;
|
|
382
|
+
function profileAt(profile, f) {
|
|
383
|
+
if (!profile || !profile.length) return void 0;
|
|
384
|
+
if (profile.length === 1) return profile[0];
|
|
385
|
+
const u = Math.min(1, Math.max(0, f)) * (profile.length - 1);
|
|
386
|
+
const i = Math.min(profile.length - 2, Math.floor(u));
|
|
387
|
+
return profile[i] + (profile[i + 1] - profile[i]) * (u - i);
|
|
388
|
+
}
|
|
389
|
+
function brushstrokeSamples(input) {
|
|
390
|
+
if (!isProfilePath(input)) return input.map((s) => ({ ...s }));
|
|
391
|
+
const pts = input.points;
|
|
392
|
+
const lengths = [0];
|
|
393
|
+
for (let i = 1; i < pts.length; i++) lengths.push(lengths[i - 1] + Math.hypot(pts[i].x - pts[i - 1].x, pts[i].y - pts[i - 1].y));
|
|
394
|
+
const total = lengths.at(-1) ?? 0;
|
|
395
|
+
return pts.map((p, i) => {
|
|
396
|
+
const f = total > 0 ? lengths[i] / total : pts.length > 1 ? i / (pts.length - 1) : 0;
|
|
397
|
+
const s = { x: p.x, y: p.y };
|
|
398
|
+
const pressure = profileAt(input.pressure, f);
|
|
399
|
+
const tiltX = profileAt(input.tiltX, f);
|
|
400
|
+
const tiltY = profileAt(input.tiltY, f);
|
|
401
|
+
if (pressure !== void 0) s.pressure = pressure;
|
|
402
|
+
if (tiltX !== void 0) s.tiltX = tiltX;
|
|
403
|
+
if (tiltY !== void 0) s.tiltY = tiltY;
|
|
404
|
+
return s;
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
var REFUSED_ENGINES = {
|
|
408
|
+
wet: "is a wet brush, and wet paint needs an area to flow in (paint it on a wet layer in the paint editor)",
|
|
409
|
+
mixer: "is a Mixer Brush, which picks up paint from under the tip and has none on a standalone stroke",
|
|
410
|
+
blender: "is a blender, which only moves paint that is already there",
|
|
411
|
+
smudge: "is a smudge brush, which only moves paint that is already there",
|
|
412
|
+
eraser: "is an eraser, which has nothing to remove on a standalone stroke"
|
|
413
|
+
};
|
|
414
|
+
function brushstrokeStrokeOptions(brush) {
|
|
415
|
+
if (!brush || typeof brush !== "object") throw new Error("A brushstroke needs a brush: tip settings ({ size, hardness, \u2026 }) or a paint brush preset.");
|
|
416
|
+
if (!("tip" in brush) || !brush.tip) return { brush: normalizeBrush(brush) };
|
|
417
|
+
const engine = brush.engine ?? "dab";
|
|
418
|
+
if (engine !== "dab") {
|
|
419
|
+
const label = brush.name ?? brush.id ?? "This brush";
|
|
420
|
+
const why = REFUSED_ENGINES[engine] ?? `uses the '${engine}' engine, which renderBrushstroke does not draw`;
|
|
421
|
+
throw new Error(`Brushstrokes render dry media only: '${label}' ${why}. Pick a dry brush (a dab-engine preset such as a pencil, pastel, charcoal, marker, ink or airbrush) or plain tip settings.`);
|
|
422
|
+
}
|
|
423
|
+
const d = brush.dynamics ?? {};
|
|
424
|
+
const tilt = { size: d.tiltSize ?? 0, roundness: d.tiltRoundness ?? 0 };
|
|
425
|
+
return {
|
|
426
|
+
brush: normalizeBrush(brush.tip),
|
|
427
|
+
followPath: brush.rotation === "stroke",
|
|
428
|
+
minSize: d.minSize ?? 0,
|
|
429
|
+
...tilt.size || tilt.roundness ? { tilt } : {}
|
|
430
|
+
};
|
|
431
|
+
}
|
|
432
|
+
function isBrushstrokeBrush(brush) {
|
|
433
|
+
return !("tip" in brush) || !brush.tip || (brush.engine ?? "dab") === "dab";
|
|
434
|
+
}
|
|
435
|
+
var finite = (v) => typeof v === "number" && Number.isFinite(v);
|
|
436
|
+
function brushCharacterOf(brush) {
|
|
437
|
+
if (!("tip" in brush) || !brush.tip) return { grain: 0, size: 0, angle: 0, opacity: 0, scatter: 0 };
|
|
438
|
+
const d = brush.dynamics ?? {};
|
|
439
|
+
const u = (v, hi = 1) => finite(v) ? Math.min(hi, Math.max(0, v)) : 0;
|
|
440
|
+
return { grain: u(brush.grain), size: u(d.sizeJitter), angle: u(d.angleJitter), opacity: u(d.opacityJitter), scatter: u(d.scatter, 4) };
|
|
441
|
+
}
|
|
442
|
+
var papers = /* @__PURE__ */ new Map();
|
|
443
|
+
function paperGrain(paper) {
|
|
444
|
+
const pattern = paper.pattern ?? "sanded";
|
|
445
|
+
const seed = finite(paper.seed) ? Math.round(Math.abs(paper.seed)) : 1;
|
|
446
|
+
const scale = finite(paper.scale) && paper.scale > 0 ? Math.min(8, Math.max(0.25, paper.scale)) : 1;
|
|
447
|
+
const key = `${pattern}:${seed}:${scale}`;
|
|
448
|
+
let g = papers.get(key);
|
|
449
|
+
if (!g) {
|
|
450
|
+
g = new PaperGrain({ pattern, seed, scale, tiling: "mirror", dry: { contrast: 1, invert: false }, wet: { contrast: 1, invert: false } });
|
|
451
|
+
if (papers.size > 16) papers.delete(papers.keys().next().value);
|
|
452
|
+
papers.set(key, g);
|
|
453
|
+
}
|
|
454
|
+
return g;
|
|
455
|
+
}
|
|
456
|
+
function renderBrushstroke(input, brush, options = {}) {
|
|
457
|
+
const strokeOptions = brushstrokeStrokeOptions(brush);
|
|
458
|
+
const samples = brushstrokeSamples(input);
|
|
459
|
+
for (const s of samples) if (!finite(s.x) || !finite(s.y)) throw new Error("Brushstroke samples need finite x and y.");
|
|
460
|
+
const solid = options.paint && !("type" in options.paint) ? options.paint.color : null;
|
|
461
|
+
const source = options.paint && "type" in options.paint ? options.paint : null;
|
|
462
|
+
const color = solid ?? options.color ?? [0, 0, 0, 255];
|
|
463
|
+
let scale = finite(options.scale) && options.scale > 0 ? Math.min(BRUSHSTROKE_MAX_SCALE, Math.max(BRUSHSTROKE_MIN_SCALE, options.scale)) : 1;
|
|
464
|
+
if (!samples.length) return { image: { width: 0, height: 0, data: new Uint8ClampedArray(0) }, bounds: null, scale, dabs: 0 };
|
|
465
|
+
const tip = strokeOptions.brush;
|
|
466
|
+
const reach = tip.size * (1 + 1.5 * (strokeOptions.tilt?.size ?? 0)) + 4;
|
|
467
|
+
let x0 = Infinity, y0 = Infinity, x1 = -Infinity, y1 = -Infinity;
|
|
468
|
+
for (const s of samples) {
|
|
469
|
+
x0 = Math.min(x0, s.x);
|
|
470
|
+
y0 = Math.min(y0, s.y);
|
|
471
|
+
x1 = Math.max(x1, s.x);
|
|
472
|
+
y1 = Math.max(y1, s.y);
|
|
473
|
+
}
|
|
474
|
+
const maxPixels = finite(options.maxPixels) && options.maxPixels > 0 ? options.maxPixels : DEFAULT_MAX_PIXELS;
|
|
475
|
+
const area = (x1 - x0 + reach) * (y1 - y0 + reach);
|
|
476
|
+
if (area * scale * scale > maxPixels) scale = Math.max(BRUSHSTROKE_MIN_SCALE, Math.sqrt(maxPixels / area));
|
|
477
|
+
const scaled = samples.map((s) => ({ ...s, x: s.x * scale, y: s.y * scale }));
|
|
478
|
+
let character = {};
|
|
479
|
+
if (options.character) {
|
|
480
|
+
const c = brushCharacterOf(brush);
|
|
481
|
+
const ch = options.character;
|
|
482
|
+
const seed = finite(ch.seed) ? ch.seed | 0 : hashString(JSON.stringify(input));
|
|
483
|
+
const jitter = c.size || c.angle || c.opacity || c.scatter ? { seed, size: c.size, angle: c.angle, opacity: c.opacity, scatter: c.scatter } : void 0;
|
|
484
|
+
const paper = ch.paper === null ? null : ch.paper ?? {};
|
|
485
|
+
const depth = paper ? Math.min(1, Math.max(0, (finite(paper.depth) ? paper.depth : 0.5) * c.grain)) : 0;
|
|
486
|
+
let grain;
|
|
487
|
+
if (paper && depth > 0) {
|
|
488
|
+
const g = paperGrain(paper);
|
|
489
|
+
const ox = ch.origin?.x ?? 0;
|
|
490
|
+
const oy = ch.origin?.y ?? 0;
|
|
491
|
+
const k = (finite(ch.unit) && ch.unit > 0 ? ch.unit : 1) / scale;
|
|
492
|
+
grain = { depth, at: (x, y) => g.at(ox + x * k, oy + y * k) };
|
|
493
|
+
}
|
|
494
|
+
character = { ...jitter ? { jitter } : {}, ...grain ? { grain } : {} };
|
|
495
|
+
}
|
|
496
|
+
const { surface, bounds, dabs } = paintPathStroke(emptySurface(4), scaled, {
|
|
497
|
+
...strokeOptions,
|
|
498
|
+
...character,
|
|
499
|
+
brush: { ...tip, size: tip.size * scale },
|
|
500
|
+
closed: options.closed ?? strokeOptions.closed,
|
|
501
|
+
color,
|
|
502
|
+
// Gradient lengths are in path units: scale them with the image.
|
|
503
|
+
...source ? { paint: { paint: source.type === "gradient" ? scalePaintGradient(source, scale) : source, seed: options.seed ?? 0 } } : {}
|
|
504
|
+
});
|
|
505
|
+
if (!bounds) return { image: { width: 0, height: 0, data: new Uint8ClampedArray(0) }, bounds: null, scale, dabs };
|
|
506
|
+
const rect = bounds;
|
|
507
|
+
const data = readRegion(surface, rect);
|
|
508
|
+
return {
|
|
509
|
+
image: { width: rect.width, height: rect.height, data },
|
|
510
|
+
bounds: { x: rect.x / scale, y: rect.y / scale, width: rect.width / scale, height: rect.height / scale },
|
|
511
|
+
scale,
|
|
512
|
+
dabs
|
|
513
|
+
};
|
|
514
|
+
}
|
|
515
|
+
function brushstrokeDataUrl(stroke) {
|
|
516
|
+
const { width, height, data } = stroke.image;
|
|
517
|
+
return width && height ? pngDataUrl(width, height, data) : "";
|
|
518
|
+
}
|
|
519
|
+
function brushstrokeToCanvas(stroke, createCanvas) {
|
|
520
|
+
const { width, height, data } = stroke.image;
|
|
521
|
+
if (!width || !height) return null;
|
|
522
|
+
const canvas = createCanvas(width, height);
|
|
523
|
+
const ctx = canvas.getContext("2d");
|
|
524
|
+
if (!ctx) return null;
|
|
525
|
+
const img = ctx.createImageData(width, height);
|
|
526
|
+
img.data.set(data);
|
|
527
|
+
ctx.putImageData(img, 0, 0);
|
|
528
|
+
return canvas;
|
|
529
|
+
}
|
|
530
|
+
function hashString(s, h = 2166136261) {
|
|
531
|
+
for (let i = 0; i < s.length; i++) {
|
|
532
|
+
h ^= s.charCodeAt(i);
|
|
533
|
+
h = Math.imul(h, 16777619) >>> 0;
|
|
534
|
+
}
|
|
535
|
+
return h;
|
|
536
|
+
}
|
|
537
|
+
function brushstrokeKey(input, brush, options = {}) {
|
|
538
|
+
const path = JSON.stringify(input);
|
|
539
|
+
const { brush: tip, ...rest } = brushstrokeStrokeOptions(brush);
|
|
540
|
+
const character = options.character ? [options.character, brushCharacterOf(brush)] : null;
|
|
541
|
+
const rest2 = JSON.stringify([tip, rest, options.paint ?? options.color ?? null, options.seed ?? 0, options.closed ?? false, options.maxPixels ?? null, ...character ? [character] : []]);
|
|
542
|
+
const scale = finite(options.scale) ? options.scale : 1;
|
|
543
|
+
return `${hashString(path).toString(16)}:${path.length}:${hashString(rest2).toString(16)}:${scale}`;
|
|
544
|
+
}
|
|
545
|
+
var BrushstrokeCache = class {
|
|
546
|
+
constructor(capacity = 64) {
|
|
547
|
+
this.capacity = capacity;
|
|
548
|
+
}
|
|
549
|
+
capacity;
|
|
550
|
+
entries = /* @__PURE__ */ new Map();
|
|
551
|
+
/** Renders that missed the cache (for tests and stats). */
|
|
552
|
+
misses = 0;
|
|
553
|
+
get size() {
|
|
554
|
+
return this.entries.size;
|
|
555
|
+
}
|
|
556
|
+
/** The cached stroke for these arguments, rendering (and caching) it on a miss. */
|
|
557
|
+
render(input, brush, options = {}) {
|
|
558
|
+
const key = brushstrokeKey(input, brush, options);
|
|
559
|
+
const hit = this.entries.get(key);
|
|
560
|
+
if (hit) {
|
|
561
|
+
this.entries.delete(key);
|
|
562
|
+
this.entries.set(key, hit);
|
|
563
|
+
return hit;
|
|
564
|
+
}
|
|
565
|
+
this.misses++;
|
|
566
|
+
const out = renderBrushstroke(input, brush, options);
|
|
567
|
+
this.entries.set(key, out);
|
|
568
|
+
while (this.entries.size > Math.max(1, this.capacity)) this.entries.delete(this.entries.keys().next().value);
|
|
569
|
+
return out;
|
|
570
|
+
}
|
|
571
|
+
clear() {
|
|
572
|
+
this.entries.clear();
|
|
573
|
+
}
|
|
574
|
+
};
|
|
575
|
+
|
|
576
|
+
export {
|
|
577
|
+
GRAIN_PATTERNS,
|
|
578
|
+
GRAIN_TILE,
|
|
579
|
+
grainHeights,
|
|
580
|
+
PaperGrain,
|
|
581
|
+
grainCatch,
|
|
582
|
+
strokeGrainCatch,
|
|
583
|
+
pathStrokeDabs,
|
|
584
|
+
pathStrokeCoverage,
|
|
585
|
+
paintPathStroke,
|
|
586
|
+
brushstrokeSamples,
|
|
587
|
+
brushstrokeStrokeOptions,
|
|
588
|
+
isBrushstrokeBrush,
|
|
589
|
+
renderBrushstroke,
|
|
590
|
+
brushstrokeDataUrl,
|
|
591
|
+
brushstrokeToCanvas,
|
|
592
|
+
brushstrokeKey,
|
|
593
|
+
BrushstrokeCache
|
|
594
|
+
};
|
|
@@ -11,10 +11,10 @@ import {
|
|
|
11
11
|
CHART_OOXML_NS,
|
|
12
12
|
CHART_OOXML_RELATIONSHIP,
|
|
13
13
|
chartToOoxml
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-L6Y7TSQ4.js";
|
|
15
15
|
import {
|
|
16
16
|
normalizeChartSpec
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-6ZZKRH7R.js";
|
|
18
18
|
|
|
19
19
|
// src/export/images.ts
|
|
20
20
|
var DOCX_IMAGE_TYPES = {
|
|
@@ -8,7 +8,7 @@ var _chunkA6QWKBJPcjs = require('./chunk-A6QWKBJP.cjs');
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
var
|
|
11
|
+
var _chunk5UEFBM2Mcjs = require('./chunk-5UEFBM2M.cjs');
|
|
12
12
|
|
|
13
13
|
// src/tokens/types.ts
|
|
14
14
|
var TOKEN_TYPES = ["color", "number", "string", "boolean"];
|
|
@@ -1389,10 +1389,10 @@ var contrastPairs = {
|
|
|
1389
1389
|
const modes = { [collection.id]: mode.id, [b.collectionId]: _nullishCoalesce(_optionalChain([findTokenMode, 'call', _26 => _26(getTokenCollection(state, b.collectionId), mode.name), 'optionalAccess', _27 => _27.id]), () => ( mode.id)) };
|
|
1390
1390
|
const fv = resolveToken(state, f.id, modes);
|
|
1391
1391
|
const bv = resolveToken(state, b.id, modes);
|
|
1392
|
-
const fc = fv.ok && typeof fv.value === "string" ?
|
|
1393
|
-
const bc = bv.ok && typeof bv.value === "string" ?
|
|
1392
|
+
const fc = fv.ok && typeof fv.value === "string" ? _chunk5UEFBM2Mcjs.parseColor.call(void 0, fv.value) : null;
|
|
1393
|
+
const bc = bv.ok && typeof bv.value === "string" ? _chunk5UEFBM2Mcjs.parseColor.call(void 0, bv.value) : null;
|
|
1394
1394
|
if (!fc || !bc) continue;
|
|
1395
|
-
const r =
|
|
1395
|
+
const r = _chunk5UEFBM2Mcjs.contrastRatio.call(void 0, fc, bc);
|
|
1396
1396
|
if (r < ratio) {
|
|
1397
1397
|
findings.push({
|
|
1398
1398
|
severity: "error",
|
|
@@ -1,12 +1,12 @@
|
|
|
1
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; }
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var _chunkEUIDTZNQcjs = require('./chunk-EUIDTZNQ.cjs');
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
var
|
|
6
|
+
var _chunkTFF2GTGNcjs = require('./chunk-TFF2GTGN.cjs');
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
var
|
|
9
|
+
var _chunk5UEFBM2Mcjs = require('./chunk-5UEFBM2M.cjs');
|
|
10
10
|
|
|
11
11
|
// src/chart/color.ts
|
|
12
12
|
var NAMED = {
|
|
@@ -83,18 +83,18 @@ function chartTextOn(fill, fallback, dark = "#0f172a", light = "#ffffff") {
|
|
|
83
83
|
return darkRatio >= lightRatio ? dark : light;
|
|
84
84
|
}
|
|
85
85
|
function chartRgbToOklab(rgb) {
|
|
86
|
-
const lab =
|
|
86
|
+
const lab = _chunk5UEFBM2Mcjs.rgbToOklab.call(void 0, { r: rgb[0], g: rgb[1], b: rgb[2], a: 1 });
|
|
87
87
|
return [lab.l, lab.a, lab.b];
|
|
88
88
|
}
|
|
89
89
|
function chartColorDistance(a, b) {
|
|
90
|
-
return
|
|
90
|
+
return _chunkTFF2GTGNcjs.deltaEOK.call(void 0,
|
|
91
91
|
{ r: a[0], g: a[1], b: a[2], a: 1 },
|
|
92
92
|
{ r: b[0], g: b[1], b: b[2], a: 1 }
|
|
93
93
|
);
|
|
94
94
|
}
|
|
95
95
|
function simulateChartVision(rgb, vision) {
|
|
96
96
|
if (vision === "normal") return rgb;
|
|
97
|
-
const c =
|
|
97
|
+
const c = _chunkEUIDTZNQcjs.simulateColorVision.call(void 0, { r: rgb[0], g: rgb[1], b: rgb[2], a: 1 }, vision);
|
|
98
98
|
return [c.r, c.g, c.b];
|
|
99
99
|
}
|
|
100
100
|
function checkChartColors(colors, options = {}) {
|