Skip to content

Commit 3106137

Browse files
authored
feat: Add scanCodesInImage(...) to scan static Images via Barcode Scanner (#3995)
feat: scan barcodes in images
1 parent 7cbd23e commit 3106137

31 files changed

Lines changed: 400 additions & 62 deletions
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { Image as RNImage } from 'react-native'
2+
import { describe, expect, it } from 'react-native-harness'
3+
import type { Image as NitroImage } from 'react-native-nitro-image'
4+
import { loadImage } from 'react-native-nitro-image'
5+
import {
6+
type Barcode,
7+
createBarcodeScanner,
8+
type TargetBarcodeFormat,
9+
} from 'react-native-vision-camera-barcode-scanner'
10+
import { withTimeout } from './test-utils'
11+
12+
const qrCodeAsset = require('../src/assets/qr-code-margelo.png')
13+
const code128Asset = require('../src/assets/code-128-mrousavy.png')
14+
15+
describe('VisionCamera - Barcode Scanner', () => {
16+
it('scans a QR code from a Nitro Image', async () => {
17+
const barcodes = await scanCodesInAssetImage(qrCodeAsset, ['qr-code'])
18+
19+
expect(barcodes).toHaveLength(1)
20+
expect(barcodes[0]?.format).toBe('qr-code')
21+
expect(barcodes[0]?.rawValue).toBe('https://margelo.com')
22+
})
23+
24+
it('scans a Code 128 barcode from a Nitro Image', async () => {
25+
const code128Barcodes = await scanCodesInAssetImage(code128Asset, [
26+
'code-128',
27+
])
28+
29+
expect(code128Barcodes).toHaveLength(1)
30+
expect(code128Barcodes[0]?.format).toBe('code-128')
31+
expect(code128Barcodes[0]?.rawValue).toBe('https://mrousavy.com')
32+
33+
const allFormatBarcodes = await scanCodesInAssetImage(code128Asset, [
34+
'all-formats',
35+
])
36+
37+
expect(allFormatBarcodes).toHaveLength(1)
38+
expect(allFormatBarcodes[0]?.format).toBe('code-128')
39+
expect(allFormatBarcodes[0]?.rawValue).toBe('https://mrousavy.com')
40+
})
41+
})
42+
43+
async function scanCodesInAssetImage(
44+
source: number,
45+
barcodeFormats: TargetBarcodeFormat[],
46+
): Promise<Barcode[]> {
47+
const image = await loadNitroImageFromAsset(source)
48+
return await scanLoadedImage(image, barcodeFormats)
49+
}
50+
51+
async function loadNitroImageFromAsset(source: number): Promise<NitroImage> {
52+
const resolvedSource = RNImage.resolveAssetSource(source)
53+
const response = await fetch(resolvedSource.uri)
54+
const buffer = await response.arrayBuffer()
55+
56+
return await loadImage({
57+
encodedImageData: {
58+
buffer,
59+
width: resolvedSource.width,
60+
height: resolvedSource.height,
61+
imageFormat: 'png',
62+
},
63+
})
64+
}
65+
66+
async function scanLoadedImage(
67+
image: NitroImage,
68+
barcodeFormats: TargetBarcodeFormat[],
69+
): Promise<Barcode[]> {
70+
const scanner = createBarcodeScanner({ barcodeFormats })
71+
try {
72+
return await withTimeout(
73+
scanner.scanCodesInImageAsync(image),
74+
15_000,
75+
`scan ${barcodeFormats.join(', ')} from image`,
76+
)
77+
} finally {
78+
scanner.dispose()
79+
image.dispose()
80+
}
81+
}

apps/simple-camera/ios/Podfile.lock

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2350,6 +2350,7 @@ PODS:
23502350
- VisionCameraBarcodeScanner (5.0.11):
23512351
- GoogleMLKit/BarcodeScanning (= 9.0.0)
23522352
- hermes-engine
2353+
- NitroImage
23532354
- NitroModules
23542355
- RCTRequired
23552356
- RCTTypeSafety
@@ -2846,7 +2847,7 @@ SPEC CHECKSUMS:
28462847
RNVectorIcons: 97f26211c07d69e45b189f9dd0dbbe5e2d2b0b92
28472848
RNWorklets: 04a35c45bd72d24914cbaf24bdfa4e30e1eab2df
28482849
VisionCamera: 204d37d39a6a59b31bc48c777094be3096594810
2849-
VisionCameraBarcodeScanner: 5de8b7612ba93bf3a7fa2164938898d231c386fe
2850+
VisionCameraBarcodeScanner: 27f6ed59ad96425067a0ff582aacb0d89484115f
28502851
VisionCameraLocation: a0289fd95ebd3317f60f52416319c5ac182bba21
28512852
VisionCameraResizer: a35ea21e06bfb8f1e652dc5d1b7b20cb0fddc7a4
28522853
VisionCameraWorklets: 38e14b319413d2caa6d9fa85062a003a821cf417
15.8 KB
Loading
437 Bytes
Loading

bun.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/content/docs/barcode-scanner.mdx

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ description: Using the Barcode Scanner view, output or plugin to detect Barcodes
66
import { Tab, Tabs } from 'fumadocs-ui/components/tabs'
77

88
The Barcode Scanner allows detecting machine readable codes (like Barcodes or QR codes) using [MLKit](https://developers.google.com/ml-kit).
9-
It ships a simple [`<CodeScanner />`](/api/react-native-vision-camera-barcode-scanner/views/CodeScanner) view, a Barcode Scanner Frame Processor Plugin, and a Barcode Scanner [`CameraOutput`](/api/react-native-vision-camera/hybrid-objects/CameraOutput) via the [react-native-vision-camera-barcode-scanner](/api/react-native-vision-camera-barcode-scanner) library.
9+
It ships a simple [`<CodeScanner />`](/api/react-native-vision-camera-barcode-scanner/views/CodeScanner) view, a Barcode Scanner Frame Processor Plugin, a Barcode Scanner [`CameraOutput`](/api/react-native-vision-camera/hybrid-objects/CameraOutput), and static image scanning for [`Image`](https://github.com/mrousavy/react-native-nitro-image) instances via the [react-native-vision-camera-barcode-scanner](/api/react-native-vision-camera-barcode-scanner) library.
1010

1111
Unlike [the Object Output](object-output) (which is iOS-only), the Barcode Scanner works on both iOS and Android.
1212

@@ -15,7 +15,7 @@ Unlike [the Object Output](object-output) (which is iOS-only), the Barcode Scann
1515
1616
### Using the Barcode Scanner
1717

18-
<Tabs items={["<CodeScanner /> (view)", "CameraOutput", "Frame Processor Plugin"]} groupId="barcode-api-style" persist>
18+
<Tabs items={["<CodeScanner /> (view)", "CameraOutput", "Frame Processor Plugin", "Static Images"]} groupId="barcode-api-style" persist>
1919
<Tab value="<CodeScanner /> (view)">
2020
The [`<CodeScanner />`](/api/react-native-vision-camera-barcode-scanner/views/CodeScanner) view is a simple view component to scan Barcodes:
2121

@@ -95,11 +95,34 @@ function App() {
9595
}
9696
```
9797
</Tab>
98+
<Tab value="Static Images">
99+
For still images, load a [`react-native-nitro-image`](https://github.com/mrousavy/react-native-nitro-image) [`Image`](https://github.com/mrousavy/react-native-nitro-image) and scan it with [`BarcodeScanner.scanCodesInImageAsync(...)`](/api/react-native-vision-camera-barcode-scanner/hybrid-objects/BarcodeScanner#scancodesinimageasync):
100+
101+
```ts
102+
import { loadImage } from 'react-native-nitro-image'
103+
import { createBarcodeScanner } from 'react-native-vision-camera-barcode-scanner'
104+
105+
async function scanBarcodeImage() {
106+
const image = await loadImage({ url: 'https://example.com/barcode.png' })
107+
const barcodeScanner = createBarcodeScanner({
108+
barcodeFormats: ['all-formats'],
109+
})
110+
111+
try {
112+
const barcodes = await barcodeScanner.scanCodesInImageAsync(image)
113+
console.log(`Detected ${barcodes.length} barcodes!`)
114+
} finally {
115+
image.dispose()
116+
barcodeScanner.dispose()
117+
}
118+
}
119+
```
120+
</Tab>
98121
</Tabs>
99122

100123
### Configuring Barcode Formats
101124

102-
The code example above are configured to detect **all** [`BarcodeFormat`](/api/react-native-vision-camera-barcode-scanner/type-aliases/BarcodeFormat)s.
125+
The examples above are configured to detect **all** [`BarcodeFormat`](/api/react-native-vision-camera-barcode-scanner/type-aliases/BarcodeFormat)s.
103126
To improve performance, you should narrow [`barcodeFormats`](/api/react-native-vision-camera-barcode-scanner/interfaces/BarcodeScannerOptions#barcodeformats) down to only the formats you need - for example [`'code-128'`](/api/react-native-vision-camera-barcode-scanner/type-aliases/BarcodeFormat) - which is a common Barcode Format, or [`'qr-code'`](/api/react-native-vision-camera-barcode-scanner/type-aliases/BarcodeFormat) for square QR codes.
104127

105128
### Test it

docs/content/docs/visioncamera-vs-expo-camera.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Both VisionCamera and Expo Camera are popular Camera libraries for React Native
2222
| Capturing [Videos](video-output) |||
2323
| Barcode [Scanning](barcode-scanner) |||
2424
| System [Barcode Scanner UI](https://docs.expo.dev/versions/latest/sdk/camera/#launchscanneroptions) |||
25-
| Scan [Barcodes from Image URL](https://docs.expo.dev/versions/latest/sdk/camera/#camerascanfromurlasyncurl-barcodetypes) | ||
25+
| Scan [Barcodes from Image URL](barcode-scanner#using-the-barcode-scanner) | ||
2626
| Locking [AE/AF/AWB](locking-ae-af-awb) |||
2727
| Configurable [`focusTo(...)`](tap-to-focus#focus-metering-options) |||
2828
| Realtime [Frame Processing](frame-output) |||

packages/react-native-vision-camera-barcode-scanner/README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,17 @@
33
This is VisionCamera Barcode Scanner. Install it through npm:
44

55
```sh
6-
npm install react-native-vision-camera-barcode-scanner
6+
npm install react-native-vision-camera-barcode-scanner react-native-nitro-image
77
```
88

9-
VisionCamera Barcode Scanner depends on VisionCamera Core.
9+
VisionCamera Barcode Scanner depends on VisionCamera Core and Nitro Image.
1010

1111
```sh
12-
# Make sure VisionCamera Core is installed.
12+
# Make sure VisionCamera Core is installed as well.
1313
```
1414

15+
You can scan live camera frames, attach a Barcode Scanner output, or scan an existing Nitro Image with `BarcodeScanner.scanCodesInImageAsync(...)`.
16+
1517
## Minimum Requirements
1618

1719
The `GoogleMLKit/BarcodeScanning` dependency (version `9.0.0`) requires a minimum iOS target version of 15.5. Adjust it in your `Podfile` if needed.

packages/react-native-vision-camera-barcode-scanner/VisionCameraBarcodeScanner.podspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ Pod::Spec.new do |s|
2828

2929
s.dependency 'GoogleMLKit/BarcodeScanning', '9.0.0'
3030
s.dependency 'VisionCamera'
31+
s.dependency 'NitroImage'
3132
s.dependency 'React-jsi'
3233
s.dependency 'React-callinvoker'
3334
install_modules_dependencies(s)

packages/react-native-vision-camera-barcode-scanner/android/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@ include_directories(
2121

2222
find_library(LOG_LIB log)
2323
find_package(react-native-vision-camera REQUIRED) # <-- for the HybridFrameSpec and HybridCameraOutputSpec
24+
find_package(react-native-nitro-image REQUIRED) # <-- for the HybridImageSpec
2425

2526
# Link all libraries together
2627
target_link_libraries(
2728
${PACKAGE_NAME}
2829
${LOG_LIB}
2930
android # <-- Android core
3031
react-native-vision-camera::VisionCamera
32+
react-native-nitro-image::NitroImage
3133
)

0 commit comments

Comments
 (0)