@ingcreators/annot-annotator 0.1.0 → 0.2.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 +16 -0
- package/README.md +11 -8
- package/dist/dsl/schema.d.ts +239 -0
- package/dist/dsl/svg-primitives.d.ts +32 -0
- package/dist/dsl/to-svg.d.ts +11 -0
- package/dist/dsl/types.d.ts +66 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +315 -78
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @ingcreators/annot-annotator
|
|
2
2
|
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 92378f9: Public DSL surface (since 0.2.0). The annotation DSL that was previously private to `@ingcreators/annot-mcp` now lives on the annotator package so any Annot consumer (test runtimes, AI agents, plugin authors) can use the same vocabulary.
|
|
8
|
+
|
|
9
|
+
New exports:
|
|
10
|
+
- Types: `BBox`, `Point`, `Intent`, `AnnotationStyle`, `BboxAnnotation` (`rect` / `circle` / `arrow` / `text` / `callout` / `raw`), `RawAnnotation`, `BboxRedactRegion`, `RedactStyle`.
|
|
11
|
+
- Converter: `bboxAnnotationsToSvg(annotations)` returns the SVG fragment string `createAnnotator(...).toPng({ annotationsSvg })` accepts.
|
|
12
|
+
- SVG primitives: `rectForBoundingBox`, `arrowBetween`, `textAt`, plus `BoundingBox` / `RectOptions` / `ArrowOptions` / `TextOptions`.
|
|
13
|
+
- JSON Schemas: `SHARED_DEFS`, `BBOX_ANNOTATION_SCHEMA`, `BBOX_REDACT_REGION_SCHEMA` (drop into MCP tool `inputSchema` `$defs` blocks).
|
|
14
|
+
|
|
15
|
+
The `intent` shorthand (`"info"` / `"warning"` / `"error"` / `"success"` / `"neutral"`) resolves to the Annot design system's semantic colour tokens automatically — no more thinking in raw hex values.
|
|
16
|
+
|
|
17
|
+
Marker id prefix in `arrowBetween` changed from `annot-pw-arrow-N` (previous helper in `@ingcreators/annot-playwright`) / `annot-mcp-arrow-N` (previous helper in `@ingcreators/annot-mcp`) to the package-neutral `annot-arrow-N`. Snapshot-on-SVG tests should expect this minor cosmetic delta.
|
|
18
|
+
|
|
3
19
|
## 0.1.0
|
|
4
20
|
|
|
5
21
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
# `@ingcreators/annot-annotator`
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@ingcreators/annot-annotator)
|
|
4
|
+
[](https://github.com/ingcreators/annot/blob/main/LICENSE)
|
|
5
|
+
|
|
3
6
|
Headless annotator — produce annotated screenshots from Node without
|
|
4
7
|
a browser. Reads an `ImageRecord`-shaped input (base image + saved
|
|
5
8
|
annotations SVG) and emits a PNG or the merged SVG.
|
|
6
9
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
>
|
|
11
|
-
> Companion package: `@ingcreators/annot-playwright` (Phase 2 of the
|
|
12
|
-
> same track) — a Playwright fixture composing this annotator into
|
|
13
|
-
> idiomatic `test.extend({ annotator })` form.
|
|
10
|
+
Companion package: [`@ingcreators/annot-playwright`](https://www.npmjs.com/package/@ingcreators/annot-playwright) —
|
|
11
|
+
a Playwright fixture composing this annotator into idiomatic
|
|
12
|
+
`test.extend({ annotator })` form.
|
|
14
13
|
|
|
15
|
-
## Install
|
|
14
|
+
## Install
|
|
16
15
|
|
|
17
16
|
```sh
|
|
18
17
|
npm install @ingcreators/annot-annotator
|
|
@@ -20,6 +19,10 @@ npm install @ingcreators/annot-annotator
|
|
|
20
19
|
pnpm add @ingcreators/annot-annotator
|
|
21
20
|
```
|
|
22
21
|
|
|
22
|
+
Peer runtime requirements: Node 20+. The package depends on
|
|
23
|
+
`@resvg/resvg-js` (native binding via `@napi-rs`) — npm install
|
|
24
|
+
fetches the platform-matched prebuild automatically.
|
|
25
|
+
|
|
23
26
|
## Usage
|
|
24
27
|
|
|
25
28
|
```ts
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/** Common subschemas to spread into a tool's `$defs` block. */
|
|
2
|
+
export declare const SHARED_DEFS: {
|
|
3
|
+
BBox: {
|
|
4
|
+
type: string;
|
|
5
|
+
required: string[];
|
|
6
|
+
additionalProperties: boolean;
|
|
7
|
+
properties: {
|
|
8
|
+
x: {
|
|
9
|
+
type: string;
|
|
10
|
+
};
|
|
11
|
+
y: {
|
|
12
|
+
type: string;
|
|
13
|
+
};
|
|
14
|
+
width: {
|
|
15
|
+
type: string;
|
|
16
|
+
minimum: number;
|
|
17
|
+
};
|
|
18
|
+
height: {
|
|
19
|
+
type: string;
|
|
20
|
+
minimum: number;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
Point: {
|
|
25
|
+
type: string;
|
|
26
|
+
required: string[];
|
|
27
|
+
additionalProperties: boolean;
|
|
28
|
+
properties: {
|
|
29
|
+
x: {
|
|
30
|
+
type: string;
|
|
31
|
+
};
|
|
32
|
+
y: {
|
|
33
|
+
type: string;
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
Intent: {
|
|
38
|
+
type: string;
|
|
39
|
+
enum: string[];
|
|
40
|
+
};
|
|
41
|
+
AnnotationStyle: {
|
|
42
|
+
type: string;
|
|
43
|
+
additionalProperties: boolean;
|
|
44
|
+
properties: {
|
|
45
|
+
intent: {
|
|
46
|
+
$ref: string;
|
|
47
|
+
};
|
|
48
|
+
stroke: {
|
|
49
|
+
type: string;
|
|
50
|
+
};
|
|
51
|
+
strokeWidth: {
|
|
52
|
+
type: string;
|
|
53
|
+
minimum: number;
|
|
54
|
+
};
|
|
55
|
+
fill: {
|
|
56
|
+
type: string;
|
|
57
|
+
};
|
|
58
|
+
color: {
|
|
59
|
+
type: string;
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
export declare const BBOX_ANNOTATION_SCHEMA: {
|
|
65
|
+
oneOf: ({
|
|
66
|
+
type: string;
|
|
67
|
+
required: string[];
|
|
68
|
+
additionalProperties: boolean;
|
|
69
|
+
properties: {
|
|
70
|
+
type: {
|
|
71
|
+
const: string;
|
|
72
|
+
};
|
|
73
|
+
bbox: {
|
|
74
|
+
$ref: string;
|
|
75
|
+
};
|
|
76
|
+
intent: {
|
|
77
|
+
$ref: string;
|
|
78
|
+
};
|
|
79
|
+
stroke: {
|
|
80
|
+
type: string;
|
|
81
|
+
};
|
|
82
|
+
strokeWidth: {
|
|
83
|
+
type: string;
|
|
84
|
+
minimum: number;
|
|
85
|
+
};
|
|
86
|
+
fill: {
|
|
87
|
+
type: string;
|
|
88
|
+
};
|
|
89
|
+
color: {
|
|
90
|
+
type: string;
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
} | {
|
|
94
|
+
type: string;
|
|
95
|
+
required: string[];
|
|
96
|
+
additionalProperties: boolean;
|
|
97
|
+
properties: {
|
|
98
|
+
type: {
|
|
99
|
+
const: string;
|
|
100
|
+
};
|
|
101
|
+
center: {
|
|
102
|
+
$ref: string;
|
|
103
|
+
};
|
|
104
|
+
radius: {
|
|
105
|
+
type: string;
|
|
106
|
+
minimum: number;
|
|
107
|
+
};
|
|
108
|
+
intent: {
|
|
109
|
+
$ref: string;
|
|
110
|
+
};
|
|
111
|
+
stroke: {
|
|
112
|
+
type: string;
|
|
113
|
+
};
|
|
114
|
+
strokeWidth: {
|
|
115
|
+
type: string;
|
|
116
|
+
minimum: number;
|
|
117
|
+
};
|
|
118
|
+
fill: {
|
|
119
|
+
type: string;
|
|
120
|
+
};
|
|
121
|
+
color: {
|
|
122
|
+
type: string;
|
|
123
|
+
};
|
|
124
|
+
};
|
|
125
|
+
} | {
|
|
126
|
+
type: string;
|
|
127
|
+
required: string[];
|
|
128
|
+
additionalProperties: boolean;
|
|
129
|
+
properties: {
|
|
130
|
+
type: {
|
|
131
|
+
const: string;
|
|
132
|
+
};
|
|
133
|
+
from: {
|
|
134
|
+
$ref: string;
|
|
135
|
+
};
|
|
136
|
+
to: {
|
|
137
|
+
$ref: string;
|
|
138
|
+
};
|
|
139
|
+
intent: {
|
|
140
|
+
$ref: string;
|
|
141
|
+
};
|
|
142
|
+
stroke: {
|
|
143
|
+
type: string;
|
|
144
|
+
};
|
|
145
|
+
strokeWidth: {
|
|
146
|
+
type: string;
|
|
147
|
+
minimum: number;
|
|
148
|
+
};
|
|
149
|
+
color: {
|
|
150
|
+
type: string;
|
|
151
|
+
};
|
|
152
|
+
};
|
|
153
|
+
} | {
|
|
154
|
+
type: string;
|
|
155
|
+
required: string[];
|
|
156
|
+
additionalProperties: boolean;
|
|
157
|
+
properties: {
|
|
158
|
+
type: {
|
|
159
|
+
const: string;
|
|
160
|
+
};
|
|
161
|
+
at: {
|
|
162
|
+
$ref: string;
|
|
163
|
+
};
|
|
164
|
+
content: {
|
|
165
|
+
type: string;
|
|
166
|
+
};
|
|
167
|
+
fontSize: {
|
|
168
|
+
type: string;
|
|
169
|
+
minimum: number;
|
|
170
|
+
};
|
|
171
|
+
anchor: {
|
|
172
|
+
type: string;
|
|
173
|
+
enum: string[];
|
|
174
|
+
};
|
|
175
|
+
intent: {
|
|
176
|
+
$ref: string;
|
|
177
|
+
};
|
|
178
|
+
color: {
|
|
179
|
+
type: string;
|
|
180
|
+
};
|
|
181
|
+
};
|
|
182
|
+
} | {
|
|
183
|
+
type: string;
|
|
184
|
+
required: string[];
|
|
185
|
+
additionalProperties: boolean;
|
|
186
|
+
properties: {
|
|
187
|
+
type: {
|
|
188
|
+
const: string;
|
|
189
|
+
};
|
|
190
|
+
at: {
|
|
191
|
+
$ref: string;
|
|
192
|
+
};
|
|
193
|
+
targetBbox: {
|
|
194
|
+
$ref: string;
|
|
195
|
+
};
|
|
196
|
+
content: {
|
|
197
|
+
type: string;
|
|
198
|
+
};
|
|
199
|
+
intent: {
|
|
200
|
+
$ref: string;
|
|
201
|
+
};
|
|
202
|
+
stroke: {
|
|
203
|
+
type: string;
|
|
204
|
+
};
|
|
205
|
+
color: {
|
|
206
|
+
type: string;
|
|
207
|
+
};
|
|
208
|
+
};
|
|
209
|
+
} | {
|
|
210
|
+
type: string;
|
|
211
|
+
required: string[];
|
|
212
|
+
additionalProperties: boolean;
|
|
213
|
+
properties: {
|
|
214
|
+
type: {
|
|
215
|
+
const: string;
|
|
216
|
+
};
|
|
217
|
+
svgFragment: {
|
|
218
|
+
type: string;
|
|
219
|
+
};
|
|
220
|
+
};
|
|
221
|
+
})[];
|
|
222
|
+
};
|
|
223
|
+
export declare const BBOX_REDACT_REGION_SCHEMA: {
|
|
224
|
+
type: string;
|
|
225
|
+
required: string[];
|
|
226
|
+
additionalProperties: boolean;
|
|
227
|
+
properties: {
|
|
228
|
+
bbox: {
|
|
229
|
+
$ref: string;
|
|
230
|
+
};
|
|
231
|
+
style: {
|
|
232
|
+
type: string;
|
|
233
|
+
enum: string[];
|
|
234
|
+
};
|
|
235
|
+
color: {
|
|
236
|
+
type: string;
|
|
237
|
+
};
|
|
238
|
+
};
|
|
239
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { BBox, Point } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Back-compat alias retained because the original
|
|
4
|
+
* `@ingcreators/annot-playwright` helpers exposed this name.
|
|
5
|
+
* Prefer importing `BBox` from `@ingcreators/annot-annotator`
|
|
6
|
+
* directly.
|
|
7
|
+
*/
|
|
8
|
+
export type BoundingBox = BBox;
|
|
9
|
+
export interface RectOptions {
|
|
10
|
+
stroke?: string;
|
|
11
|
+
strokeWidth?: number;
|
|
12
|
+
fill?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface ArrowOptions {
|
|
15
|
+
color?: string;
|
|
16
|
+
strokeWidth?: number;
|
|
17
|
+
}
|
|
18
|
+
export interface TextOptions {
|
|
19
|
+
color?: string;
|
|
20
|
+
fontSize?: number;
|
|
21
|
+
anchor?: "start" | "middle" | "end";
|
|
22
|
+
}
|
|
23
|
+
/** Outline a bounding box with an SVG `<rect>`. */
|
|
24
|
+
export declare function rectForBoundingBox(bbox: BoundingBox, opts?: RectOptions): string;
|
|
25
|
+
/**
|
|
26
|
+
* Draw an arrow from `from` to `to`. Inlines a unique-id `<marker>`
|
|
27
|
+
* definition so the helper is self-contained — call it twice and
|
|
28
|
+
* each call produces a distinct arrowhead marker.
|
|
29
|
+
*/
|
|
30
|
+
export declare function arrowBetween(from: Point, to: Point, opts?: ArrowOptions): string;
|
|
31
|
+
/** Drop a text label at a position. */
|
|
32
|
+
export declare function textAt(at: Point, content: string, opts?: TextOptions): string;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { BboxAnnotation } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Convert a list of bbox-flavour annotations into a single SVG
|
|
4
|
+
* fragment string. The fragment is suitable as the
|
|
5
|
+
* `annotationsSvg` payload for `createAnnotator(...).toPng()` /
|
|
6
|
+
* `.toSvg()`.
|
|
7
|
+
*
|
|
8
|
+
* Emits bare fragments (no outer `<svg>` wrapper); the annotator's
|
|
9
|
+
* sanitiser wraps them at rasterise time.
|
|
10
|
+
*/
|
|
11
|
+
export declare function bboxAnnotationsToSvg(annotations: readonly BboxAnnotation[]): string;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/** Axis-aligned bounding box. Coordinates are page pixels. */
|
|
2
|
+
export interface BBox {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
}
|
|
8
|
+
/** Point in page pixels. */
|
|
9
|
+
export interface Point {
|
|
10
|
+
x: number;
|
|
11
|
+
y: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Semantic colour shorthand. Resolves to the Annot design system's
|
|
15
|
+
* matching token (e.g. `intent: "error"` → `--annot-color-error`).
|
|
16
|
+
* Explicit `stroke` / `color` / `fill` on an annotation override
|
|
17
|
+
* the intent-derived defaults.
|
|
18
|
+
*/
|
|
19
|
+
export type Intent = "info" | "warning" | "error" | "success" | "neutral";
|
|
20
|
+
/** Style overrides shared across most annotation shapes. */
|
|
21
|
+
export interface AnnotationStyle {
|
|
22
|
+
intent?: Intent;
|
|
23
|
+
stroke?: string;
|
|
24
|
+
strokeWidth?: number;
|
|
25
|
+
fill?: string;
|
|
26
|
+
color?: string;
|
|
27
|
+
}
|
|
28
|
+
export type BboxRectAnnotation = AnnotationStyle & {
|
|
29
|
+
type: "rect";
|
|
30
|
+
bbox: BBox;
|
|
31
|
+
};
|
|
32
|
+
export type BboxCircleAnnotation = AnnotationStyle & {
|
|
33
|
+
type: "circle";
|
|
34
|
+
center: Point;
|
|
35
|
+
radius: number;
|
|
36
|
+
};
|
|
37
|
+
export type BboxArrowAnnotation = AnnotationStyle & {
|
|
38
|
+
type: "arrow";
|
|
39
|
+
from: Point;
|
|
40
|
+
to: Point;
|
|
41
|
+
};
|
|
42
|
+
export type BboxTextAnnotation = AnnotationStyle & {
|
|
43
|
+
type: "text";
|
|
44
|
+
at: Point;
|
|
45
|
+
content: string;
|
|
46
|
+
fontSize?: number;
|
|
47
|
+
anchor?: "start" | "middle" | "end";
|
|
48
|
+
};
|
|
49
|
+
export type BboxCalloutAnnotation = AnnotationStyle & {
|
|
50
|
+
type: "callout";
|
|
51
|
+
at: Point;
|
|
52
|
+
targetBbox: BBox;
|
|
53
|
+
content: string;
|
|
54
|
+
};
|
|
55
|
+
export interface RawAnnotation {
|
|
56
|
+
type: "raw";
|
|
57
|
+
svgFragment: string;
|
|
58
|
+
}
|
|
59
|
+
export type BboxAnnotation = BboxRectAnnotation | BboxCircleAnnotation | BboxArrowAnnotation | BboxTextAnnotation | BboxCalloutAnnotation | RawAnnotation;
|
|
60
|
+
export type RedactStyle = "solid" | "mosaic" | "blur";
|
|
61
|
+
export interface BboxRedactRegion {
|
|
62
|
+
bbox: BBox;
|
|
63
|
+
style?: RedactStyle;
|
|
64
|
+
/** CSS colour, applied only when `style` is `"solid"`. */
|
|
65
|
+
color?: string;
|
|
66
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1,5 @@
|
|
|
1
1
|
export { type Annotator, type AnnotatorInput, type AnnotatorOptions, createAnnotator, } from './annotator.js';
|
|
2
|
+
export { BBOX_ANNOTATION_SCHEMA, BBOX_REDACT_REGION_SCHEMA, SHARED_DEFS, } from './dsl/schema.js';
|
|
3
|
+
export { type ArrowOptions, arrowBetween, type BoundingBox, type RectOptions, rectForBoundingBox, type TextOptions, textAt, } from './dsl/svg-primitives.js';
|
|
4
|
+
export { bboxAnnotationsToSvg } from './dsl/to-svg.js';
|
|
5
|
+
export type { AnnotationStyle, BBox, BboxAnnotation, BboxArrowAnnotation, BboxCalloutAnnotation, BboxCircleAnnotation, BboxRectAnnotation, BboxRedactRegion, BboxTextAnnotation, Intent, Point, RawAnnotation, RedactStyle, } from './dsl/types.js';
|
package/dist/index.js
CHANGED
|
@@ -1,80 +1,317 @@
|
|
|
1
|
-
import { Resvg as
|
|
2
|
-
import { DOMParser as
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
1
|
+
import { Resvg as b } from "@resvg/resvg-js";
|
|
2
|
+
import { DOMParser as w, XMLSerializer as B } from "@xmldom/xmldom";
|
|
3
|
+
const S = "1", N = "data-annot-version";
|
|
4
|
+
function T(e) {
|
|
5
|
+
if (!e || e.trim().length === 0)
|
|
6
|
+
return "";
|
|
7
|
+
const t = new w();
|
|
8
|
+
let r;
|
|
9
|
+
try {
|
|
10
|
+
r = t.parseFromString(e, "image/svg+xml");
|
|
11
|
+
} catch {
|
|
12
|
+
return "";
|
|
13
|
+
}
|
|
14
|
+
const n = r.documentElement;
|
|
15
|
+
if (!n) return "";
|
|
16
|
+
const o = new B();
|
|
17
|
+
let i = "";
|
|
18
|
+
for (let d = 0; d < n.childNodes.length; d++) {
|
|
19
|
+
const f = n.childNodes.item(d);
|
|
20
|
+
if (!f || f.nodeType !== 1) continue;
|
|
21
|
+
const s = f, p = s.localName ?? s.tagName ?? "";
|
|
22
|
+
if (p === "defs") {
|
|
23
|
+
const c = A(s);
|
|
24
|
+
c !== null && (i += o.serializeToString(c));
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
if (!(p === "image" && !s.getAttribute("data-redact-style")) && s.getAttribute("id") !== "ui-overlay") {
|
|
28
|
+
if (s.getAttribute("id") === "annotations") {
|
|
29
|
+
for (let c = 0; c < s.childNodes.length; c++) {
|
|
30
|
+
const u = s.childNodes.item(c);
|
|
31
|
+
u && u.nodeType === 1 && (i += o.serializeToString(u));
|
|
32
|
+
}
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
i += o.serializeToString(s);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return i;
|
|
39
39
|
}
|
|
40
|
+
function A(e) {
|
|
41
|
+
const t = e.cloneNode(!0);
|
|
42
|
+
for (let r = t.childNodes.length - 1; r >= 0; r--) {
|
|
43
|
+
const n = t.childNodes.item(r);
|
|
44
|
+
if (!n || n.nodeType !== 1) continue;
|
|
45
|
+
const o = n;
|
|
46
|
+
(o.localName ?? o.tagName ?? "") === "style" && o.hasAttribute("data-annot-fonts") && t.removeChild(n);
|
|
47
|
+
}
|
|
48
|
+
return t.childNodes.length === 0 ? null : t;
|
|
49
|
+
}
|
|
50
|
+
function H(e = {}) {
|
|
51
|
+
const t = {
|
|
52
|
+
loadSystemFonts: e.loadSystemFonts ?? !1,
|
|
53
|
+
...e.fontFiles ? { fontFiles: e.fontFiles } : {},
|
|
54
|
+
...e.fontDirs ? { fontDirs: e.fontDirs } : {},
|
|
55
|
+
...e.defaultFontFamily ? { defaultFontFamily: e.defaultFontFamily } : {}
|
|
56
|
+
};
|
|
57
|
+
return {
|
|
58
|
+
toSvg(r) {
|
|
59
|
+
return m(r);
|
|
60
|
+
},
|
|
61
|
+
toPng(r) {
|
|
62
|
+
const n = m(r);
|
|
63
|
+
return new b(n, {
|
|
64
|
+
fitTo: { mode: "width", value: r.width },
|
|
65
|
+
background: "rgba(0, 0, 0, 0)",
|
|
66
|
+
font: t
|
|
67
|
+
}).render().asPng();
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function m(e) {
|
|
72
|
+
const t = "http://www.w3.org/2000/svg", r = "http://www.w3.org/1999/xlink", n = T(e.annotationsSvg);
|
|
73
|
+
return `<svg xmlns="${t}" xmlns:xlink="${r}" ${N}="${S}" width="${e.width}" height="${e.height}" viewBox="0 0 ${e.width} ${e.height}"><image href="${e.originalDataUrl}" width="${e.width}" height="${e.height}"/>` + n + "</svg>";
|
|
74
|
+
}
|
|
75
|
+
const K = {
|
|
76
|
+
BBox: {
|
|
77
|
+
type: "object",
|
|
78
|
+
required: ["x", "y", "width", "height"],
|
|
79
|
+
additionalProperties: !1,
|
|
80
|
+
properties: {
|
|
81
|
+
x: { type: "number" },
|
|
82
|
+
y: { type: "number" },
|
|
83
|
+
width: { type: "number", minimum: 0 },
|
|
84
|
+
height: { type: "number", minimum: 0 }
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
Point: {
|
|
88
|
+
type: "object",
|
|
89
|
+
required: ["x", "y"],
|
|
90
|
+
additionalProperties: !1,
|
|
91
|
+
properties: {
|
|
92
|
+
x: { type: "number" },
|
|
93
|
+
y: { type: "number" }
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
Intent: {
|
|
97
|
+
type: "string",
|
|
98
|
+
enum: ["info", "warning", "error", "success", "neutral"]
|
|
99
|
+
},
|
|
100
|
+
AnnotationStyle: {
|
|
101
|
+
type: "object",
|
|
102
|
+
additionalProperties: !1,
|
|
103
|
+
properties: {
|
|
104
|
+
intent: { $ref: "#/$defs/Intent" },
|
|
105
|
+
stroke: { type: "string" },
|
|
106
|
+
strokeWidth: { type: "number", minimum: 0 },
|
|
107
|
+
fill: { type: "string" },
|
|
108
|
+
color: { type: "string" }
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}, F = {
|
|
112
|
+
type: "object",
|
|
113
|
+
required: ["type", "bbox"],
|
|
114
|
+
additionalProperties: !1,
|
|
115
|
+
properties: {
|
|
116
|
+
type: { const: "rect" },
|
|
117
|
+
bbox: { $ref: "#/$defs/BBox" },
|
|
118
|
+
intent: { $ref: "#/$defs/Intent" },
|
|
119
|
+
stroke: { type: "string" },
|
|
120
|
+
strokeWidth: { type: "number", minimum: 0 },
|
|
121
|
+
fill: { type: "string" },
|
|
122
|
+
color: { type: "string" }
|
|
123
|
+
}
|
|
124
|
+
}, v = {
|
|
125
|
+
type: "object",
|
|
126
|
+
required: ["type", "center", "radius"],
|
|
127
|
+
additionalProperties: !1,
|
|
128
|
+
properties: {
|
|
129
|
+
type: { const: "circle" },
|
|
130
|
+
center: { $ref: "#/$defs/Point" },
|
|
131
|
+
radius: { type: "number", minimum: 0 },
|
|
132
|
+
intent: { $ref: "#/$defs/Intent" },
|
|
133
|
+
stroke: { type: "string" },
|
|
134
|
+
strokeWidth: { type: "number", minimum: 0 },
|
|
135
|
+
fill: { type: "string" },
|
|
136
|
+
color: { type: "string" }
|
|
137
|
+
}
|
|
138
|
+
}, O = {
|
|
139
|
+
type: "object",
|
|
140
|
+
required: ["type", "from", "to"],
|
|
141
|
+
additionalProperties: !1,
|
|
142
|
+
properties: {
|
|
143
|
+
type: { const: "arrow" },
|
|
144
|
+
from: { $ref: "#/$defs/Point" },
|
|
145
|
+
to: { $ref: "#/$defs/Point" },
|
|
146
|
+
intent: { $ref: "#/$defs/Intent" },
|
|
147
|
+
stroke: { type: "string" },
|
|
148
|
+
strokeWidth: { type: "number", minimum: 0 },
|
|
149
|
+
color: { type: "string" }
|
|
150
|
+
}
|
|
151
|
+
}, W = {
|
|
152
|
+
type: "object",
|
|
153
|
+
required: ["type", "at", "content"],
|
|
154
|
+
additionalProperties: !1,
|
|
155
|
+
properties: {
|
|
156
|
+
type: { const: "text" },
|
|
157
|
+
at: { $ref: "#/$defs/Point" },
|
|
158
|
+
content: { type: "string" },
|
|
159
|
+
fontSize: { type: "number", minimum: 0 },
|
|
160
|
+
anchor: { type: "string", enum: ["start", "middle", "end"] },
|
|
161
|
+
intent: { $ref: "#/$defs/Intent" },
|
|
162
|
+
color: { type: "string" }
|
|
163
|
+
}
|
|
164
|
+
}, P = {
|
|
165
|
+
type: "object",
|
|
166
|
+
required: ["type", "at", "targetBbox", "content"],
|
|
167
|
+
additionalProperties: !1,
|
|
168
|
+
properties: {
|
|
169
|
+
type: { const: "callout" },
|
|
170
|
+
at: { $ref: "#/$defs/Point" },
|
|
171
|
+
targetBbox: { $ref: "#/$defs/BBox" },
|
|
172
|
+
content: { type: "string" },
|
|
173
|
+
intent: { $ref: "#/$defs/Intent" },
|
|
174
|
+
stroke: { type: "string" },
|
|
175
|
+
color: { type: "string" }
|
|
176
|
+
}
|
|
177
|
+
}, I = {
|
|
178
|
+
type: "object",
|
|
179
|
+
required: ["type", "svgFragment"],
|
|
180
|
+
additionalProperties: !1,
|
|
181
|
+
properties: {
|
|
182
|
+
type: { const: "raw" },
|
|
183
|
+
svgFragment: { type: "string" }
|
|
184
|
+
}
|
|
185
|
+
}, Y = {
|
|
186
|
+
oneOf: [F, v, O, W, P, I]
|
|
187
|
+
}, J = {
|
|
188
|
+
type: "object",
|
|
189
|
+
required: ["bbox"],
|
|
190
|
+
additionalProperties: !1,
|
|
191
|
+
properties: {
|
|
192
|
+
bbox: { $ref: "#/$defs/BBox" },
|
|
193
|
+
style: { type: "string", enum: ["solid", "mosaic", "blur"] },
|
|
194
|
+
color: { type: "string" }
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
function $(e, t = {}) {
|
|
198
|
+
const r = t.stroke ?? "red", n = t.strokeWidth ?? 2, o = t.fill ?? "none";
|
|
199
|
+
return `<rect x="${e.x}" y="${e.y}" width="${e.width}" height="${e.height}" fill="${l(o)}" stroke="${l(r)}" stroke-width="${n}"/>`;
|
|
200
|
+
}
|
|
201
|
+
function k(e, t, r = {}) {
|
|
202
|
+
const n = r.color ?? "red", o = r.strokeWidth ?? 2, i = `annot-arrow-${_()}`;
|
|
203
|
+
return `<defs><marker id="${i}" 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="${l(n)}"/></marker></defs><line x1="${e.x}" y1="${e.y}" x2="${t.x}" y2="${t.y}" stroke="${l(n)}" stroke-width="${o}" marker-end="url(#${i})"/>`;
|
|
204
|
+
}
|
|
205
|
+
function x(e, t, r = {}) {
|
|
206
|
+
const n = r.color ?? "red", o = r.fontSize ?? 14, i = r.anchor ?? "start";
|
|
207
|
+
return `<text x="${e.x}" y="${e.y}" fill="${l(n)}" font-size="${o}" text-anchor="${i}">` + E(t) + "</text>";
|
|
208
|
+
}
|
|
209
|
+
let g = 0;
|
|
210
|
+
function _() {
|
|
211
|
+
return g = g + 1 | 0, g;
|
|
212
|
+
}
|
|
213
|
+
function l(e) {
|
|
214
|
+
return e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
215
|
+
}
|
|
216
|
+
function E(e) {
|
|
217
|
+
return e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
218
|
+
}
|
|
219
|
+
const R = {
|
|
220
|
+
info: { stroke: "#3b82f6", fill: "rgba(59, 130, 246, 0.12)", text: "#1e40af" },
|
|
221
|
+
warning: { stroke: "#f59e0b", fill: "rgba(245, 158, 11, 0.12)", text: "#92400e" },
|
|
222
|
+
error: { stroke: "#ef4444", fill: "rgba(239, 68, 68, 0.12)", text: "#991b1b" },
|
|
223
|
+
success: { stroke: "#10b981", fill: "rgba(16, 185, 129, 0.12)", text: "#065f46" },
|
|
224
|
+
neutral: { stroke: "#6b7280", fill: "rgba(107, 114, 128, 0.12)", text: "#374151" }
|
|
225
|
+
}, z = "error";
|
|
40
226
|
function a(e) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
75
|
-
function
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
|
|
227
|
+
const t = e.intent ?? z, r = R[t];
|
|
228
|
+
return {
|
|
229
|
+
stroke: e.stroke ?? r.stroke,
|
|
230
|
+
fill: e.fill ?? "none",
|
|
231
|
+
text: e.color ?? r.text
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function Q(e) {
|
|
235
|
+
return e.map(j).join("");
|
|
236
|
+
}
|
|
237
|
+
function j(e) {
|
|
238
|
+
switch (e.type) {
|
|
239
|
+
case "rect":
|
|
240
|
+
return q(e);
|
|
241
|
+
case "circle":
|
|
242
|
+
return C(e);
|
|
243
|
+
case "arrow":
|
|
244
|
+
return X(e);
|
|
245
|
+
case "text":
|
|
246
|
+
return D(e);
|
|
247
|
+
case "callout":
|
|
248
|
+
return L(e);
|
|
249
|
+
case "raw":
|
|
250
|
+
return M(e);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
function q(e) {
|
|
254
|
+
const t = a(e);
|
|
255
|
+
return $(e.bbox, {
|
|
256
|
+
stroke: t.stroke,
|
|
257
|
+
strokeWidth: e.strokeWidth ?? 2,
|
|
258
|
+
fill: t.fill
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
function C(e) {
|
|
262
|
+
const t = a(e), r = e.strokeWidth ?? 2;
|
|
263
|
+
return `<circle cx="${e.center.x}" cy="${e.center.y}" r="${e.radius}" fill="${y(t.fill)}" stroke="${y(t.stroke)}" stroke-width="${r}"/>`;
|
|
264
|
+
}
|
|
265
|
+
function X(e) {
|
|
266
|
+
const t = a(e);
|
|
267
|
+
return k(e.from, e.to, {
|
|
268
|
+
color: t.stroke,
|
|
269
|
+
strokeWidth: e.strokeWidth ?? 2
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
function D(e) {
|
|
273
|
+
const t = a(e);
|
|
274
|
+
return x(e.at, e.content, {
|
|
275
|
+
color: t.text,
|
|
276
|
+
fontSize: e.fontSize ?? 14,
|
|
277
|
+
anchor: e.anchor ?? "start"
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
function L(e) {
|
|
281
|
+
const t = a(e), r = e.targetBbox, n = U(r, e.at);
|
|
282
|
+
return $(r, {
|
|
283
|
+
stroke: t.stroke,
|
|
284
|
+
strokeWidth: e.strokeWidth ?? 2,
|
|
285
|
+
fill: t.fill
|
|
286
|
+
}) + k(e.at, n, {
|
|
287
|
+
color: t.stroke,
|
|
288
|
+
strokeWidth: 2
|
|
289
|
+
}) + x(e.at, e.content, {
|
|
290
|
+
color: t.text,
|
|
291
|
+
fontSize: 14,
|
|
292
|
+
anchor: "start"
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
function M(e) {
|
|
296
|
+
return e.svgFragment;
|
|
297
|
+
}
|
|
298
|
+
function U(e, t) {
|
|
299
|
+
const r = h(t.x, e.x, e.x + e.width), n = h(t.y, e.y, e.y + e.height);
|
|
300
|
+
return { x: r, y: n };
|
|
301
|
+
}
|
|
302
|
+
function h(e, t, r) {
|
|
303
|
+
return Math.min(Math.max(e, t), r);
|
|
304
|
+
}
|
|
305
|
+
function y(e) {
|
|
306
|
+
return e.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
307
|
+
}
|
|
308
|
+
export {
|
|
309
|
+
Y as BBOX_ANNOTATION_SCHEMA,
|
|
310
|
+
J as BBOX_REDACT_REGION_SCHEMA,
|
|
311
|
+
K as SHARED_DEFS,
|
|
312
|
+
k as arrowBetween,
|
|
313
|
+
Q as bboxAnnotationsToSvg,
|
|
314
|
+
H as createAnnotator,
|
|
315
|
+
$ as rectForBoundingBox,
|
|
316
|
+
x as textAt
|
|
317
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ingcreators/annot-annotator",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.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",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"typescript": "^6.0.3",
|
|
47
|
-
"vite": "^
|
|
47
|
+
"vite": "^6.4.2",
|
|
48
48
|
"vite-plugin-dts": "^5.0.0",
|
|
49
49
|
"@ingcreators/annot-core": "0.1.0"
|
|
50
50
|
},
|