@sealpixel/plugin-assist 1.0.0-rc.8

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/LICENSE.md ADDED
@@ -0,0 +1,59 @@
1
+ # Business Source License 1.1
2
+
3
+ ## Parameters
4
+
5
+ **Licensor:** nine feet UG (haftungsbeschränkt), Germany (https://9feet.io)
6
+
7
+ **Licensed Work:** Sealpixel, in every version the Licensor publishes: the source code, the npm packages under the `@sealpixel` scope and the unscoped `sealpixel` package, the Rust crates, the WebAssembly binaries, the documentation and the example projects. The Licensed Work is (c) 2026 nine feet UG (haftungsbeschränkt).
8
+
9
+ **Additional Use Grant:** You may make production use of the Licensed Work if you are a Small User. You are a Small User if you are a natural person acting for yourself, or if the organization you act for had less than EUR 1,000,000 of gross revenue in its most recent completed financial year. Revenue is counted across the whole group: the organization, everything that controls it, everything it controls, and everything under common control with it. Where the work is done for a client, the client's revenue decides.
10
+
11
+ This Additional Use Grant does not permit offering the Licensed Work, or a work that includes or is derived from it, to third parties as a product or service whose primary purpose is image editing, image cropping, annotation, redaction, watermarking or server-side image rendering.
12
+
13
+ **Change Date:** Four years after the date on which the Licensor first publishes a specific version of the Licensed Work.
14
+
15
+ **Change License:** Apache License, Version 2.0
16
+
17
+ For information about alternative licensing arrangements for the Licensed Work, please visit: https://sealpixel.dev/pricing
18
+
19
+ Organizations, and anyone who develops with the Licensed Work for an organization, obtain the commercial license this License refers to as developer seats under the Sealpixel Developer Seat License, published at https://sealpixel.dev/license#seats and as `LICENSE-COMMERCIAL.md` in the source repository.
20
+
21
+ ## Notice
22
+
23
+ The Business Source License (this document, or the "License") is not an Open Source license. However, the Licensed Work will eventually be made available under an Open Source License, as stated in this License.
24
+
25
+ License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved. "Business Source License" is a trademark of MariaDB Corporation Ab.
26
+
27
+ ---
28
+
29
+ ## Terms
30
+
31
+ The Licensor hereby grants you the right to copy, modify, create derivative works, redistribute, and make non-production use of the Licensed Work. The Licensor may make an Additional Use Grant, above, permitting limited production use.
32
+
33
+ Effective on the Change Date, or the fourth anniversary of the first publicly available distribution of a specific version of the Licensed Work under this License, whichever comes first, the Licensor hereby grants you rights under the terms of the Change License, and the rights granted in the paragraph above terminate.
34
+
35
+ If your use of the Licensed Work does not comply with the requirements currently in effect as described in this License, you must purchase a commercial license from the Licensor, its affiliated entities, or authorized resellers, or you must refrain from using the Licensed Work.
36
+
37
+ All copies of the original and modified Licensed Work, and derivative works of the Licensed Work, are subject to this License. This License applies separately for each version of the Licensed Work and the Change Date may vary for each version of the Licensed Work released by Licensor.
38
+
39
+ You must conspicuously display this License on each original or modified copy of the Licensed Work. If you receive the Licensed Work in original or modified form from a third party, the terms and conditions set forth in this License apply to your use of that work.
40
+
41
+ Any use of the Licensed Work in violation of this License will automatically terminate your rights under this License for the current and all other versions of the Licensed Work.
42
+
43
+ This License does not grant you any right in any trademark or logo of Licensor or its affiliates (provided that you may use a trademark or logo of Licensor as expressly required by this License).
44
+
45
+ TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND TITLE.
46
+
47
+ MariaDB hereby grants you permission to use this License's text to license your works, and to refer to it using the trademark "Business Source License", as long as you comply with the Covenants of Licensor below.
48
+
49
+ ## Covenants of Licensor
50
+
51
+ In consideration of the right to use this License's text and the "Business Source License" name and trademark, Licensor covenants to MariaDB, and to all other recipients of the licensed work to be provided by Licensor:
52
+
53
+ 1. To specify as the Change License the GPL Version 2.0 or any later version, or a license that is compatible with GPL Version 2.0 or a later version, where "compatible" means that software provided under the Change License can be included in a program with software provided under GPL Version 2.0 or a later version. Licensor may specify additional Change Licenses without limitation.
54
+
55
+ 2. To either: (a) specify an additional grant of rights to use that does not impose any additional restriction on the right granted in this License, as the Additional Use Grant; or (b) insert the text "None".
56
+
57
+ 3. To specify a Change Date.
58
+
59
+ 4. Not to modify this License in any other way.
package/README.md ADDED
@@ -0,0 +1,32 @@
1
+ # @sealpixel/plugin-assist
2
+
3
+ Assisted redaction. A detector proposes regions on the proxy, a person accepts
4
+ or rejects them, and acceptance dispatches an ordinary `redact.add`. The
5
+ suggestions live in the UI tool, never in the edit log, so a render never needs
6
+ the model again.
7
+
8
+ The plugin itself declares no operations and does no kernel work; it gives the
9
+ editor a plugin id for the toolbar button and the options. It is not in
10
+ `defaultPlugins`: a host registers it, installs the tool from `@sealpixel/ui`
11
+ (`createAssistTool`) and supplies a detector — its own, or the one from the
12
+ `/plates` entry of this package:
13
+
14
+ ```ts
15
+ import { createAssistTool, defaultPlugins } from '@sealpixel/element';
16
+ import { assistPlugin } from '@sealpixel/plugins';
17
+ import { createPlateDetector } from '@sealpixel/plugin-assist/plates';
18
+
19
+ editor.plugins = [...defaultPlugins, assistPlugin];
20
+ editor.tools = { assist: createAssistTool(createPlateDetector()) };
21
+ editor.pluginOptions = {
22
+ assist: { model: { url: '/models/plate.onnx', sha256: '…' }, wasmPaths: '/ort/' },
23
+ };
24
+ ```
25
+
26
+ `/plates` runs onnxruntime-web in a worker and imports it on the first
27
+ detection. `onnxruntime-web` is an optional peer dependency: install it and
28
+ serve its `.wasm` files and your model yourself. The SDK ships no weights.
29
+
30
+ Options: `run`, `timeoutMs`, `classes`, `minScore`, `maxSuggestions`, `model`,
31
+ `wasmPaths`, `padding`, `mode`, `amount`, `acceptAbove`, `badge`, `showScore`,
32
+ `adjust`, `bulk`. See the guide at docs.sealpixel.dev for the full contract.
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Assisted redaction.
3
+ *
4
+ * A detector proposes regions on the proxy; a person accepts or rejects them;
5
+ * acceptance dispatches an ordinary `redact.add`. The suggestions live in the
6
+ * UI tool, never in the edit log: the log holds decisions, not guesses, and a
7
+ * render must never need the model again. This plugin therefore declares no
8
+ * operations and does no kernel work. It exists so the editor has a plugin id
9
+ * to hang a toolbar button and options on.
10
+ *
11
+ * Nothing here knows about a model. `@sealpixel/plugin-assist/plates` ships a
12
+ * licence-plate detector on top of onnxruntime-web, loaded only when asked.
13
+ */
14
+ import type { Rect, RgbaBuffer } from '@sealpixel/core';
15
+ import { z } from 'zod';
16
+ /** One proposed region, in `image` space: 0..1 over the source. */
17
+ export interface Detection {
18
+ rect: Rect;
19
+ /** 0..1, higher is more confident. */
20
+ score: number;
21
+ /** What the detector thinks it found, for the UI only. */
22
+ label: string;
23
+ }
24
+ /**
25
+ * What a host injects. `image` is the unedited proxy (RGBA8, straight alpha).
26
+ * `options` are the resolved plugin options, so a detector can read its model
27
+ * location from the same JSON the host configured.
28
+ */
29
+ export interface Detector {
30
+ detect(image: RgbaBuffer, ctx: {
31
+ signal: AbortSignal;
32
+ options: AssistOptions;
33
+ }): Promise<Detection[]>;
34
+ }
35
+ /** When the detector runs: on selecting the tool, right after an image loads, or only on request. */
36
+ export type AssistRun = 'select' | 'load' | 'manual';
37
+ export interface AssistOptions {
38
+ /** When the detector runs. `load` fetches runtime and model at load time. */
39
+ run: AssistRun;
40
+ /** A detection that takes longer fails with a message instead of waiting forever. */
41
+ timeoutMs: number;
42
+ /** Labels to ask for and keep; empty means everything the detector offers. */
43
+ classes: string[];
44
+ /**
45
+ * Proposals below this score are dropped. The default sits between the
46
+ * lowest true plate (0.72) and the highest false positive (0.59) of the
47
+ * measured set; a host with a different detector sets its own.
48
+ */
49
+ minScore: number;
50
+ /** At most this many proposals, best first. */
51
+ maxSuggestions: number;
52
+ /** Where the detector fetches its model, pinned by sha256; `inputSize` picks the export. */
53
+ model: {
54
+ url: string;
55
+ sha256: string;
56
+ inputSize?: number | undefined;
57
+ } | null;
58
+ /** Directory the ML runtime loads its WebAssembly from, with a trailing slash. */
59
+ wasmPaths: string | null;
60
+ /** Grown around each proposed rect before it becomes a redaction, in image units. */
61
+ padding: number;
62
+ /** Mode of an accepted proposal; null takes the redact plugin's default. */
63
+ mode: 'pixelate' | 'blur' | null;
64
+ /** Amount of an accepted proposal in source px; null takes the redact plugin's default. */
65
+ amount: number | null;
66
+ /** Proposals at or above this score are accepted without review; null keeps every decision human. */
67
+ acceptAbove: number | null;
68
+ /** Count of open proposals on the toolbar button. */
69
+ badge: boolean;
70
+ /** Score chip on each proposed box. */
71
+ showScore: boolean;
72
+ /** Proposals can be moved before they are accepted. */
73
+ adjust: boolean;
74
+ /** "Accept all" and "Reject all" in the panel. */
75
+ bulk: boolean;
76
+ }
77
+ export declare const AssistOptionsSchema: z.ZodObject<{
78
+ run: z.ZodEnum<{
79
+ select: "select";
80
+ load: "load";
81
+ manual: "manual";
82
+ }>;
83
+ timeoutMs: z.ZodNumber;
84
+ classes: z.ZodArray<z.ZodString>;
85
+ minScore: z.ZodNumber;
86
+ maxSuggestions: z.ZodNumber;
87
+ model: z.ZodNullable<z.ZodObject<{
88
+ url: z.ZodString;
89
+ sha256: z.ZodString;
90
+ inputSize: z.ZodOptional<z.ZodNumber>;
91
+ }, z.core.$strict>>;
92
+ wasmPaths: z.ZodNullable<z.ZodString>;
93
+ padding: z.ZodNumber;
94
+ mode: z.ZodNullable<z.ZodEnum<{
95
+ pixelate: "pixelate";
96
+ blur: "blur";
97
+ }>>;
98
+ amount: z.ZodNullable<z.ZodNumber>;
99
+ acceptAbove: z.ZodNullable<z.ZodNumber>;
100
+ badge: z.ZodBoolean;
101
+ showScore: z.ZodBoolean;
102
+ adjust: z.ZodBoolean;
103
+ bulk: z.ZodBoolean;
104
+ }, z.core.$strict>;
105
+ export declare const ASSIST_DEFAULT_OPTIONS: AssistOptions;
106
+ export type AssistDoc = Record<string, never>;
107
+ declare module '@sealpixel/core' {
108
+ interface DocumentRegistry {
109
+ assist: AssistDoc;
110
+ }
111
+ }
112
+ /** Grows a rect by `padding` on every side and clamps it to the image. */
113
+ export declare function padRect(rect: Rect, padding: number): Rect;
114
+ /**
115
+ * Keeps what passes the options: the wanted classes (all, when `classes` is
116
+ * empty), at or above `minScore`, best first, at most `maxSuggestions`.
117
+ */
118
+ export declare function filterDetections(list: readonly Detection[], options: Pick<AssistOptions, 'minScore' | 'classes' | 'maxSuggestions'>): Detection[];
119
+ /** The redact options an accepted suggestion takes its mode and amount from. */
120
+ export interface RedactDefaults {
121
+ defaultMode: 'pixelate' | 'blur';
122
+ defaultAmount: number;
123
+ }
124
+ /**
125
+ * The operation an accepted suggestion becomes. Exactly the fields a
126
+ * hand-drawn rectangle carries — nothing about a model, a score or a label —
127
+ * so the log cannot tell the two apart.
128
+ */
129
+ export declare function toRedactAdd(rect: Rect, redact: RedactDefaults, id: string, override?: Pick<AssistOptions, 'mode' | 'amount'>): {
130
+ type: 'redact.add';
131
+ id: string;
132
+ region: {
133
+ kind: 'rect';
134
+ rect: Rect;
135
+ };
136
+ mode: 'pixelate' | 'blur';
137
+ amount: number;
138
+ };
139
+ /** Smallest side a region keeps; the redact schema requires `> 0`. */
140
+ export declare const MIN_SIDE = 0.002;
141
+ export declare const assistPlugin: import("@sealpixel/plugin-sdk").ConfigurablePlugin<"assist", AssistDoc, AssistOptions>;
142
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,117 @@
1
+ import { definePlugin } from '@sealpixel/plugin-sdk';
2
+ import { z } from 'zod';
3
+ const score = z.number().min(0).max(1);
4
+ export const AssistOptionsSchema = z
5
+ .object({
6
+ run: z.enum(['select', 'load', 'manual']),
7
+ timeoutMs: z.number().int().positive(),
8
+ classes: z.array(z.string().min(1)),
9
+ minScore: score,
10
+ maxSuggestions: z.number().int().positive(),
11
+ model: z
12
+ .object({
13
+ url: z.string().min(1),
14
+ sha256: z.string().regex(/^[0-9a-f]{64}$/),
15
+ inputSize: z.number().int().positive().optional(),
16
+ })
17
+ .strict()
18
+ .nullable(),
19
+ wasmPaths: z.string().endsWith('/').nullable(),
20
+ padding: z.number().min(0).max(0.5),
21
+ mode: z.enum(['pixelate', 'blur']).nullable(),
22
+ amount: z.number().gt(0).max(4096).nullable(),
23
+ acceptAbove: score.nullable(),
24
+ badge: z.boolean(),
25
+ showScore: z.boolean(),
26
+ adjust: z.boolean(),
27
+ bulk: z.boolean(),
28
+ })
29
+ .strict();
30
+ export const ASSIST_DEFAULT_OPTIONS = {
31
+ run: 'select',
32
+ timeoutMs: 20_000,
33
+ classes: [],
34
+ minScore: 0.6,
35
+ maxSuggestions: 50,
36
+ model: null,
37
+ wasmPaths: null,
38
+ padding: 0.02,
39
+ mode: null,
40
+ amount: null,
41
+ acceptAbove: null,
42
+ badge: true,
43
+ showScore: true,
44
+ adjust: true,
45
+ bulk: true,
46
+ };
47
+ /** Grows a rect by `padding` on every side and clamps it to the image. */
48
+ export function padRect(rect, padding) {
49
+ const x = clamp01(rect.x - padding);
50
+ const y = clamp01(rect.y - padding);
51
+ const right = clamp01(rect.x + rect.width + padding);
52
+ const bottom = clamp01(rect.y + rect.height + padding);
53
+ return { x, y, width: Math.max(right - x, MIN_SIDE), height: Math.max(bottom - y, MIN_SIDE) };
54
+ }
55
+ /**
56
+ * Keeps what passes the options: the wanted classes (all, when `classes` is
57
+ * empty), at or above `minScore`, best first, at most `maxSuggestions`.
58
+ */
59
+ export function filterDetections(list, options) {
60
+ return list
61
+ .filter((d) => d.score >= options.minScore)
62
+ .filter((d) => options.classes.length === 0 || options.classes.includes(d.label))
63
+ .sort((a, b) => b.score - a.score)
64
+ .slice(0, options.maxSuggestions);
65
+ }
66
+ /**
67
+ * The operation an accepted suggestion becomes. Exactly the fields a
68
+ * hand-drawn rectangle carries — nothing about a model, a score or a label —
69
+ * so the log cannot tell the two apart.
70
+ */
71
+ export function toRedactAdd(rect, redact, id, override = { mode: null, amount: null }) {
72
+ return {
73
+ type: 'redact.add',
74
+ id,
75
+ region: { kind: 'rect', rect },
76
+ mode: override.mode ?? redact.defaultMode,
77
+ amount: override.amount ?? redact.defaultAmount,
78
+ };
79
+ }
80
+ /** Smallest side a region keeps; the redact schema requires `> 0`. */
81
+ export const MIN_SIDE = 0.002;
82
+ function clamp01(v) {
83
+ return v < 0 ? 0 : v > 1 ? 1 : v;
84
+ }
85
+ export const assistPlugin = definePlugin({
86
+ id: 'assist',
87
+ version: 1,
88
+ operations: [],
89
+ initialDocument: {},
90
+ // Before redact, where the accepted regions land. Never planned: `toPlan`
91
+ // returns null, so no stage exists and the kernel never runs.
92
+ stage: { name: 'assist', order: 190 },
93
+ toPlan: () => null,
94
+ kernel: { kind: 'js', run: (image) => image },
95
+ options: {
96
+ schema: AssistOptionsSchema,
97
+ defaults: ASSIST_DEFAULT_OPTIONS,
98
+ describe: {
99
+ run: 'When the detector runs: select (the tool is chosen), load (right after an image loads; fetches runtime and model then), manual (only on request).',
100
+ timeoutMs: 'A detection that takes longer fails with a message instead of waiting forever.',
101
+ classes: 'Labels to ask for and keep; empty means everything the detector offers.',
102
+ minScore: 'Proposals below this score are dropped (0..1).',
103
+ maxSuggestions: 'At most this many proposals, best first.',
104
+ model: 'Where the detector fetches its model: { url, sha256, inputSize? }. The SDK ships no weights.',
105
+ wasmPaths: 'Directory the ML runtime loads its WebAssembly from, with a trailing slash.',
106
+ padding: 'Grown around each proposed rect before it becomes a redaction, in image units.',
107
+ mode: 'Mode of an accepted proposal; null takes the redact default.',
108
+ amount: 'Amount of an accepted proposal in source px; null takes the redact default.',
109
+ acceptAbove: 'Proposals at or above this score are accepted without review; null keeps every decision human.',
110
+ badge: 'Count of open proposals on the toolbar button.',
111
+ showScore: 'Score chip on each proposed box.',
112
+ adjust: 'Proposals can be moved before they are accepted.',
113
+ bulk: '"Accept all" and "Reject all" in the panel.',
114
+ },
115
+ },
116
+ });
117
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * The part of the plate detector that touches onnxruntime-web. It runs inside
3
+ * the worker, or on the calling thread where workers do not exist. Nothing in
4
+ * here imports the runtime statically: `loader` brings it in on first use, so
5
+ * a bundle that never calls `detect` never contains it.
6
+ */
7
+ import type { RgbaBuffer } from '@sealpixel/core';
8
+ import type { Detection } from '../index.js';
9
+ import { letterboxGeometry } from './letterbox.js';
10
+ export interface EngineConfig {
11
+ modelUrl: string;
12
+ /** Lower-case hex sha256 the fetched model must match. */
13
+ modelSha256: string;
14
+ /** Absolute URL of the directory holding the runtime's .wasm and .mjs files. */
15
+ wasmPaths: string;
16
+ /** Model input side length in pixels; the model file decides, the host states it. */
17
+ inputSize: number;
18
+ }
19
+ /** Errors this module raises, by `name`. Hosts match on the name, not the text. */
20
+ export type PlateErrorName = 'DETECTOR_UNAVAILABLE' | 'MODEL_UNAVAILABLE' | 'MODEL_MISMATCH';
21
+ export declare class PlateError extends Error {
22
+ readonly name: PlateErrorName;
23
+ constructor(name: PlateErrorName, message: string);
24
+ }
25
+ /** The slice of onnxruntime-web this engine uses; the package's own types stay out of the public .d.ts. */
26
+ export interface OrtLike {
27
+ env: {
28
+ wasm: {
29
+ wasmPaths: string;
30
+ numThreads: number;
31
+ };
32
+ };
33
+ Tensor: new (type: 'float32', data: Float32Array, dims: number[]) => TensorLike;
34
+ InferenceSession: {
35
+ create: (model: Uint8Array, options: {
36
+ executionProviders: string[];
37
+ }) => Promise<SessionLike>;
38
+ };
39
+ }
40
+ export interface TensorLike {
41
+ data: Float32Array | Int32Array | BigInt64Array;
42
+ dims: readonly number[];
43
+ }
44
+ export interface SessionLike {
45
+ inputNames: readonly string[];
46
+ outputNames: readonly string[];
47
+ run: (feeds: Record<string, TensorLike>) => Promise<Record<string, TensorLike>>;
48
+ }
49
+ export type OrtLoader = () => Promise<unknown>;
50
+ /** Loads the WASM build of onnxruntime-web; the host may substitute another. */
51
+ export declare const defaultLoader: OrtLoader;
52
+ export declare class PlateEngine {
53
+ private readonly config;
54
+ private readonly loader;
55
+ private ort;
56
+ private session;
57
+ private ready;
58
+ constructor(config: EngineConfig, loader?: OrtLoader);
59
+ /** Imports the runtime, fetches and verifies the model, creates the session. Once. */
60
+ init(): Promise<void>;
61
+ private load;
62
+ detect(image: RgbaBuffer, signal?: AbortSignal): Promise<Detection[]>;
63
+ }
64
+ /**
65
+ * The end2end export emits rows of `batch, x1, y1, x2, y2, class, score`
66
+ * (seven columns) or the same without the batch column, in input pixels.
67
+ */
68
+ export declare function decode(tensor: TensorLike, geometry: ReturnType<typeof letterboxGeometry>, width: number, height: number): Detection[];
69
+ //# sourceMappingURL=engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/plates/engine.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAQ,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAqC,MAAM,gBAAgB,CAAC;AAEtF,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,0DAA0D;IAC1D,WAAW,EAAE,MAAM,CAAC;IACpB,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAC;IAClB,qFAAqF;IACrF,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,mFAAmF;AACnF,MAAM,MAAM,cAAc,GAAG,sBAAsB,GAAG,mBAAmB,GAAG,gBAAgB,CAAC;AAE7F,qBAAa,UAAW,SAAQ,KAAK;IACnC,SAAkB,IAAI,EAAE,cAAc,CAAC;gBAC3B,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM;CAIlD;AAED,2GAA2G;AAC3G,MAAM,WAAW,OAAO;IACtB,GAAG,EAAE;QAAE,IAAI,EAAE;YAAE,SAAS,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;IACzD,MAAM,EAAE,KAAK,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,UAAU,CAAC;IAChF,gBAAgB,EAAE;QAChB,MAAM,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE;YAAE,kBAAkB,EAAE,MAAM,EAAE,CAAA;SAAE,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;KAChG,CAAC;CACH;AACD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,YAAY,GAAG,UAAU,GAAG,aAAa,CAAC;IAChD,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;CACzB;AACD,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/B,GAAG,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;CACjF;AAED,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;AAE/C,gFAAgF;AAChF,eAAO,MAAM,aAAa,EAAE,SAAgD,CAAC;AAE7E,qBAAa,WAAW;IAMpB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IANzB,OAAO,CAAC,GAAG,CAAwB;IACnC,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,KAAK,CAA8B;gBAGxB,MAAM,EAAE,YAAY,EACpB,MAAM,GAAE,SAAyB;IAGpD,sFAAsF;IACtF,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YASP,IAAI;IAoCZ,MAAM,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;CAsB5E;AAwBD;;;GAGG;AACH,wBAAgB,MAAM,CACpB,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,UAAU,CAAC,OAAO,iBAAiB,CAAC,EAC9C,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,SAAS,EAAE,CAwBb"}
@@ -0,0 +1,130 @@
1
+ import { letterboxGeometry, PAD_GREY, rgbaToNchw, unletterbox } from './letterbox.js';
2
+ export class PlateError extends Error {
3
+ name;
4
+ constructor(name, message) {
5
+ super(message);
6
+ this.name = name;
7
+ }
8
+ }
9
+ /** Loads the WASM build of onnxruntime-web; the host may substitute another. */
10
+ export const defaultLoader = () => import('onnxruntime-web/wasm');
11
+ export class PlateEngine {
12
+ config;
13
+ loader;
14
+ ort = null;
15
+ session = null;
16
+ ready = null;
17
+ constructor(config, loader = defaultLoader) {
18
+ this.config = config;
19
+ this.loader = loader;
20
+ }
21
+ /** Imports the runtime, fetches and verifies the model, creates the session. Once. */
22
+ init() {
23
+ this.ready ??= this.load().catch((error) => {
24
+ // A failed init must not stick: the next call tries again.
25
+ this.ready = null;
26
+ throw error;
27
+ });
28
+ return this.ready;
29
+ }
30
+ async load() {
31
+ let ort;
32
+ try {
33
+ ort = (await this.loader());
34
+ }
35
+ catch (error) {
36
+ throw new PlateError('DETECTOR_UNAVAILABLE', `onnxruntime-web is not installed or failed to load: ${error.message}`);
37
+ }
38
+ ort.env.wasm.wasmPaths = this.config.wasmPaths;
39
+ // One thread: multi-threading needs cross-origin isolation, which few hosts have.
40
+ ort.env.wasm.numThreads = 1;
41
+ let bytes;
42
+ try {
43
+ const res = await fetch(this.config.modelUrl);
44
+ if (!res.ok)
45
+ throw new Error(`${res.status} ${res.statusText}`);
46
+ bytes = new Uint8Array(await res.arrayBuffer());
47
+ }
48
+ catch (error) {
49
+ throw new PlateError('MODEL_UNAVAILABLE', `could not fetch the model from ${this.config.modelUrl}: ${error.message}`);
50
+ }
51
+ const digest = await sha256Hex(bytes);
52
+ if (digest !== this.config.modelSha256) {
53
+ throw new PlateError('MODEL_MISMATCH', `the model at ${this.config.modelUrl} hashes to ${digest}, not the pinned ${this.config.modelSha256}`);
54
+ }
55
+ this.session = await ort.InferenceSession.create(bytes, { executionProviders: ['wasm'] });
56
+ this.ort = ort;
57
+ }
58
+ async detect(image, signal) {
59
+ await this.init();
60
+ const ort = this.ort;
61
+ const session = this.session;
62
+ if (!ort || !session)
63
+ throw new PlateError('DETECTOR_UNAVAILABLE', 'engine did not initialise');
64
+ signal?.throwIfAborted();
65
+ const size = this.config.inputSize;
66
+ const geometry = letterboxGeometry(image.width, image.height, size);
67
+ const input = rgbaToNchw(await letterbox(image, geometry), size);
68
+ signal?.throwIfAborted();
69
+ const inputName = session.inputNames[0];
70
+ const outputName = session.outputNames[0];
71
+ const out = await session.run({
72
+ [inputName]: new ort.Tensor('float32', input, [1, 3, size, size]),
73
+ });
74
+ const tensor = out[outputName];
75
+ if (!tensor)
76
+ throw new PlateError('DETECTOR_UNAVAILABLE', `model has no output "${outputName}"`);
77
+ return decode(tensor, geometry, image.width, image.height);
78
+ }
79
+ }
80
+ /**
81
+ * Draws the image letterboxed onto a square canvas of the model's input size.
82
+ * Uses `OffscreenCanvas`, which exists in workers and on the main thread.
83
+ */
84
+ async function letterbox(image, geometry) {
85
+ const { size } = geometry;
86
+ const canvas = new OffscreenCanvas(size, size);
87
+ const ctx = canvas.getContext('2d', { willReadFrequently: true });
88
+ if (!ctx)
89
+ throw new PlateError('DETECTOR_UNAVAILABLE', 'no 2d canvas context');
90
+ ctx.fillStyle = `rgb(${PAD_GREY},${PAD_GREY},${PAD_GREY})`;
91
+ ctx.fillRect(0, 0, size, size);
92
+ const pixels = new Uint8ClampedArray(image.data.byteLength);
93
+ pixels.set(image.data);
94
+ const bitmap = await createImageBitmap(new ImageData(pixels, image.width, image.height));
95
+ ctx.drawImage(bitmap, geometry.padX, geometry.padY, geometry.scaledWidth, geometry.scaledHeight);
96
+ bitmap.close();
97
+ return ctx.getImageData(0, 0, size, size).data;
98
+ }
99
+ /**
100
+ * The end2end export emits rows of `batch, x1, y1, x2, y2, class, score`
101
+ * (seven columns) or the same without the batch column, in input pixels.
102
+ */
103
+ export function decode(tensor, geometry, width, height) {
104
+ const cols = tensor.dims[tensor.dims.length - 1] ?? 0;
105
+ const offset = cols === 7 ? 1 : cols === 6 ? 0 : -1;
106
+ if (offset < 0) {
107
+ throw new PlateError('DETECTOR_UNAVAILABLE', `unexpected model output shape ${JSON.stringify(tensor.dims)}`);
108
+ }
109
+ const data = tensor.data;
110
+ const rows = data.length / cols;
111
+ const detections = [];
112
+ for (let r = 0; r < rows; r++) {
113
+ const base = r * cols + offset;
114
+ const box = [
115
+ data[base],
116
+ data[base + 1],
117
+ data[base + 2],
118
+ data[base + 3],
119
+ ];
120
+ const rect = unletterbox(box, geometry, width, height);
121
+ if (rect)
122
+ detections.push({ rect, score: data[base + 5], label: 'plate' });
123
+ }
124
+ return detections;
125
+ }
126
+ async function sha256Hex(bytes) {
127
+ const digest = await crypto.subtle.digest('SHA-256', bytes);
128
+ return [...new Uint8Array(digest)].map((b) => b.toString(16).padStart(2, '0')).join('');
129
+ }
130
+ //# sourceMappingURL=engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/plates/engine.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAetF,MAAM,OAAO,UAAW,SAAQ,KAAK;IACjB,IAAI,CAAiB;IACvC,YAAY,IAAoB,EAAE,OAAe;QAC/C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAsBD,gFAAgF;AAChF,MAAM,CAAC,MAAM,aAAa,GAAc,GAAG,EAAE,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC;AAE7E,MAAM,OAAO,WAAW;IAMH;IACA;IANX,GAAG,GAAmB,IAAI,CAAC;IAC3B,OAAO,GAAuB,IAAI,CAAC;IACnC,KAAK,GAAyB,IAAI,CAAC;IAE3C,YACmB,MAAoB,EACpB,SAAoB,aAAa;QADjC,WAAM,GAAN,MAAM,CAAc;QACpB,WAAM,GAAN,MAAM,CAA2B;IACjD,CAAC;IAEJ,sFAAsF;IACtF,IAAI;QACF,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YACzC,2DAA2D;YAC3D,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;YAClB,MAAM,KAAK,CAAC;QACd,CAAC,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAEO,KAAK,CAAC,IAAI;QAChB,IAAI,GAAY,CAAC;QACjB,IAAI,CAAC;YACH,GAAG,GAAG,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,CAAY,CAAC;QACzC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,UAAU,CAClB,sBAAsB,EACtB,uDAAwD,KAAe,CAAC,OAAO,EAAE,CAClF,CAAC;QACJ,CAAC;QACD,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC;QAC/C,kFAAkF;QAClF,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;QAE5B,IAAI,KAAiB,CAAC;QACtB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC9C,IAAI,CAAC,GAAG,CAAC,EAAE;gBAAE,MAAM,IAAI,KAAK,CAAC,GAAG,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC,CAAC;YAChE,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;QAClD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,UAAU,CAClB,mBAAmB,EACnB,kCAAkC,IAAI,CAAC,MAAM,CAAC,QAAQ,KAAM,KAAe,CAAC,OAAO,EAAE,CACtF,CAAC;QACJ,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,MAAM,KAAK,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;YACvC,MAAM,IAAI,UAAU,CAClB,gBAAgB,EAChB,gBAAgB,IAAI,CAAC,MAAM,CAAC,QAAQ,cAAc,MAAM,oBAAoB,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CACtG,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,MAAM,GAAG,CAAC,gBAAgB,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,kBAAkB,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC1F,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAAiB,EAAE,MAAoB;QAClD,MAAM,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;QACrB,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC7B,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,UAAU,CAAC,sBAAsB,EAAE,2BAA2B,CAAC,CAAC;QAChG,MAAM,EAAE,cAAc,EAAE,CAAC;QAEzB,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC;QACnC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACpE,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,SAAS,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC;QACjE,MAAM,EAAE,cAAc,EAAE,CAAC;QAEzB,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAW,CAAC;QAClD,MAAM,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC,CAAW,CAAC;QACpD,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAC5B,CAAC,SAAS,CAAC,EAAE,IAAI,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;SAClE,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC;QAC/B,IAAI,CAAC,MAAM;YACT,MAAM,IAAI,UAAU,CAAC,sBAAsB,EAAE,wBAAwB,UAAU,GAAG,CAAC,CAAC;QACtF,OAAO,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC7D,CAAC;CACF;AAED;;;GAGG;AACH,KAAK,UAAU,SAAS,CACtB,KAAiB,EACjB,QAA8C;IAE9C,MAAM,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAC;IAC1B,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC/C,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC,CAAC;IAClE,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,UAAU,CAAC,sBAAsB,EAAE,sBAAsB,CAAC,CAAC;IAC/E,GAAG,CAAC,SAAS,GAAG,OAAO,QAAQ,IAAI,QAAQ,IAAI,QAAQ,GAAG,CAAC;IAC3D,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,IAAI,iBAAiB,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC5D,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACvB,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,IAAI,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IACzF,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC;IACjG,MAAM,CAAC,KAAK,EAAE,CAAC;IACf,OAAO,GAAG,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC;AACjD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,MAAM,CACpB,MAAkB,EAClB,QAA8C,EAC9C,KAAa,EACb,MAAc;IAEd,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;IACtD,MAAM,MAAM,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACpD,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;QACf,MAAM,IAAI,UAAU,CAClB,sBAAsB,EACtB,iCAAiC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAC/D,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAoB,CAAC;IACzC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;IAChC,MAAM,UAAU,GAAgB,EAAE,CAAC;IACnC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,CAAC,GAAG,IAAI,GAAG,MAAM,CAAC;QAC/B,MAAM,GAAG,GAAqC;YAC5C,IAAI,CAAC,IAAI,CAAW;YACpB,IAAI,CAAC,IAAI,GAAG,CAAC,CAAW;YACxB,IAAI,CAAC,IAAI,GAAG,CAAC,CAAW;YACxB,IAAI,CAAC,IAAI,GAAG,CAAC,CAAW;SACzB,CAAC;QACF,MAAM,IAAI,GAAgB,WAAW,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;QACpE,IAAI,IAAI;YAAE,UAAU,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,GAAG,CAAC,CAAW,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;IACvF,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,KAAiB;IACxC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,KAAqB,CAAC,CAAC;IAC5E,OAAO,CAAC,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC1F,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { Detector } from '../index.js';
2
+ import { type OrtLoader } from './engine.js';
3
+ export { decode, type EngineConfig, PlateEngine, PlateError, type PlateErrorName, } from './engine.js';
4
+ export { iou, letterboxGeometry, unletterbox } from './letterbox.js';
5
+ export interface PlateDetectorOptions {
6
+ /** Model input side when the options name none; the open-image-models exports are 256, 384 or 512. */
7
+ inputSize?: number;
8
+ /** Run on the calling thread even where workers exist. */
9
+ inline?: boolean;
10
+ /** Replaces the dynamic import of onnxruntime-web, for tests and custom builds. */
11
+ loader?: OrtLoader;
12
+ }
13
+ /**
14
+ * A `Detector` that reads its model location from the assist options at call
15
+ * time. The engine is created once per option set; changing `model` or
16
+ * `wasmPaths` starts a fresh one.
17
+ */
18
+ export declare function createPlateDetector(opts?: PlateDetectorOptions): Detector;
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/plates/index.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAA4B,QAAQ,EAAE,MAAM,aAAa,CAAC;AACtE,OAAO,EAAqB,KAAK,SAAS,EAA2B,MAAM,aAAa,CAAC;AAMzF,OAAO,EACL,MAAM,EACN,KAAK,YAAY,EACjB,WAAW,EACX,UAAU,EACV,KAAK,cAAc,GACpB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,GAAG,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAErE,MAAM,WAAW,oBAAoB;IACnC,sGAAsG;IACtG,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,mFAAmF;IACnF,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,GAAE,oBAAyB,GAAG,QAAQ,CAoB7E"}
@@ -0,0 +1,110 @@
1
+ import { PlateEngine, PlateError } from './engine.js';
2
+ export { decode, PlateEngine, PlateError, } from './engine.js';
3
+ export { iou, letterboxGeometry, unletterbox } from './letterbox.js';
4
+ /**
5
+ * A `Detector` that reads its model location from the assist options at call
6
+ * time. The engine is created once per option set; changing `model` or
7
+ * `wasmPaths` starts a fresh one.
8
+ */
9
+ export function createPlateDetector(opts = {}) {
10
+ const inputSize = opts.inputSize ?? 384;
11
+ let backend = null;
12
+ let backendKey = '';
13
+ return {
14
+ async detect(image, ctx) {
15
+ const config = configFrom(ctx.options, ctx.options.model?.inputSize ?? inputSize);
16
+ const key = JSON.stringify(config);
17
+ if (!backend || backendKey !== key) {
18
+ backend?.dispose();
19
+ backend =
20
+ !opts.inline && typeof Worker !== 'undefined' && !opts.loader
21
+ ? new WorkerBackend(config)
22
+ : new InlineBackend(config, opts.loader);
23
+ backendKey = key;
24
+ }
25
+ return backend.detect(image, ctx.signal);
26
+ },
27
+ };
28
+ }
29
+ function configFrom(options, inputSize) {
30
+ if (!options.model) {
31
+ throw new PlateError('MODEL_UNAVAILABLE', 'assist options carry no model: set model.url and model.sha256');
32
+ }
33
+ if (!options.wasmPaths) {
34
+ throw new PlateError('DETECTOR_UNAVAILABLE', 'assist options carry no wasmPaths for the runtime');
35
+ }
36
+ // Absolute on the main thread: a worker would resolve a relative path against its own script.
37
+ const base = typeof location !== 'undefined' ? location.href : undefined;
38
+ return {
39
+ modelUrl: new URL(options.model.url, base).href,
40
+ modelSha256: options.model.sha256.toLowerCase(),
41
+ wasmPaths: new URL(options.wasmPaths, base).href,
42
+ inputSize,
43
+ };
44
+ }
45
+ class InlineBackend {
46
+ engine;
47
+ constructor(config, loader) {
48
+ this.engine = new PlateEngine(config, loader);
49
+ }
50
+ detect(image, signal) {
51
+ return this.engine.detect(image, signal);
52
+ }
53
+ dispose() { }
54
+ }
55
+ /** Runs the engine in a dedicated worker; an abort rejects the caller and drops the late result. */
56
+ class WorkerBackend {
57
+ worker;
58
+ pending = new Map();
59
+ nextId = 1;
60
+ ready;
61
+ constructor(config) {
62
+ this.worker = new Worker(new URL('./worker.js', import.meta.url), { type: 'module' });
63
+ this.worker.addEventListener('message', (e) => {
64
+ const entry = this.pending.get(e.data.id);
65
+ if (!entry)
66
+ return;
67
+ this.pending.delete(e.data.id);
68
+ if (e.data.ok)
69
+ entry.resolve(e.data.result ?? []);
70
+ else
71
+ entry.reject(rehydrate(e.data.error));
72
+ });
73
+ this.worker.addEventListener('error', (e) => {
74
+ const error = new PlateError('DETECTOR_UNAVAILABLE', e.message || 'detector worker failed');
75
+ for (const entry of this.pending.values())
76
+ entry.reject(error);
77
+ this.pending.clear();
78
+ });
79
+ this.ready = this.call({ type: 'init', config }).then(() => undefined);
80
+ }
81
+ async detect(image, signal) {
82
+ await this.ready;
83
+ signal.throwIfAborted();
84
+ // A copy: the caller keeps its pixels, the worker gets its own.
85
+ const copy = { ...image, data: new Uint8Array(image.data) };
86
+ const result = this.call({ type: 'detect', image: copy }, [copy.data.buffer]);
87
+ return new Promise((resolve, reject) => {
88
+ const onAbort = () => reject(signal.reason ?? new DOMException('aborted', 'AbortError'));
89
+ signal.addEventListener('abort', onAbort, { once: true });
90
+ result.then(resolve, reject).finally(() => signal.removeEventListener('abort', onAbort));
91
+ });
92
+ }
93
+ dispose() {
94
+ this.worker.terminate();
95
+ this.pending.clear();
96
+ }
97
+ call(req, transfer = []) {
98
+ const id = this.nextId++;
99
+ return new Promise((resolve, reject) => {
100
+ this.pending.set(id, { resolve, reject });
101
+ this.worker.postMessage({ ...req, id }, transfer);
102
+ });
103
+ }
104
+ }
105
+ function rehydrate(error) {
106
+ const names = ['DETECTOR_UNAVAILABLE', 'MODEL_UNAVAILABLE', 'MODEL_MISMATCH'];
107
+ const name = names.find((n) => n === error.name);
108
+ return name ? new PlateError(name, error.message) : new Error(error.message);
109
+ }
110
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/plates/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Letterbox geometry for a square model input, and the way back.
3
+ *
4
+ * The proxy is scaled uniformly so its longer side fits `size`, centred on a
5
+ * grey canvas. Boxes come back in input pixels and are mapped to the proxy's
6
+ * normalised `image` space, which is also the redact operation's space.
7
+ */
8
+ import type { Rect } from '@sealpixel/core';
9
+ export interface Letterbox {
10
+ /** Model input side length in pixels. */
11
+ size: number;
12
+ /** Uniform scale from source pixels to input pixels. */
13
+ scale: number;
14
+ /** Scaled image size inside the input. */
15
+ scaledWidth: number;
16
+ scaledHeight: number;
17
+ /** Offset of the scaled image inside the input. */
18
+ padX: number;
19
+ padY: number;
20
+ }
21
+ /** Grey used by YOLO letterboxing, in 0..255. */
22
+ export declare const PAD_GREY = 114;
23
+ export declare function letterboxGeometry(width: number, height: number, size: number): Letterbox;
24
+ /**
25
+ * Converts letterboxed RGBA pixels (`size` × `size`, straight alpha ignored)
26
+ * into a planar float32 NCHW tensor in 0..1, RGB order.
27
+ */
28
+ export declare function rgbaToNchw(rgba: Uint8ClampedArray | Uint8Array, size: number): Float32Array;
29
+ /**
30
+ * Maps an `x1, y1, x2, y2` box in input pixels back to a normalised rect over
31
+ * the source. Returns `null` when the box collapses below the smallest region
32
+ * the redact schema accepts.
33
+ */
34
+ export declare function unletterbox(box: readonly [number, number, number, number], geometry: Letterbox, width: number, height: number): Rect | null;
35
+ /** Smallest normalised side worth proposing; `RectSchema` needs `> 0`. */
36
+ export declare const MIN_SIDE = 0.002;
37
+ /** Intersection over union of two normalised rects. */
38
+ export declare function iou(a: Rect, b: Rect): number;
39
+ //# sourceMappingURL=letterbox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"letterbox.d.ts","sourceRoot":"","sources":["../../src/plates/letterbox.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAE5C,MAAM,WAAW,SAAS;IACxB,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,iDAAiD;AACjD,eAAO,MAAM,QAAQ,MAAM,CAAC;AAE5B,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,CAYxF;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,iBAAiB,GAAG,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,YAAY,CAU3F;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,GAAG,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAC9C,QAAQ,EAAE,SAAS,EACnB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,IAAI,GAAG,IAAI,CASb;AAED,0EAA0E;AAC1E,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAM9B,uDAAuD;AACvD,wBAAgB,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,GAAG,MAAM,CAQ5C"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Letterbox geometry for a square model input, and the way back.
3
+ *
4
+ * The proxy is scaled uniformly so its longer side fits `size`, centred on a
5
+ * grey canvas. Boxes come back in input pixels and are mapped to the proxy's
6
+ * normalised `image` space, which is also the redact operation's space.
7
+ */
8
+ /** Grey used by YOLO letterboxing, in 0..255. */
9
+ export const PAD_GREY = 114;
10
+ export function letterboxGeometry(width, height, size) {
11
+ const scale = Math.min(size / width, size / height);
12
+ const scaledWidth = Math.round(width * scale);
13
+ const scaledHeight = Math.round(height * scale);
14
+ return {
15
+ size,
16
+ scale,
17
+ scaledWidth,
18
+ scaledHeight,
19
+ padX: Math.floor((size - scaledWidth) / 2),
20
+ padY: Math.floor((size - scaledHeight) / 2),
21
+ };
22
+ }
23
+ /**
24
+ * Converts letterboxed RGBA pixels (`size` × `size`, straight alpha ignored)
25
+ * into a planar float32 NCHW tensor in 0..1, RGB order.
26
+ */
27
+ export function rgbaToNchw(rgba, size) {
28
+ const plane = size * size;
29
+ const out = new Float32Array(3 * plane);
30
+ for (let i = 0; i < plane; i++) {
31
+ const o = i * 4;
32
+ out[i] = rgba[o] / 255;
33
+ out[plane + i] = rgba[o + 1] / 255;
34
+ out[2 * plane + i] = rgba[o + 2] / 255;
35
+ }
36
+ return out;
37
+ }
38
+ /**
39
+ * Maps an `x1, y1, x2, y2` box in input pixels back to a normalised rect over
40
+ * the source. Returns `null` when the box collapses below the smallest region
41
+ * the redact schema accepts.
42
+ */
43
+ export function unletterbox(box, geometry, width, height) {
44
+ const [x1, y1, x2, y2] = box;
45
+ const left = clamp01((x1 - geometry.padX) / geometry.scale / width);
46
+ const top = clamp01((y1 - geometry.padY) / geometry.scale / height);
47
+ const right = clamp01((x2 - geometry.padX) / geometry.scale / width);
48
+ const bottom = clamp01((y2 - geometry.padY) / geometry.scale / height);
49
+ const rect = { x: left, y: top, width: right - left, height: bottom - top };
50
+ if (rect.width <= MIN_SIDE || rect.height <= MIN_SIDE)
51
+ return null;
52
+ return rect;
53
+ }
54
+ /** Smallest normalised side worth proposing; `RectSchema` needs `> 0`. */
55
+ export const MIN_SIDE = 0.002;
56
+ function clamp01(v) {
57
+ return v < 0 ? 0 : v > 1 ? 1 : v;
58
+ }
59
+ /** Intersection over union of two normalised rects. */
60
+ export function iou(a, b) {
61
+ const x1 = Math.max(a.x, b.x);
62
+ const y1 = Math.max(a.y, b.y);
63
+ const x2 = Math.min(a.x + a.width, b.x + b.width);
64
+ const y2 = Math.min(a.y + a.height, b.y + b.height);
65
+ const inter = Math.max(0, x2 - x1) * Math.max(0, y2 - y1);
66
+ const union = a.width * a.height + b.width * b.height - inter;
67
+ return union > 0 ? inter / union : 0;
68
+ }
69
+ //# sourceMappingURL=letterbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"letterbox.js","sourceRoot":"","sources":["../../src/plates/letterbox.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Worker entry for the plate detector: one engine per worker, requests
3
+ * correlated by id, pixels handed over as transferables.
4
+ */
5
+ import type { RgbaBuffer } from '@sealpixel/core';
6
+ import type { Detection } from '../index.js';
7
+ import { type EngineConfig } from './engine.js';
8
+ export type WorkerRequest = {
9
+ id: number;
10
+ type: 'init';
11
+ config: EngineConfig;
12
+ } | {
13
+ id: number;
14
+ type: 'detect';
15
+ image: RgbaBuffer;
16
+ };
17
+ export type WorkerResponse = {
18
+ id: number;
19
+ ok: true;
20
+ result: Detection[] | null;
21
+ } | {
22
+ id: number;
23
+ ok: false;
24
+ error: {
25
+ name: string;
26
+ message: string;
27
+ };
28
+ };
29
+ //# sourceMappingURL=worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/plates/worker.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,KAAK,YAAY,EAAe,MAAM,aAAa,CAAC;AAE7D,MAAM,MAAM,aAAa,GACrB;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,YAAY,CAAA;CAAE,GAClD;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,CAAC;AACtD,MAAM,MAAM,cAAc,GACtB;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI,CAAA;CAAE,GACpD;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC"}
@@ -0,0 +1,29 @@
1
+ import { PlateEngine } from './engine.js';
2
+ let engine = null;
3
+ self.addEventListener('message', async (event) => {
4
+ const req = event.data;
5
+ try {
6
+ let result = null;
7
+ if (req.type === 'init') {
8
+ engine = new PlateEngine(req.config);
9
+ await engine.init();
10
+ }
11
+ else {
12
+ if (!engine)
13
+ throw new Error('detect before init');
14
+ result = await engine.detect(req.image);
15
+ }
16
+ const response = { id: req.id, ok: true, result };
17
+ self.postMessage(response);
18
+ }
19
+ catch (error) {
20
+ const e = error;
21
+ const response = {
22
+ id: req.id,
23
+ ok: false,
24
+ error: { name: e.name, message: e.message },
25
+ };
26
+ self.postMessage(response);
27
+ }
28
+ });
29
+ //# sourceMappingURL=worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.js","sourceRoot":"","sources":["../../src/plates/worker.ts"],"names":[],"mappings":"AAMA,OAAO,EAAqB,WAAW,EAAE,MAAM,aAAa,CAAC;AAS7D,IAAI,MAAM,GAAuB,IAAI,CAAC;AAEtC,IAAI,CAAC,gBAAgB,CAAC,SAAS,EAAE,KAAK,EAAE,KAAkC,EAAE,EAAE;IAC5E,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC;IACvB,IAAI,CAAC;QACH,IAAI,MAAM,GAAuB,IAAI,CAAC;QACtC,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACxB,MAAM,GAAG,IAAI,WAAW,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YACrC,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QACtB,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,MAAM;gBAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;YACnD,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC1C,CAAC;QACD,MAAM,QAAQ,GAAmB,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QAClE,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC7B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,GAAG,KAAc,CAAC;QACzB,MAAM,QAAQ,GAAmB;YAC/B,EAAE,EAAE,GAAG,CAAC,EAAE;YACV,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE;SAC5C,CAAC;QACF,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC7B,CAAC;AACH,CAAC,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@sealpixel/plugin-assist",
3
+ "version": "1.0.0-rc.8",
4
+ "description": "Assisted redaction: a detector proposes regions on the proxy, the user accepts or rejects, acceptance dispatches a plain redact.add. No operations, no kernel work; the ML runtime loads only from the /plates entry, and only on demand.",
5
+ "license": "BUSL-1.1",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/9feet/sealpixel.git",
9
+ "directory": "packages/plugins/assist"
10
+ },
11
+ "homepage": "https://docs.sealpixel.dev",
12
+ "bugs": "https://github.com/9feet/sealpixel/issues",
13
+ "type": "module",
14
+ "sideEffects": false,
15
+ "files": [
16
+ "dist",
17
+ "README.md"
18
+ ],
19
+ "keywords": [
20
+ "sealpixel-plugin"
21
+ ],
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "default": "./dist/index.js"
26
+ },
27
+ "./plates": {
28
+ "types": "./dist/plates/index.d.ts",
29
+ "default": "./dist/plates/index.js"
30
+ },
31
+ "./package.json": "./package.json"
32
+ },
33
+ "dependencies": {
34
+ "@sealpixel/plugin-sdk": "1.0.0-rc.7"
35
+ },
36
+ "peerDependencies": {
37
+ "@sealpixel/core": "1.0.0-rc.7",
38
+ "onnxruntime-web": "^1.27.0",
39
+ "zod": "^4.0.0"
40
+ },
41
+ "peerDependenciesMeta": {
42
+ "onnxruntime-web": {
43
+ "optional": true
44
+ }
45
+ },
46
+ "devDependencies": {
47
+ "@sealpixel/config": "0.0.0",
48
+ "@sealpixel/core": "1.0.0-rc.7",
49
+ "@sealpixel/plugin-redact": "1.0.0-rc.7",
50
+ "@types/node": "^24.0.0",
51
+ "onnxruntime-web": "1.27.0",
52
+ "typescript": "^6.0.0",
53
+ "vitest": "^5.0.0",
54
+ "zod": "^4.0.0"
55
+ },
56
+ "scripts": {
57
+ "build": "tsc -p tsconfig.build.json",
58
+ "typecheck": "tsc -p tsconfig.json --noEmit",
59
+ "test": "vitest run"
60
+ }
61
+ }