Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added code format to see type of code scanned #633

Merged
merged 8 commits into from
Apr 30, 2024
7 changes: 5 additions & 2 deletions android/src/main/java/com/rncamerakit/CKCamera.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import kotlin.math.min
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.RectF
import com.google.mlkit.vision.barcode.common.Barcode

class RectOverlay constructor(context: Context) :
View(context) {
Expand Down Expand Up @@ -457,9 +458,11 @@ class CKCamera(context: ThemedReactContext) : FrameLayout(context), LifecycleObs
rectOverlay.drawRectBounds(focusRects)
}

private fun onBarcodeRead(barcodes: List<String>) {
private fun onBarcodeRead(barcodes: List<Barcode>) {
val event: WritableMap = Arguments.createMap()
event.putString("codeStringValue", barcodes.first())
event.putString("codeStringValue", barcodes.first().rawValue)
val codeFormat = CodeFormat.fromBarcodeType(barcodes.first().format);
event.putString("codeFormat",codeFormat.code );
currentContext.getJSModule(RCTEventEmitter::class.java).receiveEvent(
id,
"onReadCode",
Expand Down
56 changes: 56 additions & 0 deletions android/src/main/java/com/rncamerakit/CodeFormat.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.rncamerakit

import com.google.mlkit.vision.barcode.common.Barcode

enum class CodeFormat(val code: String) {
CODE_128("code-128"),
CODE_39("code-39"),
CODE_93("code-93"),
CODABAR("codabar"),
EAN_13("ean-13"),
EAN_8("ean-8"),
ITF("itf"),
UPC_E("upc-e"),
QR("qr"),
PDF_417("pdf-417"),
AZTEC("aztec"),
DATA_MATRIX("data-matrix"),
UNKNOWN("unknown");

fun toBarcodeType(): Int {
return when (this) {
CODE_128 -> Barcode.FORMAT_CODE_128
CODE_39 -> Barcode.FORMAT_CODE_39
CODE_93 -> Barcode.FORMAT_CODE_93
CODABAR -> Barcode.FORMAT_CODABAR
EAN_13 -> Barcode.FORMAT_EAN_13
EAN_8 -> Barcode.FORMAT_EAN_8
ITF -> Barcode.FORMAT_ITF
UPC_E -> Barcode.FORMAT_UPC_E
QR -> Barcode.FORMAT_QR_CODE
PDF_417 -> Barcode.FORMAT_PDF417
AZTEC -> Barcode.FORMAT_AZTEC
DATA_MATRIX -> Barcode.FORMAT_DATA_MATRIX
UNKNOWN -> -1 // Or any other default value you prefer
}
}

companion object {
fun fromBarcodeType(@Barcode.BarcodeFormat barcodeType: Int): CodeFormat =
when (barcodeType) {
Barcode.FORMAT_CODE_128 -> CODE_128
Barcode.FORMAT_CODE_39 -> CODE_39
Barcode.FORMAT_CODE_93 -> CODE_93
Barcode.FORMAT_CODABAR -> CODABAR
Barcode.FORMAT_EAN_13 -> EAN_13
Barcode.FORMAT_EAN_8 -> EAN_8
Barcode.FORMAT_ITF -> ITF
Barcode.FORMAT_UPC_E -> UPC_E
Barcode.FORMAT_QR_CODE -> QR
Barcode.FORMAT_PDF417 -> PDF_417
Barcode.FORMAT_AZTEC -> AZTEC
Barcode.FORMAT_DATA_MATRIX -> DATA_MATRIX
else -> UNKNOWN
}
}
}
7 changes: 4 additions & 3 deletions android/src/main/java/com/rncamerakit/QRCodeAnalyzer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import androidx.camera.core.ExperimentalGetImage
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageProxy
import com.google.mlkit.vision.barcode.BarcodeScanning
import com.google.mlkit.vision.barcode.common.Barcode
import com.google.mlkit.vision.common.InputImage

class QRCodeAnalyzer (
private val onQRCodesDetected: (qrCodes: List<String>) -> Unit
private val onQRCodesDetected: (qrCodes: List<Barcode>) -> Unit
) : ImageAnalysis.Analyzer {
@SuppressLint("UnsafeExperimentalUsageError")
@ExperimentalGetImage
Expand All @@ -18,9 +19,9 @@ class QRCodeAnalyzer (
val scanner = BarcodeScanning.getClient()
scanner.process(inputImage)
.addOnSuccessListener { barcodes ->
val strBarcodes = mutableListOf<String>()
val strBarcodes = mutableListOf<Barcode>()
barcodes.forEach { barcode ->
strBarcodes.add(barcode.rawValue ?: return@forEach)
strBarcodes.add(barcode ?: return@forEach)
}
onQRCodesDetected(strBarcodes)
}
Expand Down
2 changes: 2 additions & 0 deletions example/src/BarcodeScreenExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ const BarcodeExample = ({ onBack }: { onBack: () => void }) => {
Vibration.vibrate(100);
setBarcode(event.nativeEvent.codeStringValue);
console.log('barcode', event.nativeEvent.codeStringValue);
console.log('codeFormat', event.nativeEvent.codeFormat);

}}
/>
</View>
Expand Down
4 changes: 4 additions & 0 deletions ios/ReactNativeCameraKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
46C558CF2A4AAD7300C68BA0 /* FocusInterfaceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46C558CE2A4AAD7300C68BA0 /* FocusInterfaceView.swift */; };
46F30C012A3A859B000597F6 /* ScannerFrameView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46F30C002A3A859B000597F6 /* ScannerFrameView.swift */; };
46F30C032A3ABB9D000597F6 /* ScannerInterfaceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46F30C022A3ABB9D000597F6 /* ScannerInterfaceView.swift */; };
B5C747452B35924D00C95030 /* CodeFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5C747442B35924D00C95030 /* CodeFormat.swift */; };
/* End PBXBuildFile section */

/* Begin PBXCopyFilesBuildPhase section */
Expand Down Expand Up @@ -55,6 +56,7 @@
46C558CE2A4AAD7300C68BA0 /* FocusInterfaceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FocusInterfaceView.swift; sourceTree = "<group>"; };
46F30C002A3A859B000597F6 /* ScannerFrameView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScannerFrameView.swift; sourceTree = "<group>"; };
46F30C022A3ABB9D000597F6 /* ScannerInterfaceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScannerInterfaceView.swift; sourceTree = "<group>"; };
B5C747442B35924D00C95030 /* CodeFormat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeFormat.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -104,6 +106,7 @@
46C558CE2A4AAD7300C68BA0 /* FocusInterfaceView.swift */,
4620AA682A2BFDBC00BC8929 /* ReactNativeCameraKit-Bridging-Header.h */,
463096892A2C7D89002ABA1A /* ReactNativeCameraKit.h */,
B5C747442B35924D00C95030 /* CodeFormat.swift */,
);
path = ReactNativeCameraKit;
sourceTree = "<group>";
Expand Down Expand Up @@ -181,6 +184,7 @@
26550AF61CFC7086007FF2DF /* CKCameraManager.m in Sources */,
46C558CB2A4AAB3400C68BA0 /* CameraProtocol.swift in Sources */,
4620AA722A2C4FA500BC8929 /* CameraManager.swift in Sources */,
B5C747452B35924D00C95030 /* CodeFormat.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
7 changes: 4 additions & 3 deletions ios/ReactNativeCameraKit/CameraProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import AVFoundation
protocol CameraProtocol: AnyObject, FocusInterfaceViewDelegate {
var previewView: UIView { get }

func setup(cameraType: CameraType, supportedBarcodeType: [AVMetadataObject.ObjectType])
func setup(cameraType: CameraType, supportedBarcodeType: [CodeFormat])
func cameraRemovedFromSuperview()

func update(torchMode: TorchMode)
Expand All @@ -23,8 +23,9 @@ protocol CameraProtocol: AnyObject, FocusInterfaceViewDelegate {
func zoomPinchChange(pinchScale: CGFloat)

func isBarcodeScannerEnabled(_ isEnabled: Bool,
supportedBarcodeType: [AVMetadataObject.ObjectType],
onBarcodeRead: ((_ barcode: String) -> Void)?)
supportedBarcodeTypes: [CodeFormat],
onBarcodeRead: ((_ barcode: String, _ codeFormat: CodeFormat) -> Void)?)

func update(scannerFrameSize: CGRect?)

func capturePicture(onWillCapture: @escaping () -> Void,
Expand Down
17 changes: 12 additions & 5 deletions ios/ReactNativeCameraKit/CameraView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,12 @@ class CameraView: UIView {
private func setupCamera() {
if (hasPropBeenSetup && hasPermissionBeenGranted && !hasCameraBeenSetup) {
hasCameraBeenSetup = true
camera.setup(cameraType: cameraType, supportedBarcodeType: scanBarcode && onReadCode != nil ? supportedBarcodeType : [])
let supportedFormats = supportedBarcodeType.map { CodeFormat.fromAVMetadataObjectType($0) }
camera.setup(cameraType: cameraType, supportedBarcodeType: scanBarcode && onReadCode != nil ? supportedFormats : [])
}
}


// MARK: Lifecycle

@available(*, unavailable)
Expand Down Expand Up @@ -184,11 +186,16 @@ class CameraView: UIView {

// Scanner
if changedProps.contains("scanBarcode") || changedProps.contains("onReadCode") {
let supportedFormats = supportedBarcodeType.map { CodeFormat.fromAVMetadataObjectType($0) }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use CodeFormat for supportedBarcodeType line 23, so no need to map it here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yes I should have just done that :D

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DavidBertet check now

camera.isBarcodeScannerEnabled(scanBarcode,
supportedBarcodeType: supportedBarcodeType,
onBarcodeRead: { [weak self] barcode in self?.onBarcodeRead(barcode: barcode) })
supportedBarcodeTypes: supportedFormats,
onBarcodeRead: { [weak self] (barcode, codeFormat) in
self?.onBarcodeRead(barcode: barcode, codeFormat: codeFormat)
})
}



if changedProps.contains("showFrame") || changedProps.contains("scanBarcode") {
DispatchQueue.main.async {
self.scannerInterfaceView.isHidden = !self.showFrame
Expand Down Expand Up @@ -324,7 +331,7 @@ class CameraView: UIView {
return temporaryFileURL
}

private func onBarcodeRead(barcode: String) {
private func onBarcodeRead(barcode: String, codeFormat:CodeFormat) {
// Throttle barcode detection
let now = Date.timeIntervalSinceReferenceDate
guard lastBarcodeDetectedTime + Double(scanThrottleDelay) / 1000 < now else {
Expand All @@ -333,7 +340,7 @@ class CameraView: UIView {

lastBarcodeDetectedTime = now

onReadCode?(["codeStringValue": barcode])
onReadCode?(["codeStringValue": barcode,"codeFormat":codeFormat.rawValue])
}

// MARK: - Gesture selectors
Expand Down
60 changes: 60 additions & 0 deletions ios/ReactNativeCameraKit/CodeFormat.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//
// CodeFormat.swift
// ReactNativeCameraKit
//
// Created by Imdad on 2023-12-22.
//

import Foundation
import AVFoundation

enum CodeFormat: String {
case code128 = "code-128"
case code39 = "code-39"
case code93 = "code-93"
case ean13 = "ean-13"
case ean8 = "ean-8"
case itf14 = "itf-14"
case upce = "upc-e"
case qr = "qr"
case pdf417 = "pdf-417"
case aztec = "aztec"
case dataMatrix = "data-matrix"
case unknown = "unknown"

// Convert from AVMetadataObject.ObjectType to CodeFormat
static func fromAVMetadataObjectType(_ type: AVMetadataObject.ObjectType) -> CodeFormat {
switch type {
case .code128: return .code128
case .code39: return .code39
case .code93: return .code93
case .ean13: return .ean13
case .ean8: return .ean8
case .itf14: return .itf14
case .upce: return .upce
case .qr: return .qr
case .pdf417: return .pdf417
case .aztec: return .aztec
case .dataMatrix: return .dataMatrix
default: return .unknown
}
}

// Convert from CodeFormat to AVMetadataObject.ObjectType
func toAVMetadataObjectType() -> AVMetadataObject.ObjectType {
switch self {
case .code128: return .code128
case .code39: return .code39
case .code93: return .code93
case .ean13: return .ean13
case .ean8: return .ean8
case .itf14: return .itf14
case .upce: return .upce
case .qr: return .qr
case .pdf417: return .pdf417
case .aztec: return .aztec
case .dataMatrix: return .dataMatrix
case .unknown: return .init(rawValue: "unknown")
}
}
}
22 changes: 13 additions & 9 deletions ios/ReactNativeCameraKit/RealCamera.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
private var torchMode: TorchMode = .off
private var resetFocus: (() -> Void)?
private var focusFinished: (() -> Void)?
private var onBarcodeRead: ((_ barcode: String) -> Void)?
private var onBarcodeRead: ((_ barcode: String,_ codeFormat : CodeFormat) -> Void)?
private var scannerFrameSize: CGRect? = nil
private var onOrientationChange: RCTDirectEventBlock?
private var onZoomCallback: RCTDirectEventBlock?
Expand Down Expand Up @@ -89,7 +89,7 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega

// MARK: - Public

func setup(cameraType: CameraType, supportedBarcodeType: [AVMetadataObject.ObjectType]) {
func setup(cameraType: CameraType, supportedBarcodeType: [CodeFormat]) {
DispatchQueue.main.async {
self.cameraPreview.session = self.session
self.cameraPreview.previewLayer.videoGravity = .resizeAspect
Expand Down Expand Up @@ -335,14 +335,15 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
}

func isBarcodeScannerEnabled(_ isEnabled: Bool,
supportedBarcodeType: [AVMetadataObject.ObjectType],
onBarcodeRead: ((_ barcode: String) -> Void)?) {
supportedBarcodeTypes supportedBarcodeType: [CodeFormat],
onBarcodeRead: ((_ barcode: String,_ codeFormat:CodeFormat) -> Void)?) {
sessionQueue.async {
self.onBarcodeRead = onBarcodeRead
let newTypes: [AVMetadataObject.ObjectType]
if isEnabled && onBarcodeRead != nil {
let availableTypes = self.metadataOutput.availableMetadataObjectTypes
newTypes = supportedBarcodeType.filter { type in availableTypes.contains(type) }
newTypes = supportedBarcodeType.map { $0.toAVMetadataObjectType() }
.filter { availableTypes.contains($0) }
} else {
newTypes = []
}
Expand Down Expand Up @@ -388,8 +389,10 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
let codeStringValue = machineReadableCodeObject.stringValue else {
return
}
// Determine the barcode type and convert it to CodeFormat
let barcodeType = CodeFormat.fromAVMetadataObjectType(machineReadableCodeObject.type)

onBarcodeRead?(codeStringValue)
onBarcodeRead?(codeStringValue,barcodeType)
}

// MARK: - Private
Expand Down Expand Up @@ -445,7 +448,7 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
}

private func setupCaptureSession(cameraType: CameraType,
supportedBarcodeType: [AVMetadataObject.ObjectType]) -> SetupResult {
supportedBarcodeType: [CodeFormat]) -> SetupResult {
guard let videoDevice = self.getBestDevice(for: cameraType),
let videoDeviceInput = try? AVCaptureDeviceInput(device: videoDevice) else {
return .sessionConfigurationFailed
Expand Down Expand Up @@ -482,8 +485,9 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)

let availableTypes = self.metadataOutput.availableMetadataObjectTypes
let filteredTypes = supportedBarcodeType.filter { type in availableTypes.contains(type) }
metadataOutput.metadataObjectTypes = filteredTypes
let filteredTypes = supportedBarcodeType.filter { type in availableTypes.contains(type.toAVMetadataObjectType()) }

metadataOutput.metadataObjectTypes = filteredTypes.map { $0.toAVMetadataObjectType() }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are doing toAVMetadataObjectType twice for the same objects. Something like that should do the same

let filteredTypes = supportedBarcodeType
  .map { $0.toAVMetadataObjectType() }
  .filter { availableTypes.contains($0) }

metadataOutput.metadataObjectTypes = filteredTypes

}

session.commitConfiguration()
Expand Down
6 changes: 3 additions & 3 deletions ios/ReactNativeCameraKit/SimulatorCamera.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class SimulatorCamera: CameraProtocol {

// MARK: - Public

func setup(cameraType: CameraType, supportedBarcodeType: [AVMetadataObject.ObjectType]) {
func setup(cameraType: CameraType, supportedBarcodeType: [CodeFormat]) {
DispatchQueue.main.async {
self.mockPreview.cameraTypeLabel.text = "Camera type: \(cameraType)"
}
Expand Down Expand Up @@ -164,8 +164,8 @@ class SimulatorCamera: CameraProtocol {


func isBarcodeScannerEnabled(_ isEnabled: Bool,
supportedBarcodeType: [AVMetadataObject.ObjectType],
onBarcodeRead: ((_ barcode: String) -> Void)?) {}
supportedBarcodeTypes: [CodeFormat],
onBarcodeRead: ((_ barcode: String,_ codeFormat:CodeFormat) -> Void)?) {}
func update(scannerFrameSize: CGRect?) {}

func capturePicture(onWillCapture: @escaping () -> Void,
Expand Down
3 changes: 2 additions & 1 deletion src/Camera.d.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { CameraApi, FlashMode, FocusMode, ZoomMode, TorchMode, CameraType } from './types';
import { CameraApi, FlashMode, FocusMode, ZoomMode, TorchMode, CameraType,CodeFormat } from './types';
scarlac marked this conversation as resolved.
Show resolved Hide resolved
import { Orientation } from './index';

export type OnReadCodeData = {
nativeEvent: {
codeStringValue: string;
codeFormat: CodeFormat;
};
};

Expand Down
4 changes: 4 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ export enum CameraType {
Back = 'back',
}

export type CodeFormat = 'code-128' | 'code-39' | 'code-93' | 'codabar' | 'ean-13' | 'ean-8' | 'itf' | 'upc-e' | 'qr' | 'pdf-417' | 'aztec' | 'data-matrix' | 'unknown';

export type TorchMode = 'on' | 'off';

export type FlashMode = 'on' | 'off' | 'auto';
Expand All @@ -28,3 +30,5 @@ export type CameraApi = {
requestDeviceCameraAuthorization: () => Promise<boolean>;
checkDeviceCameraAuthorizationStatus: () => Promise<boolean>;
};