@nddeps/barcode-scanner 0.2.0 → 0.3.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.
@@ -0,0 +1,34 @@
1
+ import { type ScanArea } from './utils';
2
+ declare function createBarcodeScanner(video: HTMLVideoElement, { calcScanArea, }?: {
3
+ calcScanArea?: (video: HTMLVideoElement) => ScanArea;
4
+ }): {
5
+ destroy: () => Promise<void>;
6
+ pause: () => void;
7
+ start: ({ facingMode }: {
8
+ facingMode?: "environment" | "user";
9
+ } | undefined, onDecodeSuccess: (data: string, area: ScanArea) => void, onDecodeFailure?: () => void) => Promise<void>;
10
+ state: {
11
+ calcScanArea: (video: HTMLVideoElement) => ScanArea;
12
+ canvas: HTMLCanvasElement;
13
+ canvasContext: CanvasRenderingContext2D;
14
+ debug: boolean;
15
+ decodeFrameRequestTimestamp: number;
16
+ facingMode: "environment" | "user";
17
+ isDecodeFrameProcessed: boolean;
18
+ isDestroyed: boolean;
19
+ isReady: boolean;
20
+ isVideoActive: boolean;
21
+ isVideoPaused: boolean;
22
+ onDecodeFailure: () => void;
23
+ onDecodeSuccess: (data: string, area: ScanArea) => void;
24
+ requestFrame: (callback: () => void) => number;
25
+ resumeOnVisibilityChange: boolean;
26
+ scanArea: ScanArea;
27
+ scanRate: number;
28
+ video: HTMLVideoElement;
29
+ worker: null | Worker;
30
+ };
31
+ stop: () => void;
32
+ watch: <T>(source: () => T, callback: (newValue: T) => void) => () => void;
33
+ };
34
+ export { createBarcodeScanner };
@@ -0,0 +1,5 @@
1
+ declare function createWatchable<T extends object>(init: T): {
2
+ state: T;
3
+ watch: <T_1>(source: () => T_1, callback: (newValue: T_1) => void) => () => void;
4
+ };
5
+ export { createWatchable };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,4 @@
1
- import { BarcodeScanner } from './barcode-scanner';
2
- export type * from './barcode-detector.type';
3
- export type * from './barcode-scanner.types';
4
- export * as utils from './utils';
5
- export { BarcodeScanner };
6
- export default BarcodeScanner;
1
+ import { createBarcodeScanner } from './create-barcode-scanner';
2
+ export * from './utils';
3
+ export { createBarcodeScanner };
4
+ export default createBarcodeScanner;
package/dist/index.js CHANGED
@@ -1,187 +1,289 @@
1
- var __defProp = Object.defineProperty, __export = (t, n) => {
2
- let r = {};
3
- for (var i in t) __defProp(r, i, {
4
- get: t[i],
5
- enumerable: !0
1
+ function createWatchable(e) {
2
+ let r = new EventTarget(), i = new Proxy(e, {
3
+ get(e, r, i) {
4
+ return Reflect.get(e, r, i);
5
+ },
6
+ set(e, i, a, o) {
7
+ let s = Reflect.set(e, i, a, o);
8
+ return r.dispatchEvent(new CustomEvent("change")), s;
9
+ }
6
10
  });
7
- return n && __defProp(r, Symbol.toStringTag, { value: "Module" }), r;
8
- };
9
- function getVideoRenderedOffset(e, t) {
10
- let [n, r] = window.getComputedStyle(e).objectPosition.split(" ").map((n, r) => n.endsWith("%") ? (r === 0 ? e.offsetWidth - t.width : e.offsetHeight - t.height) * parseFloat(n) / 100 : parseFloat(n));
11
+ function a(e, i) {
12
+ let a = e();
13
+ function o() {
14
+ let r = e();
15
+ JSON.stringify(r) !== JSON.stringify(a) && (a = r, i(r));
16
+ }
17
+ return r.addEventListener("change", o), () => r.removeEventListener("change", o);
18
+ }
19
+ return {
20
+ state: i,
21
+ watch: a
22
+ };
23
+ }
24
+ async function hasCameraAccess() {
25
+ try {
26
+ return (await navigator.permissions.query({ name: "camera" })).state === "granted";
27
+ } catch {
28
+ return (await navigator.mediaDevices.enumerateDevices()).filter((e) => e.deviceId && e.kind === "videoinput").length > 0;
29
+ }
30
+ }
31
+ async function getCameraAccess() {
32
+ if (await hasCameraAccess()) return !0;
33
+ try {
34
+ let e = (await navigator.mediaDevices.getUserMedia({ video: !0 })).getTracks();
35
+ for (let r of e) r.stop();
36
+ return !0;
37
+ } catch {
38
+ return !1;
39
+ }
40
+ }
41
+ function getScanArea(e) {
42
+ let r = Math.round(2 / 3 * Math.min(e.videoWidth, e.videoHeight));
43
+ return {
44
+ height: r,
45
+ width: r,
46
+ x: Math.round((e.videoWidth - r) / 2),
47
+ y: Math.round((e.videoHeight - r) / 2)
48
+ };
49
+ }
50
+ function getVideoRenderOffset(e, r) {
51
+ let [i, a] = window.getComputedStyle(e).objectPosition.split(" ").map((i, a) => i.endsWith("%") ? (a === 0 ? e.offsetWidth - r.width : e.offsetHeight - r.height) * parseFloat(i) / 100 : parseFloat(i));
11
52
  return {
12
- x: n,
13
- y: r
53
+ x: i,
54
+ y: a
14
55
  };
15
56
  }
16
- function getVideoRenderedSize(e) {
17
- let t = window.getComputedStyle(e), n = e.offsetWidth / e.offsetHeight, r = e.videoWidth / e.videoHeight;
18
- switch (t.objectFit) {
57
+ function getVideoRenderSize(e) {
58
+ let r = window.getComputedStyle(e), i = {
59
+ height: e.offsetHeight,
60
+ width: e.offsetWidth
61
+ }, a = i.width / i.height, o = {
62
+ height: e.videoHeight,
63
+ width: e.videoWidth
64
+ }, s = o.width / o.height;
65
+ switch (r.objectFit) {
19
66
  case "contain": return {
20
- height: r < n ? e.offsetHeight : e.offsetWidth / r,
21
- width: r < n ? e.offsetHeight * r : e.offsetWidth
67
+ height: s < a ? e.offsetHeight : e.offsetWidth / s,
68
+ width: s < a ? e.offsetHeight * s : e.offsetWidth
22
69
  };
23
70
  case "cover": return {
24
- height: r > n ? e.offsetHeight : e.offsetWidth / r,
25
- width: r > n ? e.offsetHeight * r : e.offsetWidth
26
- };
27
- case "fill": return {
28
- height: e.offsetHeight,
29
- width: e.offsetWidth
30
- };
31
- case "none": return {
32
- height: e.videoHeight,
33
- width: e.videoWidth
71
+ height: s > a ? e.offsetHeight : e.offsetWidth / s,
72
+ width: s > a ? e.offsetHeight * s : e.offsetWidth
34
73
  };
74
+ case "fill": return i;
75
+ case "none": return o;
35
76
  case "scale-down": return {
36
- height: Math.min(r < n ? e.offsetHeight : e.offsetWidth / r, e.videoHeight),
37
- width: Math.min(r < n ? e.offsetHeight * r : e.offsetWidth, e.videoWidth)
38
- };
39
- default: return {
40
- height: e.videoHeight,
41
- width: e.videoWidth
77
+ height: Math.min(s < a ? e.offsetHeight : e.offsetWidth / s, e.videoHeight),
78
+ width: Math.min(s < a ? e.offsetHeight * s : e.offsetWidth, e.videoWidth)
42
79
  };
80
+ default: return o;
43
81
  }
44
82
  }
45
- function convertToElementArea(e, t) {
46
- let i = /scaleX\(-1\)/.test(e.style.transform), a = e.videoHeight, o = e.videoWidth, s = getVideoRenderedSize(e), c = getVideoRenderedOffset(e, s), l = i ? o - t.x : t.x, u = t.y;
83
+ function isBarcodeDetectorAvailable(e) {
84
+ return "BarcodeDetector" in e;
85
+ }
86
+ function translateAreaToVideoRender(e, r) {
87
+ let i = /scaleX\(-1\)/.test(e.style.transform), a = getVideoRenderSize(e), c = getVideoRenderOffset(e, a), l = i ? e.videoWidth - r.x - r.width : r.x, u = r.y;
47
88
  return {
48
- height: t.height / a * s.height,
49
- width: t.width / o * s.width,
50
- x: l / o * s.width + c.x,
51
- y: u / a * s.height + c.y
89
+ height: r.height / e.videoHeight * a.height,
90
+ width: r.width / e.videoWidth * a.width,
91
+ x: l / e.videoWidth * a.width + c.x,
92
+ y: u / e.videoHeight * a.height + c.y
52
93
  };
53
94
  }
54
- function convertToVideoArea(e, t) {
55
- let i = /scaleX\(-1\)/.test(e.style.transform), a = e.videoHeight, o = e.videoWidth, s = getVideoRenderedSize(e), c = getVideoRenderedOffset(e, s), l = o / s.width, u = a / s.height, d = t.x - c.x, f = i ? s.width - d - t.width : d, p = t.y - c.y;
95
+ function translateAreaToVideoSource(e, r) {
96
+ let i = /scaleX\(-1\)/.test(e.style.transform), a = getVideoRenderSize(e), c = getVideoRenderOffset(e, a), l = i ? a.width - (r.x - c.x) - r.width : r.x - c.x, u = r.y - c.y, d = e.videoHeight / a.height, f = e.videoWidth / a.width;
56
97
  return {
57
- height: t.height * u,
58
- width: t.width * l,
59
- x: f * l,
60
- y: p * u
98
+ height: r.height * d,
99
+ width: r.width * f,
100
+ x: l * f,
101
+ y: u * d
61
102
  };
62
103
  }
63
- function isBarcodeDetectorAvailable(e) {
64
- return "BarcodeDetector" in e;
104
+ function wait(e) {
105
+ return new Promise((r) => setTimeout(r, e));
65
106
  }
66
- var utils_exports = /* @__PURE__ */ __export({
67
- convertToElementArea: () => convertToElementArea,
68
- convertToVideoArea: () => convertToVideoArea,
69
- getVideoRenderedOffset: () => getVideoRenderedOffset,
70
- getVideoRenderedSize: () => getVideoRenderedSize,
71
- isBarcodeDetectorAvailable: () => isBarcodeDetectorAvailable
72
- }, 1), BarcodeScanner = class {
73
- calcScanArea;
74
- canvas;
75
- canvasContext;
76
- debug;
77
- decodeFrameRequestTimestamp;
78
- decodeTimeout;
79
- isDecodeFrameProcessed;
80
- isDestroyed;
81
- onDecode;
82
- onDecodeError;
83
- onVisibilityChange;
84
- requestFrame;
85
- resumeOnVisibilityChange;
86
- scanArea;
87
- scanRate;
88
- video;
89
- videoActive;
90
- videoPaused;
91
- worker;
92
- constructor({ onDecode: e, onDecodeError: t, options: n, video: r }) {
93
- if (r && !(r instanceof HTMLVideoElement)) throw Error("video is not a HTMLVideoElement");
94
- if (e && !(e instanceof Function)) throw Error("onDecode is not a function");
95
- if (t && !(t instanceof Function)) throw Error("onDecodeError is not a function");
96
- this.canvas = document.createElement("canvas");
97
- let i = this.canvas.getContext("2d", { willReadFrequently: !0 });
98
- if (!i) throw Error("Failed to get canvas context");
99
- this.calcScanArea = n?.calcScanArea ?? this.getScanArea, this.canvasContext = i, this.debug = n?.debug, this.decodeTimeout = n?.decodeTimeout ?? 1e3, this.isDecodeFrameProcessed = !1, this.isDestroyed = !1, this.onDecode = e, this.onDecodeError = t, this.requestFrame = r.requestVideoFrameCallback ? r.requestVideoFrameCallback.bind(r) : requestAnimationFrame, this.decodeFrameRequestTimestamp = performance.now(), this.resumeOnVisibilityChange = !1, this.scanArea = this.calcScanArea(r), this.scanRate = n?.scanRate ?? 24, this.video = r, this.video.autoplay = !0, this.video.disablePictureInPicture = !0, this.video.hidden = !1, this.video.muted = !0, this.video.playsInline = !0, this.videoActive = !1, this.videoPaused = !1, this.onVisibilityChange = () => {
100
- document.visibilityState === "hidden" ? (this.videoActive && this.videoPaused === !1 && (this.resumeOnVisibilityChange = !0), this.pause()) : this.resumeOnVisibilityChange && (this.resumeOnVisibilityChange = !1, this.start());
101
- }, document.addEventListener("visibilitychange", this.onVisibilityChange), this.worker = new Worker(new URL(
102
- /* @vite-ignore */
103
- "" + new URL("barcode-scanner.worker.js", import.meta.url).href,
104
- "" + import.meta.url
105
- ), { type: "module" });
106
- }
107
- decode(e) {
108
- if (!(e instanceof ImageData)) throw Error("Invalid decode data");
109
- let t = `${performance.now()}-${Math.random().toString(36).slice(2)}`;
110
- return new Promise((n, r) => {
111
- let i = 0, a = ({ data: { data: e, uuid: r } }) => {
112
- r === t && (clearTimeout(i), this.worker.removeEventListener("message", a), n(e));
113
- };
114
- i = setTimeout(() => {
115
- this.worker.removeEventListener("message", a), r(null);
116
- }, this.decodeTimeout), this.worker.addEventListener("message", a), this.worker.postMessage({
107
+ var Dt = [
108
+ ["Aztec", "M"],
109
+ ["Codabar", "L"],
110
+ ["Code39", "L"],
111
+ ["Code93", "L"],
112
+ ["Code128", "L"],
113
+ ["DataBar", "L"],
114
+ ["DataBarExpanded", "L"],
115
+ ["DataMatrix", "M"],
116
+ ["EAN-8", "L"],
117
+ ["EAN-13", "L"],
118
+ ["ITF", "L"],
119
+ ["MaxiCode", "M"],
120
+ ["PDF417", "M"],
121
+ ["QRCode", "M"],
122
+ ["UPC-A", "L"],
123
+ ["UPC-E", "L"],
124
+ ["MicroQRCode", "M"],
125
+ ["rMQRCode", "M"],
126
+ ["DXFilmEdge", "L"],
127
+ ["DataBarLimited", "L"]
128
+ ], Mt = Dt.map(([e]) => e);
129
+ Mt.filter((e, r) => Dt[r][1] === "L"), Mt.filter((e, r) => Dt[r][1] === "M");
130
+ var It = {
131
+ formats: [],
132
+ tryHarder: !0,
133
+ tryRotate: !0,
134
+ tryInvert: !0,
135
+ tryDownscale: !0,
136
+ tryDenoise: !1,
137
+ binarizer: "LocalAverage",
138
+ isPure: !1,
139
+ downscaleFactor: 3,
140
+ downscaleThreshold: 500,
141
+ minLineCount: 2,
142
+ maxNumberOfSymbols: 255,
143
+ tryCode39ExtendedMode: !0,
144
+ returnErrors: !1,
145
+ eanAddOnSymbol: "Ignore",
146
+ textMode: "HRI",
147
+ characterSet: "Unknown"
148
+ };
149
+ ({ ...It }), [...It.formats], [...[
150
+ ["aztec", "Aztec"],
151
+ ["code_128", "Code128"],
152
+ ["code_39", "Code39"],
153
+ ["code_93", "Code93"],
154
+ ["codabar", "Codabar"],
155
+ ["databar", "DataBar"],
156
+ ["databar_expanded", "DataBarExpanded"],
157
+ ["databar_limited", "DataBarLimited"],
158
+ ["data_matrix", "DataMatrix"],
159
+ ["dx_film_edge", "DXFilmEdge"],
160
+ ["ean_13", "EAN-13"],
161
+ ["ean_8", "EAN-8"],
162
+ ["itf", "ITF"],
163
+ ["maxi_code", "MaxiCode"],
164
+ ["micro_qr_code", "MicroQRCode"],
165
+ ["pdf417", "PDF417"],
166
+ ["qr_code", "QRCode"],
167
+ ["rm_qr_code", "rMQRCode"],
168
+ ["upc_a", "UPC-A"],
169
+ ["upc_e", "UPC-E"],
170
+ ["linear_codes", "Linear-Codes"],
171
+ ["matrix_codes", "Matrix-Codes"],
172
+ ["any", "Any"]
173
+ ], ["unknown"]].map((e) => e[0]);
174
+ var instance = { value: null };
175
+ async function decode(e) {
176
+ let r = instance.value;
177
+ if (!r) throw Error("Worker not installed");
178
+ let i = `${performance.now()}-${Math.random().toString(36).slice(2)}`;
179
+ return new Promise((a, o) => {
180
+ let s = 0, c = ({ data: { payload: e, type: o } }) => {
181
+ o !== "decode" || e.uuid !== i || (clearTimeout(s), r.removeEventListener("message", c), a(e.data));
182
+ };
183
+ s = setTimeout(() => {
184
+ r.removeEventListener("message", c), o(null);
185
+ }, 1e3), r.addEventListener("message", c), r.postMessage({
186
+ payload: {
117
187
  data: e,
118
- uuid: t
119
- });
188
+ uuid: i
189
+ },
190
+ type: "decode"
120
191
  });
192
+ });
193
+ }
194
+ function install() {
195
+ if (instance.value) return Promise.resolve(instance.value);
196
+ let e = new Worker(new URL(
197
+ /* @vite-ignore */
198
+ "" + new URL("worker.js", import.meta.url).href,
199
+ "" + import.meta.url
200
+ ), { type: "module" });
201
+ return new Promise((r, i) => {
202
+ e.addEventListener("message", ({ data: { type: a } }) => {
203
+ a === "init" ? r(e) : i(/* @__PURE__ */ Error("Worker load failed"));
204
+ }, { once: !0 }), instance.value = e;
205
+ });
206
+ }
207
+ function createBarcodeScanner(r, { calcScanArea: o } = {}) {
208
+ if (!(r instanceof HTMLVideoElement)) throw Error("video is not a HTMLVideoElement");
209
+ let s = document.createElement("canvas"), c = s.getContext("2d", { willReadFrequently: !0 });
210
+ if (!c) throw Error("Failed to get canvas context");
211
+ let { state: u, watch: d } = createWatchable({
212
+ calcScanArea: o ?? getScanArea,
213
+ canvas: s,
214
+ canvasContext: c,
215
+ debug: !0,
216
+ decodeFrameRequestTimestamp: performance.now(),
217
+ facingMode: "environment",
218
+ isDecodeFrameProcessed: !1,
219
+ isDestroyed: !1,
220
+ isReady: !1,
221
+ isVideoActive: !1,
222
+ isVideoPaused: !1,
223
+ onDecodeFailure: () => {},
224
+ onDecodeSuccess: () => {},
225
+ requestFrame: r.requestVideoFrameCallback ? r.requestVideoFrameCallback.bind(r) : requestAnimationFrame,
226
+ resumeOnVisibilityChange: !1,
227
+ scanArea: {
228
+ height: 0,
229
+ width: 0,
230
+ x: 0,
231
+ y: 0
232
+ },
233
+ scanRate: 24,
234
+ video: r,
235
+ worker: null
236
+ });
237
+ install().then((e) => u.worker = e).then(() => Promise.resolve()).then(() => u.isReady = !0), u.video.autoplay = !0, u.video.disablePictureInPicture = !0, u.video.hidden = !1, u.video.muted = !0, u.video.playsInline = !0, document.addEventListener("visibilitychange", f);
238
+ function f() {
239
+ document.visibilityState === "hidden" ? u.isVideoActive && u.isVideoPaused === !1 && (u.resumeOnVisibilityChange = !0, h()) : u.resumeOnVisibilityChange && (u.resumeOnVisibilityChange = !1, g({ facingMode: u.facingMode }, u.onDecodeSuccess, u.onDecodeFailure));
121
240
  }
122
- async destroy() {
123
- this.isDestroyed ||= (await this.stop(), document.removeEventListener("visibilitychange", this.onVisibilityChange), this.worker.terminate(), !0);
124
- }
125
- async getCameraAccess() {
126
- if (await this.hasCameraAccess()) return !0;
127
- try {
128
- let e = (await navigator.mediaDevices.getUserMedia({ video: !0 })).getTracks();
129
- for (let t of e) t.stop();
130
- return !0;
131
- } catch {
132
- return !1;
133
- }
134
- }
135
- getScanArea(e) {
136
- let t = Math.round(2 / 3 * Math.min(e.videoWidth, e.videoHeight));
137
- return {
138
- height: t,
139
- width: t,
140
- x: Math.round((e.videoWidth - t) / 2),
141
- y: Math.round((e.videoHeight - t) / 2)
142
- };
143
- }
144
- async hasCameraAccess() {
145
- try {
146
- return (await navigator.permissions.query({ name: "camera" })).state === "granted";
147
- } catch {
148
- return (await navigator.mediaDevices.enumerateDevices()).filter((e) => e.deviceId && e.kind === "videoinput").length > 0;
149
- }
150
- }
151
- pause() {
152
- this.canvas.height = this.video.videoHeight, this.canvas.width = this.video.videoWidth, this.canvasContext.clearRect(0, 0, this.canvas.width, this.canvas.height), this.canvasContext.drawImage(this.video, 0, 0, this.canvas.width, this.canvas.height, 0, 0, this.canvas.width, this.canvas.height), this.video.poster = this.canvas.toDataURL(), this.video.srcObject instanceof MediaStream && this.video.srcObject.getTracks().forEach((e) => e.stop()), this.video.srcObject = null, this.videoPaused = !0;
153
- }
154
- async start({ facingMode: e = "environment" } = {}) {
155
- if (!await this.getCameraAccess()) throw Error("No camera access");
156
- this.video.srcObject instanceof MediaStream && this.videoActive && this.videoPaused === !1 || (this.video.srcObject instanceof MediaStream || (this.video.srcObject = await navigator.mediaDevices.getUserMedia({ video: { facingMode: e } })), await this.video.play(), this.video.style.transform = e === "user" ? "scaleX(-1)" : "none", this.videoActive = !0, this.videoPaused = !1, this.decodeFrame());
157
- }
158
- async stop() {
159
- this.video.srcObject instanceof MediaStream && this.video.srcObject.getTracks().forEach((e) => e.stop()), this.video.poster = "", this.video.srcObject = null, this.videoActive = !1, this.videoPaused = !1;
160
- }
161
- decodeFrame() {
162
- this.isDestroyed || this.videoActive === !1 || this.videoPaused || this.requestFrame(() => {
163
- if (performance.now() - this.decodeFrameRequestTimestamp < 1e3 / this.scanRate || this.isDecodeFrameProcessed || this.video.ended || this.video.paused || this.video.readyState <= 1) {
164
- this.decodeFrameRequestTimestamp = performance.now(), this.decodeFrame();
241
+ function p(e, r) {
242
+ u.isDestroyed || u.isVideoActive === !1 || u.isVideoPaused || u.requestFrame(() => {
243
+ if (performance.now() - u.decodeFrameRequestTimestamp < 1e3 / u.scanRate || u.isDecodeFrameProcessed || u.video.ended || u.video.paused || u.video.readyState <= 1) {
244
+ u.decodeFrameRequestTimestamp = performance.now(), p(e, r);
165
245
  return;
166
246
  }
167
- this.isDecodeFrameProcessed = !0, this.scanArea = this.calcScanArea(this.video), this.canvas.height = this.scanArea.height, this.canvas.width = this.scanArea.width, this.canvasContext.clearRect(0, 0, this.canvas.width, this.canvas.height), this.canvasContext.drawImage(this.video, this.scanArea.x, this.scanArea.y, this.scanArea.width, this.scanArea.height, 0, 0, this.canvas.width, this.canvas.height);
168
- let e = this.canvasContext.getImageData(0, 0, this.canvas.width, this.canvas.height);
169
- this.debug && window.dispatchEvent(new CustomEvent("barcode-scanner:decode-frame", { detail: { imageData: e } })), this.decode(e).then((e) => {
170
- if (e) {
171
- let t = e.cornerPoints.map((e) => e.x), n = e.cornerPoints.map((e) => e.y);
172
- this.onDecode(e.rawValue, convertToElementArea(this.video, {
173
- height: Math.max(...n) - Math.min(...n),
174
- width: Math.max(...t) - Math.min(...t),
175
- x: Math.min(...t) + this.scanArea.x,
176
- y: Math.min(...n) + this.scanArea.y
247
+ u.isDecodeFrameProcessed = !0, u.scanArea = u.calcScanArea(u.video), u.canvas.height = u.scanArea.height, u.canvas.width = u.scanArea.width, u.canvasContext.clearRect(0, 0, u.canvas.width, u.canvas.height), u.canvasContext.drawImage(u.video, u.scanArea.x, u.scanArea.y, u.scanArea.width, u.scanArea.height, 0, 0, u.canvas.width, u.canvas.height);
248
+ let i = u.canvasContext.getImageData(0, 0, u.canvas.width, u.canvas.height);
249
+ u.debug && window.dispatchEvent(new CustomEvent("barcode-scanner:decode-frame", { detail: { imageData: i } })), decode(i).then((i) => {
250
+ if (i) {
251
+ let r = i.cornerPoints.map((e) => e.x), a = i.cornerPoints.map((e) => e.y);
252
+ e(i.rawValue, translateAreaToVideoRender(u.video, {
253
+ height: Math.max(...a) - Math.min(...a),
254
+ width: Math.max(...r) - Math.min(...r),
255
+ x: Math.min(...r) + u.scanArea.x,
256
+ y: Math.min(...a) + u.scanArea.y
177
257
  }));
178
- } else this.onDecode(null, convertToElementArea(this.video, this.scanArea));
258
+ } else r();
179
259
  }).catch(() => {
180
- this.onDecodeError?.();
260
+ console.error("Failed to decode barcode");
181
261
  }).finally(() => {
182
- this.isDecodeFrameProcessed = !1, this.decodeFrameRequestTimestamp = performance.now(), this.decodeFrame();
262
+ u.isDecodeFrameProcessed = !1, u.decodeFrameRequestTimestamp = performance.now(), p(e, r);
183
263
  });
184
264
  });
185
265
  }
186
- }, lib_default = BarcodeScanner;
187
- export { BarcodeScanner, lib_default as default, utils_exports as utils };
266
+ async function m() {
267
+ u.isDestroyed || (_(), document.removeEventListener("visibilitychange", f), u.worker?.terminate(), u.worker = null, u.isDestroyed = !0, u.isReady = !1);
268
+ }
269
+ function h() {
270
+ u.canvas.height = u.video.videoHeight, u.canvas.width = u.video.videoWidth, u.canvasContext.clearRect(0, 0, u.canvas.width, u.canvas.height), u.canvasContext.drawImage(u.video, 0, 0, u.canvas.width, u.canvas.height, 0, 0, u.canvas.width, u.canvas.height), u.video.poster = u.canvas.toDataURL(), u.video.srcObject instanceof MediaStream && u.video.srcObject.getTracks().forEach((e) => e.stop()), u.video.srcObject = null, u.isVideoPaused = !0;
271
+ }
272
+ async function g({ facingMode: e = "environment" } = {}, r, a = () => {}) {
273
+ if (!await getCameraAccess()) throw Error("No camera access");
274
+ u.video.srcObject instanceof MediaStream && u.isVideoActive && u.isVideoPaused === !1 || (u.video.srcObject instanceof MediaStream || (u.video.srcObject = await navigator.mediaDevices.getUserMedia({ video: { facingMode: e } })), await u.video.play(), u.facingMode = e, u.isVideoActive = !0, u.isVideoPaused = !1, u.onDecodeFailure = a, u.onDecodeSuccess = r, u.scanArea = u.calcScanArea(u.video), u.video.style.transform = e === "user" ? "scaleX(-1)" : "none", p(r, a));
275
+ }
276
+ function _() {
277
+ u.video.srcObject instanceof MediaStream && u.video.srcObject.getTracks().forEach((e) => e.stop()), u.video.poster = "", u.video.srcObject = null, u.isVideoActive = !1, u.isVideoPaused = !1;
278
+ }
279
+ return {
280
+ destroy: m,
281
+ pause: h,
282
+ start: g,
283
+ state: u,
284
+ stop: _,
285
+ watch: d
286
+ };
287
+ }
288
+ var lib_default = createBarcodeScanner;
289
+ export { createBarcodeScanner, lib_default as default, getCameraAccess, getScanArea, getVideoRenderOffset, getVideoRenderSize, hasCameraAccess, isBarcodeDetectorAvailable, translateAreaToVideoRender, translateAreaToVideoSource, wait };
@@ -0,0 +1,2 @@
1
+ declare function getCameraAccess(): Promise<boolean>;
2
+ export { getCameraAccess };
@@ -0,0 +1,9 @@
1
+ type ScanArea = {
2
+ height: number;
3
+ width: number;
4
+ x: number;
5
+ y: number;
6
+ };
7
+ declare function getScanArea(video: HTMLVideoElement): ScanArea;
8
+ export type { ScanArea };
9
+ export { getScanArea };
@@ -0,0 +1,8 @@
1
+ import type { RenderSize } from './get-video-render-size';
2
+ type RenderOffset = {
3
+ x: number;
4
+ y: number;
5
+ };
6
+ declare function getVideoRenderOffset(video: HTMLVideoElement, renderSize: RenderSize): RenderOffset;
7
+ export type { RenderOffset };
8
+ export { getVideoRenderOffset };
@@ -0,0 +1,7 @@
1
+ type RenderSize = {
2
+ height: number;
3
+ width: number;
4
+ };
5
+ declare function getVideoRenderSize(video: HTMLVideoElement): RenderSize;
6
+ export type { RenderSize };
7
+ export { getVideoRenderSize };
@@ -0,0 +1,2 @@
1
+ declare function hasCameraAccess(): Promise<boolean>;
2
+ export { hasCameraAccess };
@@ -1,5 +1,9 @@
1
- export * from './convert-to-element-area';
2
- export * from './convert-to-video-area';
3
- export * from './get-video-rendered-offset';
4
- export * from './get-video-rendered-size';
1
+ export * from './get-camera-access';
2
+ export * from './get-scan-area';
3
+ export * from './get-video-render-offset';
4
+ export * from './get-video-render-size';
5
+ export * from './has-camera-access';
5
6
  export * from './is-barcode-detector-available';
7
+ export * from './translate-area-to-video-render';
8
+ export * from './translate-area-to-video-source';
9
+ export * from './wait';
@@ -1,5 +1,7 @@
1
- import type { BarcodeDetector } from '../barcode-detector.type';
1
+ import type { BarcodeDetector, BarcodeDetectorOptions } from 'barcode-detector/ponyfill';
2
2
  declare function isBarcodeDetectorAvailable<T extends object>(value: T): value is {
3
- BarcodeDetector: BarcodeDetector;
3
+ BarcodeDetector: {
4
+ new (barcodeDetectorOptions?: BarcodeDetectorOptions): BarcodeDetector;
5
+ } & BarcodeDetector;
4
6
  } & T;
5
7
  export { isBarcodeDetectorAvailable };
@@ -0,0 +1,3 @@
1
+ import type { ScanArea } from './get-scan-area';
2
+ declare function translateAreaToVideoRender(video: HTMLVideoElement, area: ScanArea): ScanArea;
3
+ export { translateAreaToVideoRender };
@@ -0,0 +1,3 @@
1
+ import type { ScanArea } from './get-scan-area';
2
+ declare function translateAreaToVideoSource(video: HTMLVideoElement, area: ScanArea): ScanArea;
3
+ export { translateAreaToVideoSource };
@@ -0,0 +1,2 @@
1
+ declare function wait(ms: number): Promise<unknown>;
2
+ export { wait };
@@ -0,0 +1,3 @@
1
+ export * from './worker.decode';
2
+ export * from './worker.install';
3
+ export * from './worker.instance';
@@ -0,0 +1,3 @@
1
+ import { type DetectedBarcode } from 'barcode-detector/ponyfill';
2
+ declare function decode(imageData: ImageData): Promise<DetectedBarcode | null>;
3
+ export { decode };
@@ -0,0 +1,2 @@
1
+ declare function install(): Promise<Worker>;
2
+ export { install };
@@ -0,0 +1,4 @@
1
+ declare const instance: {
2
+ value: null | Worker;
3
+ };
4
+ export { instance };
@@ -0,0 +1,16 @@
1
+ import type { DetectedBarcode } from 'barcode-detector/ponyfill';
2
+ type DecodeReq = {
3
+ payload: {
4
+ data: ImageData;
5
+ uuid: string;
6
+ };
7
+ type: 'decode';
8
+ };
9
+ type DecodeRes = {
10
+ payload: {
11
+ data: DetectedBarcode | null;
12
+ uuid: string;
13
+ };
14
+ type: 'decode';
15
+ };
16
+ export type { DecodeReq, DecodeRes };