@ingcreators/annot-annotator 0.6.0 → 0.7.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/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # @ingcreators/annot-annotator
2
2
 
3
+ ## 0.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - `toEditablePng`'s `EditableInput` gains the schema-2.0 provenance
8
+ fields (`sourceUrl` / `createdAt` / `producer` / `dpr`), written
9
+ into the XMP packet as first-class elements. `producer` defaults
10
+ to `"annotator"`. Prefer these over the old `WELL_KNOWN_TAG_KEYS`
11
+ smuggling convention (`source` / `capturedAt` tags).
12
+
3
13
  ## 0.6.0
4
14
 
5
15
  ### Minor Changes
@@ -22,19 +22,27 @@ export interface AnnotatorInput {
22
22
  }
23
23
  /**
24
24
  * Input for {@link Annotator.toEditablePng}. Same shape as
25
- * {@link AnnotatorInput} plus optional opaque kv `tags` written into
26
- * the embedded XMP for provenance / debugging.
25
+ * {@link AnnotatorInput} plus optional opaque kv `tags` and the
26
+ * schema-2.0 provenance fields written into the embedded XMP.
27
27
  *
28
- * Soft-convention key names (not validated by the writer; documented
29
- * in `@ingcreators/annot-core/xmp-bytes`'s `WELL_KNOWN_TAG_KEYS`):
30
- * - `source` what produced the PNG (`"docs-tour"`, `"playwright-fixture"`, `"annot-mcp"`).
31
- * - `screen` for living-product-docs, the `<Screen id>` value.
32
- * - `capturedAt` ISO timestamp.
33
- * - `commit` — git SHA when applicable.
28
+ * Since XMP schema 2.0 (`docs/metadata-format.md`), provenance has
29
+ * first-class fields — prefer `sourceUrl` / `createdAt` / `producer`
30
+ * / `dpr` over smuggling the equivalent through `tags` (`source` /
31
+ * `capturedAt` from the old `WELL_KNOWN_TAG_KEYS` convention).
32
+ * `screen` / `commit` remain tags.
34
33
  */
35
34
  export interface EditableInput extends AnnotatorInput {
36
35
  /** Optional opaque kv tags. */
37
36
  tags?: Record<string, string>;
37
+ /** URL of the captured page, when applicable. */
38
+ sourceUrl?: string;
39
+ /** ISO timestamp of the capture moment. */
40
+ createdAt?: string;
41
+ /** What produced the PNG (`"annotator"` / `"mcp"` / `"playwright"`
42
+ * / a caller-supplied identifier). Defaults to `"annotator"`. */
43
+ producer?: string;
44
+ /** devicePixelRatio at capture time, when known. */
45
+ dpr?: number;
38
46
  }
39
47
  /** Annotator construction options. All optional. */
40
48
  export interface AnnotatorOptions {
package/dist/index.js CHANGED
@@ -6,23 +6,26 @@ import { DOMParser as i, XMLSerializer as a } from "@xmldom/xmldom";
6
6
  var o = "data-annot-version", s = "annot", c = "https://ingcreators.com/annot/ns/1.0/";
7
7
  new TextEncoder().encode("http://ns.adobe.com/xap/1.0/\0"), new TextEncoder().encode("annot:OriginalImage\0");
8
8
  var l = new TextEncoder().encode("XML:com.adobe.xmp");
9
- function u(e, t, n, r) {
10
- let i = r && Object.keys(r).length > 0 ? JSON.stringify(r) : "";
11
- return `<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
9
+ function u(e) {
10
+ return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
11
+ }
12
+ function d(e) {
13
+ let t = [], n = (e, n) => t.push(`\n <${s}:${e}>${n}</${s}:${e}>`), r = e.tags && Object.keys(e.tags).length > 0 ? JSON.stringify(e.tags) : "";
14
+ return r && n("tags", u(r)), e.sourceUrl && n("sourceUrl", u(e.sourceUrl)), e.createdAt && n("createdAt", u(e.createdAt)), e.producer && n("producer", u(e.producer)), e.dpr && e.dpr > 0 && n("dpr", String(e.dpr)), `<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
12
15
  <x:xmpmeta xmlns:x="adobe:ns:meta/">
13
16
  <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
14
17
  <rdf:Description rdf:about=""
15
18
  xmlns:${s}="${c}">
16
- <${s}:annotations><![CDATA[${e}]]></${s}:annotations>
17
- <${s}:width>${t}</${s}:width>
18
- <${s}:height>${n}</${s}:height>
19
- <${s}:version>1.0</${s}:version>${i ? `\n <${s}:tags>${i}</${s}:tags>` : ""}
19
+ <${s}:annotations><![CDATA[${e.annotationsSvg}]]></${s}:annotations>
20
+ <${s}:width>${e.width}</${s}:width>
21
+ <${s}:height>${e.height}</${s}:height>
22
+ <${s}:version>2.0</${s}:version>${t.join("")}
20
23
  </rdf:Description>
21
24
  </rdf:RDF>
22
25
  </x:xmpmeta>
23
26
  <?xpacket end="w"?>`;
24
27
  }
25
- function d(e) {
28
+ function f(e) {
26
29
  return new Uint8Array([
27
30
  e >> 24 & 255,
28
31
  e >> 16 & 255,
@@ -30,27 +33,27 @@ function d(e) {
30
33
  e & 255
31
34
  ]);
32
35
  }
33
- function f(e, t) {
36
+ function p(e, t) {
34
37
  return (e[t] << 24 | e[t + 1] << 16 | e[t + 2] << 8 | e[t + 3]) >>> 0;
35
38
  }
36
- function p(...e) {
39
+ function m(...e) {
37
40
  let t = 0;
38
41
  for (let n of e) t += n.length;
39
42
  let n = new Uint8Array(t), r = 0;
40
43
  for (let t of e) n.set(t, r), r += t.length;
41
44
  return n;
42
45
  }
43
- function m(e, t, n) {
46
+ function h(e, t, n) {
44
47
  if (t + n.length > e.length) return !1;
45
48
  for (let r = 0; r < n.length; r++) if (e[t + r] !== n[r]) return !1;
46
49
  return !0;
47
50
  }
48
- function h(e) {
51
+ function g(e) {
49
52
  let t = e.split(",")[1] || "", n = atob(t), r = new Uint8Array(n.length);
50
53
  for (let e = 0; e < n.length; e++) r[e] = n.charCodeAt(e);
51
54
  return r;
52
55
  }
53
- var g = (() => {
56
+ var _ = (() => {
54
57
  let e = /* @__PURE__ */ new Uint32Array(256);
55
58
  for (let t = 0; t < 256; t++) {
56
59
  let n = t;
@@ -59,56 +62,56 @@ var g = (() => {
59
62
  }
60
63
  return e;
61
64
  })();
62
- function _(e) {
65
+ function v(e) {
63
66
  let t = 4294967295;
64
- for (let n = 0; n < e.length; n++) t = g[(t ^ e[n]) & 255] ^ t >>> 8;
67
+ for (let n = 0; n < e.length; n++) t = _[(t ^ e[n]) & 255] ^ t >>> 8;
65
68
  return (t ^ 4294967295) >>> 0;
66
69
  }
67
- function v(e, t) {
68
- let n = p(e, t), r = _(n);
69
- return p(d(t.length), n, d(r));
70
+ function y(e, t) {
71
+ let n = m(e, t), r = v(n);
72
+ return m(f(t.length), n, f(r));
70
73
  }
71
- function y(e) {
72
- let t = p(l, new Uint8Array([
74
+ function b(e) {
75
+ let t = m(l, new Uint8Array([
73
76
  0,
74
77
  0,
75
78
  0,
76
79
  0,
77
80
  0
78
81
  ]), e);
79
- return v(new TextEncoder().encode("iTXt"), t);
82
+ return y(new TextEncoder().encode("iTXt"), t);
80
83
  }
81
- function b(e) {
84
+ function x(e) {
82
85
  let t = [e.slice(0, 8)], n = 8;
83
86
  for (; n + 12 <= e.length;) {
84
- let r = f(e, n), i = e.slice(n + 4, n + 8), a = n + 8, o = a + r + 4;
87
+ let r = p(e, n), i = e.slice(n + 4, n + 8), a = n + 8, o = a + r + 4;
85
88
  if (o > e.length) break;
86
89
  let s = String.fromCharCode(...i);
87
- !(s === "iTXt" && m(e, a, l)) && s !== "svGo" && t.push(e.slice(n, o)), n = o;
90
+ !(s === "iTXt" && h(e, a, l)) && s !== "svGo" && t.push(e.slice(n, o)), n = o;
88
91
  }
89
- return p(...t);
92
+ return m(...t);
90
93
  }
91
- function x(e, t, n) {
92
- let r = y(t), i = v(new TextEncoder().encode("svGo"), n), a = b(e), o = a.length - 12;
93
- return p(a.slice(0, o), r, i, a.slice(o));
94
+ function S(e, t, n) {
95
+ let r = b(t), i = y(new TextEncoder().encode("svGo"), n), a = x(e), o = a.length - 12;
96
+ return m(a.slice(0, o), r, i, a.slice(o));
94
97
  }
95
- function S(e) {
96
- let t = u(e.annotationsSvg, e.width, e.height, e.tags), n = new TextEncoder().encode(t), r = typeof e.originalImage == "string" ? h(e.originalImage) : e.originalImage;
97
- return x(e.renderedPng, n, r);
98
+ function C(e) {
99
+ let t = d(e), n = new TextEncoder().encode(t), r = typeof e.originalImage == "string" ? g(e.originalImage) : e.originalImage;
100
+ return S(e.renderedPng, n, r);
98
101
  }
99
102
  //#endregion
100
103
  //#region ../core/src/encode/options.ts
101
- var C = {
104
+ var w = {
102
105
  light: 1280,
103
106
  standard: 1920,
104
107
  highQuality: 2560,
105
108
  original: null
106
- }, w = {
109
+ }, T = {
107
110
  light: "Light (1280px)",
108
111
  standard: "Standard (1920px)",
109
112
  highQuality: "High Quality (2560px)",
110
113
  original: "Original"
111
- }, T = {
114
+ }, E = {
112
115
  format: "smart",
113
116
  smartFallback: "png",
114
117
  smartColorThreshold: 15e3,
@@ -116,8 +119,8 @@ var C = {
116
119
  saveSizePreset: "standard",
117
120
  quantizer: "median-cut"
118
121
  };
119
- function E(e, t, n) {
120
- let r = C[n];
122
+ function D(e, t, n) {
123
+ let r = w[n];
121
124
  if (r === null || e <= r) return {
122
125
  width: e,
123
126
  height: t,
@@ -132,7 +135,7 @@ function E(e, t, n) {
132
135
  }
133
136
  //#endregion
134
137
  //#region ../core/src/encode/png8.ts
135
- var D = new Uint8Array([
138
+ var O = new Uint8Array([
136
139
  137,
137
140
  80,
138
141
  78,
@@ -141,7 +144,7 @@ var D = new Uint8Array([
141
144
  10,
142
145
  26,
143
146
  10
144
- ]), O = (() => {
147
+ ]), k = (() => {
145
148
  let e = /* @__PURE__ */ new Uint32Array(256);
146
149
  for (let t = 0; t < 256; t++) {
147
150
  let n = t;
@@ -150,20 +153,20 @@ var D = new Uint8Array([
150
153
  }
151
154
  return e;
152
155
  })();
153
- function k(e) {
156
+ function A(e) {
154
157
  let t = 4294967295;
155
- for (let n = 0; n < e.length; n++) t = O[(t ^ e[n]) & 255] ^ t >>> 8;
158
+ for (let n = 0; n < e.length; n++) t = k[(t ^ e[n]) & 255] ^ t >>> 8;
156
159
  return (t ^ 4294967295) >>> 0;
157
160
  }
158
- function A(e, t) {
161
+ function j(e, t) {
159
162
  let n = new Uint8Array(12 + t.length), r = new DataView(n.buffer);
160
163
  r.setUint32(0, t.length, !1);
161
164
  for (let t = 0; t < 4; t++) n[4 + t] = e.charCodeAt(t);
162
165
  n.set(t, 8);
163
166
  let i = n.subarray(4, 8 + t.length);
164
- return r.setUint32(8 + t.length, k(i), !1), n;
167
+ return r.setUint32(8 + t.length, A(i), !1), n;
165
168
  }
166
- function j(e, t, n, i, a = 9) {
169
+ function ee(e, t, n, i, a = 9) {
167
170
  if (n <= 0 || i <= 0) throw Error("encodePng8: invalid dimensions");
168
171
  if (e.length % 4 != 0) throw Error("encodePng8: palette must be RGBA bytes (multiple of 4)");
169
172
  let o = e.length >>> 2;
@@ -188,11 +191,11 @@ function j(e, t, n, i, a = 9) {
188
191
  memLevel: 9,
189
192
  windowBits: 15
190
193
  }), g = [
191
- D,
192
- A("IHDR", s),
193
- A("PLTE", l)
194
+ O,
195
+ j("IHDR", s),
196
+ j("PLTE", l)
194
197
  ];
195
- f && g.push(A("tRNS", f)), g.push(A("IDAT", h)), g.push(A("IEND", /* @__PURE__ */ new Uint8Array()));
198
+ f && g.push(j("tRNS", f)), g.push(j("IDAT", h)), g.push(j("IEND", /* @__PURE__ */ new Uint8Array()));
196
199
  let _ = 0;
197
200
  for (let e of g) _ += e.length;
198
201
  let v = new Uint8Array(_), y = 0;
@@ -201,12 +204,12 @@ function j(e, t, n, i, a = 9) {
201
204
  }
202
205
  //#endregion
203
206
  //#region ../core/src/encode/quantize-median-cut.ts
204
- function ee(e, t, n, r) {
207
+ function te(e, t, n, r) {
205
208
  if (!Number.isInteger(t) || t <= 0) throw Error(`quantizeMedianCut: invalid width ${t}`);
206
209
  if (!Number.isInteger(n) || n <= 0) throw Error(`quantizeMedianCut: invalid height ${n}`);
207
210
  let i = t * n * 4;
208
211
  if (e.length !== i) throw Error(`quantizeMedianCut: rgba length ${e.length} != width*height*4 = ${i}`);
209
- let a = Math.max(1, Math.min(256, Math.floor(r))), { opaqueSamples: o, hasTransparent: s, transparentCount: c } = te(e), l = ne(o, s ? Math.max(1, a - 1) : a), u = l.length, d = u + +!!s, f = new Uint8Array(d * 4), p = 0;
212
+ let a = Math.max(1, Math.min(256, Math.floor(r))), { opaqueSamples: o, hasTransparent: s, transparentCount: c } = ne(e), l = re(o, s ? Math.max(1, a - 1) : a), u = l.length, d = u + +!!s, f = new Uint8Array(d * 4), p = 0;
210
213
  s && (f[0] = 0, f[1] = 0, f[2] = 0, f[3] = 0, p = 1);
211
214
  let m = p * 4;
212
215
  for (let e = 0; e < u; e++) {
@@ -215,11 +218,11 @@ function ee(e, t, n, r) {
215
218
  }
216
219
  return {
217
220
  palette: f,
218
- indices: ie(e, t, n, f, m, s, c > 0)
221
+ indices: ae(e, t, n, f, m, s, c > 0)
219
222
  };
220
223
  }
221
224
  var M = 16;
222
- function te(e) {
225
+ function ne(e) {
223
226
  let t = /* @__PURE__ */ new Map(), n = 0, r = e.length;
224
227
  for (let i = 0; i < r; i += 4) {
225
228
  if (e[i + 3] < M) {
@@ -242,7 +245,7 @@ function te(e) {
242
245
  transparentCount: n
243
246
  };
244
247
  }
245
- function ne(e, t) {
248
+ function re(e, t) {
246
249
  if (e.length === 0) return [];
247
250
  if (t <= 1) return [N(e, 0, e.length, 0)];
248
251
  let n = [N(e, 0, e.length, 0)], r = 1;
@@ -254,7 +257,7 @@ function ne(e, t) {
254
257
  }
255
258
  if (t < 0) break;
256
259
  let o = n[t], s = o.rMax - o.rMin, c = o.gMax - o.gMin, l = o.bMax - o.bMin, u;
257
- u = s >= c && s >= l ? 0 : c >= l ? 1 : 2, re(e, o.start, o.end, u);
260
+ u = s >= c && s >= l ? 0 : c >= l ? 1 : 2, ie(e, o.start, o.end, u);
258
261
  let d = o.population >>> 1, f = 0, p = o.start + 1;
259
262
  for (let t = o.start; t < o.end; t++) if (f += e[t].count, f >= d) {
260
263
  p = t + 1;
@@ -290,12 +293,12 @@ function N(e, t, n, r) {
290
293
  insertOrder: r
291
294
  };
292
295
  }
293
- function re(e, t, n, r) {
296
+ function ie(e, t, n, r) {
294
297
  let i = e.slice(t, n);
295
298
  r === 0 ? i.sort((e, t) => e.r - t.r) : r === 1 ? i.sort((e, t) => e.g - t.g) : i.sort((e, t) => e.b - t.b);
296
299
  for (let n = 0; n < i.length; n++) e[t + n] = i[n];
297
300
  }
298
- function ie(e, t, n, r, i, a, o) {
301
+ function ae(e, t, n, r, i, a, o) {
299
302
  let s = t * n, c = new Uint8Array(s), l = new Float32Array(t), u = new Float32Array(t), d = new Float32Array(t), f = new Float32Array(t), p = new Float32Array(t), m = new Float32Array(t), h = r.length - i >>> 2, g = new Int32Array(h), _ = new Int32Array(h), v = new Int32Array(h);
300
303
  for (let e = 0; e < h; e++) {
301
304
  let t = i + e * 4;
@@ -330,9 +333,9 @@ function ie(e, t, n, r, i, a, o) {
330
333
  }
331
334
  //#endregion
332
335
  //#region src/encode/quantize.ts
333
- function ae(e, t, n) {
334
- let { palette: r, indices: i } = ee(e, t, n, 256);
335
- return j(r, i, t, n, 9);
336
+ function oe(e, t, n) {
337
+ let { palette: r, indices: i } = te(e, t, n, 256);
338
+ return ee(r, i, t, n, 9);
336
339
  }
337
340
  function P(e, t) {
338
341
  let n = new Uint32Array(e.buffer, e.byteOffset, e.byteLength >>> 2), r = n.length;
@@ -343,9 +346,9 @@ function P(e, t) {
343
346
  }
344
347
  //#endregion
345
348
  //#region src/encode/encode.ts
346
- var oe = 1e7;
347
- async function F(e, t, n, r = T) {
348
- let i = E(t, n, r.saveSizePreset ?? "original"), a = i.scaled ? ce(e, t, n, i.width, i.height) : e, o = i.width, s = i.height;
349
+ var se = 1e7;
350
+ async function F(e, t, n, r = E) {
351
+ let i = D(t, n, r.saveSizePreset ?? "original"), a = i.scaled ? le(e, t, n, i.width, i.height) : e, o = i.width, s = i.height;
349
352
  return r.format === "png" ? {
350
353
  bytes: I(a, o, s),
351
354
  chosen: "png",
@@ -356,7 +359,7 @@ async function F(e, t, n, r = T) {
356
359
  chosen: "jpeg",
357
360
  width: o,
358
361
  height: s
359
- } : o * s > oe ? {
362
+ } : o * s > se ? {
360
363
  bytes: I(a, o, s),
361
364
  chosen: "png",
362
365
  reason: "too-large-for-png8",
@@ -375,14 +378,14 @@ async function F(e, t, n, r = T) {
375
378
  width: o,
376
379
  height: s
377
380
  } : {
378
- bytes: ae(a, o, s),
381
+ bytes: oe(a, o, s),
379
382
  chosen: "png",
380
383
  reason: "png-8",
381
384
  width: o,
382
385
  height: s
383
386
  };
384
387
  }
385
- async function se(e, r = T) {
388
+ async function ce(e, r = E) {
386
389
  let i = await n(Buffer.from(e)), a = t(i.width, i.height).getContext("2d");
387
390
  a.drawImage(i, 0, 0);
388
391
  let o = a.getImageData(0, 0, i.width, i.height).data;
@@ -400,7 +403,7 @@ function L(e, n, r, i) {
400
403
  let c = a.toBuffer("image/jpeg", i);
401
404
  return new Uint8Array(c.buffer, c.byteOffset, c.byteLength);
402
405
  }
403
- function ce(e, n, r, i, a) {
406
+ function le(e, n, r, i, a) {
404
407
  let o = t(n, r), s = o.getContext("2d"), c = s.createImageData(n, r);
405
408
  c.data.set(e), s.putImageData(c, 0, 0);
406
409
  let l = t(i, a).getContext("2d");
@@ -410,7 +413,7 @@ function ce(e, n, r, i, a) {
410
413
  }
411
414
  //#endregion
412
415
  //#region src/sanitise-svg.ts
413
- function le(e) {
416
+ function ue(e) {
414
417
  if (!e || e.trim().length === 0) return "";
415
418
  let t = new i(), n;
416
419
  try {
@@ -426,7 +429,7 @@ function le(e) {
426
429
  if (!t || t.nodeType !== 1) continue;
427
430
  let n = t, i = n.localName ?? n.tagName ?? "";
428
431
  if (i === "defs") {
429
- let e = ue(n);
432
+ let e = de(n);
430
433
  e !== null && (s += o.serializeToString(e));
431
434
  continue;
432
435
  }
@@ -443,7 +446,7 @@ function le(e) {
443
446
  }
444
447
  return s;
445
448
  }
446
- function ue(e) {
449
+ function de(e) {
447
450
  let t = e.cloneNode(!0);
448
451
  for (let e = t.childNodes.length - 1; e >= 0; e--) {
449
452
  let n = t.childNodes.item(e);
@@ -455,7 +458,7 @@ function ue(e) {
455
458
  }
456
459
  //#endregion
457
460
  //#region src/annotator.ts
458
- function de(t = {}) {
461
+ function fe(t = {}) {
459
462
  let n = {
460
463
  loadSystemFonts: t.loadSystemFonts ?? !1,
461
464
  ...t.fontFiles ? { fontFiles: t.fontFiles } : {},
@@ -492,7 +495,7 @@ function de(t = {}) {
492
495
  }).render().asPng();
493
496
  },
494
497
  toEditablePng(t) {
495
- return S({
498
+ return C({
496
499
  renderedPng: new e(R(t), {
497
500
  fitTo: {
498
501
  mode: "width",
@@ -505,7 +508,11 @@ function de(t = {}) {
505
508
  annotationsSvg: t.annotationsSvg,
506
509
  width: t.width,
507
510
  height: t.height,
508
- tags: t.tags
511
+ tags: t.tags,
512
+ sourceUrl: t.sourceUrl,
513
+ createdAt: t.createdAt,
514
+ producer: t.producer || "annotator",
515
+ dpr: t.dpr
509
516
  });
510
517
  },
511
518
  async toEncoded(e, t) {
@@ -515,44 +522,44 @@ function de(t = {}) {
515
522
  };
516
523
  }
517
524
  function R(e) {
518
- let t = le(e.annotationsSvg);
525
+ let t = ue(e.annotationsSvg);
519
526
  return `<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" ${o}="1" width="${e.width}" height="${e.height}" viewBox="0 0 ${e.width} ${e.height}"><image href="${e.originalDataUrl}" width="${e.width}" height="${e.height}"/>` + t + "</svg>";
520
527
  }
521
528
  //#endregion
522
529
  //#region src/redact-burn.ts
523
- var fe = "solid", pe = "#000000", z = 16, me = 12;
530
+ var pe = "solid", me = "#000000", z = 16, he = 12;
524
531
  async function B(e, r) {
525
532
  if (r.length === 0) return e;
526
533
  let i = await n(Buffer.from(e)), a = t(i.width, i.height), o = a.getContext("2d");
527
534
  o.drawImage(i, 0, 0);
528
- for (let e of r) if (!(e.bbox.width <= 0 || e.bbox.height <= 0)) switch (e.style ?? fe) {
535
+ for (let e of r) if (!(e.bbox.width <= 0 || e.bbox.height <= 0)) switch (e.style ?? pe) {
529
536
  case "solid":
530
- he(o, e.bbox, e.color ?? pe);
537
+ ge(o, e.bbox, e.color ?? me);
531
538
  break;
532
539
  case "mosaic":
533
- ge(o, i, e.bbox);
540
+ _e(o, i, e.bbox);
534
541
  break;
535
542
  case "blur":
536
- _e(o, i, e.bbox);
543
+ ve(o, i, e.bbox);
537
544
  break;
538
545
  }
539
546
  let s = a.toBuffer("image/png");
540
547
  return new Uint8Array(s.buffer, s.byteOffset, s.byteLength);
541
548
  }
542
- function he(e, t, n) {
549
+ function ge(e, t, n) {
543
550
  e.save(), e.fillStyle = n, e.fillRect(t.x, t.y, t.width, t.height), e.restore();
544
551
  }
545
- function ge(e, n, r) {
552
+ function _e(e, n, r) {
546
553
  let i = Math.max(1, Math.round(r.width / z)), a = Math.max(1, Math.round(r.height / z)), o = t(i, a), s = o.getContext("2d");
547
554
  s.imageSmoothingEnabled = !1, s.drawImage(n, r.x, r.y, r.width, r.height, 0, 0, i, a), e.save(), e.imageSmoothingEnabled = !1, e.drawImage(o, 0, 0, i, a, r.x, r.y, r.width, r.height), e.restore();
548
555
  }
549
- function _e(e, t, n) {
550
- e.save(), e.beginPath(), e.rect(n.x, n.y, n.width, n.height), e.clip(), e.filter = `blur(${me}px)`, e.drawImage(t, 0, 0), e.restore();
556
+ function ve(e, t, n) {
557
+ e.save(), e.beginPath(), e.rect(n.x, n.y, n.width, n.height), e.clip(), e.filter = `blur(${he}px)`, e.drawImage(t, 0, 0), e.restore();
551
558
  }
552
- var ve = B;
559
+ var ye = B;
553
560
  //#endregion
554
561
  //#region ../../node_modules/.pnpm/pixelmatch@7.2.0/node_modules/pixelmatch/index.js
555
- function ye(e, t, n, r, i, a = {}) {
562
+ function be(e, t, n, r, i, a = {}) {
556
563
  let { threshold: o = .1, alpha: s = .1, aaColor: c = [
557
564
  255,
558
565
  255,
@@ -576,7 +583,7 @@ function ye(e, t, n, r, i, a = {}) {
576
583
  }
577
584
  let v = 35215 * o * o, [y, b, x] = c, [S, C, w] = l, [T, E, D] = f || l, O = 0;
578
585
  for (let a = 0, o = 0; a < m; a++, o += 4) {
579
- let c = h[a] === g[a] ? 0 : be(e, t, o, o, u);
586
+ let c = h[a] === g[a] ? 0 : xe(e, t, o, o, u);
580
587
  if (Math.abs(c) > v) {
581
588
  let s = a % r, l = a / r | 0;
582
589
  !d && (H(e, s, l, r, i, h, g, u) || H(t, s, l, r, i, g, h, u)) ? n && !p && W(n, o, y, b, x) : (n && (c < 0 ? W(n, o, T, E, D) : W(n, o, S, C, w)), O++);
@@ -591,7 +598,7 @@ function H(e, t, n, r, i, a, o, s) {
591
598
  let c = Math.max(t - 1, 0), l = Math.max(n - 1, 0), u = Math.min(t + 1, r - 1), d = Math.min(n + 1, i - 1), f = (n * r + t) * 4, p = e[f], m = e[f + 1], h = e[f + 2], g = e[f + 3], _ = +(t === c || t === u || n === l || n === d), v = 0, y = 0, b = 0, x = 0, S = 0, C = 0;
592
599
  for (let i = c; i <= u; i++) for (let a = l; a <= d; a++) {
593
600
  if (i === t && a === n) continue;
594
- let o = xe(e, f, (a * r + i) * 4, p, m, h, g, s);
601
+ let o = Se(e, f, (a * r + i) * 4, p, m, h, g, s);
595
602
  if (o === 0) {
596
603
  if (_++, _ > 2) return !1;
597
604
  } else o < v ? (v = o, b = i, x = a) : o > y && (y = o, S = i, C = a);
@@ -603,7 +610,7 @@ function U(e, t, n, r, i) {
603
610
  for (let i = a; i <= s; i++) for (let a = o; a <= c; a++) if (!(i === t && a === n) && (u += +(l === e[a * r + i]), u > 2)) return !0;
604
611
  return !1;
605
612
  }
606
- function be(e, t, n, r, i) {
613
+ function xe(e, t, n, r, i) {
607
614
  let a = e[n], o = e[n + 1], s = e[n + 2], c = e[n + 3], l = t[r], u = t[r + 1], d = t[r + 2], f = t[r + 3], p = a - l, m = o - u, h = s - d, g = c - f;
608
615
  if (c < 255 || f < 255) {
609
616
  let e = 255, t = 255, r = 255;
@@ -612,7 +619,7 @@ function be(e, t, n, r, i) {
612
619
  let _ = p * .29889531 + m * .58662247 + h * .11448223, v = p * .59597799 - m * .2741761 - h * .32180189, y = p * .21147017 - m * .52261711 + h * .31114694, b = .5053 * _ * _ + .299 * v * v + .1957 * y * y;
613
620
  return _ > 0 ? -b : b;
614
621
  }
615
- function xe(e, t, n, r, i, a, o, s) {
622
+ function Se(e, t, n, r, i, a, o, s) {
616
623
  let c = e[n], l = e[n + 1], u = e[n + 2], d = e[n + 3], f = r - c, p = i - l, m = a - u, h = o - d;
617
624
  if (!f && !p && !m && !h) return 0;
618
625
  if (o < 255 || d < 255) {
@@ -630,14 +637,14 @@ function G(e, t, n, r) {
630
637
  }
631
638
  //#endregion
632
639
  //#region src/diff-aggregate.ts
633
- var Se = 4;
640
+ var Ce = 4;
634
641
  function K(e, t, n) {
635
642
  let r = new Uint8Array(t * n), i = [];
636
643
  for (let a = 0; a < n; a++) for (let o = 0; o < t; o++) {
637
644
  let s = a * t + o;
638
- if (r[s] || !Ce(e, s)) continue;
639
- let c = we(e, r, o, a, t, n);
640
- c.count >= Se && i.push({
645
+ if (r[s] || !we(e, s)) continue;
646
+ let c = Te(e, r, o, a, t, n);
647
+ c.count >= Ce && i.push({
641
648
  x: c.minX,
642
649
  y: c.minY,
643
650
  width: c.maxX - c.minX + 1,
@@ -646,10 +653,10 @@ function K(e, t, n) {
646
653
  }
647
654
  return i;
648
655
  }
649
- function Ce(e, t) {
656
+ function we(e, t) {
650
657
  return e[t * 4 + 3] > 0;
651
658
  }
652
- function we(e, t, n, r, i, a) {
659
+ function Te(e, t, n, r, i, a) {
653
660
  let o = {
654
661
  count: 0,
655
662
  minX: n,
@@ -661,29 +668,29 @@ function we(e, t, n, r, i, a) {
661
668
  let n = s.pop(), r = s.pop();
662
669
  if (r < 0 || r >= i || n < 0 || n >= a) continue;
663
670
  let c = n * i + r;
664
- t[c] || Ce(e, c) && (t[c] = 1, o.count += 1, r < o.minX && (o.minX = r), n < o.minY && (o.minY = n), r > o.maxX && (o.maxX = r), n > o.maxY && (o.maxY = n), s.push(r + 1, n), s.push(r - 1, n), s.push(r, n + 1), s.push(r, n - 1));
671
+ t[c] || we(e, c) && (t[c] = 1, o.count += 1, r < o.minX && (o.minX = r), n < o.minY && (o.minY = n), r > o.maxX && (o.maxX = r), n > o.maxY && (o.maxY = n), s.push(r + 1, n), s.push(r - 1, n), s.push(r, n + 1), s.push(r, n - 1));
665
672
  }
666
673
  return o;
667
674
  }
668
675
  //#endregion
669
676
  //#region src/diff.ts
670
- var Te = class extends Error {
677
+ var Ee = class extends Error {
671
678
  constructor(e, t) {
672
679
  super(`Cannot compare screenshots of different dimensions: before is ${e.width}×${e.height}, after is ${t.width}×${t.height}.`), this.name = "DimensionMismatchError";
673
680
  }
674
681
  };
675
- async function Ee(e, t, r = {}) {
682
+ async function De(e, t, r = {}) {
676
683
  let [i, a] = await Promise.all([n(Buffer.from(e)), n(Buffer.from(t))]);
677
- if (i.width !== a.width || i.height !== a.height) throw new Te({
684
+ if (i.width !== a.width || i.height !== a.height) throw new Ee({
678
685
  width: i.width,
679
686
  height: i.height
680
687
  }, {
681
688
  width: a.width,
682
689
  height: a.height
683
690
  });
684
- let { width: o, height: s } = i, c = De(i, o, s), l = De(a, o, s), u = new Uint8Array(o * s * 4);
691
+ let { width: o, height: s } = i, c = Oe(i, o, s), l = Oe(a, o, s), u = new Uint8Array(o * s * 4);
685
692
  return {
686
- mismatchedPixels: ye(c, l, u, o, s, {
693
+ mismatchedPixels: be(c, l, u, o, s, {
687
694
  threshold: r.threshold ?? .1,
688
695
  includeAA: !1,
689
696
  diffMask: !0
@@ -693,7 +700,7 @@ async function Ee(e, t, r = {}) {
693
700
  height: s
694
701
  };
695
702
  }
696
- function De(e, n, r) {
703
+ function Oe(e, n, r) {
697
704
  let i = t(n, r).getContext("2d");
698
705
  i.drawImage(e, 0, 0);
699
706
  let a = i.getImageData(0, 0, n, r).data;
@@ -701,12 +708,12 @@ function De(e, n, r) {
701
708
  }
702
709
  //#endregion
703
710
  //#region src/flatten-editable-png.ts
704
- function Oe(e) {
705
- return b(e);
711
+ function ke(e) {
712
+ return x(e);
706
713
  }
707
714
  //#endregion
708
715
  //#region src/dsl/schema.ts
709
- var ke = {
716
+ var Ae = {
710
717
  BBox: {
711
718
  type: "object",
712
719
  required: [
@@ -762,7 +769,7 @@ var ke = {
762
769
  color: { type: "string" }
763
770
  }
764
771
  }
765
- }, Ae = { oneOf: [
772
+ }, je = { oneOf: [
766
773
  {
767
774
  type: "object",
768
775
  required: ["type", "bbox"],
@@ -977,7 +984,7 @@ var ke = {
977
984
  svgFragment: { type: "string" }
978
985
  }
979
986
  }
980
- ] }, je = {
987
+ ] }, Me = {
981
988
  type: "object",
982
989
  required: ["bbox"],
983
990
  additionalProperties: !1,
@@ -1001,26 +1008,26 @@ function q(e, t = {}) {
1001
1008
  return `<rect x="${e.x}" y="${e.y}" width="${e.width}" height="${e.height}" fill="${Z(i)}" stroke="${Z(n)}" stroke-width="${r}"/>`;
1002
1009
  }
1003
1010
  function J(e, t, n = {}) {
1004
- let r = n.color ?? "red", i = n.strokeWidth ?? 2, a = `annot-arrow-${Me()}`;
1011
+ let r = n.color ?? "red", i = n.strokeWidth ?? 2, a = `annot-arrow-${Ne()}`;
1005
1012
  return `<defs><marker id="${a}" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto" markerUnits="strokeWidth"><path d="M 0 0 L 10 5 L 0 10 z" fill="${Z(r)}"/></marker></defs><line x1="${e.x}" y1="${e.y}" x2="${t.x}" y2="${t.y}" stroke="${Z(r)}" stroke-width="${i}" marker-end="url(#${a})"/>`;
1006
1013
  }
1007
1014
  function Y(e, t, n = {}) {
1008
1015
  let r = n.color ?? "red", i = n.fontSize ?? 14, a = n.anchor ?? "start";
1009
- return `<text x="${e.x}" y="${e.y}" fill="${Z(r)}" font-size="${i}" text-anchor="${a}">` + Ne(t) + "</text>";
1016
+ return `<text x="${e.x}" y="${e.y}" fill="${Z(r)}" font-size="${i}" text-anchor="${a}">` + Pe(t) + "</text>";
1010
1017
  }
1011
1018
  var X = 0;
1012
- function Me() {
1019
+ function Ne() {
1013
1020
  return X = X + 1 | 0, X;
1014
1021
  }
1015
1022
  function Z(e) {
1016
1023
  return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
1017
1024
  }
1018
- function Ne(e) {
1025
+ function Pe(e) {
1019
1026
  return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
1020
1027
  }
1021
1028
  //#endregion
1022
1029
  //#region src/dsl/to-svg.ts
1023
- var Pe = {
1030
+ var Fe = {
1024
1031
  info: {
1025
1032
  stroke: "#3b82f6",
1026
1033
  fill: "rgba(59, 130, 246, 0.12)",
@@ -1046,32 +1053,32 @@ var Pe = {
1046
1053
  fill: "rgba(107, 114, 128, 0.12)",
1047
1054
  text: "#374151"
1048
1055
  }
1049
- }, Fe = "error";
1056
+ }, Ie = "error";
1050
1057
  function Q(e) {
1051
- let t = Pe[e.intent ?? Fe];
1058
+ let t = Fe[e.intent ?? Ie];
1052
1059
  return {
1053
1060
  stroke: e.stroke ?? t.stroke,
1054
1061
  fill: e.fill ?? "none",
1055
1062
  text: e.color ?? t.text
1056
1063
  };
1057
1064
  }
1058
- function Ie(e) {
1059
- return e.map(Le).join("");
1060
- }
1061
1065
  function Le(e) {
1066
+ return e.map(Re).join("");
1067
+ }
1068
+ function Re(e) {
1062
1069
  switch (e.type) {
1063
- case "rect": return Re(e);
1064
- case "circle": return ze(e);
1065
- case "arrow": return Be(e);
1066
- case "text": return Ve(e);
1067
- case "callout": return He(e);
1068
- case "numberedBadge": return Je(e);
1069
- case "freehand": return We(e);
1070
- case "focusMask": return Ke(e);
1071
- case "raw": return Ue(e);
1070
+ case "rect": return ze(e);
1071
+ case "circle": return Be(e);
1072
+ case "arrow": return Ve(e);
1073
+ case "text": return He(e);
1074
+ case "callout": return Ue(e);
1075
+ case "numberedBadge": return Ye(e);
1076
+ case "freehand": return Ge(e);
1077
+ case "focusMask": return qe(e);
1078
+ case "raw": return We(e);
1072
1079
  }
1073
1080
  }
1074
- function Re(e) {
1081
+ function ze(e) {
1075
1082
  let t = Q(e);
1076
1083
  return q(e.bbox, {
1077
1084
  stroke: t.stroke,
@@ -1079,18 +1086,18 @@ function Re(e) {
1079
1086
  fill: t.fill
1080
1087
  });
1081
1088
  }
1082
- function ze(e) {
1089
+ function Be(e) {
1083
1090
  let t = Q(e), n = e.strokeWidth ?? 2;
1084
1091
  return `<circle cx="${e.center.x}" cy="${e.center.y}" r="${e.radius}" fill="${$(t.fill)}" stroke="${$(t.stroke)}" stroke-width="${n}"/>`;
1085
1092
  }
1086
- function Be(e) {
1093
+ function Ve(e) {
1087
1094
  let t = Q(e);
1088
1095
  return J(e.from, e.to, {
1089
1096
  color: t.stroke,
1090
1097
  strokeWidth: e.strokeWidth ?? 2
1091
1098
  });
1092
1099
  }
1093
- function Ve(e) {
1100
+ function He(e) {
1094
1101
  let t = Q(e);
1095
1102
  return Y(e.at, e.content, {
1096
1103
  color: t.text,
@@ -1098,8 +1105,8 @@ function Ve(e) {
1098
1105
  anchor: e.anchor ?? "start"
1099
1106
  });
1100
1107
  }
1101
- function He(e) {
1102
- let t = Q(e), n = e.targetBbox, r = Ze(n, e.at);
1108
+ function Ue(e) {
1109
+ let t = Q(e), n = e.targetBbox, r = Qe(n, e.at);
1103
1110
  return q(n, {
1104
1111
  stroke: t.stroke,
1105
1112
  strokeWidth: e.strokeWidth ?? 2,
@@ -1113,28 +1120,28 @@ function He(e) {
1113
1120
  anchor: "start"
1114
1121
  });
1115
1122
  }
1116
- function Ue(e) {
1123
+ function We(e) {
1117
1124
  return e.svgFragment;
1118
1125
  }
1119
- function We(e) {
1126
+ function Ge(e) {
1120
1127
  let t = Q(e), n = e.fill ?? "none", r = e.strokeWidth ?? 2;
1121
1128
  return `<path d="${$(e.path)}" fill="${$(n)}" stroke="${$(t.stroke)}" stroke-width="${r}" stroke-linecap="round" stroke-linejoin="round"/>`;
1122
1129
  }
1123
- var Ge = "rgba(0,0,0,0.5)";
1124
- function Ke(e) {
1125
- let { cutout: t, imageWidth: n, imageHeight: r } = e, i = e.dimColor ?? Ge;
1130
+ var Ke = "rgba(0,0,0,0.5)";
1131
+ function qe(e) {
1132
+ let { cutout: t, imageWidth: n, imageHeight: r } = e, i = e.dimColor ?? Ke;
1126
1133
  return `<path d="${$(`M0,0 H${n} V${r} H0 Z M${t.x},${t.y} H${t.x + t.width} V${t.y + t.height} H${t.x} Z`)}" fill="${$(i)}" fill-rule="evenodd" stroke="none"/>`;
1127
1134
  }
1128
- var qe = 40;
1129
- function Je(e) {
1130
- let t = Q(e), n = e.badgeSize ?? qe, r = Ye(e, n), i = q(e.bbox, {
1135
+ var Je = 40;
1136
+ function Ye(e) {
1137
+ let t = Q(e), n = e.badgeSize ?? Je, r = Xe(e, n), i = q(e.bbox, {
1131
1138
  stroke: t.stroke,
1132
1139
  strokeWidth: e.strokeWidth ?? 3,
1133
1140
  fill: e.fill ?? "none"
1134
- }), a = Xe(e.bbox, r), o = n / 2, s = `<circle cx="${a.x}" cy="${a.y}" r="${o}" fill="${t.stroke}" stroke="#ffffff" stroke-width="${Math.max(2, o * .12)}" />`, c = Math.round(o * 1.1), l = `<text x="${a.x}" y="${a.y}" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif" font-size="${c}" font-weight="700" fill="#ffffff" text-anchor="middle" dominant-baseline="central">${$(String(e.number))}</text>`;
1141
+ }), a = Ze(e.bbox, r), o = n / 2, s = `<circle cx="${a.x}" cy="${a.y}" r="${o}" fill="${t.stroke}" stroke="#ffffff" stroke-width="${Math.max(2, o * .12)}" />`, c = Math.round(o * 1.1), l = `<text x="${a.x}" y="${a.y}" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif" font-size="${c}" font-weight="700" fill="#ffffff" text-anchor="middle" dominant-baseline="central">${$(String(e.number))}</text>`;
1135
1142
  return i + s + l;
1136
1143
  }
1137
- function Ye(e, t) {
1144
+ function Xe(e, t) {
1138
1145
  if (e.placement && e.placement !== "auto") return e.placement;
1139
1146
  if (e.imageWidth === void 0 || e.imageHeight === void 0) return "topRight";
1140
1147
  let n = t / 2, r = [
@@ -1165,7 +1172,7 @@ function Ye(e, t) {
1165
1172
  }
1166
1173
  return i.kind;
1167
1174
  }
1168
- function Xe(e, t) {
1175
+ function Ze(e, t) {
1169
1176
  switch (t) {
1170
1177
  case "topLeft": return {
1171
1178
  x: e.x,
@@ -1185,17 +1192,17 @@ function Xe(e, t) {
1185
1192
  };
1186
1193
  }
1187
1194
  }
1188
- function Ze(e, t) {
1195
+ function Qe(e, t) {
1189
1196
  return {
1190
- x: Qe(t.x, e.x, e.x + e.width),
1191
- y: Qe(t.y, e.y, e.y + e.height)
1197
+ x: $e(t.x, e.x, e.x + e.width),
1198
+ y: $e(t.y, e.y, e.y + e.height)
1192
1199
  };
1193
1200
  }
1194
- function Qe(e, t, n) {
1201
+ function $e(e, t, n) {
1195
1202
  return Math.min(Math.max(e, t), n);
1196
1203
  }
1197
1204
  function $(e) {
1198
1205
  return e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
1199
1206
  }
1200
1207
  //#endregion
1201
- export { Ae as BBOX_ANNOTATION_SCHEMA, je as BBOX_REDACT_REGION_SCHEMA, T as DEFAULT_ENCODE_OPTIONS, Te as DimensionMismatchError, w as SAVE_SIZE_LABEL, C as SAVE_SIZE_MAX_WIDTH, ke as SHARED_DEFS, K as aggregateDiffRegions, J as arrowBetween, Ie as bboxAnnotationsToSvg, B as burnRedactions, ve as burnRegions, E as computeResizeTarget, de as createAnnotator, se as decodeAndEncodeImage, Ee as diffScreenshots, F as encodeRgba, Oe as flattenEditablePng, P as isPhotoHeavy, q as rectForBoundingBox, Y as textAt };
1208
+ export { je as BBOX_ANNOTATION_SCHEMA, Me as BBOX_REDACT_REGION_SCHEMA, E as DEFAULT_ENCODE_OPTIONS, Ee as DimensionMismatchError, T as SAVE_SIZE_LABEL, w as SAVE_SIZE_MAX_WIDTH, Ae as SHARED_DEFS, K as aggregateDiffRegions, J as arrowBetween, Le as bboxAnnotationsToSvg, B as burnRedactions, ye as burnRegions, D as computeResizeTarget, fe as createAnnotator, ce as decodeAndEncodeImage, De as diffScreenshots, F as encodeRgba, ke as flattenEditablePng, P as isPhotoHeavy, q as rectForBoundingBox, Y as textAt };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ingcreators/annot-annotator",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Headless annotator — render annotated screenshots from Node without a browser. Built on @resvg/resvg-js. Pairs with @ingcreators/annot-playwright for fail-on-test annotated reports.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "ingcreators",
@@ -48,15 +48,15 @@
48
48
  },
49
49
  "devDependencies": {
50
50
  "typescript": "^6.0.3",
51
- "vite": "^8.0.16",
51
+ "vite": "^8.1.3",
52
52
  "vite-plugin-dts": "^5.0.3",
53
- "@ingcreators/annot-core": "0.3.0"
53
+ "@ingcreators/annot-core": "0.4.0"
54
54
  },
55
55
  "dependencies": {
56
- "@napi-rs/canvas": "^1.0.0",
56
+ "@napi-rs/canvas": "^1.0.2",
57
57
  "@resvg/resvg-js": "^2.6.2",
58
58
  "@xmldom/xmldom": "^0.9.10",
59
- "pako": "^2.1.0",
59
+ "pako": "^3.0.1",
60
60
  "pixelmatch": "^7.1.0"
61
61
  },
62
62
  "scripts": {