Skip to content

Commit

Permalink
added code format to see type of code scanned (#633)
Browse files Browse the repository at this point in the history
* added code format to see type of code scanned

* Update ios/ReactNativeCameraKit/SimulatorCamera.swift

Changed supported barcode types to list of CodeFormat

Co-authored-by: David Bertet <[email protected]>

* Update android/src/main/java/com/rncamerakit/CodeFormat.kt

Added annotation for int type

Co-authored-by: David Bertet <[email protected]>

* Added CodeFormat types and fixed an indentation on a function to match other functions

* Replaced AVMetadataObject with CodeFormat in all files

* Updated code format to case Iterable and changed supportedBarcodeType to code format cases

* Update src/Camera.d.ts

---------

Co-authored-by: David Bertet <[email protected]>
Co-authored-by: Seph Soliman <[email protected]>
  • Loading branch information
3 people authored Apr 30, 2024
1 parent 6c5ae90 commit 234e7f8
Show file tree
Hide file tree
Showing 12 changed files with 172 additions and 30 deletions.
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 @@ -151,6 +151,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
22 changes: 13 additions & 9 deletions ios/ReactNativeCameraKit/CameraView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ class CameraView: UIView {
// scanner
private var lastBarcodeDetectedTime: TimeInterval = 0
private var scannerInterfaceView: ScannerInterfaceView
private var supportedBarcodeType: [AVMetadataObject.ObjectType] = [.upce, .code39, .code39Mod43,
.ean13, .ean8, .code93,
.code128, .pdf417, .qr,
.aztec, .dataMatrix, .interleaved2of5]
private var supportedBarcodeType: [CodeFormat] = {
return CodeFormat.allCases
}()

// camera
private var ratioOverlayView: RatioOverlayView?

Expand Down Expand Up @@ -69,14 +69,14 @@ class CameraView: UIView {
setupCamera()
}
}

private func setupCamera() {
if hasPropBeenSetup && hasPermissionBeenGranted && !hasCameraBeenSetup {
hasCameraBeenSetup = true
camera.setup(cameraType: cameraType, supportedBarcodeType: scanBarcode && onReadCode != nil ? supportedBarcodeType : [])
}
}


// MARK: Lifecycle

@available(*, unavailable)
Expand Down Expand Up @@ -186,10 +186,14 @@ class CameraView: UIView {
// Scanner
if changedProps.contains("scanBarcode") || changedProps.contains("onReadCode") {
camera.isBarcodeScannerEnabled(scanBarcode,
supportedBarcodeType: supportedBarcodeType,
onBarcodeRead: { [weak self] barcode in self?.onBarcodeRead(barcode: barcode) })
supportedBarcodeTypes: supportedBarcodeType,
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 @@ -330,7 +334,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 @@ -339,7 +343,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, CaseIterable {
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")
}
}
}
24 changes: 15 additions & 9 deletions ios/ReactNativeCameraKit/RealCamera.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ 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 scannerFrameSize: CGRect?
private var onBarcodeRead: ((_ barcode: String,_ codeFormat : CodeFormat) -> Void)?
private var scannerFrameSize: CGRect? = nil
private var onOrientationChange: RCTDirectEventBlock?
private var onZoomCallback: RCTDirectEventBlock?
private var lastOnZoom: Double?
Expand Down Expand Up @@ -93,7 +93,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 @@ -340,14 +340,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 @@ -396,8 +397,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 @@ -453,7 +456,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 @@ -489,7 +492,10 @@ 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) }
let filteredTypes = supportedBarcodeType
.map { $0.toAVMetadataObjectType() }
.filter { availableTypes.contains($0) }

metadataOutput.metadataObjectTypes = filteredTypes
}

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 @@ -162,8 +162,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';
import { Orientation } from './index';

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

Expand Down
Loading

0 comments on commit 234e7f8

Please sign in to comment.