@annotorious/plugin-segment-anything 0.2.1 → 0.2.3

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/README.md CHANGED
@@ -1,5 +1,58 @@
1
- # plugin-segment-anything
1
+ # Annotorious SegmentAnything Plugin
2
2
 
3
3
  A fully browser-based smart polygon selection tool for Annotorious based on the [sam2-hiera-tiny](https://huggingface.co/g-ronimo/sam2-tiny) SegmentAnything model. The basic approach is inspired by this [blog post](https://medium.com/@geronimo7/in-browser-image-segmentation-with-segment-anything-model-2-c72680170d92) and [demo code](https://github.com/geronimi73/next-sam).
4
4
 
5
+ ![Demo](/screenshot.gif "Demo screenshot")
6
+
7
+ > **Important:** this plugin only supports `@annotorious/openseadragon` at this time. Support for
8
+ > plain (JPEG, PNG,...) images is not yet implemented. [Get in touch via the forum](https://github.com/orgs/annotorious/discussions) if you are interested in
9
+ > using this with the `@annotorious/annotorious` or `@annotorious/react` packages.
10
+
11
+ ## Using with OpenSeadragon
12
+
13
+ ```
14
+ npm install @annotorious/plugin-segment-anything
15
+ ```
16
+
17
+ ```ts
18
+ import OpenSeadragon from 'openseadragon';
19
+ import { createOSDAnnotator } from '@annotorious/openseadragon';
20
+ import { mountOpenSeadragonPlugin } from '@annotorious/plugin-segment-anything/openseadragon';
21
+
22
+ import '@annotorious/openseadragon/annotorious-openseadragon.css';
23
+
24
+ const viewer = OpenSeadragon({
25
+ /** init your viewer **/
26
+ });
27
+
28
+ const anno = createOSDAnnotator(viewer, { /* options */ });
29
+
30
+ // Initialize the plugin
31
+ const plugin = mountOpenSeadragonPlugin(anno);
32
+
33
+ // This will start initializing the plugin, incl.
34
+ // download of the model (this may take a while).
35
+ plugin.init();
36
+
37
+ plugin.on('downloadStart', () => {
38
+ console.log('downloading the model - this may take a while');
39
+ });
40
+
41
+ plugin.on('downloadProgress', progress => {
42
+ if (progress.complete)
43
+ console.log('downloading complete');
44
+ });
45
+
46
+ plugin.on('initialized', () => {
47
+ console.log('plugin ready');
48
+ });
49
+
50
+ plugin.on('encodingStart', () => {
51
+ console.log('busy - encoding viewport');
52
+ });
53
+
54
+ plugin.on('encodingFinished', () => {
55
+ console.log('ready - click to create annotation!');
56
+ });
57
+ ```
5
58
 
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { m as R, c as r, a as k, M as C, j as T, g as H, W, b as O, v as V } from "./get-image-bounds-sysVJFVF.js";
1
+ import { m as I, c as r, a as k, M as C, j as T, g as H, W, b as O, v as V } from "./get-image-bounds-sysVJFVF.js";
2
2
  const L = (n, a, d = {}) => {
3
3
  if (!Number.isFinite(a))
4
4
  throw new TypeError("Expected `wait` to be a finite number");
@@ -29,7 +29,7 @@ L.promise = (n) => {
29
29
  };
30
30
  };
31
31
  const z = (n, a, d) => {
32
- const { canvas: t } = R(
32
+ const { canvas: t } = I(
33
33
  n,
34
34
  a,
35
35
  [255, 255, 255, 255],
@@ -111,7 +111,7 @@ const z = (n, a, d) => {
111
111
  renderMask: (o) => {
112
112
  var l;
113
113
  if (!t) return;
114
- const { canvas: i } = R(
114
+ const { canvas: i } = I(
115
115
  o,
116
116
  a,
117
117
  [0, 114, 189, 255],
@@ -142,8 +142,8 @@ const z = (n, a, d) => {
142
142
  }, 1);
143
143
  return N(o).then(({ canvas: p, bounds: w, scale: E }) => {
144
144
  const h = (f) => {
145
- const m = o.naturalWidth / (E * o.offsetWidth), g = o.naturalHeight / (E * o.offsetHeight), { offsetX: b, offsetY: M } = f, _ = b * m + w.x, I = M * g + w.y;
146
- return { x: _, y: I };
145
+ const m = o.naturalWidth / (E * o.offsetWidth), g = o.naturalHeight / (E * o.offsetHeight), { offsetX: b, offsetY: M } = f, _ = b * m + w.x, R = M * g + w.y;
146
+ return { x: _, y: R };
147
147
  };
148
148
  l = (f) => {
149
149
  if (s.include.length + s.exclude.length > 0) return;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../node_modules/p-debounce/index.js","../src/utils/mask-to-polygon.ts","../src/utils/prepare-sam2-canvas.ts","../src/input-marker-canvas.ts","../src/preview-canvas.ts","../src/index.ts"],"sourcesContent":["const pDebounce = (fn, wait, options = {}) => {\n\tif (!Number.isFinite(wait)) {\n\t\tthrow new TypeError('Expected `wait` to be a finite number');\n\t}\n\n\tlet leadingValue;\n\tlet timeout;\n\tlet resolveList = [];\n\n\treturn function (...arguments_) {\n\t\treturn new Promise(resolve => {\n\t\t\tconst shouldCallNow = options.before && !timeout;\n\n\t\t\tclearTimeout(timeout);\n\n\t\t\ttimeout = setTimeout(() => {\n\t\t\t\ttimeout = null;\n\n\t\t\t\tconst result = options.before ? leadingValue : fn.apply(this, arguments_);\n\n\t\t\t\tfor (resolve of resolveList) {\n\t\t\t\t\tresolve(result);\n\t\t\t\t}\n\n\t\t\t\tresolveList = [];\n\t\t\t}, wait);\n\n\t\t\tif (shouldCallNow) {\n\t\t\t\tleadingValue = fn.apply(this, arguments_);\n\t\t\t\tresolve(leadingValue);\n\t\t\t} else {\n\t\t\t\tresolveList.push(resolve);\n\t\t\t}\n\t\t});\n\t};\n};\n\npDebounce.promise = function_ => {\n\tlet currentPromise;\n\n\treturn async function (...arguments_) {\n\t\tif (currentPromise) {\n\t\t\treturn currentPromise;\n\t\t}\n\n\t\ttry {\n\t\t\tcurrentPromise = function_.apply(this, arguments_);\n\t\t\treturn await currentPromise;\n\t\t} finally {\n\t\t\tcurrentPromise = undefined;\n\t\t}\n\t};\n};\n\nexport default pDebounce;\n","import cv from '@techstark/opencv-js';\nimport type { InferenceSession } from 'onnxruntime-web/all';\nimport type { Bounds } from '@/types';\nimport { maskToCanvas } from './mask-to-canvas';\nimport { boundsFromPoints, ShapeType, type Polygon } from '@annotorious/annotorious';\nimport { chaikinSmooth } from './chaikin-smooth';\n\nexport const maskToPolygon = (\n result: InferenceSession.ReturnType, \n bounds: Bounds,\n scale: number\n) => {\n const { canvas } = maskToCanvas(\n result, \n bounds,\n [255, 255, 255, 255],\n [0, 0, 0, 255]\n );\n\n const src = cv.imread(canvas);\n\n const dst = new cv.Mat();\n const contours = new cv.MatVector();\n const hierarchy = new cv.Mat();\n\n // To grayscale\n cv.cvtColor(src, dst, cv.COLOR_RGBA2GRAY);\n\n // Smoothing\n const size = new cv.Size(9, 9);\n cv.GaussianBlur(dst, dst, size, 0);\n cv.threshold(dst, dst, 80, 255, cv.THRESH_BINARY);\n\n // Fill small gaps\n const kernel = cv.Mat.ones(3, 3, cv.CV_8U);\n cv.morphologyEx(dst, dst, cv.MORPH_CLOSE, kernel);\n\n // Find countours\n cv.findContours(dst, contours, hierarchy, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE);\n\n // Collect polygons\n const polygons: Polygon[] = [];\n\n if (contours.size() > 0) {\n let largestContourIdx = 0;\n let largestContourSize = 0;\n \n for (let i = 0; i < contours.size(); i++) {\n let contourSize = contours.get(i).rows;\n if (contourSize > largestContourSize) {\n largestContourSize = contourSize;\n largestContourIdx = i;\n }\n }\n \n let contour = contours.get(largestContourIdx);\n \n let epsilon = 0.005 * cv.arcLength(contour, true);\n let simplifiedContour = new cv.Mat();\n\n cv.approxPolyDP(contour, simplifiedContour, epsilon, true);\n \n let points: [number, number][] = [];\n\n for (let i = 0; i < simplifiedContour.rows; i++) {\n points.push([\n simplifiedContour.data32S[i * 2] * scale,\n simplifiedContour.data32S[i * 2 + 1] * scale\n ]);\n }\n \n const smoothed = chaikinSmooth(points, 1);\n\n const polygon: Polygon = {\n type: ShapeType.POLYGON,\n geometry: {\n bounds: boundsFromPoints(smoothed),\n points: smoothed\n }\n }\n polygons.push(polygon);\n\n simplifiedContour.delete();\n }\n\n src.delete(); \n dst.delete(); \n contours.delete(); \n hierarchy.delete();\n\n return polygons[0];\n\n}","import type { Bounds } from '@/types';\nimport { getImageBounds } from './get-image-bounds';\n\n// Ported to TS from geronimi73 (MIT license)\n// https://github.com/geronimi73/next-sam/blob/main/lib/imageutils.js\nexport const prepareSAM2Canvas = (\n image: HTMLImageElement\n): Promise<{ canvas: HTMLCanvasElement, bounds: Bounds, scale: number }> => new Promise((resolve, reject) => {\n const copy = new Image();\n copy.crossOrigin = 'anonymous';\n\n copy.onload = () => {\n const { bounds, scale } = getImageBounds(\n { h: copy.naturalHeight, w: copy.naturalWidth },\n { h: 1024, w: 1024 }\n );\n\n const canvas = document.createElement('canvas');\n canvas.width = 1024;\n canvas.height = 1024;\n\n canvas\n .getContext('2d')!\n .drawImage(\n copy,\n 0,\n 0,\n copy.naturalWidth,\n copy.naturalHeight,\n bounds.x,\n bounds.y,\n bounds.w,\n bounds.h\n );\n \n resolve({ canvas, bounds, scale });\n }\n\n copy.onerror = error => {\n reject(error);\n }\n\n copy.src = image.src;\n});","import type { Bounds, Point, SAM2DecoderPrompt } from './types';\n\nconst R = window.devicePixelRatio || 1;\n\nexport const createInputMarkerCanvas = (container: HTMLDivElement, bounds: Bounds, scale: number) => {\n const canvas = document.createElement('canvas');\n canvas.setAttribute('class', 'a9s-sam-input-markers');\n canvas.width = R * container.offsetWidth;\n canvas.height = R * container.offsetHeight;\n\n const ctx = canvas.getContext('2d');\n if (!ctx) throw 'Error initializing canvas'; // Should never happen\n\n container.appendChild(canvas);\n\n const clear = () => {\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n }\n\n const drawPoint = (pt: Point, color: string) => {\n const x = R * (pt.x - bounds.x) * scale;\n const y = R * (pt.y - bounds.y) * scale;\n\n ctx.beginPath();\n ctx.arc(x, y, 5 * R, 0, 2 * Math.PI, false);\n ctx.fillStyle = color;\n ctx.fill();\n ctx.lineWidth = 1 * R;\n ctx.strokeStyle = '#000';\n ctx.stroke();\n }\n\n const setInput = (input: SAM2DecoderPrompt) => {\n clear();\n input.include.forEach(pt => drawPoint(pt, '#33ff33'));\n input.exclude.forEach(pt => drawPoint(pt, '#ff3333'));\n }\n\n return {\n clear,\n setInput\n }\n}","import type { InferenceSession } from 'onnxruntime-web/all';\nimport { maskToCanvas } from './utils';\nimport type { Bounds } from './types';\n\nexport const createPreviewCanvas = (container: HTMLDivElement, bounds: Bounds) => {\n const image = container?.querySelector('img');\n if (!image) return;\n\n let _visible = true;\n\n const renderMask = (result: InferenceSession.ReturnType) => {\n if (!_visible) return;\n\n const { canvas } = maskToCanvas(\n result, \n bounds,\n [0, 114, 189, 255],\n [0, 0, 0, 0]\n );\n\n container.querySelector('.a9s-sam-preview')?.remove();\n container.appendChild(canvas);\n }\n\n const setVisible = (visible: boolean) => {\n _visible = visible;\n\n if (!visible)\n container.querySelector('.a9s-sam-preview')?.remove();\n }\n\n return {\n renderMask,\n setVisible\n }\n}","import pDebounce from 'p-debounce';\nimport { v4 as uuidv4 } from 'uuid';\nimport type { ImageAnnotation, ImageAnnotator } from '@annotorious/annotorious';\nimport SAM2Worker from './sam2/sam2-worker.ts?worker';\nimport type { SAM2WorkerResult } from './sam2';\nimport { canvasToFloat32Array, maskToPolygon, prepareSAM2Canvas } from './utils';\nimport { createInputMarkerCanvas } from './input-marker-canvas';\nimport { createPreviewCanvas } from './preview-canvas';\nimport type { Point, SAM2DecoderPrompt, SAMPluginOpts } from './types';\n\nimport './index.css';\n\nexport const mountPlugin = (anno: ImageAnnotator, opts: SAMPluginOpts = {}) => {\n let _enabled = false;\n \n let _showPreview = true;\n\n let currentAnnotationId: string;\n\n const container = anno.element;\n\n let input: SAM2DecoderPrompt = {\n\n include: [],\n \n exclude: []\n \n }; \n\n const image = container?.querySelector('img') as HTMLImageElement;\n if (!image) return;\n\n const SAM2 = new SAM2Worker();\n\n let onPointerMove: ((evt: PointerEvent) => void) | null = null;\n let onPointerDown: ((evt: PointerEvent) => void) | null = null;\n\n let inputMarkerCanvas: ReturnType<typeof createInputMarkerCanvas>;\n\n let previewCanvas: ReturnType<typeof createPreviewCanvas>;\n\n const updateEventListeners = () => {\n if (!onPointerMove || !onPointerDown) return;\n \n if (_enabled) {\n container.addEventListener('pointermove', onPointerMove);\n container.addEventListener('pointerdown', onPointerDown);\n } else {\n container.removeEventListener('pointermove', onPointerMove);\n container.removeEventListener('pointerdown', onPointerDown);\n }\n }\n\n const debouncedPreview = pDebounce((pt: Point) => {\n SAM2.postMessage({ type: 'decode_preview', point: pt });\n }, 1);\n\n // Off-screen copy, resized and padded to 1024x1024px.\n prepareSAM2Canvas(image).then(({ canvas: bufferedImage, bounds, scale }) => {\n const viewportToSAM2Coordinates = (evt: PointerEvent) => {\n const scaleX = image.naturalWidth / (scale * image.offsetWidth);\n const scaleY = image.naturalHeight / (scale * image.offsetHeight);\n \n const { offsetX, offsetY } = evt;\n \n const x = (offsetX * scaleX) + bounds.x;\n const y = (offsetY * scaleY) + bounds.y;\n\n return { x, y };\n }\n\n onPointerMove = (evt: PointerEvent) => {\n if (input.include.length + input.exclude.length > 0) return;\n \n const { x, y } = viewportToSAM2Coordinates(evt); \n debouncedPreview({ x, y });\n }\n\n onPointerDown = (evt: PointerEvent) => {\n const { x, y } = viewportToSAM2Coordinates(evt);\n\n if (evt.shiftKey) {\n input.exclude.push({ x, y });\n } else {\n input.include.push({ x, y });\n }\n\n previewCanvas?.setVisible(false);\n\n inputMarkerCanvas?.setInput(input);\n\n SAM2.postMessage({ type: 'decode', input });\n }\n\n previewCanvas = createPreviewCanvas(anno.element, bounds);\n\n inputMarkerCanvas = createInputMarkerCanvas(anno.element, bounds, scale);\n\n SAM2.onmessage = ((message: MessageEvent<SAM2WorkerResult>) => {\n const { type } = message.data;\n \n if (type === 'init_success') {\n // Models loaded - encode the image\n console.log('[annotorious-sam] Encoding image...');\n\n const data = canvasToFloat32Array(bufferedImage);\n SAM2.postMessage({ type: 'encode', data });\n } else if (type === 'encode_success') {\n console.log('[annotorious-sam] Encoding complete');\n\n // Image encoded – add pointer listeners\n updateEventListeners();\n } else if (type === 'decode_preview_success') {\n // Render mask every time the worker has decoded one\n previewCanvas?.renderMask(message.data.result);\n } else if (type === 'decode_success') {\n // Render mask every time the worker has decoded one\n const polygon = maskToPolygon(message.data.result, bounds, scale);\n\n const annotation: ImageAnnotation = {\n id: currentAnnotationId,\n bodies: [],\n target: {\n annotation: currentAnnotationId,\n selector: polygon,\n creator: { id: 'rainer' },\n created: new Date()\n }\n };\n\n const { store, selection } = anno.state;\n\n const exists = store.getAnnotation(currentAnnotationId);\n if (exists) {\n store.updateAnnotation(currentAnnotationId, annotation);\n } else {\n store.addAnnotation(annotation);\n }\n\n // selection.setSelected(currentAnnotationId);\n }\n });\n \n SAM2.postMessage({ type: 'init' });\n });\n\n const setEnabled = (enabled: boolean) => {\n _enabled = enabled;\n\n currentAnnotationId = uuidv4();\n\n updateEventListeners();\n\n previewCanvas?.setVisible(enabled);\n }\n\n const setShowPreview = (showPreview: boolean) => {\n _showPreview = showPreview;\n previewCanvas?.setVisible(showPreview);\n }\n\n return {\n setEnabled,\n setShowPreview\n }\n\n}\n\nexport * from './types';"],"names":["pDebounce","fn","wait","options","leadingValue","timeout","resolveList","arguments_","resolve","shouldCallNow","result","function_","currentPromise","maskToPolygon","bounds","scale","canvas","maskToCanvas","src","cv","dst","contours","hierarchy","size","kernel","polygons","largestContourIdx","largestContourSize","i","contourSize","contour","epsilon","simplifiedContour","points","smoothed","chaikinSmooth","polygon","ShapeType","boundsFromPoints","prepareSAM2Canvas","image","reject","copy","getImageBounds","error","R","createInputMarkerCanvas","container","ctx","clear","drawPoint","pt","color","x","y","input","createPreviewCanvas","_visible","_a","visible","mountPlugin","anno","opts","_enabled","currentAnnotationId","SAM2","SAM2Worker","onPointerMove","onPointerDown","inputMarkerCanvas","previewCanvas","updateEventListeners","debouncedPreview","bufferedImage","viewportToSAM2Coordinates","evt","scaleX","scaleY","offsetX","offsetY","message","type","data","canvasToFloat32Array","annotation","store","selection","enabled","uuidv4","showPreview"],"mappings":";AAAA,MAAMA,IAAY,CAACC,GAAIC,GAAMC,IAAU,CAAA,MAAO;AAC7C,MAAI,CAAC,OAAO,SAASD,CAAI;AACxB,UAAM,IAAI,UAAU,uCAAuC;AAG5D,MAAIE,GACAC,GACAC,IAAc,CAAE;AAEpB,SAAO,YAAaC,GAAY;AAC/B,WAAO,IAAI,QAAQ,CAAAC,MAAW;AAC7B,YAAMC,IAAgBN,EAAQ,UAAU,CAACE;AAEzC,mBAAaA,CAAO,GAEpBA,IAAU,WAAW,MAAM;AAC1B,QAAAA,IAAU;AAEV,cAAMK,IAASP,EAAQ,SAASC,IAAeH,EAAG,MAAM,MAAMM,CAAU;AAExE,aAAKC,KAAWF;AACf,UAAAE,EAAQE,CAAM;AAGf,QAAAJ,IAAc,CAAE;AAAA,MAChB,GAAEJ,CAAI,GAEHO,KACHL,IAAeH,EAAG,MAAM,MAAMM,CAAU,GACxCC,EAAQJ,CAAY,KAEpBE,EAAY,KAAKE,CAAO;AAAA,IAE5B,CAAG;AAAA,EACD;AACF;AAEAR,EAAU,UAAU,CAAAW,MAAa;AAChC,MAAIC;AAEJ,SAAO,kBAAmBL,GAAY;AACrC,QAAIK;AACH,aAAOA;AAGR,QAAI;AACH,aAAAA,IAAiBD,EAAU,MAAM,MAAMJ,CAAU,GAC1C,MAAMK;AAAA,IAChB,UAAY;AACT,MAAAA,IAAiB;AAAA,IACpB;AAAA,EACE;AACF;AC7CO,MAAMC,IAAgB,CAC3BH,GACAI,GACAC,MACG;AACG,QAAA,EAAE,QAAAC,MAAWC;AAAA,IACjBP;AAAA,IACAI;AAAA,IACA,CAAC,KAAK,KAAK,KAAK,GAAG;AAAA,IACnB,CAAC,GAAG,GAAG,GAAG,GAAG;AAAA,EACf,GAEMI,IAAMC,EAAG,OAAOH,CAAM,GAEtBI,IAAM,IAAID,EAAG,IAAI,GACjBE,IAAW,IAAIF,EAAG,UAAU,GAC5BG,IAAY,IAAIH,EAAG,IAAI;AAG7B,EAAAA,EAAG,SAASD,GAAKE,GAAKD,EAAG,eAAe;AAGxC,QAAMI,IAAO,IAAIJ,EAAG,KAAK,GAAG,CAAC;AAC7B,EAAAA,EAAG,aAAaC,GAAKA,GAAKG,GAAM,CAAC,GACjCJ,EAAG,UAAUC,GAAKA,GAAK,IAAI,KAAKD,EAAG,aAAa;AAGhD,QAAMK,IAASL,EAAG,IAAI,KAAK,GAAG,GAAGA,EAAG,KAAK;AACzC,EAAAA,EAAG,aAAaC,GAAKA,GAAKD,EAAG,aAAaK,CAAM,GAGhDL,EAAG,aAAaC,GAAKC,GAAUC,GAAWH,EAAG,eAAeA,EAAG,mBAAmB;AAGlF,QAAMM,IAAsB,CAAC;AAEzB,MAAAJ,EAAS,KAAK,IAAI,GAAG;AACvB,QAAIK,IAAoB,GACpBC,IAAqB;AAEzB,aAASC,IAAI,GAAGA,IAAIP,EAAS,KAAA,GAAQO,KAAK;AACxC,UAAIC,IAAcR,EAAS,IAAIO,CAAC,EAAE;AAClC,MAAIC,IAAcF,MACKA,IAAAE,GACDH,IAAAE;AAAA,IACtB;AAGE,QAAAE,IAAUT,EAAS,IAAIK,CAAiB,GAExCK,IAAU,OAAQZ,EAAG,UAAUW,GAAS,EAAI,GAC5CE,IAAoB,IAAIb,EAAG,IAAI;AAEnC,IAAAA,EAAG,aAAaW,GAASE,GAAmBD,GAAS,EAAI;AAEzD,QAAIE,IAA6B,CAAC;AAElC,aAASL,IAAI,GAAGA,IAAII,EAAkB,MAAMJ;AAC1C,MAAAK,EAAO,KAAK;AAAA,QACVD,EAAkB,QAAQJ,IAAI,CAAC,IAAIb;AAAA,QACnCiB,EAAkB,QAAQJ,IAAI,IAAI,CAAC,IAAIb;AAAA,MAAA,CACxC;AAGG,UAAAmB,IAAWC,EAAcF,CAAS,GAElCG,IAAmB;AAAA,MACvB,MAAMC,EAAU;AAAA,MAChB,UAAU;AAAA,QACR,QAAQC,EAAiBJ,CAAQ;AAAA,QACjC,QAAQA;AAAA,MAAA;AAAA,IAEZ;AACA,IAAAT,EAAS,KAAKW,CAAO,GAErBJ,EAAkB,OAAO;AAAA,EAAA;AAG3B,SAAAd,EAAI,OAAO,GACXE,EAAI,OAAO,GACXC,EAAS,OAAO,GAChBC,EAAU,OAAO,GAEVG,EAAS,CAAC;AAEnB,GCvFac,IAAoB,CAC/BC,MAC0E,IAAI,QAAQ,CAAChC,GAASiC,MAAW;AACrG,QAAAC,IAAO,IAAI,MAAM;AACvB,EAAAA,EAAK,cAAc,aAEnBA,EAAK,SAAS,MAAM;AACZ,UAAA,EAAE,QAAA5B,GAAQ,OAAAC,EAAA,IAAU4B;AAAA,MACxB,EAAE,GAAGD,EAAK,eAAe,GAAGA,EAAK,aAAa;AAAA,MAC9C,EAAE,GAAG,MAAM,GAAG,KAAK;AAAA,IACrB,GAEM1B,IAAS,SAAS,cAAc,QAAQ;AAC9C,IAAAA,EAAO,QAAQ,MACfA,EAAO,SAAS,MAGbA,EAAA,WAAW,IAAI,EACf;AAAA,MACC0B;AAAA,MACA;AAAA,MACA;AAAA,MACAA,EAAK;AAAA,MACLA,EAAK;AAAA,MACL5B,EAAO;AAAA,MACPA,EAAO;AAAA,MACPA,EAAO;AAAA,MACPA,EAAO;AAAA,IACT,GAEFN,EAAQ,EAAE,QAAAQ,GAAQ,QAAAF,GAAQ,OAAAC,EAAA,CAAO;AAAA,EACnC,GAEA2B,EAAK,UAAU,CAASE,MAAA;AACtB,IAAAH,EAAOG,CAAK;AAAA,EACd,GAEAF,EAAK,MAAMF,EAAM;AACnB,CAAC,GCzCKK,IAAI,OAAO,oBAAoB,GAExBC,IAA0B,CAACC,GAA2BjC,GAAgBC,MAAkB;AAC7F,QAAAC,IAAS,SAAS,cAAc,QAAQ;AACvC,EAAAA,EAAA,aAAa,SAAS,uBAAuB,GAC7CA,EAAA,QAAQ6B,IAAIE,EAAU,aACtB/B,EAAA,SAAS6B,IAAIE,EAAU;AAExB,QAAAC,IAAMhC,EAAO,WAAW,IAAI;AAC9B,MAAA,CAACgC,EAAW,OAAA;AAEhB,EAAAD,EAAU,YAAY/B,CAAM;AAE5B,QAAMiC,IAAQ,MAAM;AAClB,IAAAD,EAAI,UAAU,GAAG,GAAGhC,EAAO,OAAOA,EAAO,MAAM;AAAA,EACjD,GAEMkC,IAAY,CAACC,GAAWC,MAAkB;AAC9C,UAAMC,IAAIR,KAAKM,EAAG,IAAIrC,EAAO,KAAKC,GAC5BuC,IAAIT,KAAKM,EAAG,IAAIrC,EAAO,KAAKC;AAElC,IAAAiC,EAAI,UAAU,GACVA,EAAA,IAAIK,GAAGC,GAAG,IAAIT,GAAG,GAAG,IAAI,KAAK,IAAI,EAAK,GAC1CG,EAAI,YAAYI,GAChBJ,EAAI,KAAK,GACTA,EAAI,YAAY,IAAIH,GACpBG,EAAI,cAAc,QAClBA,EAAI,OAAO;AAAA,EACb;AAQO,SAAA;AAAA,IACL,OAAAC;AAAA,IACA,UARe,CAACM,MAA6B;AACvC,MAAAN,EAAA,GACNM,EAAM,QAAQ,QAAQ,CAAAJ,MAAMD,EAAUC,GAAI,SAAS,CAAC,GACpDI,EAAM,QAAQ,QAAQ,CAAAJ,MAAMD,EAAUC,GAAI,SAAS,CAAC;AAAA,IACtD;AAAA,EAKA;AACF,GCtCaK,IAAsB,CAACT,GAA2BjC,MAAmB;AAEhF,MAAI,EADUiC,KAAA,gBAAAA,EAAW,cAAc,QAC3B;AAEZ,MAAIU,IAAW;AAuBR,SAAA;AAAA,IACL,YAtBiB,CAAC/C,MAAwC;;AAC1D,UAAI,CAAC+C,EAAU;AAET,YAAA,EAAE,QAAAzC,MAAWC;AAAA,QACjBP;AAAA,QACAI;AAAA,QACA,CAAC,GAAG,KAAK,KAAK,GAAG;AAAA,QACjB,CAAC,GAAG,GAAG,GAAG,CAAC;AAAA,MACb;AAEU,OAAA4C,IAAAX,EAAA,cAAc,kBAAkB,MAAhC,QAAAW,EAAmC,UAC7CX,EAAU,YAAY/B,CAAM;AAAA,IAC9B;AAAA,IAWE,YATiB,CAAC2C,MAAqB;;AAC5B,MAAAF,IAAAE,GAENA,MACOD,IAAAX,EAAA,cAAc,kBAAkB,MAAhC,QAAAW,EAAmC;AAAA,IACjD;AAAA,EAKA;AACF,GCvBaE,IAAc,CAACC,GAAsBC,IAAsB,OAAO;AAC7E,MAAIC,IAAW,IAIXC;AAEJ,QAAMjB,IAAYc,EAAK;AAEvB,MAAIN,IAA2B;AAAA,IAE7B,SAAS,CAAC;AAAA,IAEV,SAAS,CAAA;AAAA,EAEX;AAEM,QAAAf,IAAQO,KAAA,gBAAAA,EAAW,cAAc;AACvC,MAAI,CAACP,EAAO;AAEN,QAAAyB,IAAO,IAAIC,EAAW;AAE5B,MAAIC,IAAsD,MACtDC,IAAsD,MAEtDC,GAEAC;AAEJ,QAAMC,IAAuB,MAAM;AAC7B,IAAA,CAACJ,KAAiB,CAACC,MAEnBL,KACQhB,EAAA,iBAAiB,eAAeoB,CAAa,GAC7CpB,EAAA,iBAAiB,eAAeqB,CAAa,MAE7CrB,EAAA,oBAAoB,eAAeoB,CAAa,GAChDpB,EAAA,oBAAoB,eAAeqB,CAAa;AAAA,EAE9D,GAEMI,IAAmBxE,EAAU,CAACmD,MAAc;AAChD,IAAAc,EAAK,YAAY,EAAE,MAAM,kBAAkB,OAAOd,GAAI;AAAA,KACrD,CAAC;AAGc,SAAAZ,EAAAC,CAAK,EAAE,KAAK,CAAC,EAAE,QAAQiC,GAAe,QAAA3D,GAAQ,OAAAC,QAAY;AACpE,UAAA2D,IAA4B,CAACC,MAAsB;AACvD,YAAMC,IAASpC,EAAM,gBAAgBzB,IAAQyB,EAAM,cAC7CqC,IAASrC,EAAM,iBAAiBzB,IAAQyB,EAAM,eAE9C,EAAE,SAAAsC,GAAS,SAAAC,EAAA,IAAYJ,GAEvBtB,IAAKyB,IAAUF,IAAU9D,EAAO,GAChCwC,IAAKyB,IAAUF,IAAU/D,EAAO;AAE/B,aAAA,EAAE,GAAAuC,GAAG,GAAAC,EAAE;AAAA,IAChB;AAEA,IAAAa,IAAgB,CAACQ,MAAsB;AACrC,UAAIpB,EAAM,QAAQ,SAASA,EAAM,QAAQ,SAAS,EAAG;AAErD,YAAM,EAAE,GAAAF,GAAG,GAAAC,MAAMoB,EAA0BC,CAAG;AAC7B,MAAAH,EAAA,EAAE,GAAAnB,GAAG,GAAAC,GAAG;AAAA,IAC3B,GAEAc,IAAgB,CAACO,MAAsB;AACrC,YAAM,EAAE,GAAAtB,GAAG,GAAAC,MAAMoB,EAA0BC,CAAG;AAE9C,MAAIA,EAAI,WACNpB,EAAM,QAAQ,KAAK,EAAE,GAAAF,GAAG,GAAAC,GAAG,IAE3BC,EAAM,QAAQ,KAAK,EAAE,GAAAF,GAAG,GAAAC,GAAG,GAG7BgB,KAAA,QAAAA,EAAe,WAAW,KAE1BD,KAAA,QAAAA,EAAmB,SAASd,IAE5BU,EAAK,YAAY,EAAE,MAAM,UAAU,OAAAV,GAAO;AAAA,IAC5C,GAEgBe,IAAAd,EAAoBK,EAAK,SAAS/C,CAAM,GAExDuD,IAAoBvB,EAAwBe,EAAK,SAAS/C,GAAQC,CAAK,GAElEkD,EAAA,YAAa,CAACe,MAA4C;AACvD,YAAA,EAAE,MAAAC,MAASD,EAAQ;AAEzB,UAAIC,MAAS,gBAAgB;AAE3B,gBAAQ,IAAI,qCAAqC;AAE3C,cAAAC,IAAOC,EAAqBV,CAAa;AAC/C,QAAAR,EAAK,YAAY,EAAE,MAAM,UAAU,MAAAiB,GAAM;AAAA,MAAA,WAChCD,MAAS;AAClB,gBAAQ,IAAI,qCAAqC,GAG5BV,EAAA;AAAA,eACZU,MAAS;AAEH,QAAAX,KAAA,QAAAA,EAAA,WAAWU,EAAQ,KAAK;AAAA,eAC9BC,MAAS,kBAAkB;AAEpC,cAAM7C,IAAUvB,EAAcmE,EAAQ,KAAK,QAAQlE,GAAQC,CAAK,GAE1DqE,IAA8B;AAAA,UAClC,IAAIpB;AAAA,UACJ,QAAQ,CAAC;AAAA,UACT,QAAQ;AAAA,YACN,YAAYA;AAAA,YACZ,UAAU5B;AAAA,YACV,SAAS,EAAE,IAAI,SAAS;AAAA,YACxB,6BAAa,KAAK;AAAA,UAAA;AAAA,QAEtB,GAEM,EAAE,OAAAiD,GAAO,WAAAC,EAAU,IAAIzB,EAAK;AAGlC,QADewB,EAAM,cAAcrB,CAAmB,IAE9CqB,EAAA,iBAAiBrB,GAAqBoB,CAAU,IAEtDC,EAAM,cAAcD,CAAU;AAAA,MAChC;AAAA,IAIJ,GAEAnB,EAAK,YAAY,EAAE,MAAM,OAAA,CAAQ;AAAA,EAAA,CAClC,GAiBM;AAAA,IACL,YAhBiB,CAACsB,MAAqB;AAC5B,MAAAxB,IAAAwB,GAEXvB,IAAsBwB,EAAO,GAERjB,EAAA,GAErBD,KAAA,QAAAA,EAAe,WAAWiB;AAAA,IAC5B;AAAA,IASE,gBAPqB,CAACE,MAAyB;AAE/C,MAAAnB,KAAA,QAAAA,EAAe,WAAWmB;AAAA,IAC5B;AAAA,EAKA;AAEF;","x_google_ignoreList":[0]}
1
+ {"version":3,"file":"index.js","sources":["../node_modules/p-debounce/index.js","../src/utils/mask-to-polygon.ts","../src/utils/prepare-sam2-canvas.ts","../src/prompt-marker-canvas.ts","../src/preview-canvas.ts","../src/index.ts"],"sourcesContent":["const pDebounce = (fn, wait, options = {}) => {\n\tif (!Number.isFinite(wait)) {\n\t\tthrow new TypeError('Expected `wait` to be a finite number');\n\t}\n\n\tlet leadingValue;\n\tlet timeout;\n\tlet resolveList = [];\n\n\treturn function (...arguments_) {\n\t\treturn new Promise(resolve => {\n\t\t\tconst shouldCallNow = options.before && !timeout;\n\n\t\t\tclearTimeout(timeout);\n\n\t\t\ttimeout = setTimeout(() => {\n\t\t\t\ttimeout = null;\n\n\t\t\t\tconst result = options.before ? leadingValue : fn.apply(this, arguments_);\n\n\t\t\t\tfor (resolve of resolveList) {\n\t\t\t\t\tresolve(result);\n\t\t\t\t}\n\n\t\t\t\tresolveList = [];\n\t\t\t}, wait);\n\n\t\t\tif (shouldCallNow) {\n\t\t\t\tleadingValue = fn.apply(this, arguments_);\n\t\t\t\tresolve(leadingValue);\n\t\t\t} else {\n\t\t\t\tresolveList.push(resolve);\n\t\t\t}\n\t\t});\n\t};\n};\n\npDebounce.promise = function_ => {\n\tlet currentPromise;\n\n\treturn async function (...arguments_) {\n\t\tif (currentPromise) {\n\t\t\treturn currentPromise;\n\t\t}\n\n\t\ttry {\n\t\t\tcurrentPromise = function_.apply(this, arguments_);\n\t\t\treturn await currentPromise;\n\t\t} finally {\n\t\t\tcurrentPromise = undefined;\n\t\t}\n\t};\n};\n\nexport default pDebounce;\n","import cv from '@techstark/opencv-js';\nimport type { InferenceSession } from 'onnxruntime-web/all';\nimport type { Bounds } from '@/types';\nimport { maskToCanvas } from './mask-to-canvas';\nimport { boundsFromPoints, ShapeType, type Polygon } from '@annotorious/annotorious';\nimport { chaikinSmooth } from './chaikin-smooth';\n\nexport const maskToPolygon = (\n result: InferenceSession.ReturnType, \n bounds: Bounds,\n scale: number\n) => {\n const { canvas } = maskToCanvas(\n result, \n bounds,\n [255, 255, 255, 255],\n [0, 0, 0, 255]\n );\n\n const src = cv.imread(canvas);\n\n const dst = new cv.Mat();\n const contours = new cv.MatVector();\n const hierarchy = new cv.Mat();\n\n // To grayscale\n cv.cvtColor(src, dst, cv.COLOR_RGBA2GRAY);\n\n // Smoothing\n const size = new cv.Size(9, 9);\n cv.GaussianBlur(dst, dst, size, 0);\n cv.threshold(dst, dst, 80, 255, cv.THRESH_BINARY);\n\n // Fill small gaps\n const kernel = cv.Mat.ones(3, 3, cv.CV_8U);\n cv.morphologyEx(dst, dst, cv.MORPH_CLOSE, kernel);\n\n // Find countours\n cv.findContours(dst, contours, hierarchy, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE);\n\n // Collect polygons\n const polygons: Polygon[] = [];\n\n if (contours.size() > 0) {\n let largestContourIdx = 0;\n let largestContourSize = 0;\n \n for (let i = 0; i < contours.size(); i++) {\n let contourSize = contours.get(i).rows;\n if (contourSize > largestContourSize) {\n largestContourSize = contourSize;\n largestContourIdx = i;\n }\n }\n \n let contour = contours.get(largestContourIdx);\n \n let epsilon = 0.005 * cv.arcLength(contour, true);\n let simplifiedContour = new cv.Mat();\n\n cv.approxPolyDP(contour, simplifiedContour, epsilon, true);\n \n let points: [number, number][] = [];\n\n for (let i = 0; i < simplifiedContour.rows; i++) {\n points.push([\n simplifiedContour.data32S[i * 2] * scale,\n simplifiedContour.data32S[i * 2 + 1] * scale\n ]);\n }\n \n const smoothed = chaikinSmooth(points, 1);\n\n const polygon: Polygon = {\n type: ShapeType.POLYGON,\n geometry: {\n bounds: boundsFromPoints(smoothed),\n points: smoothed\n }\n }\n polygons.push(polygon);\n\n simplifiedContour.delete();\n }\n\n src.delete(); \n dst.delete(); \n contours.delete(); \n hierarchy.delete();\n\n return polygons[0];\n\n}","import type { Bounds } from '@/types';\nimport { getImageBounds } from './get-image-bounds';\n\n// Ported to TS from geronimi73 (MIT license)\n// https://github.com/geronimi73/next-sam/blob/main/lib/imageutils.js\nexport const prepareSAM2Canvas = (\n image: HTMLImageElement\n): Promise<{ canvas: HTMLCanvasElement, bounds: Bounds, scale: number }> => new Promise((resolve, reject) => {\n const copy = new Image();\n copy.crossOrigin = 'anonymous';\n\n copy.onload = () => {\n const { bounds, scale } = getImageBounds(\n { h: copy.naturalHeight, w: copy.naturalWidth },\n { h: 1024, w: 1024 }\n );\n\n const canvas = document.createElement('canvas');\n canvas.width = 1024;\n canvas.height = 1024;\n\n canvas\n .getContext('2d')!\n .drawImage(\n copy,\n 0,\n 0,\n copy.naturalWidth,\n copy.naturalHeight,\n bounds.x,\n bounds.y,\n bounds.w,\n bounds.h\n );\n \n resolve({ canvas, bounds, scale });\n }\n\n copy.onerror = error => {\n reject(error);\n }\n\n copy.src = image.src;\n});","import type { Bounds, Point, SAM2DecoderPrompt } from './types';\n\nconst R = window.devicePixelRatio || 1;\n\nexport const createPromptMarkerCanvas = (container: HTMLDivElement, bounds: Bounds, scale: number) => {\n const canvas = document.createElement('canvas');\n canvas.setAttribute('class', 'a9s-sam-input-markers');\n canvas.width = R * container.offsetWidth;\n canvas.height = R * container.offsetHeight;\n\n const ctx = canvas.getContext('2d');\n if (!ctx) throw 'Error initializing canvas'; // Should never happen\n\n container.appendChild(canvas);\n\n const clear = () => {\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n }\n\n const drawPoint = (pt: Point, color: string) => {\n const x = R * (pt.x - bounds.x) * scale;\n const y = R * (pt.y - bounds.y) * scale;\n\n ctx.beginPath();\n ctx.arc(x, y, 5 * R, 0, 2 * Math.PI, false);\n ctx.fillStyle = color;\n ctx.fill();\n ctx.lineWidth = 1 * R;\n ctx.strokeStyle = '#000';\n ctx.stroke();\n }\n\n const setInput = (input: SAM2DecoderPrompt) => {\n clear();\n input.include.forEach(pt => drawPoint(pt, '#33ff33'));\n input.exclude.forEach(pt => drawPoint(pt, '#ff3333'));\n }\n\n return {\n clear,\n setInput\n }\n}","import type { InferenceSession } from 'onnxruntime-web/all';\nimport { maskToCanvas } from './utils';\nimport type { Bounds } from './types';\n\nexport const createPreviewCanvas = (container: HTMLDivElement, bounds: Bounds) => {\n const image = container?.querySelector('img');\n if (!image) return;\n\n let _visible = true;\n\n const renderMask = (result: InferenceSession.ReturnType) => {\n if (!_visible) return;\n\n const { canvas } = maskToCanvas(\n result, \n bounds,\n [0, 114, 189, 255],\n [0, 0, 0, 0]\n );\n\n container.querySelector('.a9s-sam-preview')?.remove();\n container.appendChild(canvas);\n }\n\n const setVisible = (visible: boolean) => {\n _visible = visible;\n\n if (!visible)\n container.querySelector('.a9s-sam-preview')?.remove();\n }\n\n return {\n renderMask,\n setVisible\n }\n}","import pDebounce from 'p-debounce';\nimport { v4 as uuidv4 } from 'uuid';\nimport type { ImageAnnotation, ImageAnnotator } from '@annotorious/annotorious';\nimport SAM2Worker from './sam2/sam2-worker.ts?worker';\nimport type { SAM2WorkerResult } from './sam2';\nimport { canvasToFloat32Array, maskToPolygon, prepareSAM2Canvas } from './utils';\nimport { createPromptMarkerCanvas } from './prompt-marker-canvas';\nimport { createPreviewCanvas } from './preview-canvas';\nimport type { Point, SAM2DecoderPrompt, SAMPluginOpts } from './types';\n\nimport './index.css';\n\nexport const mountPlugin = (anno: ImageAnnotator, opts: SAMPluginOpts = {}) => {\n let _enabled = false;\n\n let currentAnnotationId: string;\n\n const container = anno.element;\n\n let input: SAM2DecoderPrompt = {\n\n include: [],\n \n exclude: []\n \n }; \n\n const image = container?.querySelector('img') as HTMLImageElement;\n if (!image) return;\n\n const SAM2 = new SAM2Worker();\n\n let onPointerMove: ((evt: PointerEvent) => void) | null = null;\n let onPointerDown: ((evt: PointerEvent) => void) | null = null;\n\n let promptMarkerCanvas: ReturnType<typeof createPromptMarkerCanvas>;\n\n let previewCanvas: ReturnType<typeof createPreviewCanvas>;\n\n const updateEventListeners = () => {\n if (!onPointerMove || !onPointerDown) return;\n \n if (_enabled) {\n container.addEventListener('pointermove', onPointerMove);\n container.addEventListener('pointerdown', onPointerDown);\n } else {\n container.removeEventListener('pointermove', onPointerMove);\n container.removeEventListener('pointerdown', onPointerDown);\n }\n }\n\n const debouncedPreview = pDebounce((pt: Point) => {\n SAM2.postMessage({ type: 'decode_preview', point: pt });\n }, 1);\n\n // Off-screen copy, resized and padded to 1024x1024px.\n prepareSAM2Canvas(image).then(({ canvas: bufferedImage, bounds, scale }) => {\n const viewportToSAM2Coordinates = (evt: PointerEvent) => {\n const scaleX = image.naturalWidth / (scale * image.offsetWidth);\n const scaleY = image.naturalHeight / (scale * image.offsetHeight);\n \n const { offsetX, offsetY } = evt;\n \n const x = (offsetX * scaleX) + bounds.x;\n const y = (offsetY * scaleY) + bounds.y;\n\n return { x, y };\n }\n\n onPointerMove = (evt: PointerEvent) => {\n if (input.include.length + input.exclude.length > 0) return;\n \n const { x, y } = viewportToSAM2Coordinates(evt); \n debouncedPreview({ x, y });\n }\n\n onPointerDown = (evt: PointerEvent) => {\n const { x, y } = viewportToSAM2Coordinates(evt);\n\n if (evt.shiftKey) {\n input.exclude.push({ x, y });\n } else {\n input.include.push({ x, y });\n }\n\n previewCanvas?.setVisible(false);\n\n promptMarkerCanvas?.setInput(input);\n\n SAM2.postMessage({ type: 'decode', input });\n }\n\n previewCanvas = createPreviewCanvas(anno.element, bounds);\n\n promptMarkerCanvas = createPromptMarkerCanvas(anno.element, bounds, scale);\n\n SAM2.onmessage = ((message: MessageEvent<SAM2WorkerResult>) => {\n const { type } = message.data;\n \n if (type === 'init_success') {\n // Models loaded - encode the image\n console.log('[annotorious-sam] Encoding image...');\n\n const data = canvasToFloat32Array(bufferedImage);\n SAM2.postMessage({ type: 'encode', data });\n } else if (type === 'encode_success') {\n console.log('[annotorious-sam] Encoding complete');\n\n // Image encoded – add pointer listeners\n updateEventListeners();\n } else if (type === 'decode_preview_success') {\n // Render mask every time the worker has decoded one\n previewCanvas?.renderMask(message.data.result);\n } else if (type === 'decode_success') {\n // Render mask every time the worker has decoded one\n const polygon = maskToPolygon(message.data.result, bounds, scale);\n\n const annotation: ImageAnnotation = {\n id: currentAnnotationId,\n bodies: [],\n target: {\n annotation: currentAnnotationId,\n selector: polygon,\n creator: { id: 'rainer' },\n created: new Date()\n }\n };\n\n const { store, selection } = anno.state;\n\n const exists = store.getAnnotation(currentAnnotationId);\n if (exists) {\n store.updateAnnotation(currentAnnotationId, annotation);\n } else {\n store.addAnnotation(annotation);\n }\n\n // selection.setSelected(currentAnnotationId);\n }\n });\n \n SAM2.postMessage({ type: 'init' });\n });\n\n const setEnabled = (enabled: boolean) => {\n _enabled = enabled;\n\n currentAnnotationId = uuidv4();\n\n updateEventListeners();\n\n previewCanvas?.setVisible(enabled);\n }\n\n const setShowPreview = (showPreview: boolean) => {\n previewCanvas?.setVisible(showPreview);\n }\n\n return {\n setEnabled,\n setShowPreview\n }\n\n}\n\nexport * from './types';"],"names":["pDebounce","fn","wait","options","leadingValue","timeout","resolveList","arguments_","resolve","shouldCallNow","result","function_","currentPromise","maskToPolygon","bounds","scale","canvas","maskToCanvas","src","cv","dst","contours","hierarchy","size","kernel","polygons","largestContourIdx","largestContourSize","i","contourSize","contour","epsilon","simplifiedContour","points","smoothed","chaikinSmooth","polygon","ShapeType","boundsFromPoints","prepareSAM2Canvas","image","reject","copy","getImageBounds","error","R","createPromptMarkerCanvas","container","ctx","clear","drawPoint","pt","color","x","y","input","createPreviewCanvas","_visible","_a","visible","mountPlugin","anno","opts","_enabled","currentAnnotationId","SAM2","SAM2Worker","onPointerMove","onPointerDown","promptMarkerCanvas","previewCanvas","updateEventListeners","debouncedPreview","bufferedImage","viewportToSAM2Coordinates","evt","scaleX","scaleY","offsetX","offsetY","message","type","data","canvasToFloat32Array","annotation","store","selection","enabled","uuidv4","showPreview"],"mappings":"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","x_google_ignoreList":[0]}