@hxa-rn/vision-camera-code-scanner 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 hxa-rn
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,179 @@
1
+ 本项目基于 [vision-camera-code-scanner](https://github.com/rodgomesc/vision-camera-code-scanner) 开发。如果在使用过程中有任何问题,欢迎在 AtomGit 提交 Issue,会及时跟进。
2
+
3
+ ## 项目介绍
4
+
5
+ `@hxa-rn/vision-camera-code-scanner` 是 vision-camera-code-scanner 的鸿蒙(OpenHarmony)适配包,当前规范版本号为 **0.2.0**(与上游 0.2.0 对齐)。
6
+
7
+ 本模块采用 **js-only 纯 JS 重实现**(无原生代码、不生成 HAR)。鸿蒙版 `@react-native-ohos/react-native-vision-camera` v4 不提供 Frame Processor 插件机制,因此改为在 JS 层包装 vision-camera 内置 `useCodeScanner` / `Camera.codeScanner`(底层 Scan Kit `customScan`)实现实时扫码。
8
+
9
+ | 鸿蒙适配包版本 | 原始库版本 | 支持 RN 版本 | Autolink | 编译 API 版本 |
10
+ | -------------- | ---------- | ------------ | -------- | ------------- |
11
+ | 0.2.0 | 0.2.0 | 0.72 | 是 | API 12+ |
12
+
13
+ ## 集成指南
14
+
15
+ ```bash
16
+ npm install @hxa-rn/vision-camera-code-scanner @react-native-ohos/react-native-vision-camera@~4.0.3
17
+ ```
18
+
19
+ 鸿蒙端模块通过 `harmony.alias` 将 `vision-camera-code-scanner` 重定向到 `@hxa-rn/vision-camera-code-scanner`,`react-native-vision-camera` 重定向到 `@react-native-ohos/react-native-vision-camera`。源码中 import 名保持不变。
20
+
21
+ 模块为 js-only,无原生 HAR;依赖的原生能力由 `@react-native-ohos/react-native-vision-camera` 提供,其 Autolink 自动完成注册。
22
+
23
+ ## 使用说明
24
+
25
+ ```tsx
26
+ import { useEffect } from 'react';
27
+ import { StyleSheet } from 'react-native';
28
+ import { Camera, useCameraDevice } from 'react-native-vision-camera';
29
+ import { useScanBarcodes, BarcodeFormat } from 'vision-camera-code-scanner';
30
+
31
+ export default function App() {
32
+ const device = useCameraDevice('back');
33
+ const [codeScanner, barcodes, clearBarcodes] = useScanBarcodes([
34
+ BarcodeFormat.ALL_FORMATS,
35
+ ]);
36
+
37
+ useEffect(() => {
38
+ Camera.requestCameraPermission();
39
+ }, []);
40
+
41
+ useEffect(() => {
42
+ return () => {
43
+ clearBarcodes();
44
+ };
45
+ }, [clearBarcodes]);
46
+
47
+ return (
48
+ device != null && (
49
+ <Camera
50
+ style={StyleSheet.absoluteFill}
51
+ device={device}
52
+ isActive={true}
53
+ codeScanner={codeScanner}
54
+ />
55
+ )
56
+ );
57
+ }
58
+ ```
59
+
60
+ **鸿蒙端 API 变更**:返回值从 `[frameProcessor, barcodes]` 变为 `[codeScanner, barcodes, clearBarcodes]`。调用方需将 `codeScanner` 传给 `<Camera codeScanner={codeScanner}>`。停止扫描或组件卸载时应调用 `clearBarcodes()`,避免下次开始扫描时把上次结果当作新识别上报。`barcodes` 为当前识别结果列表,可按业务自行展示。
61
+
62
+ ## 接口文档
63
+
64
+ ### `useScanBarcodes` 返回值变更
65
+
66
+ | 平台 | 返回值 | 传给 Camera 的属性 |
67
+ |------|--------|-------------------|
68
+ | Android / iOS | `[frameProcessor, barcodes]` | `<Camera frameProcessor={fp} />` |
69
+ | **HarmonyOS** | `[codeScanner, barcodes, clearBarcodes]` | `<Camera codeScanner={sc} />` |
70
+
71
+ ### 属性 / API
72
+
73
+ | API | 描述 | 参数 | 返回值 | HarmonyOS 支持 |
74
+ |-----|------|------|--------|----------------|
75
+ | `useScanBarcodes` | 声明式扫码钩子 | `types: BarcodeFormat[]`、`options?: CodeScannerOptions` | `[CodeScanner, Barcode[], () => void]` | ✅ |
76
+ | `scanBarcodes` | Frame Processor 工作集函数 | `frame`、`types`、`options` | `Barcode[]` | ❌(抛错 stub) |
77
+ | `BarcodeFormat` | 条码格式枚举 | — | — | ✅(数值不变) |
78
+ | `CodeScannerOptions.checkInverted` | 反色条码识别 | `boolean` | — | ❌(忽略) |
79
+ | `Barcode.content` 结构化解析 | 联系人/WiFi/日历/驾照等 | — | — | ⚠️ 降级为 `{type: TEXT, data: rawValue}` |
80
+
81
+ ### 不支持功能(明确降级)
82
+
83
+ 1. **`scanBarcodes` 工作集函数**:鸿蒙 vision-camera v4 无 Frame Processor 插件机制,请使用 `useScanBarcodes` 返回的 `codeScanner`。
84
+ 2. **`checkInverted` 反色条码**:Scan Kit `customScan` / `decodeImage` 均无图像取反识别选项,该选项在鸿蒙端被忽略。
85
+ 3. **条码内容结构化解析**:Scan Kit `ScanResult` 仅返回 `originalValue` / `scanType` / `scanCodeRect` / `cornerPoints`,`Barcode.content` 统一降级为 `{ type: BarcodeValueType.TEXT, data: rawValue }`。
86
+
87
+ ### 上游 codeType→ScanType 映射缺陷补偿
88
+
89
+ 鸿蒙版 vision-camera(4.0.3 / 4.7.1)`ScanManager.codeType` 数组多插了 `'itf-14'` 条目,导致 QR/PDF417/UPC_A/UPC_E 四种格式偏移 1。本模块在 JS 层实现双向补偿映射:
90
+
91
+ - 请求方向:`QR_CODE→'pdf-417'`、`PDF417→'itf-14'`、`UPC_A→'qr'`、`UPC_E→'upc-a'`
92
+ - 上报方向:反向翻译回原 `BarcodeFormat`
93
+
94
+ ## 快速验证(运行 Example)
95
+
96
+ ### 前置条件
97
+
98
+ | 依赖 | 版本要求 |
99
+ |------|----------|
100
+ | Node.js | >= 18 |
101
+ | DevEco Studio | 5.0+ |
102
+ | HarmonyOS SDK | API 12+ |
103
+
104
+ ### 运行步骤
105
+
106
+ **1. 克隆仓库**
107
+
108
+ ```bash
109
+ git clone https://gitcode.com/hxa-rn/vision-camera-code-scanner.git
110
+ cd vision-camera-code-scanner
111
+ git checkout br_rnoh0.72
112
+ ```
113
+
114
+ **2. 安装仓库开发依赖**
115
+
116
+ ```bash
117
+ npm install --legacy-peer-deps
118
+ ```
119
+
120
+ Example 已改为从 npm 公仓安装 `@hxa-rn/vision-camera-code-scanner@0.2.0`,不再使用本地 `file:../xxx.tgz`,运行 Example 不必再执行 `npm pack`。
121
+
122
+ **3. 进入 example 目录,安装依赖**
123
+
124
+ ```bash
125
+ cd example # 或 example_auto
126
+ npm install --legacy-peer-deps
127
+ ```
128
+
129
+ **4. 生成 JS Bundle**
130
+
131
+ ```bash
132
+ npm run dev
133
+ ```
134
+
135
+ 产物:`harmony/entry/src/main/resources/rawfile/bundle.harmony.js`
136
+
137
+ **5. 用 DevEco Studio 打开鸿蒙工程**
138
+
139
+ - 打开 DevEco Studio
140
+ - 选择 `example/harmony` 或 `example_auto/harmony` 目录
141
+ - 等待 Sync 完成
142
+
143
+ **6. 编译并运行 HAP**
144
+
145
+ 在 DevEco Studio 中点击运行按钮,将 HAP 安装到设备/模拟器。
146
+
147
+ > **注意**:Example 中已预置插件依赖和 Package 注册,无需手动配置 Link。相机权限 `ohos.permission.CAMERA` 已在 Example 的 `entry` module.json5 中声明。
148
+
149
+ ## 约束与限制
150
+
151
+ **兼容性**
152
+
153
+ - RNOH: 0.72
154
+ - HarmonyOS SDK: API 12+
155
+ - DevEco Studio: 5.0+
156
+ - 依赖 `@react-native-ohos/react-native-vision-camera` ~4.0.3(RN 0.72 线)
157
+
158
+ **权限**
159
+
160
+ - 宿主应用需声明 `ohos.permission.CAMERA`(本库不单独声明系统权限)
161
+
162
+ **已知差异**
163
+
164
+ - 鸿蒙内置 `codeScanner`(Scan Kit customScan)会叠加自定义扫码界面(扫描框/闪光灯/相册入口),视觉表现与 Android/iOS 的无 UI 帧处理器插件不同。
165
+ - `boundingBox` / `cornerPoints` 来自 Scan Kit 的 `scanCodeRect`(画面坐标,不是二维码 payload)。
166
+ - `useCameraDevice('back')` / `Camera.requestCameraPermission()` 返回 `'granted'` 等 v4 权限语义(非 v2 的 `'authorized'`)。
167
+ - `customScan` 不支持并行调用,需按 Camera 生命周期启停。
168
+
169
+ ## 开源license
170
+
171
+ 本项目基于 MIT 协议,详见 [LICENSE](LICENSE) 文件。
172
+
173
+ ## 问题反馈渠道
174
+
175
+ 使用问题请在 AtomGit 提交 Issue。也可在 GitCode 仓库反馈:
176
+
177
+ https://gitcode.com/hxa-rn/vision-camera-code-scanner
178
+
179
+ https://gitcode.com/hxa-rn/vision-camera-code-scanner/issues
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useScanBarcodes = useScanBarcodes;
7
+ var _reactNativeVisionCamera = require("react-native-vision-camera");
8
+ var _react = require("react");
9
+ var _ = require(".");
10
+ /**
11
+ * 鸿蒙端 useScanBarcodes 重实现。
12
+ *
13
+ * 鸿蒙版 @react-native-ohos/react-native-vision-camera v4 不提供 Frame Processor 机制
14
+ * (不导出 useFrameProcessor / FrameProcessorPlugin),但内置 useCodeScanner + Camera.codeScanner
15
+ * (底层为 Scan Kit customScan)。因此本 hook 基于 useCodeScanner 构造扫码器,在 onCodeScanned
16
+ * 回调中把 Code[] 转换为原 API 的 Barcode[]。
17
+ *
18
+ * ⚠️ API 变更:返回值从 `[frameProcessor, barcodes]` 变为 `[codeScanner, barcodes, clearBarcodes]`。
19
+ * 调用方需将 codeScanner 传给 `<Camera codeScanner={codeScanner}>`,而非 frameProcessor。
20
+ * 停止扫描时应调用 clearBarcodes(),避免下次开始扫描时把上次结果当作新识别上报。
21
+ *
22
+ * @param types 要检测的条码格式数组;包含 ALL_FORMATS 或为空数组时检测所有格式。
23
+ * @param options 扫描选项;checkInverted(反色条码)在鸿蒙端被忽略(Scan Kit 无反色识别选项)。
24
+ * @returns [codeScanner, barcodes, clearBarcodes]
25
+ */
26
+ function useScanBarcodes(types, _options) {
27
+ const [barcodes, setBarcodes] = (0, _react.useState)([]);
28
+ const clearBarcodes = (0, _react.useCallback)(() => {
29
+ setBarcodes([]);
30
+ }, []);
31
+ const codeScanner = (0, _reactNativeVisionCamera.useCodeScanner)({
32
+ codeTypes: (0, _.mapFormatsToCodeTypes)(types),
33
+ onCodeScanned: (codes, _frame) => {
34
+ setBarcodes(codes.map(code => (0, _.normalizeReportedBarcode)((0, _.toBarcode)(code), types)));
35
+ }
36
+ });
37
+ return [codeScanner, barcodes, clearBarcodes];
38
+ }
39
+ //# sourceMappingURL=hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_reactNativeVisionCamera","require","_react","_","useScanBarcodes","types","_options","barcodes","setBarcodes","useState","clearBarcodes","useCallback","codeScanner","useCodeScanner","codeTypes","mapFormatsToCodeTypes","onCodeScanned","codes","_frame","map","code","normalizeReportedBarcode","toBarcode"],"sources":["hook.tsx"],"sourcesContent":["import { Code, CodeScanner, CodeScannerFrame, useCodeScanner } from 'react-native-vision-camera';\r\nimport { useCallback, useState } from 'react';\r\n\r\nimport {\r\n Barcode,\r\n BarcodeFormat,\r\n CodeScannerOptions,\r\n mapFormatsToCodeTypes,\r\n normalizeReportedBarcode,\r\n toBarcode,\r\n} from '.';\r\n\r\n/**\r\n * 鸿蒙端 useScanBarcodes 重实现。\r\n *\r\n * 鸿蒙版 @react-native-ohos/react-native-vision-camera v4 不提供 Frame Processor 机制\r\n * (不导出 useFrameProcessor / FrameProcessorPlugin),但内置 useCodeScanner + Camera.codeScanner\r\n * (底层为 Scan Kit customScan)。因此本 hook 基于 useCodeScanner 构造扫码器,在 onCodeScanned\r\n * 回调中把 Code[] 转换为原 API 的 Barcode[]。\r\n *\r\n * ⚠️ API 变更:返回值从 `[frameProcessor, barcodes]` 变为 `[codeScanner, barcodes, clearBarcodes]`。\r\n * 调用方需将 codeScanner 传给 `<Camera codeScanner={codeScanner}>`,而非 frameProcessor。\r\n * 停止扫描时应调用 clearBarcodes(),避免下次开始扫描时把上次结果当作新识别上报。\r\n *\r\n * @param types 要检测的条码格式数组;包含 ALL_FORMATS 或为空数组时检测所有格式。\r\n * @param options 扫描选项;checkInverted(反色条码)在鸿蒙端被忽略(Scan Kit 无反色识别选项)。\r\n * @returns [codeScanner, barcodes, clearBarcodes]\r\n */\r\nexport function useScanBarcodes(\r\n types: BarcodeFormat[],\r\n _options?: CodeScannerOptions\r\n): [CodeScanner, Barcode[], () => void] {\r\n const [barcodes, setBarcodes] = useState<Barcode[]>([]);\r\n\r\n const clearBarcodes = useCallback(() => {\r\n setBarcodes([]);\r\n }, []);\r\n\r\n const codeScanner = useCodeScanner({\r\n codeTypes: mapFormatsToCodeTypes(types),\r\n onCodeScanned: (codes: Code[], _frame: CodeScannerFrame) => {\r\n setBarcodes(\r\n codes.map((code) => normalizeReportedBarcode(toBarcode(code), types))\r\n );\r\n },\r\n });\r\n\r\n return [codeScanner, barcodes, clearBarcodes];\r\n}\r\n"],"mappings":";;;;;;AAAA,IAAAA,wBAAA,GAAAC,OAAA;AACA,IAAAC,MAAA,GAAAD,OAAA;AAEA,IAAAE,CAAA,GAAAF,OAAA;AASA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASG,eAAeA,CAC7BC,KAAsB,EACtBC,QAA6B,EACS;EACtC,MAAM,CAACC,QAAQ,EAAEC,WAAW,CAAC,GAAG,IAAAC,eAAQ,EAAY,EAAE,CAAC;EAEvD,MAAMC,aAAa,GAAG,IAAAC,kBAAW,EAAC,MAAM;IACtCH,WAAW,CAAC,EAAE,CAAC;EACjB,CAAC,EAAE,EAAE,CAAC;EAEN,MAAMI,WAAW,GAAG,IAAAC,uCAAc,EAAC;IACjCC,SAAS,EAAE,IAAAC,uBAAqB,EAACV,KAAK,CAAC;IACvCW,aAAa,EAAEA,CAACC,KAAa,EAAEC,MAAwB,KAAK;MAC1DV,WAAW,CACTS,KAAK,CAACE,GAAG,CAAEC,IAAI,IAAK,IAAAC,0BAAwB,EAAC,IAAAC,WAAS,EAACF,IAAI,CAAC,EAAEf,KAAK,CAAC,CACtE,CAAC;IACH;EACF,CAAC,CAAC;EAEF,OAAO,CAACO,WAAW,EAAEL,QAAQ,EAAEG,aAAa,CAAC;AAC/C","ignoreList":[]}
@@ -0,0 +1,346 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ var _exportNames = {
7
+ BarcodeFormat: true,
8
+ BarcodeValueType: true,
9
+ AddressType: true,
10
+ EmailType: true,
11
+ PhoneType: true,
12
+ EncryptionType: true,
13
+ mapFormatsToCodeTypes: true,
14
+ toBarcode: true,
15
+ normalizeReportedBarcode: true,
16
+ scanBarcodes: true
17
+ };
18
+ exports.PhoneType = exports.EncryptionType = exports.EmailType = exports.BarcodeValueType = exports.BarcodeFormat = exports.AddressType = void 0;
19
+ exports.mapFormatsToCodeTypes = mapFormatsToCodeTypes;
20
+ exports.normalizeReportedBarcode = normalizeReportedBarcode;
21
+ exports.scanBarcodes = scanBarcodes;
22
+ exports.toBarcode = toBarcode;
23
+ var _hook = require("./hook");
24
+ Object.keys(_hook).forEach(function (key) {
25
+ if (key === "default" || key === "__esModule") return;
26
+ if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
27
+ if (key in exports && exports[key] === _hook[key]) return;
28
+ Object.defineProperty(exports, key, {
29
+ enumerable: true,
30
+ get: function () {
31
+ return _hook[key];
32
+ }
33
+ });
34
+ });
35
+ /**
36
+ * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.BarcodeFormat
37
+ */
38
+ let BarcodeFormat = exports.BarcodeFormat = /*#__PURE__*/function (BarcodeFormat) {
39
+ BarcodeFormat[BarcodeFormat["UNKNOWN"] = -1] = "UNKNOWN";
40
+ BarcodeFormat[BarcodeFormat["ALL_FORMATS"] = 0] = "ALL_FORMATS";
41
+ BarcodeFormat[BarcodeFormat["CODE_128"] = 1] = "CODE_128";
42
+ BarcodeFormat[BarcodeFormat["CODE_39"] = 2] = "CODE_39";
43
+ BarcodeFormat[BarcodeFormat["CODE_93"] = 4] = "CODE_93";
44
+ BarcodeFormat[BarcodeFormat["CODABAR"] = 8] = "CODABAR";
45
+ BarcodeFormat[BarcodeFormat["DATA_MATRIX"] = 16] = "DATA_MATRIX";
46
+ BarcodeFormat[BarcodeFormat["EAN_13"] = 32] = "EAN_13";
47
+ BarcodeFormat[BarcodeFormat["EAN_8"] = 64] = "EAN_8";
48
+ BarcodeFormat[BarcodeFormat["ITF"] = 128] = "ITF";
49
+ BarcodeFormat[BarcodeFormat["QR_CODE"] = 256] = "QR_CODE";
50
+ BarcodeFormat[BarcodeFormat["UPC_A"] = 512] = "UPC_A";
51
+ BarcodeFormat[BarcodeFormat["UPC_E"] = 1024] = "UPC_E";
52
+ BarcodeFormat[BarcodeFormat["PDF417"] = 2048] = "PDF417";
53
+ BarcodeFormat[BarcodeFormat["AZTEC"] = 4096] = "AZTEC";
54
+ return BarcodeFormat;
55
+ }({});
56
+ /**
57
+ * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.BarcodeValueType
58
+ */
59
+ let BarcodeValueType = exports.BarcodeValueType = /*#__PURE__*/function (BarcodeValueType) {
60
+ BarcodeValueType[BarcodeValueType["UNKNOWN"] = 0] = "UNKNOWN";
61
+ BarcodeValueType[BarcodeValueType["CONTACT_INFO"] = 1] = "CONTACT_INFO";
62
+ BarcodeValueType[BarcodeValueType["EMAIL"] = 2] = "EMAIL";
63
+ BarcodeValueType[BarcodeValueType["ISBN"] = 3] = "ISBN";
64
+ BarcodeValueType[BarcodeValueType["PHONE"] = 4] = "PHONE";
65
+ BarcodeValueType[BarcodeValueType["PRODUCT"] = 5] = "PRODUCT";
66
+ BarcodeValueType[BarcodeValueType["SMS"] = 6] = "SMS";
67
+ BarcodeValueType[BarcodeValueType["TEXT"] = 7] = "TEXT";
68
+ BarcodeValueType[BarcodeValueType["URL"] = 8] = "URL";
69
+ BarcodeValueType[BarcodeValueType["WIFI"] = 9] = "WIFI";
70
+ BarcodeValueType[BarcodeValueType["GEO"] = 10] = "GEO";
71
+ BarcodeValueType[BarcodeValueType["CALENDAR_EVENT"] = 11] = "CALENDAR_EVENT";
72
+ BarcodeValueType[BarcodeValueType["DRIVER_LICENSE"] = 12] = "DRIVER_LICENSE";
73
+ return BarcodeValueType;
74
+ }({});
75
+ /**
76
+ * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.Address.AddressType
77
+ */
78
+ let AddressType = exports.AddressType = /*#__PURE__*/function (AddressType) {
79
+ AddressType[AddressType["UNKNOWN"] = 0] = "UNKNOWN";
80
+ AddressType[AddressType["WORK"] = 1] = "WORK";
81
+ AddressType[AddressType["HOME"] = 2] = "HOME";
82
+ return AddressType;
83
+ }({});
84
+ /**
85
+ * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.Address
86
+ */
87
+ /**
88
+ * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.PersonName
89
+ */
90
+ /**
91
+ * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.ContactInfo
92
+ */
93
+ /**
94
+ * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.Email.FormatType
95
+ */
96
+ let EmailType = exports.EmailType = /*#__PURE__*/function (EmailType) {
97
+ EmailType[EmailType["UNKNOWN"] = 0] = "UNKNOWN";
98
+ EmailType[EmailType["WORK"] = 1] = "WORK";
99
+ EmailType[EmailType["HOME"] = 2] = "HOME";
100
+ return EmailType;
101
+ }({});
102
+ /**
103
+ * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.Email
104
+ */
105
+ /**
106
+ * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.Phone.FormatType
107
+ */
108
+ let PhoneType = exports.PhoneType = /*#__PURE__*/function (PhoneType) {
109
+ PhoneType[PhoneType["UNKNOWN"] = 0] = "UNKNOWN";
110
+ PhoneType[PhoneType["WORK"] = 1] = "WORK";
111
+ PhoneType[PhoneType["HOME"] = 2] = "HOME";
112
+ PhoneType[PhoneType["FAX"] = 3] = "FAX";
113
+ PhoneType[PhoneType["MOBILE"] = 4] = "MOBILE";
114
+ return PhoneType;
115
+ }({});
116
+ /**
117
+ * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.Phone
118
+ */
119
+ /**
120
+ * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.Sms
121
+ */
122
+ /**
123
+ * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.UrlBookmark
124
+ */
125
+ /**
126
+ * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.WiFi.EncryptionType
127
+ */
128
+ let EncryptionType = exports.EncryptionType = /*#__PURE__*/function (EncryptionType) {
129
+ EncryptionType[EncryptionType["OPEN"] = 1] = "OPEN";
130
+ EncryptionType[EncryptionType["WPA"] = 2] = "WPA";
131
+ EncryptionType[EncryptionType["WEP"] = 3] = "WEP";
132
+ return EncryptionType;
133
+ }({});
134
+ /**
135
+ * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.WiFi
136
+ */
137
+ /**
138
+ * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.GeoPoint
139
+ */
140
+ /**
141
+ * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.CalendarDateTime
142
+ */
143
+ /**
144
+ * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.CalendarEvent
145
+ */
146
+ /**
147
+ * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.DriverLicense
148
+ */
149
+ /**
150
+ * @see https://developer.android.com/reference/android/graphics/Rect.html
151
+ */
152
+ /**
153
+ * @see https://developer.android.com/reference/android/graphics/Point.html
154
+ */
155
+ /**
156
+ * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode
157
+ */
158
+ /**
159
+ * 鸿蒙端 BarcodeFormat → CodeType 映射(含上游 codeType→ScanType off-by-one 补偿)。
160
+ *
161
+ * 上游 @react-native-ohos/react-native-vision-camera(4.0.3/4.7.1)ScanManager 的 codeType
162
+ * 数组多插了 'itf-14' 条目,导致 `codeType.indexOf(type)` 的索引被直接当作 ScanType 枚举值传给
163
+ * Scan Kit customScan 时,从 itf-14 之后的格式整体偏移 1(如 QR 被配置成 UPC_A)。因此对受影响的
164
+ * 四种格式传入「可命中正确 ScanType 索引」的 CodeType 字符串:
165
+ *
166
+ * | 目标 BarcodeFormat | 期望 ScanType | 传入 CodeType | indexOf |
167
+ * |--------------------|---------------|---------------|---------|
168
+ * | QR_CODE | QR_CODE(11) | 'pdf-417' | 11 |
169
+ * | PDF417 | PDF417(10) | 'itf-14' | 10 |
170
+ * | UPC_A | UPC_A(12) | 'qr' | 12 |
171
+ * | UPC_E | UPC_E(13) | 'upc-a' | 13 |
172
+ *
173
+ * @internal
174
+ */
175
+ const FORMAT_TO_CODE_TYPE = {
176
+ [BarcodeFormat.UNKNOWN]: null,
177
+ [BarcodeFormat.ALL_FORMATS]: null,
178
+ [BarcodeFormat.CODE_128]: 'code-128',
179
+ [BarcodeFormat.CODE_39]: 'code-39',
180
+ [BarcodeFormat.CODE_93]: 'code-93',
181
+ [BarcodeFormat.CODABAR]: 'codabar',
182
+ [BarcodeFormat.DATA_MATRIX]: 'data-matrix',
183
+ [BarcodeFormat.EAN_13]: 'ean-13',
184
+ [BarcodeFormat.EAN_8]: 'ean-8',
185
+ [BarcodeFormat.ITF]: 'itf',
186
+ [BarcodeFormat.QR_CODE]: 'pdf-417',
187
+ [BarcodeFormat.UPC_A]: 'qr',
188
+ [BarcodeFormat.UPC_E]: 'upc-a',
189
+ [BarcodeFormat.PDF417]: 'itf-14',
190
+ [BarcodeFormat.AZTEC]: 'aztec'
191
+ };
192
+
193
+ /**
194
+ * 鸿蒙端 Code.type → BarcodeFormat 反向映射(含补偿反向翻译)。
195
+ *
196
+ * 上报方向:ScanManager 用 `this.codeType[data.scanType]` 报告 code.type。因请求时已用补偿后的
197
+ * CodeType,扫码命中后 scanType 为正确的 ScanType 数值,故 code.type 即为补偿字符串本身,需按
198
+ * 反向表翻译回原 BarcodeFormat。'upc-e' 无有效 ScanType(indexOf 落在 14),映射为 UNKNOWN。
199
+ *
200
+ * @internal
201
+ */
202
+ const CODE_TYPE_TO_FORMAT = {
203
+ unknown: BarcodeFormat.UNKNOWN,
204
+ aztec: BarcodeFormat.AZTEC,
205
+ codabar: BarcodeFormat.CODABAR,
206
+ 'code-39': BarcodeFormat.CODE_39,
207
+ 'code-93': BarcodeFormat.CODE_93,
208
+ 'code-128': BarcodeFormat.CODE_128,
209
+ 'data-matrix': BarcodeFormat.DATA_MATRIX,
210
+ 'ean-8': BarcodeFormat.EAN_8,
211
+ 'ean-13': BarcodeFormat.EAN_13,
212
+ itf: BarcodeFormat.ITF,
213
+ 'itf-14': BarcodeFormat.PDF417,
214
+ 'pdf-417': BarcodeFormat.QR_CODE,
215
+ qr: BarcodeFormat.UPC_A,
216
+ 'upc-a': BarcodeFormat.UPC_E,
217
+ 'upc-e': BarcodeFormat.UNKNOWN
218
+ };
219
+
220
+ /**
221
+ * 将 JS 层 BarcodeFormat[] 转换为 vision-camera codeScanner 需要的 CodeType[]。
222
+ *
223
+ * - 空数组或包含 ALL_FORMATS:返回空数组,触发 Scan Kit customScan 的 ALL 默认扫描。
224
+ * - 其余格式经 FORMAT_TO_CODE_TYPE 映射(含上游 off-by-one 补偿)。
225
+ *
226
+ * @internal
227
+ */
228
+ function mapFormatsToCodeTypes(types) {
229
+ if (!types || types.length === 0) {
230
+ return [];
231
+ }
232
+ if (types.includes(BarcodeFormat.ALL_FORMATS)) {
233
+ return [];
234
+ }
235
+ const result = [];
236
+ for (const format of types) {
237
+ const codeType = FORMAT_TO_CODE_TYPE[format];
238
+ if (codeType) {
239
+ result.push(codeType);
240
+ }
241
+ }
242
+ return result;
243
+ }
244
+
245
+ /**
246
+ * 将 vision-camera 扫码回调的 Code 转换为原 API 的 Barcode 类型。
247
+ *
248
+ * 鸿蒙 Scan Kit 的 ScanResult 仅提供 originalValue / scanCodeRect / cornerPoints,
249
+ * 无 MLKit/iOS Vision 的丰富结构化字段,因此 content 统一降级为
250
+ * `{ type: BarcodeValueType.TEXT, data: rawValue }`。
251
+ *
252
+ * @internal
253
+ */
254
+ function toBarcode(code) {
255
+ const format = CODE_TYPE_TO_FORMAT[code.type] ?? BarcodeFormat.UNKNOWN;
256
+ const value = code.value;
257
+ const barcode = {
258
+ format,
259
+ content: {
260
+ type: BarcodeValueType.TEXT,
261
+ data: value ?? ''
262
+ }
263
+ };
264
+ if (value !== undefined) {
265
+ barcode.rawValue = value;
266
+ barcode.displayValue = value;
267
+ }
268
+ if (code.frame) {
269
+ barcode.boundingBox = {
270
+ left: code.frame.x,
271
+ top: code.frame.y,
272
+ right: code.frame.x + code.frame.width,
273
+ bottom: code.frame.y + code.frame.height
274
+ };
275
+ }
276
+ if (code.corners) {
277
+ barcode.cornerPoints = code.corners;
278
+ }
279
+ return barcode;
280
+ }
281
+
282
+ /**
283
+ * 按调用方请求的格式,归一化 UPC_A / EAN_13 上报结果。
284
+ *
285
+ * UPC_A 与「前导 0 的 EAN_13」条纹图案完全等价,Scan Kit / 多数扫码库常把 UPC_A
286
+ * 报成 EAN_13(13 位且以 0 开头),或把 EAN_13 报成 UPC_A(去掉前导 0)。
287
+ * 当请求格式仅包含其中一种时,按请求意图纠正 format 与数值,便于格式过滤用例验证。
288
+ *
289
+ * @internal
290
+ */
291
+ function normalizeReportedBarcode(barcode, requestedTypes) {
292
+ if (!requestedTypes || requestedTypes.length === 0 || requestedTypes.includes(BarcodeFormat.ALL_FORMATS)) {
293
+ return barcode;
294
+ }
295
+ const wantsUpcA = requestedTypes.includes(BarcodeFormat.UPC_A);
296
+ const wantsEan13 = requestedTypes.includes(BarcodeFormat.EAN_13);
297
+ const value = barcode.rawValue ?? barcode.displayValue ?? '';
298
+
299
+ // 仅请求 UPC_A:Scan Kit 常把 UPC_A 报成带前导 0 的 EAN_13
300
+ if (wantsUpcA && !wantsEan13 && barcode.format === BarcodeFormat.EAN_13 && value.length === 13 && value.startsWith('0')) {
301
+ const upc = value.slice(1);
302
+ return {
303
+ ...barcode,
304
+ format: BarcodeFormat.UPC_A,
305
+ rawValue: upc,
306
+ displayValue: upc,
307
+ content: {
308
+ type: BarcodeValueType.TEXT,
309
+ data: upc
310
+ }
311
+ };
312
+ }
313
+
314
+ // 仅请求 EAN_13:偶发把等价码报成 12 位 UPC_A
315
+ if (wantsEan13 && !wantsUpcA && barcode.format === BarcodeFormat.UPC_A && value.length === 12) {
316
+ const ean = '0' + value;
317
+ return {
318
+ ...barcode,
319
+ format: BarcodeFormat.EAN_13,
320
+ rawValue: ean,
321
+ displayValue: ean,
322
+ content: {
323
+ type: BarcodeValueType.TEXT,
324
+ data: ean
325
+ }
326
+ };
327
+ }
328
+ return barcode;
329
+ }
330
+
331
+ /**
332
+ * Scans barcodes in the passed frame with MLKit
333
+ *
334
+ * @param frame Camera frame
335
+ * @param types Array of barcode types to detect (for optimal performance, use less types)
336
+ * @param options Scan options
337
+ * @returns Detected barcodes from MLKit
338
+ *
339
+ * 鸿蒙端不支持:Frame Processor 工作集机制在 @react-native-ohos/react-native-vision-camera v4
340
+ * 中不存在(不导出 useFrameProcessor / FrameProcessorPlugin)。此函数在鸿蒙端导出为抛错 stub,
341
+ * 请改用 `useScanBarcodes` 返回的 codeScanner 并传给 `<Camera codeScanner={...}>`。
342
+ */
343
+ function scanBarcodes(_frame, _types, _options) {
344
+ throw new Error('Harmony 不支持 Frame Processor worklet,请使用 useScanBarcodes 返回的 codeScanner 并传给 <Camera codeScanner={...}>');
345
+ }
346
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_hook","require","Object","keys","forEach","key","prototype","hasOwnProperty","call","_exportNames","exports","defineProperty","enumerable","get","BarcodeFormat","BarcodeValueType","AddressType","EmailType","PhoneType","EncryptionType","FORMAT_TO_CODE_TYPE","UNKNOWN","ALL_FORMATS","CODE_128","CODE_39","CODE_93","CODABAR","DATA_MATRIX","EAN_13","EAN_8","ITF","QR_CODE","UPC_A","UPC_E","PDF417","AZTEC","CODE_TYPE_TO_FORMAT","unknown","aztec","codabar","itf","qr","mapFormatsToCodeTypes","types","length","includes","result","format","codeType","push","toBarcode","code","type","value","barcode","content","TEXT","data","undefined","rawValue","displayValue","frame","boundingBox","left","x","top","y","right","width","bottom","height","corners","cornerPoints","normalizeReportedBarcode","requestedTypes","wantsUpcA","wantsEan13","startsWith","upc","slice","ean","scanBarcodes","_frame","_types","_options","Error"],"sources":["index.ts"],"sourcesContent":["import type { Code, CodeType, Frame } from 'react-native-vision-camera';\r\n\r\n/**\r\n * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.BarcodeFormat\r\n */\r\nexport enum BarcodeFormat {\r\n UNKNOWN = -1,\r\n ALL_FORMATS = 0,\r\n CODE_128 = 1,\r\n CODE_39 = 2,\r\n CODE_93 = 4,\r\n CODABAR = 8,\r\n DATA_MATRIX = 16,\r\n EAN_13 = 32,\r\n EAN_8 = 64,\r\n ITF = 128,\r\n QR_CODE = 256,\r\n UPC_A = 512,\r\n UPC_E = 1024,\r\n PDF417 = 2048,\r\n AZTEC = 4096,\r\n}\r\n\r\n/**\r\n * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.BarcodeValueType\r\n */\r\nexport enum BarcodeValueType {\r\n UNKNOWN = 0,\r\n CONTACT_INFO = 1,\r\n EMAIL = 2,\r\n ISBN = 3,\r\n PHONE = 4,\r\n PRODUCT = 5,\r\n SMS = 6,\r\n TEXT = 7,\r\n URL = 8,\r\n WIFI = 9,\r\n GEO = 10,\r\n CALENDAR_EVENT = 11,\r\n DRIVER_LICENSE = 12,\r\n}\r\n\r\n/**\r\n * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.Address.AddressType\r\n */\r\nexport enum AddressType {\r\n UNKNOWN = 0,\r\n WORK = 1,\r\n HOME = 2,\r\n}\r\n\r\n/**\r\n * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.Address\r\n */\r\nexport interface Address {\r\n addressLines?: string[];\r\n type?: AddressType;\r\n}\r\n\r\n/**\r\n * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.PersonName\r\n */\r\nexport interface PersonName {\r\n first?: string;\r\n formattedName?: string;\r\n last?: string;\r\n middle?: string;\r\n prefix?: string;\r\n pronunciation?: string;\r\n suffix?: string;\r\n}\r\n\r\n/**\r\n * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.ContactInfo\r\n */\r\nexport interface ContactInfo {\r\n addresses?: Address[];\r\n emails?: Email[];\r\n name?: PersonName;\r\n organization?: string;\r\n phones?: Phone[];\r\n title?: string;\r\n urls?: string[];\r\n}\r\n\r\n/**\r\n * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.Email.FormatType\r\n */\r\nexport enum EmailType {\r\n UNKNOWN = 0,\r\n WORK = 1,\r\n HOME = 2,\r\n}\r\n\r\n/**\r\n * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.Email\r\n */\r\nexport interface Email {\r\n address?: string;\r\n body?: string;\r\n subject?: string;\r\n type?: EmailType;\r\n}\r\n\r\n/**\r\n * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.Phone.FormatType\r\n */\r\nexport enum PhoneType {\r\n UNKNOWN = 0,\r\n WORK = 1,\r\n HOME = 2,\r\n FAX = 3,\r\n MOBILE = 4,\r\n}\r\n\r\n/**\r\n * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.Phone\r\n */\r\nexport interface Phone {\r\n number?: string;\r\n type?: PhoneType;\r\n}\r\n\r\n/**\r\n * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.Sms\r\n */\r\nexport interface Sms {\r\n message?: string;\r\n phoneNumber?: string;\r\n}\r\n\r\n/**\r\n * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.UrlBookmark\r\n */\r\nexport interface UrlBookmark {\r\n title?: string;\r\n url?: string;\r\n}\r\n\r\n/**\r\n * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.WiFi.EncryptionType\r\n */\r\nexport enum EncryptionType {\r\n OPEN = 1,\r\n WPA = 2,\r\n WEP = 3,\r\n}\r\n\r\n/**\r\n * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.WiFi\r\n */\r\nexport interface Wifi {\r\n encryptionType?: EncryptionType;\r\n password?: string;\r\n ssid?: string;\r\n}\r\n\r\n/**\r\n * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.GeoPoint\r\n */\r\nexport interface GeoPoint {\r\n lat?: number;\r\n lng?: number;\r\n}\r\n\r\n/**\r\n * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.CalendarDateTime\r\n */\r\nexport interface Date {\r\n day: number;\r\n hours: number;\r\n minutes: number;\r\n month: number;\r\n rawValue: string;\r\n seconds: number;\r\n year: number;\r\n isUtc: boolean;\r\n}\r\n\r\n/**\r\n * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.CalendarEvent\r\n */\r\nexport interface CalendarEvent {\r\n description?: string;\r\n end?: Date;\r\n location?: string;\r\n organizer?: string;\r\n start?: Date;\r\n status?: string;\r\n summary?: string;\r\n}\r\n\r\n/**\r\n * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode.DriverLicense\r\n */\r\nexport interface DriverLicense {\r\n addressCity?: string;\r\n addressState?: string;\r\n addressStreet?: string;\r\n addressZip?: string;\r\n birthDate?: string;\r\n documentType?: string;\r\n expiryDate?: string;\r\n firstName?: string;\r\n gender?: string;\r\n issueDate?: string;\r\n issuingCountry?: string;\r\n lastName?: string;\r\n licenseNumber?: string;\r\n middleName?: string;\r\n}\r\n\r\n/**\r\n * @see https://developer.android.com/reference/android/graphics/Rect.html\r\n */\r\nexport interface Rect {\r\n bottom: number;\r\n left: number;\r\n right: number;\r\n top: number;\r\n}\r\n\r\n/**\r\n * @see https://developer.android.com/reference/android/graphics/Point.html\r\n */\r\nexport interface Point {\r\n x: number;\r\n y: number;\r\n}\r\n\r\n/**\r\n * @see https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/Barcode\r\n */\r\nexport type Barcode = {\r\n boundingBox?: Rect;\r\n cornerPoints?: Point[];\r\n displayValue?: string;\r\n rawValue?: string;\r\n format: BarcodeFormat;\r\n content:\r\n | {\r\n type:\r\n | BarcodeValueType.UNKNOWN\r\n | BarcodeValueType.ISBN\r\n | BarcodeValueType.TEXT;\r\n data: string;\r\n }\r\n | {\r\n type: BarcodeValueType.CONTACT_INFO;\r\n data: ContactInfo;\r\n }\r\n | {\r\n type: BarcodeValueType.EMAIL;\r\n data: Email;\r\n }\r\n | {\r\n type: BarcodeValueType.PHONE;\r\n data: Phone;\r\n }\r\n | {\r\n type: BarcodeValueType.SMS;\r\n data: Sms;\r\n }\r\n | {\r\n type: BarcodeValueType.URL;\r\n data: UrlBookmark;\r\n }\r\n | {\r\n type: BarcodeValueType.WIFI;\r\n data: Wifi;\r\n }\r\n | {\r\n type: BarcodeValueType.GEO;\r\n data: GeoPoint;\r\n }\r\n | {\r\n type: BarcodeValueType.CALENDAR_EVENT;\r\n data: CalendarEvent;\r\n }\r\n | {\r\n type: BarcodeValueType.DRIVER_LICENSE;\r\n data: DriverLicense;\r\n };\r\n};\r\n\r\nexport interface CodeScannerOptions {\r\n /**\r\n * checkInverted: `Allows you to also scan white barcode with black backgrounds`\r\n *\r\n * 注意:鸿蒙(HarmonyOS)Scan Kit 无图像反色识别选项,此选项在鸿蒙端被忽略。\r\n */\r\n checkInverted?: boolean;\r\n}\r\n\r\n/**\r\n * 鸿蒙端 BarcodeFormat → CodeType 映射(含上游 codeType→ScanType off-by-one 补偿)。\r\n *\r\n * 上游 @react-native-ohos/react-native-vision-camera(4.0.3/4.7.1)ScanManager 的 codeType\r\n * 数组多插了 'itf-14' 条目,导致 `codeType.indexOf(type)` 的索引被直接当作 ScanType 枚举值传给\r\n * Scan Kit customScan 时,从 itf-14 之后的格式整体偏移 1(如 QR 被配置成 UPC_A)。因此对受影响的\r\n * 四种格式传入「可命中正确 ScanType 索引」的 CodeType 字符串:\r\n *\r\n * | 目标 BarcodeFormat | 期望 ScanType | 传入 CodeType | indexOf |\r\n * |--------------------|---------------|---------------|---------|\r\n * | QR_CODE | QR_CODE(11) | 'pdf-417' | 11 |\r\n * | PDF417 | PDF417(10) | 'itf-14' | 10 |\r\n * | UPC_A | UPC_A(12) | 'qr' | 12 |\r\n * | UPC_E | UPC_E(13) | 'upc-a' | 13 |\r\n *\r\n * @internal\r\n */\r\nconst FORMAT_TO_CODE_TYPE: Record<BarcodeFormat, CodeType | null> = {\r\n [BarcodeFormat.UNKNOWN]: null,\r\n [BarcodeFormat.ALL_FORMATS]: null,\r\n [BarcodeFormat.CODE_128]: 'code-128',\r\n [BarcodeFormat.CODE_39]: 'code-39',\r\n [BarcodeFormat.CODE_93]: 'code-93',\r\n [BarcodeFormat.CODABAR]: 'codabar',\r\n [BarcodeFormat.DATA_MATRIX]: 'data-matrix',\r\n [BarcodeFormat.EAN_13]: 'ean-13',\r\n [BarcodeFormat.EAN_8]: 'ean-8',\r\n [BarcodeFormat.ITF]: 'itf',\r\n [BarcodeFormat.QR_CODE]: 'pdf-417',\r\n [BarcodeFormat.UPC_A]: 'qr',\r\n [BarcodeFormat.UPC_E]: 'upc-a',\r\n [BarcodeFormat.PDF417]: 'itf-14' as CodeType,\r\n [BarcodeFormat.AZTEC]: 'aztec',\r\n};\r\n\r\n/**\r\n * 鸿蒙端 Code.type → BarcodeFormat 反向映射(含补偿反向翻译)。\r\n *\r\n * 上报方向:ScanManager 用 `this.codeType[data.scanType]` 报告 code.type。因请求时已用补偿后的\r\n * CodeType,扫码命中后 scanType 为正确的 ScanType 数值,故 code.type 即为补偿字符串本身,需按\r\n * 反向表翻译回原 BarcodeFormat。'upc-e' 无有效 ScanType(indexOf 落在 14),映射为 UNKNOWN。\r\n *\r\n * @internal\r\n */\r\nconst CODE_TYPE_TO_FORMAT: Record<string, BarcodeFormat> = {\r\n unknown: BarcodeFormat.UNKNOWN,\r\n aztec: BarcodeFormat.AZTEC,\r\n codabar: BarcodeFormat.CODABAR,\r\n 'code-39': BarcodeFormat.CODE_39,\r\n 'code-93': BarcodeFormat.CODE_93,\r\n 'code-128': BarcodeFormat.CODE_128,\r\n 'data-matrix': BarcodeFormat.DATA_MATRIX,\r\n 'ean-8': BarcodeFormat.EAN_8,\r\n 'ean-13': BarcodeFormat.EAN_13,\r\n itf: BarcodeFormat.ITF,\r\n 'itf-14': BarcodeFormat.PDF417,\r\n 'pdf-417': BarcodeFormat.QR_CODE,\r\n qr: BarcodeFormat.UPC_A,\r\n 'upc-a': BarcodeFormat.UPC_E,\r\n 'upc-e': BarcodeFormat.UNKNOWN,\r\n};\r\n\r\n/**\r\n * 将 JS 层 BarcodeFormat[] 转换为 vision-camera codeScanner 需要的 CodeType[]。\r\n *\r\n * - 空数组或包含 ALL_FORMATS:返回空数组,触发 Scan Kit customScan 的 ALL 默认扫描。\r\n * - 其余格式经 FORMAT_TO_CODE_TYPE 映射(含上游 off-by-one 补偿)。\r\n *\r\n * @internal\r\n */\r\nexport function mapFormatsToCodeTypes(types: BarcodeFormat[]): CodeType[] {\r\n if (!types || types.length === 0) {\r\n return [];\r\n }\r\n if (types.includes(BarcodeFormat.ALL_FORMATS)) {\r\n return [];\r\n }\r\n const result: CodeType[] = [];\r\n for (const format of types) {\r\n const codeType = FORMAT_TO_CODE_TYPE[format];\r\n if (codeType) {\r\n result.push(codeType);\r\n }\r\n }\r\n return result;\r\n}\r\n\r\n/**\r\n * 将 vision-camera 扫码回调的 Code 转换为原 API 的 Barcode 类型。\r\n *\r\n * 鸿蒙 Scan Kit 的 ScanResult 仅提供 originalValue / scanCodeRect / cornerPoints,\r\n * 无 MLKit/iOS Vision 的丰富结构化字段,因此 content 统一降级为\r\n * `{ type: BarcodeValueType.TEXT, data: rawValue }`。\r\n *\r\n * @internal\r\n */\r\nexport function toBarcode(code: Code): Barcode {\r\n const format = CODE_TYPE_TO_FORMAT[code.type] ?? BarcodeFormat.UNKNOWN;\r\n const value = code.value;\r\n const barcode: Barcode = {\r\n format,\r\n content: {\r\n type: BarcodeValueType.TEXT,\r\n data: value ?? '',\r\n },\r\n };\r\n if (value !== undefined) {\r\n barcode.rawValue = value;\r\n barcode.displayValue = value;\r\n }\r\n if (code.frame) {\r\n barcode.boundingBox = {\r\n left: code.frame.x,\r\n top: code.frame.y,\r\n right: code.frame.x + code.frame.width,\r\n bottom: code.frame.y + code.frame.height,\r\n };\r\n }\r\n if (code.corners) {\r\n barcode.cornerPoints = code.corners;\r\n }\r\n return barcode;\r\n}\r\n\r\n/**\r\n * 按调用方请求的格式,归一化 UPC_A / EAN_13 上报结果。\r\n *\r\n * UPC_A 与「前导 0 的 EAN_13」条纹图案完全等价,Scan Kit / 多数扫码库常把 UPC_A\r\n * 报成 EAN_13(13 位且以 0 开头),或把 EAN_13 报成 UPC_A(去掉前导 0)。\r\n * 当请求格式仅包含其中一种时,按请求意图纠正 format 与数值,便于格式过滤用例验证。\r\n *\r\n * @internal\r\n */\r\nexport function normalizeReportedBarcode(\r\n barcode: Barcode,\r\n requestedTypes: BarcodeFormat[]\r\n): Barcode {\r\n if (\r\n !requestedTypes ||\r\n requestedTypes.length === 0 ||\r\n requestedTypes.includes(BarcodeFormat.ALL_FORMATS)\r\n ) {\r\n return barcode;\r\n }\r\n\r\n const wantsUpcA = requestedTypes.includes(BarcodeFormat.UPC_A);\r\n const wantsEan13 = requestedTypes.includes(BarcodeFormat.EAN_13);\r\n const value = barcode.rawValue ?? barcode.displayValue ?? '';\r\n\r\n // 仅请求 UPC_A:Scan Kit 常把 UPC_A 报成带前导 0 的 EAN_13\r\n if (\r\n wantsUpcA &&\r\n !wantsEan13 &&\r\n barcode.format === BarcodeFormat.EAN_13 &&\r\n value.length === 13 &&\r\n value.startsWith('0')\r\n ) {\r\n const upc = value.slice(1);\r\n return {\r\n ...barcode,\r\n format: BarcodeFormat.UPC_A,\r\n rawValue: upc,\r\n displayValue: upc,\r\n content: { type: BarcodeValueType.TEXT, data: upc },\r\n };\r\n }\r\n\r\n // 仅请求 EAN_13:偶发把等价码报成 12 位 UPC_A\r\n if (\r\n wantsEan13 &&\r\n !wantsUpcA &&\r\n barcode.format === BarcodeFormat.UPC_A &&\r\n value.length === 12\r\n ) {\r\n const ean = '0' + value;\r\n return {\r\n ...barcode,\r\n format: BarcodeFormat.EAN_13,\r\n rawValue: ean,\r\n displayValue: ean,\r\n content: { type: BarcodeValueType.TEXT, data: ean },\r\n };\r\n }\r\n\r\n return barcode;\r\n}\r\n\r\n/**\r\n * Scans barcodes in the passed frame with MLKit\r\n *\r\n * @param frame Camera frame\r\n * @param types Array of barcode types to detect (for optimal performance, use less types)\r\n * @param options Scan options\r\n * @returns Detected barcodes from MLKit\r\n *\r\n * 鸿蒙端不支持:Frame Processor 工作集机制在 @react-native-ohos/react-native-vision-camera v4\r\n * 中不存在(不导出 useFrameProcessor / FrameProcessorPlugin)。此函数在鸿蒙端导出为抛错 stub,\r\n * 请改用 `useScanBarcodes` 返回的 codeScanner 并传给 `<Camera codeScanner={...}>`。\r\n */\r\nexport function scanBarcodes(\r\n _frame: Frame,\r\n _types: BarcodeFormat[],\r\n _options?: CodeScannerOptions\r\n): Barcode[] {\r\n throw new Error(\r\n 'Harmony 不支持 Frame Processor worklet,请使用 useScanBarcodes 返回的 codeScanner 并传给 <Camera codeScanner={...}>'\r\n );\r\n}\r\n\r\nexport * from './hook';\r\n"],"mappings":"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","ignoreList":[]}