vision-camera-simple-scanner
Version:
High performance barcode scanner for React Native using VisionCamera, forked from vision-camera-barcode-scanner
117 lines (110 loc) • 3.32 kB
text/typescript
import { Platform } from 'react-native';
import type { Code, Frame } from 'react-native-vision-camera';
import type {
AndroidBarcode,
Barcode,
BoundingBox,
Point,
iOSBarcode,
} from 'src/types';
import { normalizeAndroidCodeType, normalizeiOSCodeType } from './types';
export const isIOSBarcode = (
barcode: iOSBarcode | AndroidBarcode,
): barcode is iOSBarcode => {
'worklet';
return Platform.OS === 'ios';
};
export const isAndroidBarcode = (
barcode: iOSBarcode | AndroidBarcode,
): barcode is AndroidBarcode => {
'worklet';
return Platform.OS === 'android';
};
export const computeBoundingBoxFromCornerPoints = (
cornerPoints: Point[],
): BoundingBox => {
'worklet';
const xArray = cornerPoints.map((corner) => corner.x);
const yArray = cornerPoints.map((corner) => corner.y);
// @NOTE we can't use destructuring here because babel would wrap it in non-worklet functions
const x = Math.min.apply(null, xArray);
const y = Math.min.apply(null, yArray);
const width = Math.max.apply(null, xArray) - x;
const height = Math.max.apply(null, yArray) - y;
return {
origin: { x, y },
size: {
width,
height,
},
};
};
export const normalizePrecision = (number: number): number => {
'worklet';
return Math.round(number);
};
export const normalizeNativeBarcode = (
barcode: iOSBarcode | AndroidBarcode,
frame: Frame,
): Barcode => {
'worklet';
if (isIOSBarcode(barcode)) {
const { payload, symbology, boundingBox, corners } = barcode;
return {
value: payload,
type: normalizeiOSCodeType(symbology),
boundingBox: {
origin: {
x: normalizePrecision(boundingBox.origin.x * frame.width),
y: normalizePrecision(boundingBox.origin.y * frame.height),
},
size: {
width: normalizePrecision(boundingBox.size.width * frame.width),
height: normalizePrecision(boundingBox.size.height * frame.height),
},
},
// This explicitly defined to match android's implementation which is to start top left and go clockwise.
// https://developers.google.com/android/reference/com/google/mlkit/vision/barcode/common/Barcode#public-point[]-getcornerpoints
cornerPoints: [
corners.topLeft,
corners.topRight,
corners.bottomRight,
corners.bottomLeft,
].map(({ x, y }) => ({
x: normalizePrecision(x * frame.width),
y: normalizePrecision(y * frame.height),
})),
native: barcode,
};
} else if (isAndroidBarcode(barcode)) {
const { rawValue, format, cornerPoints } = barcode;
return {
value: rawValue,
type: normalizeAndroidCodeType(format),
boundingBox: computeBoundingBoxFromCornerPoints(cornerPoints),
cornerPoints,
native: barcode,
};
} else {
throw new Error(`Unsupported platform: ${Platform.OS}`);
}
};
export const convertVisionCameraCodeToBarcode = (
code: Code,
): Omit<Barcode, 'native'> => {
return {
value: code.value ?? null,
type: code.type,
boundingBox: {
origin: {
x: code.frame?.x ?? 0,
y: code.frame?.y ?? 0,
},
size: {
width: code.frame?.width ?? 0,
height: code.frame?.height ?? 0,
},
},
cornerPoints: code.corners ?? [],
};
};