@pixerate/editor 0.248.0 → 0.250.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 (122) hide show
  1. package/README.md +1 -0
  2. package/dist/animation-editor/index.cjs +118 -114
  3. package/dist/animation-editor/index.js +11 -7
  4. package/dist/{brushstrokeRender-QLCXROJK.js → brushstrokeRender-2FHFLSEG.js} +8 -4
  5. package/dist/{brushstrokeRender-DTDPFBLC.cjs → brushstrokeRender-QGRXOKDA.cjs} +15 -11
  6. package/dist/canvas/index.cjs +71 -15
  7. package/dist/canvas/index.d.cts +1 -0
  8. package/dist/canvas/index.d.ts +1 -0
  9. package/dist/canvas/index.js +58 -2
  10. package/dist/canvas/stickers.d.cts +35 -0
  11. package/dist/canvas/stickers.d.ts +35 -0
  12. package/dist/{chunk-RXZL4NG5.js → chunk-226QDRO3.js} +1 -1
  13. package/dist/{chunk-SC2RZ5EF.js → chunk-2VJAVXLI.js} +2 -2
  14. package/dist/{chunk-OLNIPTB3.cjs → chunk-2VX55NFM.cjs} +1 -320
  15. package/dist/chunk-3K6HWEXZ.cjs +92 -0
  16. package/dist/{chunk-UOOK7HTX.js → chunk-3PPJRMIG.js} +1 -1
  17. package/dist/{chunk-ZFSLEOSQ.js → chunk-3TWOCSCY.js} +11 -9
  18. package/dist/chunk-4D6KP5BV.js +92 -0
  19. package/dist/chunk-4JNWA3VT.cjs +302 -0
  20. package/dist/{chunk-L3JFOTBQ.js → chunk-5E2Q7ZHI.js} +1 -1
  21. package/dist/{chunk-2ONK3ERD.cjs → chunk-75K3W4D6.cjs} +20 -20
  22. package/dist/{chunk-AU6MWQKZ.js → chunk-ABL7IWFZ.js} +1 -1
  23. package/dist/chunk-ATK6ABN3.cjs +303 -0
  24. package/dist/{chunk-7T7JWTVE.cjs → chunk-BOHDJJ2O.cjs} +8 -8
  25. package/dist/{chunk-2PBZBRP5.js → chunk-D5KGAO4Z.js} +10 -92
  26. package/dist/{chunk-HB4ICNNA.cjs → chunk-DPYAO5U6.cjs} +42 -42
  27. package/dist/{chunk-6G6ZDDDB.cjs → chunk-GT77U7QG.cjs} +303 -149
  28. package/dist/{chunk-PQ3H2AAN.cjs → chunk-I7NJPHWV.cjs} +122 -204
  29. package/dist/{chunk-42TWUPNJ.js → chunk-IRSTHLQQ.js} +1 -320
  30. package/dist/{chunk-GHCSC2WP.cjs → chunk-ISIO63Q5.cjs} +21 -15
  31. package/dist/{chunk-OFH6Q67U.js → chunk-JA57JIT5.js} +9 -3
  32. package/dist/{chunk-VMROIWLL.cjs → chunk-KBYB7OWB.cjs} +3 -3
  33. package/dist/{chunk-Q2HA52V4.js → chunk-KDLBJ6QR.js} +2 -2
  34. package/dist/{chunk-WVS5KQDH.cjs → chunk-M2VKFE5L.cjs} +246 -244
  35. package/dist/{chunk-5GLYUSNT.js → chunk-NOHJP5TK.js} +1 -1
  36. package/dist/{chunk-XNRBMYNB.js → chunk-NTRAVM2I.js} +1 -1
  37. package/dist/{chunk-VNBUDVD4.js → chunk-OTEPAQJX.js} +228 -74
  38. package/dist/chunk-OTTT5N3K.js +322 -0
  39. package/dist/{chunk-QOBCBGGI.cjs → chunk-QKXO6JPP.cjs} +14 -14
  40. package/dist/{chunk-NZ3O3A5C.js → chunk-SMSGP2HQ.js} +1 -1
  41. package/dist/chunk-SZTI6EER.js +13 -0
  42. package/dist/chunk-U4NUOKBT.js +303 -0
  43. package/dist/chunk-U67EN7GG.cjs +13 -0
  44. package/dist/chunk-W5M3J7PV.cjs +322 -0
  45. package/dist/{chunk-4P6H35HU.js → chunk-WA44NKPF.js} +2 -2
  46. package/dist/chunk-WKH5ZAUA.js +302 -0
  47. package/dist/{chunk-L6REDLNB.cjs → chunk-WPUXGDH4.cjs} +7 -7
  48. package/dist/{chunk-P3NIPIKS.js → chunk-WQCNC4DK.js} +1 -1
  49. package/dist/{chunk-IBDU6EGZ.cjs → chunk-X7WRL5ZZ.cjs} +35 -35
  50. package/dist/{chunk-XWTRATIM.cjs → chunk-YM6ZBTXG.cjs} +23 -23
  51. package/dist/{chunk-TPWB4Y6L.cjs → chunk-YW43M56C.cjs} +1 -1
  52. package/dist/{chunk-K5DS2JTA.cjs → chunk-Z3BRH4JK.cjs} +6 -6
  53. package/dist/{chunk-XNZFVYC2.cjs → chunk-ZBCT5MEA.cjs} +7 -7
  54. package/dist/effects/helpers.d.cts +6 -0
  55. package/dist/effects/helpers.d.ts +6 -0
  56. package/dist/effects/index.cjs +62 -60
  57. package/dist/effects/index.js +5 -3
  58. package/dist/effects/tools.d.cts +6 -0
  59. package/dist/effects/tools.d.ts +6 -0
  60. package/dist/image-editor/effects.d.cts +1 -1
  61. package/dist/image-editor/effects.d.ts +1 -1
  62. package/dist/image-editor/index.cjs +1097 -1069
  63. package/dist/image-editor/index.d.cts +1 -0
  64. package/dist/image-editor/index.d.ts +1 -0
  65. package/dist/image-editor/index.js +58 -30
  66. package/dist/image-editor/stickers.d.cts +9 -0
  67. package/dist/image-editor/stickers.d.ts +9 -0
  68. package/dist/paint/index.cjs +8 -5
  69. package/dist/paint/index.js +13 -10
  70. package/dist/paint-editor/controller.d.cts +37 -1
  71. package/dist/paint-editor/controller.d.ts +37 -1
  72. package/dist/paint-editor/index.cjs +753 -609
  73. package/dist/paint-editor/index.d.cts +3 -0
  74. package/dist/paint-editor/index.d.ts +3 -0
  75. package/dist/paint-editor/index.js +187 -43
  76. package/dist/paint-editor/sticker-art.d.cts +55 -0
  77. package/dist/paint-editor/sticker-art.d.ts +55 -0
  78. package/dist/paint-editor/stickers.d.cts +30 -17
  79. package/dist/paint-editor/stickers.d.ts +30 -17
  80. package/dist/paint-editor/stroke.d.cts +4 -0
  81. package/dist/paint-editor/stroke.d.ts +4 -0
  82. package/dist/paint-editor/ui.d.cts +10 -2
  83. package/dist/paint-editor/ui.d.ts +10 -2
  84. package/dist/raster/index.cjs +6 -4
  85. package/dist/raster/index.js +12 -10
  86. package/dist/stickers/browser.d.cts +48 -0
  87. package/dist/stickers/browser.d.ts +48 -0
  88. package/dist/stickers/combine.d.cts +10 -0
  89. package/dist/stickers/combine.d.ts +10 -0
  90. package/dist/stickers/conformance.d.cts +18 -0
  91. package/dist/stickers/conformance.d.ts +18 -0
  92. package/dist/stickers/editor.d.cts +14 -0
  93. package/dist/stickers/editor.d.ts +14 -0
  94. package/dist/stickers/errors.d.cts +6 -0
  95. package/dist/stickers/errors.d.ts +6 -0
  96. package/dist/stickers/fake.d.cts +16 -0
  97. package/dist/stickers/fake.d.ts +16 -0
  98. package/dist/stickers/helpers.d.cts +51 -0
  99. package/dist/stickers/helpers.d.ts +51 -0
  100. package/dist/stickers/index.cjs +337 -0
  101. package/dist/stickers/index.d.cts +16 -0
  102. package/dist/stickers/index.d.ts +16 -0
  103. package/dist/stickers/index.js +337 -0
  104. package/dist/stickers/stamps.d.cts +13 -0
  105. package/dist/stickers/stamps.d.ts +13 -0
  106. package/dist/stickers/tools.d.cts +81 -0
  107. package/dist/stickers/tools.d.ts +81 -0
  108. package/dist/stickers/types.d.cts +123 -0
  109. package/dist/stickers/types.d.ts +123 -0
  110. package/dist/vector/index.cjs +1018 -981
  111. package/dist/vector/index.d.cts +1 -0
  112. package/dist/vector/index.d.ts +1 -0
  113. package/dist/vector/index.js +44 -7
  114. package/dist/vector/stickers.d.cts +11 -0
  115. package/dist/vector/stickers.d.ts +11 -0
  116. package/dist/video-editor/index.cjs +344 -344
  117. package/dist/video-editor/index.js +4 -4
  118. package/package.json +11 -1
  119. package/skills/README.md +1 -0
  120. package/skills/pixerate-image-editor/SKILL.md +1 -1
  121. package/skills/pixerate-paint-editor/SKILL.md +8 -5
  122. package/skills/pixerate-stickers/SKILL.md +57 -0
@@ -0,0 +1,303 @@
1
+ import {
2
+ EDITOR_STICKERS_ID,
3
+ STAMP_KINDS,
4
+ stampCoverage,
5
+ stickerPage,
6
+ stickerRefOf
7
+ } from "./chunk-WKH5ZAUA.js";
8
+ import {
9
+ StickerError
10
+ } from "./chunk-SZTI6EER.js";
11
+ import {
12
+ pngDataUrl
13
+ } from "./chunk-OTTT5N3K.js";
14
+
15
+ // src/stickers/editor.ts
16
+ var BOX = 100;
17
+ var GRID = 128;
18
+ var SHAPE_SEED = 7;
19
+ var LICENCE = { spdx: "MIT", name: "MIT", commercial: true };
20
+ var META = {
21
+ dot: { name: "Dot", category: "shapes", tags: ["circle", "round", "spot"], colour: "#2563eb", description: "A round dot." },
22
+ star: { name: "Star", category: "shapes", tags: ["five-pointed", "favourite", "rating"], colour: "#f59e0b", description: "A five-pointed star, one point up." },
23
+ heart: { name: "Heart", category: "shapes", tags: ["love", "like"], colour: "#e11d48", description: "A heart." },
24
+ leaf: { name: "Leaf", category: "nature", tags: ["plant", "green"], colour: "#16a34a", description: "A pointed leaf with a midrib." },
25
+ flower: { name: "Flower", category: "nature", tags: ["petals", "blossom"], colour: "#db2777", description: "A five-petal flower." },
26
+ confetti: { name: "Confetti", category: "party", tags: ["celebration", "rectangle"], colour: "#7c3aed", description: "A small strip of confetti." },
27
+ splat: { name: "Splat", category: "party", tags: ["paint", "splash", "blob"], colour: "#0891b2", description: "A paint splat with drops." },
28
+ sparkle: { name: "Sparkle", category: "party", tags: ["twinkle", "shine", "glint"], colour: "#eab308", description: "A four-pointed twinkle." },
29
+ ring: { name: "Ring", category: "shapes", tags: ["circle", "outline", "hoop"], colour: "#0f766e", description: "A ring." }
30
+ };
31
+ var HEX = /^#[0-9a-fA-F]{6}$/;
32
+ function stampOutline(kind) {
33
+ const n = GRID;
34
+ const f = new Float32Array((n + 1) * (n + 1));
35
+ for (let j = 0; j <= n; j++) for (let i = 0; i <= n; i++) f[j * (n + 1) + i] = stampCoverage(kind, i / n * 2 - 1, j / n * 2 - 1, SHAPE_SEED) - 0.5;
36
+ const at = (i, j) => f[j * (n + 1) + i];
37
+ const points = /* @__PURE__ */ new Map();
38
+ const point = (key, i0, j0, i1, j1) => {
39
+ if (!points.has(key)) {
40
+ const a = at(i0, j0);
41
+ const b = at(i1, j1);
42
+ const t = a / (a - b);
43
+ points.set(key, [(i0 + (i1 - i0) * t) / n * BOX, (j0 + (j1 - j0) * t) / n * BOX]);
44
+ }
45
+ return key;
46
+ };
47
+ const next = /* @__PURE__ */ new Map();
48
+ for (let j = 0; j < n; j++) {
49
+ for (let i = 0; i < n; i++) {
50
+ const tl = at(i, j) > 0 ? 1 : 0;
51
+ const tr = at(i + 1, j) > 0 ? 1 : 0;
52
+ const br = at(i + 1, j + 1) > 0 ? 1 : 0;
53
+ const bl = at(i, j + 1) > 0 ? 1 : 0;
54
+ const code = tl << 3 | tr << 2 | br << 1 | bl;
55
+ if (code === 0 || code === 15) continue;
56
+ const top = () => point(`h${i},${j}`, i, j, i + 1, j);
57
+ const right = () => point(`v${i + 1},${j}`, i + 1, j, i + 1, j + 1);
58
+ const bottom = () => point(`h${i},${j + 1}`, i, j + 1, i + 1, j + 1);
59
+ const left = () => point(`v${i},${j}`, i, j, i, j + 1);
60
+ const seg = (a, b) => next.set(a, b);
61
+ const centre = at(i, j) + at(i + 1, j) + at(i + 1, j + 1) + at(i, j + 1) > 0;
62
+ switch (code) {
63
+ case 1:
64
+ seg(left(), bottom());
65
+ break;
66
+ case 2:
67
+ seg(bottom(), right());
68
+ break;
69
+ case 3:
70
+ seg(left(), right());
71
+ break;
72
+ case 4:
73
+ seg(right(), top());
74
+ break;
75
+ case 5:
76
+ if (centre) {
77
+ seg(left(), top());
78
+ seg(right(), bottom());
79
+ } else {
80
+ seg(left(), bottom());
81
+ seg(right(), top());
82
+ }
83
+ break;
84
+ case 6:
85
+ seg(bottom(), top());
86
+ break;
87
+ case 7:
88
+ seg(left(), top());
89
+ break;
90
+ case 8:
91
+ seg(top(), left());
92
+ break;
93
+ case 9:
94
+ seg(top(), bottom());
95
+ break;
96
+ case 10:
97
+ if (centre) {
98
+ seg(top(), right());
99
+ seg(bottom(), left());
100
+ } else {
101
+ seg(top(), left());
102
+ seg(bottom(), right());
103
+ }
104
+ break;
105
+ case 11:
106
+ seg(top(), right());
107
+ break;
108
+ case 12:
109
+ seg(right(), left());
110
+ break;
111
+ case 13:
112
+ seg(right(), bottom());
113
+ break;
114
+ case 14:
115
+ seg(bottom(), left());
116
+ break;
117
+ }
118
+ }
119
+ }
120
+ const loops = [];
121
+ const seen = /* @__PURE__ */ new Set();
122
+ for (const start of next.keys()) {
123
+ if (seen.has(start)) continue;
124
+ const loop = [];
125
+ let k = start;
126
+ while (k !== void 0 && !seen.has(k)) {
127
+ seen.add(k);
128
+ loop.push(points.get(k));
129
+ k = next.get(k);
130
+ }
131
+ if (loop.length >= 3) loops.push(simplify(loop, 0.12));
132
+ }
133
+ const fmt = (v) => String(Math.round(v * 100) / 100);
134
+ return loops.map((l) => "M" + l.map(([x, y]) => `${fmt(x)} ${fmt(y)}`).join("L") + "Z").join("");
135
+ }
136
+ function simplify(loop, eps) {
137
+ if (loop.length < 8) return loop;
138
+ const keep = new Uint8Array(loop.length);
139
+ const rdp = (a, b) => {
140
+ const [ax, ay] = loop[a];
141
+ const [bx, by] = loop[b];
142
+ const len = Math.hypot(bx - ax, by - ay) || 1e-9;
143
+ let worst = -1;
144
+ let far = 0;
145
+ for (let i = a + 1; i < b; i++) {
146
+ const d = Math.abs((bx - ax) * (ay - loop[i][1]) - (ax - loop[i][0]) * (by - ay)) / len;
147
+ if (d > far) {
148
+ far = d;
149
+ worst = i;
150
+ }
151
+ }
152
+ if (worst !== -1 && far > eps) {
153
+ keep[worst] = 1;
154
+ rdp(a, worst);
155
+ rdp(worst, b);
156
+ }
157
+ };
158
+ const mid = Math.floor(loop.length / 2);
159
+ keep[0] = keep[mid] = 1;
160
+ rdp(0, mid);
161
+ rdp(mid, loop.length - 1);
162
+ keep[loop.length - 1] = 1;
163
+ return loop.filter((_, i) => keep[i]);
164
+ }
165
+ function stampPixels(kind, size, colour) {
166
+ const out = new Uint8ClampedArray(size * size * 4);
167
+ const n = parseInt(colour.slice(1), 16);
168
+ const ss = size <= 128 ? 3 : 2;
169
+ for (let y = 0; y < size; y++) {
170
+ for (let x = 0; x < size; x++) {
171
+ let c = 0;
172
+ for (let sy = 0; sy < ss; sy++) for (let sx = 0; sx < ss; sx++) c += stampCoverage(kind, (x + (sx + 0.5) / ss) / size * 2 - 1, (y + (sy + 0.5) / ss) / size * 2 - 1, SHAPE_SEED);
173
+ const a = Math.round(c / (ss * ss) * 255);
174
+ if (!a) continue;
175
+ const i = (y * size + x) * 4;
176
+ out[i] = n >> 16 & 255;
177
+ out[i + 1] = n >> 8 & 255;
178
+ out[i + 2] = n & 255;
179
+ out[i + 3] = a;
180
+ }
181
+ }
182
+ return out;
183
+ }
184
+ function editorStickers() {
185
+ const outlines = /* @__PURE__ */ new Map();
186
+ const thumbs = /* @__PURE__ */ new Map();
187
+ const outline = (k) => outlines.get(k) ?? (outlines.set(k, stampOutline(k)), outlines.get(k));
188
+ const summary = (k) => {
189
+ const m = META[k];
190
+ if (!thumbs.has(k)) thumbs.set(k, pngDataUrl(48, 48, stampPixels(k, 48, m.colour)));
191
+ return { id: k, name: m.name, category: m.category, tags: m.tags, description: m.description, width: BOX, height: BOX, thumbnail: thumbs.get(k), formats: ["svg", "png"], licence: { ...LICENCE }, tintable: true };
192
+ };
193
+ const kind = (id) => {
194
+ if (!STAMP_KINDS.includes(id)) throw new StickerError("unknown_sticker", `The editor has no sticker "${id}"; its stickers are ${STAMP_KINDS.join(", ")}.`);
195
+ return id;
196
+ };
197
+ return {
198
+ id: EDITOR_STICKERS_ID,
199
+ name: "Editor stickers",
200
+ version: "1",
201
+ capabilities: { supportsSearch: true, supportsSvg: true, supportsRaster: true, maxSize: 1024 },
202
+ list: (options) => stickerPage(STAMP_KINDS.map(summary), options),
203
+ search: (query, options) => stickerPage(STAMP_KINDS.map(summary), options, query),
204
+ describe(id) {
205
+ if (!STAMP_KINDS.includes(id)) return void 0;
206
+ const k = id;
207
+ return { ...summary(k), silhouette: outline(k), colours: [META[k].colour] };
208
+ },
209
+ categories: () => [...new Set(STAMP_KINDS.map((k) => META[k].category))].map((c) => ({ id: c, name: c[0].toUpperCase() + c.slice(1), count: STAMP_KINDS.filter((k) => META[k].category === c).length })),
210
+ load(id, options = {}) {
211
+ const k = kind(id);
212
+ const colour = options.colour ?? META[k].colour;
213
+ if (!HEX.test(colour)) throw new StickerError("invalid_argument", `colour ${JSON.stringify(colour)} must be #rrggbb.`);
214
+ if (options.format === "png") {
215
+ const size = options.size ?? 256;
216
+ if (!(Number.isInteger(size) && size >= 8 && size <= 1024)) throw new StickerError("invalid_argument", `size must be a whole number of px from 8 to 1024, got ${size}.`);
217
+ return { kind: "image", url: pngDataUrl(size, size, stampPixels(k, size, colour.toLowerCase())), width: size, height: size };
218
+ }
219
+ if (options.format !== void 0 && options.format !== "svg") throw new StickerError("unsupported_format", `format must be svg or png, got ${JSON.stringify(options.format)}.`);
220
+ const d = outline(k);
221
+ const svg = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${BOX} ${BOX}" width="${BOX}" height="${BOX}"><path fill="${colour.toLowerCase()}" fill-rule="evenodd" d="${d}"/></svg>`;
222
+ return { kind: "svg", svg, silhouette: d };
223
+ }
224
+ };
225
+ }
226
+
227
+ // src/stickers/browser.ts
228
+ var StickerBrowser = class {
229
+ constructor(provider, pageSize = 24) {
230
+ this.provider = provider;
231
+ this.pageSize = pageSize;
232
+ this.s = { query: "", category: "", items: [], total: 0, hasMore: false, loading: false, error: null, categories: [], provider: provider().name };
233
+ }
234
+ provider;
235
+ pageSize;
236
+ s;
237
+ next;
238
+ run = 0;
239
+ listeners = /* @__PURE__ */ new Set();
240
+ get state() {
241
+ return this.s;
242
+ }
243
+ subscribe(listener) {
244
+ this.listeners.add(listener);
245
+ return () => this.listeners.delete(listener);
246
+ }
247
+ set(patch) {
248
+ this.s = { ...this.s, ...patch };
249
+ for (const l of [...this.listeners]) l();
250
+ }
251
+ /** Loads the first page (and the categories) again, for the current provider. */
252
+ async refresh() {
253
+ const run = ++this.run;
254
+ const p = this.provider();
255
+ this.next = void 0;
256
+ this.set({ loading: true, error: null, items: [], total: 0, hasMore: false, provider: p.name });
257
+ try {
258
+ const categories = await p.categories?.() ?? [];
259
+ if (run !== this.run) return;
260
+ this.set({ categories });
261
+ await this.page(run, p, true);
262
+ } catch (e) {
263
+ if (run === this.run) this.set({ loading: false, error: e instanceof Error ? e.message : String(e) });
264
+ }
265
+ }
266
+ /** Searches for `query` (words; `''` lists everything) from the first page. */
267
+ setQuery(query) {
268
+ this.s = { ...this.s, query };
269
+ return this.refresh();
270
+ }
271
+ /** Shows one category (`''` for all) from the first page. */
272
+ setCategory(category) {
273
+ this.s = { ...this.s, category };
274
+ return this.refresh();
275
+ }
276
+ /** Loads the next page onto the list. */
277
+ async more() {
278
+ if (!this.next || this.s.loading) return;
279
+ const run = this.run;
280
+ this.set({ loading: true });
281
+ try {
282
+ await this.page(run, this.provider(), false);
283
+ } catch (e) {
284
+ if (run === this.run) this.set({ loading: false, error: e instanceof Error ? e.message : String(e) });
285
+ }
286
+ }
287
+ async page(run, p, first) {
288
+ const options = { limit: this.pageSize, ...this.s.category ? { category: this.s.category } : {}, ...!first && this.next ? { after: this.next } : {} };
289
+ const q = this.s.query.trim();
290
+ const res = q && p.capabilities.supportsSearch ? await p.search(q, options) : await p.list(options);
291
+ if (run !== this.run) return;
292
+ this.next = res.next;
293
+ const items = res.items.map((s) => ({ ...s, ref: stickerRefOf(p, s.id) }));
294
+ this.set({ items: first ? items : [...this.s.items, ...items], total: res.total, hasMore: Boolean(res.next), loading: false });
295
+ }
296
+ };
297
+
298
+ export {
299
+ stampOutline,
300
+ stampPixels,
301
+ editorStickers,
302
+ StickerBrowser
303
+ };
@@ -0,0 +1,13 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true});// src/stickers/errors.ts
2
+ var StickerError = class extends Error {
3
+ constructor(code, message) {
4
+ super(message);
5
+ this.code = code;
6
+ this.name = "StickerError";
7
+ }
8
+
9
+ };
10
+
11
+
12
+
13
+ exports.StickerError = StickerError;
@@ -0,0 +1,322 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
2
+
3
+
4
+ var _chunkXFM3OCHUcjs = require('./chunk-XFM3OCHU.cjs');
5
+
6
+ // src/raster/png.ts
7
+ var SIGNATURE = [137, 80, 78, 71, 13, 10, 26, 10];
8
+ var crcTable = null;
9
+ function crc32(bytes, start, end) {
10
+ if (!crcTable) {
11
+ crcTable = new Uint32Array(256);
12
+ for (let n = 0; n < 256; n++) {
13
+ let c2 = n;
14
+ for (let k = 0; k < 8; k++) c2 = c2 & 1 ? 3988292384 ^ c2 >>> 1 : c2 >>> 1;
15
+ crcTable[n] = c2 >>> 0;
16
+ }
17
+ }
18
+ let c = 4294967295;
19
+ for (let i = start; i < end; i++) c = crcTable[(c ^ bytes[i]) & 255] ^ c >>> 8;
20
+ return (c ^ 4294967295) >>> 0;
21
+ }
22
+ function paeth(a, b, c) {
23
+ const p = a + b - c;
24
+ const pa = Math.abs(p - a);
25
+ const pb = Math.abs(p - b);
26
+ const pc = Math.abs(p - c);
27
+ return pa <= pb && pa <= pc ? a : pb <= pc ? b : c;
28
+ }
29
+ function encodePng(width, height, data, channels = 4) {
30
+ const stride = width * channels;
31
+ const raw = new Uint8Array((stride + 1) * height);
32
+ const bpp = channels;
33
+ const cand = [new Uint8Array(stride), new Uint8Array(stride), new Uint8Array(stride), new Uint8Array(stride), new Uint8Array(stride)];
34
+ for (let y = 0; y < height; y++) {
35
+ const row = y * stride;
36
+ const prevRow = (y - 1) * stride;
37
+ let best = 0;
38
+ let bestScore = Infinity;
39
+ for (let f = 0; f < 5; f++) {
40
+ const out2 = cand[f];
41
+ let score = 0;
42
+ for (let x = 0; x < stride; x++) {
43
+ const v = data[row + x];
44
+ const a = x >= bpp ? data[row + x - bpp] : 0;
45
+ const b = y > 0 ? data[prevRow + x] : 0;
46
+ const c = x >= bpp && y > 0 ? data[prevRow + x - bpp] : 0;
47
+ let r;
48
+ switch (f) {
49
+ case 0:
50
+ r = v;
51
+ break;
52
+ case 1:
53
+ r = v - a;
54
+ break;
55
+ case 2:
56
+ r = v - b;
57
+ break;
58
+ case 3:
59
+ r = v - (a + b >> 1);
60
+ break;
61
+ default:
62
+ r = v - paeth(a, b, c);
63
+ }
64
+ r &= 255;
65
+ out2[x] = r;
66
+ score += r < 128 ? r : 256 - r;
67
+ if (score >= bestScore) break;
68
+ }
69
+ if (score < bestScore) {
70
+ bestScore = score;
71
+ best = f;
72
+ }
73
+ }
74
+ const o = y * (stride + 1);
75
+ raw[o] = best;
76
+ raw.set(cand[best], o + 1);
77
+ }
78
+ const idat = _chunkXFM3OCHUcjs.deflate.call(void 0, raw);
79
+ const chunks = [];
80
+ const ihdr = new Uint8Array(13);
81
+ writeU32(ihdr, 0, width);
82
+ writeU32(ihdr, 4, height);
83
+ ihdr[8] = 8;
84
+ ihdr[9] = channels === 1 ? 0 : 6;
85
+ chunks.push(["IHDR", ihdr], ["IDAT", idat], ["IEND", new Uint8Array(0)]);
86
+ let size = 8;
87
+ for (const [, d] of chunks) size += 12 + d.length;
88
+ const out = new Uint8Array(size);
89
+ out.set(SIGNATURE, 0);
90
+ let p = 8;
91
+ for (const [type, d] of chunks) {
92
+ writeU32(out, p, d.length);
93
+ for (let i = 0; i < 4; i++) out[p + 4 + i] = type.charCodeAt(i);
94
+ out.set(d, p + 8);
95
+ writeU32(out, p + 8 + d.length, crc32(out, p + 4, p + 8 + d.length));
96
+ p += 12 + d.length;
97
+ }
98
+ return out;
99
+ }
100
+ function writeU32(b, o, v) {
101
+ b[o] = v >>> 24;
102
+ b[o + 1] = v >>> 16 & 255;
103
+ b[o + 2] = v >>> 8 & 255;
104
+ b[o + 3] = v & 255;
105
+ }
106
+ function readU32(b, o) {
107
+ return (b[o] << 24 | b[o + 1] << 16 | b[o + 2] << 8 | b[o + 3]) >>> 0;
108
+ }
109
+ function isPng(bytes) {
110
+ return bytes.length > 8 && SIGNATURE.every((v, i) => bytes[i] === v);
111
+ }
112
+ function decodePng(bytes, options = {}) {
113
+ if (!isPng(bytes)) throw new Error("Not a PNG image.");
114
+ let p = 8;
115
+ let width = 0;
116
+ let height = 0;
117
+ let depth = 0;
118
+ let type = 0;
119
+ let interlace = 0;
120
+ let palette = null;
121
+ let trns = null;
122
+ const idat = [];
123
+ while (p + 8 <= bytes.length) {
124
+ const len = readU32(bytes, p);
125
+ const t = String.fromCharCode(bytes[p + 4], bytes[p + 5], bytes[p + 6], bytes[p + 7]);
126
+ const body = bytes.subarray(p + 8, p + 8 + len);
127
+ if (p + 12 + len > bytes.length) throw new Error("Truncated PNG.");
128
+ if (t === "IHDR") {
129
+ width = readU32(body, 0);
130
+ height = readU32(body, 4);
131
+ depth = body[8];
132
+ type = body[9];
133
+ interlace = body[12];
134
+ } else if (t === "PLTE") palette = body;
135
+ else if (t === "tRNS") trns = body;
136
+ else if (t === "IDAT") idat.push(body);
137
+ else if (t === "IEND") break;
138
+ p += 12 + len;
139
+ }
140
+ if (!width || !height) throw new Error("PNG has no image header.");
141
+ if (interlace) throw new Error("Interlaced PNGs are not supported here; decode them with a canvas.");
142
+ const maxPixels = _nullishCoalesce(options.maxPixels, () => ( 1 << 28));
143
+ if (width * height > maxPixels) throw new Error(`PNG is too large (${width}\xD7${height}).`);
144
+ const samples = type === 0 ? 1 : type === 2 ? 3 : type === 3 ? 1 : type === 4 ? 2 : type === 6 ? 4 : 0;
145
+ if (!samples || ![1, 2, 4, 8, 16].includes(depth)) throw new Error(`Unsupported PNG format (type ${type}, depth ${depth}).`);
146
+ let total = 0;
147
+ for (const c of idat) total += c.length;
148
+ const z = new Uint8Array(total);
149
+ let o = 0;
150
+ for (const c of idat) {
151
+ z.set(c, o);
152
+ o += c.length;
153
+ }
154
+ const bitsPerPixel = samples * depth;
155
+ const stride = Math.ceil(width * bitsPerPixel / 8);
156
+ const raw = _chunkXFM3OCHUcjs.inflate.call(void 0, z, { maxOutput: (stride + 1) * height, sizeHint: (stride + 1) * height });
157
+ if (raw.length < (stride + 1) * height) throw new Error("PNG image data is truncated.");
158
+ const bpp = Math.max(1, bitsPerPixel >> 3);
159
+ const lines = new Uint8Array(stride * height);
160
+ for (let y = 0; y < height; y++) {
161
+ const f = raw[y * (stride + 1)];
162
+ const src = y * (stride + 1) + 1;
163
+ const dst = y * stride;
164
+ const up = dst - stride;
165
+ for (let x = 0; x < stride; x++) {
166
+ const v = raw[src + x];
167
+ const a = x >= bpp ? lines[dst + x - bpp] : 0;
168
+ const b = y > 0 ? lines[up + x] : 0;
169
+ const c = x >= bpp && y > 0 ? lines[up + x - bpp] : 0;
170
+ let r;
171
+ switch (f) {
172
+ case 0:
173
+ r = v;
174
+ break;
175
+ case 1:
176
+ r = v + a;
177
+ break;
178
+ case 2:
179
+ r = v + b;
180
+ break;
181
+ case 3:
182
+ r = v + (a + b >> 1);
183
+ break;
184
+ case 4:
185
+ r = v + paeth(a, b, c);
186
+ break;
187
+ default:
188
+ throw new Error(`Invalid PNG filter ${f}.`);
189
+ }
190
+ lines[dst + x] = r & 255;
191
+ }
192
+ }
193
+ const sample = (y, i) => {
194
+ const row = y * stride;
195
+ if (depth === 8) return lines[row + i];
196
+ if (depth === 16) return lines[row + i * 2];
197
+ const perByte = 8 / depth;
198
+ const byte = lines[row + Math.floor(i / perByte)];
199
+ const shift = 8 - depth * (i % perByte + 1);
200
+ const v = byte >> shift & (1 << depth) - 1;
201
+ return type === 3 ? v : Math.round(v * 255 / ((1 << depth) - 1));
202
+ };
203
+ const gray = options.keepGray && type === 0 && !trns;
204
+ const channels = gray ? 1 : 4;
205
+ const out = new Uint8ClampedArray(width * height * channels);
206
+ const trnsGray = trns && type === 0 ? depth === 16 ? trns[0] : sample16(trns, 0, depth) : -1;
207
+ const trnsRgb = trns && type === 2 ? [0, 1, 2].map((k) => depth === 16 ? trns[k * 2] : sample16(trns, k, depth)) : null;
208
+ for (let y = 0; y < height; y++) {
209
+ for (let x = 0; x < width; x++) {
210
+ const d = (y * width + x) * channels;
211
+ if (type === 0) {
212
+ const v = sample(y, x);
213
+ if (gray) out[d] = v;
214
+ else {
215
+ out[d] = out[d + 1] = out[d + 2] = v;
216
+ out[d + 3] = v === trnsGray && trns ? 0 : 255;
217
+ }
218
+ } else if (type === 2) {
219
+ const r = sample(y, x * 3);
220
+ const g = sample(y, x * 3 + 1);
221
+ const b = sample(y, x * 3 + 2);
222
+ out[d] = r;
223
+ out[d + 1] = g;
224
+ out[d + 2] = b;
225
+ out[d + 3] = trnsRgb && r === trnsRgb[0] && g === trnsRgb[1] && b === trnsRgb[2] ? 0 : 255;
226
+ } else if (type === 3) {
227
+ const i = sample(y, x);
228
+ if (!palette || i * 3 + 2 >= palette.length) throw new Error("PNG palette index out of range.");
229
+ out[d] = palette[i * 3];
230
+ out[d + 1] = palette[i * 3 + 1];
231
+ out[d + 2] = palette[i * 3 + 2];
232
+ out[d + 3] = trns && i < trns.length ? trns[i] : 255;
233
+ } else if (type === 4) {
234
+ const v = sample(y, x * 2);
235
+ out[d] = out[d + 1] = out[d + 2] = v;
236
+ out[d + 3] = sample(y, x * 2 + 1);
237
+ } else {
238
+ out[d] = sample(y, x * 4);
239
+ out[d + 1] = sample(y, x * 4 + 1);
240
+ out[d + 2] = sample(y, x * 4 + 2);
241
+ out[d + 3] = sample(y, x * 4 + 3);
242
+ }
243
+ }
244
+ }
245
+ return { width, height, channels, data: out };
246
+ }
247
+ function sample16(trns, k, depth) {
248
+ const v = trns[k * 2] << 8 | trns[k * 2 + 1];
249
+ if (depth === 8) return v & 255;
250
+ return Math.round((v & (1 << depth) - 1) * 255 / ((1 << depth) - 1));
251
+ }
252
+ var B64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
253
+ var B64_INV = null;
254
+ function bytesToBase64(bytes) {
255
+ const parts = [];
256
+ const CHUNK = 3 * 4096;
257
+ for (let start = 0; start < bytes.length; start += CHUNK) {
258
+ const end = Math.min(bytes.length, start + CHUNK);
259
+ let s = "";
260
+ let i = start;
261
+ for (; i + 2 < end; i += 3) {
262
+ const n = bytes[i] << 16 | bytes[i + 1] << 8 | bytes[i + 2];
263
+ s += B64[n >> 18] + B64[n >> 12 & 63] + B64[n >> 6 & 63] + B64[n & 63];
264
+ }
265
+ if (i < end) {
266
+ const n = bytes[i] << 16 | (i + 1 < end ? bytes[i + 1] << 8 : 0);
267
+ s += B64[n >> 18] + B64[n >> 12 & 63] + (i + 1 < end ? B64[n >> 6 & 63] : "=") + "=";
268
+ }
269
+ parts.push(s);
270
+ }
271
+ return parts.join("");
272
+ }
273
+ function base64ToBytes(text) {
274
+ if (!B64_INV) {
275
+ B64_INV = new Int16Array(128).fill(-1);
276
+ for (let i = 0; i < 64; i++) B64_INV[B64.charCodeAt(i)] = i;
277
+ B64_INV["-".charCodeAt(0)] = 62;
278
+ B64_INV["_".charCodeAt(0)] = 63;
279
+ }
280
+ const inv = B64_INV;
281
+ const clean = text.replace(/[\s=]/g, "");
282
+ const out = new Uint8Array(Math.floor(clean.length * 3 / 4));
283
+ let bits = 0;
284
+ let acc = 0;
285
+ let o = 0;
286
+ for (let i = 0; i < clean.length; i++) {
287
+ const c = clean.charCodeAt(i);
288
+ const v = c < 128 ? inv[c] : -1;
289
+ if (v < 0) throw new Error("Invalid base64 data.");
290
+ acc = acc << 6 | v;
291
+ bits += 6;
292
+ if (bits >= 8) {
293
+ bits -= 8;
294
+ out[o++] = acc >> bits & 255;
295
+ }
296
+ }
297
+ return out.subarray(0, o);
298
+ }
299
+ function parseDataUrl(url) {
300
+ const m = /^data:([^;,]*)((?:;[^;,]*)*?),/i.exec(url);
301
+ if (!m) return null;
302
+ const body = url.slice(m[0].length);
303
+ const isBase64 = /;base64/i.test(m[2]);
304
+ if (isBase64) return { mime: m[1] || "text/plain", bytes: base64ToBytes(body) };
305
+ const text = decodeURIComponent(body);
306
+ const bytes = new Uint8Array(text.length);
307
+ for (let i = 0; i < text.length; i++) bytes[i] = text.charCodeAt(i) & 255;
308
+ return { mime: m[1] || "text/plain", bytes };
309
+ }
310
+ function pngDataUrl(width, height, data, channels = 4) {
311
+ return `data:image/png;base64,${bytesToBase64(encodePng(width, height, data, channels))}`;
312
+ }
313
+
314
+
315
+
316
+
317
+
318
+
319
+
320
+
321
+
322
+ exports.encodePng = encodePng; exports.isPng = isPng; exports.decodePng = decodePng; exports.bytesToBase64 = bytesToBase64; exports.base64ToBytes = base64ToBytes; exports.parseDataUrl = parseDataUrl; exports.pngDataUrl = pngDataUrl;
@@ -13,12 +13,12 @@ import {
13
13
  dabRect,
14
14
  put255,
15
15
  rasterizeDab
16
- } from "./chunk-2PBZBRP5.js";
16
+ } from "./chunk-D5KGAO4Z.js";
17
17
  import {
18
18
  blendPixel,
19
19
  srgbDecode,
20
20
  srgbEncode
21
- } from "./chunk-42TWUPNJ.js";
21
+ } from "./chunk-IRSTHLQQ.js";
22
22
  import {
23
23
  TILE,
24
24
  tileKey