feat(mlkit): add mlkit barcode detection ios (#2209)

extend barcode type cases for android
This commit is contained in:
Daniil Ovoshchnikov 2019-04-16 20:33:46 +02:00 committed by Sibelius Seraphini
parent 028736b7c7
commit 1b9fb63e56
16 changed files with 1016 additions and 67 deletions

View File

@ -225,9 +225,9 @@ end
5. In XCode, in the project navigator, select your project. Add `libRNCamera.a` to your project's `Build Phases``Link Binary With Libraries`
6. Click `RNCamera.xcodeproj` in the project navigator and go the `Build Settings` tab. Make sure 'All' is toggled on (instead of 'Basic'). In the `Search Paths` section, look for `Header Search Paths` and make sure it contains both `$(SRCROOT)/../../react-native/React` and `$(SRCROOT)/../../../React` - mark both as `recursive`.
##### Face Detection or Text Recognition Steps
##### Face Detection/Text Recognition/BarCode(using MLKit) Steps
Face Detection/Text Recognition are optional on iOS. If you want them, you are going to use CocoaPods path and set-up Firebase project for your app (detailed steps below).
Face Detection/Text Recognition/BarCode(using MLKit) are optional on iOS. If you want them, you will need to use CocoaPods path and set-up Firebase project for your app (detailed steps below).
_Note:_ Installing react-native-firebase package is NOT necessary.
@ -256,12 +256,21 @@ pod 'react-native-camera', path: '../node_modules/react-native-camera', subspecs
]
```
or to (Both Face and Text detection)
or to (for Text Recognition)
```
pod 'react-native-camera', path: '../node_modules/react-native-camera', subspecs: [
'BarcodeDetectorMLKit'
]
```
or to (all possible detections)
```
pod 'react-native-camera', path: '../node_modules/react-native-camera', subspecs: [
'TextDetector',
'FaceDetectorMLKit'
'FaceDetectorMLKit',
'BarcodeDetectorMLKit'
]
```

View File

@ -36,6 +36,7 @@ public class BarcodeFormatUtils {
map.put(FirebaseVisionBarcode.FORMAT_AZTEC, "AZTEC");
map.put(FirebaseVisionBarcode.FORMAT_ALL_FORMATS, "ALL");
map.put(FirebaseVisionBarcode.FORMAT_UPC_A, "UPC_A");
map.put(FirebaseVisionBarcode.FORMAT_ALL_FORMATS, "ALL");
map.put(-1, "None");
FORMATS = map;

View File

@ -160,6 +160,119 @@ public class BarcodeDetectorAsyncTask extends android.os.AsyncTask<Void, Void, V
serializedBarcode.putString("url", url);
serializedBarcode.putString("title", title);
break;
case FirebaseVisionBarcode.TYPE_SMS:
String message = barcode.getSms().getMessage();
String phoneNumber = barcode.getSms().getPhoneNumber();
serializedBarcode.putString("message", message);
serializedBarcode.putString("title", phoneNumber);
break;
case FirebaseVisionBarcode.TYPE_PHONE:
String number = barcode.getPhone().getNumber();
int typePhone = barcode.getPhone().getType();
serializedBarcode.putString("number", number);
String typeStringPhone = getPhoneType(typePhone);
serializedBarcode.putString("phoneType", typeStringPhone);
break;
case FirebaseVisionBarcode.TYPE_CALENDAR_EVENT:
serializedBarcode.putString("description", barcode.getCalendarEvent().getDescription());
serializedBarcode.putString("location", barcode.getCalendarEvent().getLocation());
serializedBarcode.putString("organizer", barcode.getCalendarEvent().getOrganizer());
serializedBarcode.putString("status", barcode.getCalendarEvent().getStatus());
serializedBarcode.putString("summary", barcode.getCalendarEvent().getSummary());
FirebaseVisionBarcode.CalendarDateTime start = barcode.getCalendarEvent().getStart();
FirebaseVisionBarcode.CalendarDateTime end = barcode.getCalendarEvent().getEnd();
if (start != null) {
serializedBarcode.putString("start", start.getRawValue());
}
if (end != null) {
serializedBarcode.putString("end", start.getRawValue());
}
break;
case FirebaseVisionBarcode.TYPE_DRIVER_LICENSE:
serializedBarcode.putString("addressCity", barcode.getDriverLicense().getAddressCity());
serializedBarcode.putString("addressState", barcode.getDriverLicense().getAddressState());
serializedBarcode.putString("addressStreet", barcode.getDriverLicense().getAddressStreet());
serializedBarcode.putString("addressZip", barcode.getDriverLicense().getAddressZip());
serializedBarcode.putString("birthDate", barcode.getDriverLicense().getBirthDate());
serializedBarcode.putString("documentType", barcode.getDriverLicense().getDocumentType());
serializedBarcode.putString("expiryDate", barcode.getDriverLicense().getExpiryDate());
serializedBarcode.putString("firstName", barcode.getDriverLicense().getFirstName());
serializedBarcode.putString("middleName", barcode.getDriverLicense().getMiddleName());
serializedBarcode.putString("lastName", barcode.getDriverLicense().getLastName());
serializedBarcode.putString("gender", barcode.getDriverLicense().getGender());
serializedBarcode.putString("issueDate", barcode.getDriverLicense().getIssueDate());
serializedBarcode.putString("issuingCountry", barcode.getDriverLicense().getIssuingCountry());
serializedBarcode.putString("licenseNumber", barcode.getDriverLicense().getLicenseNumber());
break;
case FirebaseVisionBarcode.TYPE_GEO:
serializedBarcode.putDouble("latitude", barcode.getGeoPoint().getLat());
serializedBarcode.putDouble("longitude", barcode.getGeoPoint().getLng());
break;
case FirebaseVisionBarcode.TYPE_CONTACT_INFO:
serializedBarcode.putString("organization", barcode.getContactInfo().getOrganization());
serializedBarcode.putString("title", barcode.getContactInfo().getTitle());
FirebaseVisionBarcode.PersonName name = barcode.getContactInfo().getName();
if (name != null) {
serializedBarcode.putString("firstName", name.getFirst());
serializedBarcode.putString("lastName", name.getLast());
serializedBarcode.putString("middleName", name.getMiddle());
serializedBarcode.putString("formattedName", name.getFormattedName());
serializedBarcode.putString("prefix", name.getPrefix());
serializedBarcode.putString("pronunciation", name.getPronunciation());
serializedBarcode.putString("suffix", name.getSuffix());
}
List<FirebaseVisionBarcode.Phone> phones = barcode.getContactInfo().getPhones();
WritableArray phonesList = Arguments.createArray();
for (FirebaseVisionBarcode.Phone phone : phones) {
WritableMap phoneObject = Arguments.createMap();
phoneObject.putString("number", phone.getNumber());
phoneObject.putString("phoneType", getPhoneType(phone.getType()));
phonesList.pushMap(phoneObject);
}
serializedBarcode.putArray("phones", phonesList);
List<FirebaseVisionBarcode.Address> addresses = barcode.getContactInfo().getAddresses();
WritableArray addressesList = Arguments.createArray();
for (FirebaseVisionBarcode.Address address : addresses) {
WritableMap addressesData = Arguments.createMap();
WritableArray addressesLinesList = Arguments.createArray();
String[] addressesLines = address.getAddressLines();
for (String line : addressesLines) {
addressesLinesList.pushString(line);
}
addressesData.putArray("addressLines", addressesLinesList);
int addressType = address.getType();
String addressTypeString = "UNKNOWN";
switch(addressType) {
case FirebaseVisionBarcode.Address.TYPE_WORK:
addressTypeString = "Work";
break;
case FirebaseVisionBarcode.Address.TYPE_HOME:
addressTypeString = "Home";
break;
}
addressesData.putString("addressType", addressTypeString);
addressesList.pushMap(addressesData);
}
serializedBarcode.putArray("addresses", addressesList);
List<FirebaseVisionBarcode.Email> emails = barcode.getContactInfo().getEmails();
WritableArray emailsList = Arguments.createArray();
for (FirebaseVisionBarcode.Email email : emails) {
WritableMap emailData = processEmail(email);
emailsList.pushMap(emailData);
}
serializedBarcode.putArray("emails", emailsList);
String[] urls = barcode.getContactInfo().getUrls();
WritableArray urlsList = Arguments.createArray();
for (String urlContact : urls) {
urlsList.pushString(urlContact);
}
serializedBarcode.putArray("urls", urlsList);
break;
case FirebaseVisionBarcode.TYPE_EMAIL:
WritableMap emailData = processEmail(barcode.getEmail());
serializedBarcode.putMap("email", emailData);
break;
}
serializedBarcode.putString("data", barcode.getDisplayValue());
@ -172,6 +285,44 @@ public class BarcodeDetectorAsyncTask extends android.os.AsyncTask<Void, Void, V
return barcodesList;
}
private WritableMap processEmail(FirebaseVisionBarcode.Email email) {
WritableMap emailData = Arguments.createMap();
emailData.putString("address", email.getAddress());
emailData.putString("body", email.getBody());
emailData.putString("subject", email.getSubject());
int emailType = email.getType();
String emailTypeString = "UNKNOWN";
switch (emailType) {
case FirebaseVisionBarcode.Email.TYPE_WORK:
emailTypeString = "Work";
break;
case FirebaseVisionBarcode.Email.TYPE_HOME:
emailTypeString = "Home";
break;
}
emailData.putString("emailType", emailTypeString);
return emailData;
}
private String getPhoneType(int typePhone) {
String typeStringPhone = "UNKNOWN";
switch(typePhone) {
case FirebaseVisionBarcode.Phone.TYPE_WORK:
typeStringPhone = "Work";
break;
case FirebaseVisionBarcode.Phone.TYPE_HOME:
typeStringPhone = "Home";
break;
case FirebaseVisionBarcode.Phone.TYPE_FAX:
typeStringPhone = "Fax";
break;
case FirebaseVisionBarcode.Phone.TYPE_MOBILE:
typeStringPhone = "Mobile";
break;
}
return typeStringPhone;
}
private WritableMap processBounds(Rect frame) {
WritableMap origin = Arguments.createMap();
int x = frame.left;

View File

@ -409,14 +409,29 @@ The following barcode types can be recognised:
An array of barcode types to search for. Defaults to all types listed above. No effect if `onBarCodeRead` is undefined.
Example: `<RNCamera barCodeTypes={[RNCamera.Constants.BarCodeType.qr]} />`
#### `Android` `onGoogleVisionBarcodesDetected`
#### `onGoogleVisionBarcodesDetected`
Like `onBarCodeRead`, but we will use Google Play Service Vision to scan barcodes, which is pretty fast on Android. Note: If you already set `onBarCodeRead`, this will be invalid.
Like `onBarCodeRead`, but using Firebase MLKit to scan barcodes. More info can be found [here](https://firebase.google.com/docs/ml-kit/read-barcodes) Note: If you already set `onBarCodeRead`, this will be invalid.
#### `Android` `googleVisionBarcodeType`
#### `googleVisionBarcodeType`
Like `barCodeTypes`, but applies to the Google Play Service Vision barcode detector.
Like `barCodeTypes`, but applies to the Firebase MLKit barcode detector.
Example: `<RNCamera googleVisionBarcodeType={RNCamera.Constants.GoogleVisionBarcodeDetection.BarcodeType.DATA_MATRIX} />`
Available settings:
- CODE_128
- CODE_39
- CODE_93
- CODABAR
- EAN_13
- EAN_8
- ITF
- UPC_A
- UPC_E
- QR_CODE
- PDF417
- AZTEC
- DATA_MATRIX
- ALL
#### `Android` `googleVisionBarcodeMode`
@ -425,11 +440,11 @@ Example: `<RNCamera googleVisionBarcodeMode={RNCamera.Constants.GoogleVisionBarc
### Face Detection Related props
RNCamera uses the Google Mobile Vision frameworks for Face Detection, you can read more info about it [here](https://developers.google.com/android/reference/com/google/android/gms/vision/face/FaceDetector).
RNCamera uses the Firebase MLKit for Face Detection, you can read more about it [here](https://firebase.google.com/docs/ml-kit/detect-faces).
#### `onFacesDetected`
Method to be called when face is detected. Receives a Faces Detected Event object. The interesting value of this object is the `faces` value, which is an array with objects of the [Face](https://developers.google.com/android/reference/com/google/android/gms/vision/face/Face) properties.
Method to be called when face is detected. Receives a Faces Detected Event object. The interesting value of this object is the `faces` value, which is an array of Face objects. You can find more details about the possible values of these objects [here](https://firebase.google.com/docs/ml-kit/face-detection-concepts)
#### `onFaceDetectionError`
@ -457,11 +472,11 @@ Classification is determining whether a certain facial characteristic is present
### Text Recognition Related props
RNCamera uses the Google Mobile Vision frameworks for Text Recognition, you can read more info about it [here](https://developers.google.com/vision/android/text-overview).
RNCamera uses the Firebase MLKit for Text Recognition, you can read more info about it [here](https://firebase.google.com/docs/ml-kit/recognize-text).
#### `onTextRecognized`
Method to be called when text is detected. Receives a Text Recognized Event object. The interesting value of this object is the `textBlocks` value, which is an array with objects of the [TextBlock](https://developers.google.com/android/reference/com/google/android/gms/vision/text/TextBlock) properties.
Method to be called when text is detected. Receives a Text Recognized Event object. The interesting value of this object is the `textBlocks` value, which is an array of TextBlock objects.
## Component instance methods
@ -612,9 +627,10 @@ Read more about [react-native-barcode-mask](https://github.com/shahnawaz/react-n
To learn about how to test components which uses `RNCamera` check its [documentation about testing](./tests.md).
## Example
## Examples
To see more of the `RNCamera` in action you can check out the [RNCamera examples directory](https://github.com/react-native-community/react-native-camera/tree/master/examples).
Firebase MLKit-base features (such as Text, Face and Barcode detection) can be found in the [mlkit](https://github.com/react-native-community/react-native-camera/tree/master/examples/mlkit) example.
## Open Collective

View File

@ -2,7 +2,7 @@
import React from 'react';
import { StyleSheet, Text, View, TouchableOpacity, Slider } from 'react-native';
// eslint-disable-next-line import/no-unresolved
import { FaceDetector, RNCamera } from 'react-native-camera';
import { RNCamera } from 'react-native-camera';
const flashModeOrder = {
off: 'on',
@ -267,6 +267,7 @@ export default class CameraScreen extends React.Component {
onFacesDetected={canDetectFaces ? this.facesDetected : null}
onTextRecognized={canDetectText ? this.textRecognized : null}
onGoogleVisionBarcodesDetected={canDetectBarcode ? this.barcodeRecognized : null}
googleVisionBarcodeType={RNCamera.Constants.GoogleVisionBarcodeDetection.BarcodeType.ALL}
>
<View
style={{

View File

@ -26,7 +26,8 @@ target 'mlkit' do
pod 'react-native-camera', path: '../../../', subspecs: [
'TextDetector',
'FaceDetectorMLKit'
'FaceDetectorMLKit',
'BarcodeDetectorMLKit'
]
pod 'Firebase/Core'

View File

@ -9,6 +9,9 @@ PODS:
- Firebase/MLVision (5.16.0):
- Firebase/CoreOnly
- FirebaseMLVision (= 0.14.0)
- Firebase/MLVisionBarcodeModel (5.16.0):
- Firebase/CoreOnly
- FirebaseMLVisionBarcodeModel (= 0.14.0)
- Firebase/MLVisionFaceModel (5.16.0):
- Firebase/CoreOnly
- FirebaseMLVisionFaceModel (= 0.14.0)
@ -41,6 +44,8 @@ PODS:
- GoogleAPIClientForREST/Core (~> 1.3)
- GoogleAPIClientForREST/Vision (~> 1.3)
- GoogleMobileVision/Detector (~> 1.4)
- FirebaseMLVisionBarcodeModel (0.14.0):
- GoogleMobileVision/BarcodeDetector (~> 1.4)
- FirebaseMLVisionFaceModel (0.14.0):
- GoogleMobileVision/FaceDetector (~> 1.4)
- FirebaseMLVisionTextModel (0.14.0):
@ -61,6 +66,8 @@ PODS:
- GoogleUtilities/Network (~> 5.2)
- "GoogleUtilities/NSData+zlib (~> 5.2)"
- nanopb (~> 0.3)
- GoogleMobileVision/BarcodeDetector (1.5.0):
- GoogleMobileVision/Detector (~> 1.5)
- GoogleMobileVision/Detector (1.5.0):
- GoogleToolboxForMac/Logger (~> 2.1)
- "GoogleToolboxForMac/NSData+zlib (~> 2.1)"
@ -106,17 +113,23 @@ PODS:
- Protobuf (3.7.0)
- React (0.59.1):
- React/Core (= 0.59.1)
- react-native-camera/FaceDetectorMLKit (2.2.1):
- react-native-camera/BarcodeDetectorMLKit (2.2.2):
- Firebase/MLVision
- Firebase/MLVisionBarcodeModel
- React
- react-native-camera/RCT
- react-native-camera/RN
- react-native-camera/FaceDetectorMLKit (2.2.2):
- Firebase/MLVision
- Firebase/MLVisionFaceModel
- React
- react-native-camera/RCT
- react-native-camera/RN
- react-native-camera/RCT (2.2.1):
- react-native-camera/RCT (2.2.2):
- React
- react-native-camera/RN (2.2.1):
- react-native-camera/RN (2.2.2):
- React
- react-native-camera/TextDetector (2.2.1):
- react-native-camera/TextDetector (2.2.2):
- Firebase/MLVision
- Firebase/MLVisionTextModel
- React
@ -169,6 +182,7 @@ DEPENDENCIES:
- Firebase/Core
- Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`)
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
- react-native-camera/BarcodeDetectorMLKit (from `../../../`)
- react-native-camera/FaceDetectorMLKit (from `../../../`)
- react-native-camera/TextDetector (from `../../../`)
- React/Core (from `../node_modules/react-native`)
@ -189,6 +203,7 @@ SPEC REPOS:
- FirebaseInstanceID
- FirebaseMLCommon
- FirebaseMLVision
- FirebaseMLVisionBarcodeModel
- FirebaseMLVisionFaceModel
- FirebaseMLVisionTextModel
- GoogleAPIClientForREST
@ -223,6 +238,7 @@ SPEC CHECKSUMS:
FirebaseInstanceID: 97ea7a5dca9afd72c79bfcdddb7a44aa1cbb42a1
FirebaseMLCommon: d8a789e36a7faa175b1a5d1139e7fc7323c8db7b
FirebaseMLVision: 07c0da3ceaa5ecde621528a985748d6098a84388
FirebaseMLVisionBarcodeModel: 7ae6e777c4c268505f08761afdfb64613c41204d
FirebaseMLVisionFaceModel: 8c80355e22cfcf100ad2ac9c618536d19daf266b
FirebaseMLVisionTextModel: c6b3bf6129cb97cba51f8f90e80b40a66228dfa1
Folly: de497beb10f102453a1afa9edbf8cf8a251890de
@ -236,9 +252,9 @@ SPEC CHECKSUMS:
nanopb: 2901f78ea1b7b4015c860c2fdd1ea2fee1a18d48
Protobuf: 7a877b7f3e5964e3fce995e2eb323dbc6831bb5a
React: 1d605e098d69bdf08960787f3446f0a9dc2e2ccf
react-native-camera: d13de9a2dfb5bec5ab2ee0a87a0188fbe9f91937
react-native-camera: 9c50d7def800895e7991ccda6203929553ceec9c
yoga: 128daf064cacaede0c3bb27424b6b4c71052e6cd
PODFILE CHECKSUM: ac79060dabdb42d0c1880375ab074e4a801d9223
PODFILE CHECKSUM: ea5c4e2c8f2c607fe7c1cd69dc26067aef6c2ce1
COCOAPODS: 1.5.3

View File

@ -0,0 +1,17 @@
#import <UIKit/UIKit.h>
#if __has_include(<FirebaseMLVision/FirebaseMLVision.h>)
#import <FirebaseMLVision/FirebaseMLVision.h>
#endif
@interface BarcodeDetectorManagerMlkit : NSObject
typedef void(^postRecognitionBlock)(NSArray *barcodes);
- (instancetype)init;
-(BOOL)isRealDetector;
-(void)setType:(id)json queue:(dispatch_queue_t)sessionQueue;
-(void)findBarcodesInFrame:(UIImage *)image scaleX:(float)scaleX scaleY:(float)scaleY completed:(postRecognitionBlock)completed;
+(NSDictionary *)constants;
@end

View File

@ -0,0 +1,439 @@
#import "BarcodeDetectorManagerMlkit.h"
#import <React/RCTConvert.h>
#if __has_include(<FirebaseMLVision/FirebaseMLVision.h>)
@interface BarcodeDetectorManagerMlkit ()
@property(nonatomic, strong) FIRVisionBarcodeDetector *barcodeRecognizer;
@property(nonatomic, strong) FIRVision *vision;
@property(nonatomic, assign) FIRVisionBarcodeFormat setOption;
@property(nonatomic, assign) float scaleX;
@property(nonatomic, assign) float scaleY;
@end
@implementation BarcodeDetectorManagerMlkit
- (instancetype)init
{
if (self = [super init]) {
self.vision = [FIRVision vision];
self.barcodeRecognizer = [_vision barcodeDetector];
}
return self;
}
- (BOOL)isRealDetector
{
return true;
}
+ (NSDictionary *)constants
{
return @{
@"CODE_128" : @(FIRVisionBarcodeFormatCode128),
@"CODE_39" : @(FIRVisionBarcodeFormatCode39),
@"CODE_93" : @(FIRVisionBarcodeFormatCode93),
@"CODABAR" : @(FIRVisionBarcodeFormatCodaBar),
@"EAN_13" : @(FIRVisionBarcodeFormatEAN13),
@"EAN_8" : @(FIRVisionBarcodeFormatEAN8),
@"ITF" : @(FIRVisionBarcodeFormatITF),
@"UPC_A" : @(FIRVisionBarcodeFormatUPCA),
@"UPC_E" : @(FIRVisionBarcodeFormatUPCE),
@"QR_CODE" : @(FIRVisionBarcodeFormatQRCode),
@"PDF417" : @(FIRVisionBarcodeFormatPDF417),
@"AZTEC" : @(FIRVisionBarcodeFormatAztec),
@"DATA_MATRIX" : @(FIRVisionBarcodeFormatDataMatrix),
@"ALL" : @(FIRVisionBarcodeFormatAll),
};
}
- (void)setType:(id)json queue:(dispatch_queue_t)sessionQueue
{
NSInteger requestedValue = [RCTConvert NSInteger:json];
if (self.setOption != requestedValue) {
if (sessionQueue) {
dispatch_async(sessionQueue, ^{
self.setOption = requestedValue;
FIRVisionBarcodeDetectorOptions *options =
[[FIRVisionBarcodeDetectorOptions alloc]
initWithFormats: requestedValue];
self.barcodeRecognizer =
[self.vision barcodeDetectorWithOptions:options];
});
}
}
}
- (void)findBarcodesInFrame:(UIImage *)uiImage
scaleX:(float)scaleX
scaleY:(float)scaleY
completed:(void (^)(NSArray *result))completed
{
self.scaleX = scaleX;
self.scaleY = scaleY;
FIRVisionImage *image = [[FIRVisionImage alloc] initWithImage:uiImage];
NSMutableArray *emptyResult = [[NSMutableArray alloc] init];
[_barcodeRecognizer detectInImage:image
completion:^(NSArray<FIRVisionBarcode *> *barcodes, NSError *error) {
if (error != nil || barcodes == nil) {
completed(emptyResult);
} else {
completed([self processBarcodes:barcodes]);
}
}];
}
- (NSArray *)processBarcodes:(NSArray *)barcodes
{
NSMutableArray *result = [[NSMutableArray alloc] init];
for (FIRVisionBarcode *barcode in barcodes) {
NSMutableDictionary *resultDict =
[[NSMutableDictionary alloc] initWithCapacity:20];
// Boundaries of a barcode in image
NSDictionary *bounds = [self processBounds:barcode.frame];
[resultDict setObject:bounds forKey:@"bounds"];
// TODO send points to javascript - implement on android at the same time
// Point[] corners = barcode.getCornerPoints();
NSString *rawValue = barcode.rawValue;
NSString *displayValue = barcode.displayValue;
[resultDict setObject:rawValue forKey:@"dataRaw"];
[resultDict setObject:displayValue forKey:@"data"];
FIRVisionBarcodeValueType valueType = barcode.valueType;
[resultDict setObject:[self getType:barcode.valueType] forKey:@"type"];
switch (valueType) {
case FIRVisionBarcodeValueTypeWiFi:
if(barcode.wifi.ssid) {[resultDict setObject:barcode.wifi.ssid forKey:@"ssid"]; }
if(barcode.wifi.password) {[resultDict setObject:barcode.wifi.password forKey:@"password"]; }
if(barcode.wifi.type) {
NSString *encryptionTypeString = @"UNKNOWN";
int type = barcode.wifi.type;
switch (type) {
case FIRVisionBarcodeWiFiEncryptionTypeWEP:
encryptionTypeString = @"WEP";
break;
case FIRVisionBarcodeWiFiEncryptionTypeWPA:
encryptionTypeString = @"WPA";
break;
case FIRVisionBarcodeWiFiEncryptionTypeOpen:
encryptionTypeString = @"Open";
break;
default:
break;
}
[resultDict setObject:encryptionTypeString forKey:@"encryptionType"];
}
break;
case FIRVisionBarcodeValueTypeURL:
if(barcode.URL.url) { [resultDict setObject:barcode.URL.url forKey:@"url"]; }
if(barcode.URL.title) { [resultDict setObject:barcode.URL.title forKey:@"title"]; }
break;
case FIRVisionBarcodeValueTypeContactInfo:
if(barcode.contactInfo.addresses) {
NSMutableArray *addresses = [[NSMutableArray alloc] init];
for (FIRVisionBarcodeAddress *address in barcode.contactInfo.addresses) {
[addresses addObject:[self processAddress:address]];
}
[resultDict setObject:addresses forKey:@"addresses"];
}
if(barcode.contactInfo.emails) {
NSMutableArray *emails = [[NSMutableArray alloc] init];
for (FIRVisionBarcodeEmail *email in barcode.contactInfo.emails) {
[emails addObject:[self processEmail:email]];
}
[resultDict setObject:emails forKey:@"emails"];
}
if(barcode.contactInfo.name) {
FIRVisionBarcodePersonName *name = barcode.contactInfo.name;
NSObject *nameObject = @{
@"formattedName" : name.formattedName,
@"firstName" : name.first,
@"middleName" : name.middle,
@"lastName" : name.last,
@"prefix" : name.prefix,
@"pronounciation" : name.pronounciation,
@"suffix" : name.suffix,
};
[resultDict setObject:nameObject forKey:@"name"];
}
if(barcode.contactInfo.phones) {
NSMutableArray *phones = [[NSMutableArray alloc] init];
for (FIRVisionBarcodePhone *phone in barcode.contactInfo.phones) {
[phones addObject:[self processPhone:phone]];
}
[resultDict setObject:phones forKey:@"phones"];
}
if(barcode.contactInfo.urls) {[resultDict setObject:barcode.contactInfo.urls forKey:@"urls"]; }
if(barcode.contactInfo.organization) {[resultDict setObject:barcode.contactInfo.organization forKey:@"organization"]; }
break;
case FIRVisionBarcodeValueTypeSMS:
if(barcode.sms.message) {[resultDict setObject:barcode.sms.message forKey:@"message"]; }
if(barcode.sms.phoneNumber) {[resultDict setObject:barcode.sms.phoneNumber forKey:@"phoneNumber"]; }
break;
case FIRVisionBarcodeValueTypeGeographicCoordinates:
if(barcode.geoPoint.latitude) {[resultDict setObject:@(barcode.geoPoint.latitude) forKey:@"latitude"]; }
if(barcode.geoPoint.longitude) {[resultDict setObject:@(barcode.geoPoint.longitude) forKey:@"longitude"]; }
break;
case FIRVisionBarcodeValueTypeDriversLicense:
if(barcode.driverLicense.firstName) {[resultDict setObject:barcode.driverLicense.firstName forKey:@"firstName"]; }
if(barcode.driverLicense.middleName) {[resultDict setObject:barcode.driverLicense.middleName forKey:@"middleName"]; }
if(barcode.driverLicense.lastName) {[resultDict setObject:barcode.driverLicense.lastName forKey:@"lastName"]; }
if(barcode.driverLicense.gender) {[resultDict setObject:barcode.driverLicense.gender forKey:@"gender"]; }
if(barcode.driverLicense.addressCity) {[resultDict setObject:barcode.driverLicense.addressCity forKey:@"addressCity"]; }
if(barcode.driverLicense.addressState) {[resultDict setObject:barcode.driverLicense.addressState forKey:@"addressState"]; }
if(barcode.driverLicense.addressStreet) {[resultDict setObject:barcode.driverLicense.addressStreet forKey:@"addressStreet"]; }
if(barcode.driverLicense.addressZip) {[resultDict setObject:barcode.driverLicense.addressZip forKey:@"addressZip"]; }
if(barcode.driverLicense.birthDate) {[resultDict setObject:barcode.driverLicense.birthDate forKey:@"birthDate"]; }
if(barcode.driverLicense.documentType) {[resultDict setObject:barcode.driverLicense.documentType forKey:@"documentType"]; }
if(barcode.driverLicense.licenseNumber) {[resultDict setObject:barcode.driverLicense.licenseNumber forKey:@"licenseNumber"]; }
if(barcode.driverLicense.expiryDate) {[resultDict setObject:barcode.driverLicense.expiryDate forKey:@"expiryDate"]; }
if(barcode.driverLicense.issuingDate) {[resultDict setObject:barcode.driverLicense.issuingDate forKey:@"issuingDate"]; }
if(barcode.driverLicense.issuingCountry) {[resultDict setObject:barcode.driverLicense.issuingCountry forKey:@"issuingCountry"]; }
break;
case FIRVisionBarcodeValueTypeCalendarEvent:
if(barcode.calendarEvent.eventDescription) {[resultDict setObject:barcode.calendarEvent.eventDescription forKey:@"eventDescription"]; }
if(barcode.calendarEvent.location) {[resultDict setObject:barcode.calendarEvent.location forKey:@"location"]; }
if(barcode.calendarEvent.organizer) {[resultDict setObject:barcode.calendarEvent.organizer forKey:@"organizer"]; }
if(barcode.calendarEvent.status) {[resultDict setObject:barcode.calendarEvent.status forKey:@"status"]; }
if(barcode.calendarEvent.summary) {[resultDict setObject:barcode.calendarEvent.summary forKey:@"summary"]; }
if(barcode.calendarEvent.start) {
[resultDict setObject:[self processDate:barcode.calendarEvent.start] forKey:@"start"];
}
if(barcode.calendarEvent.end) {
[resultDict setObject:[self processDate:barcode.calendarEvent.end] forKey:@"end"];
}
break;
case FIRVisionBarcodeValueTypePhone:
if(barcode.phone.number) {[resultDict setObject:barcode.phone.number forKey:@"number"]; }
if(barcode.phone.type) {
[resultDict setObject:[self getPhoneType:barcode.phone.type] forKey:@"phoneType"];
}
break;
case FIRVisionBarcodeValueTypeEmail:
if(barcode.email.address) {[resultDict setObject:barcode.email.address forKey:@"address"]; }
if(barcode.email.body) {[resultDict setObject:barcode.email.body forKey:@"body"]; }
if(barcode.email.subject) {[resultDict setObject:barcode.email.subject forKey:@"subject"]; }
if(barcode.email.type) {[resultDict setObject:[self getEmailType:barcode.email.type] forKey:@"emailType"]; }
break;
default:
break;
}
[result addObject:resultDict];
}
return result;
}
- (NSString *)getType:(int)type
{
NSString *barcodeType = @"UNKNOWN";
switch (type) {
case FIRVisionBarcodeValueTypeEmail:
barcodeType = @"EMAIL";
break;
case FIRVisionBarcodeValueTypePhone:
barcodeType = @"PHONE";
break;
case FIRVisionBarcodeValueTypeCalendarEvent:
barcodeType = @"CALENDAR_EVENT";
break;
case FIRVisionBarcodeValueTypeDriversLicense:
barcodeType = @"DRIVER_LICENSE";
break;
case FIRVisionBarcodeValueTypeGeographicCoordinates:
barcodeType = @"GEO";
break;
case FIRVisionBarcodeValueTypeSMS:
barcodeType = @"SMS";
break;
case FIRVisionBarcodeValueTypeContactInfo:
barcodeType = @"CONTACT_INFO";
break;
case FIRVisionBarcodeValueTypeWiFi:
barcodeType = @"WIFI";
break;
case FIRVisionBarcodeValueTypeText:
barcodeType = @"TEXT";
break;
case FIRVisionBarcodeValueTypeISBN:
barcodeType = @"ISBN";
break;
case FIRVisionBarcodeValueTypeProduct:
barcodeType = @"PRODUCT";
break;
default:
break;
}
return barcodeType;
}
- (NSString *)getPhoneType:(int)type
{
NSString *typeString = @"UNKNOWN";
switch (type) {
case FIRVisionBarcodePhoneTypeFax:
typeString = @"Fax";
break;
case FIRVisionBarcodePhoneTypeHome:
typeString = @"Home";
case FIRVisionBarcodePhoneTypeWork:
typeString = @"Work";
case FIRVisionBarcodePhoneTypeMobile:
typeString = @"Mobile";
default:
break;
}
return typeString;
}
- (NSString *)getEmailType:(int)type
{
NSString *typeString = @"UNKNOWN";
switch (type) {
case FIRVisionBarcodeEmailTypeWork:
typeString = @"Work";
break;
case FIRVisionBarcodeEmailTypeHome:
typeString = @"Home";
default:
break;
}
return typeString;
}
- (NSDictionary *)processPhone:(FIRVisionBarcodePhone *)phone
{
NSString *number = @"";
NSString *typeString = @"UNKNOWN";
if (phone) {
typeString = [self getPhoneType:phone.type];
number = phone.number;
}
return @{@"number" : number, @"phoneType" : typeString};
}
- (NSDictionary *)processAddress:(FIRVisionBarcodeAddress *)address
{
NSArray *addressLines = [[NSArray alloc] init];
NSString *typeString = @"UNKNOWN";
if (address) {
int type = address.type;
NSString *typeString = @"UNKNOWN";
switch (type) {
case FIRVisionBarcodeAddressTypeWork:
typeString = @"Work";
break;
case FIRVisionBarcodeAddressTypeHome:
typeString = @"Home";
default:
break;
}
addressLines = address.addressLines;
}
return @{@"addressLines" : addressLines, @"addressType" : typeString};
}
- (NSDictionary *)processEmail:(FIRVisionBarcodeEmail *)email
{
NSString *subject = @"";
NSString *address =@"";
NSString *body =@"";
NSString *typeString = @"UNKNOWN";
if (email) {
if (email.subject) { subject = email.subject; }
if (email.address) { address = email.address; }
if (email.body) { body = email.body; }
typeString = [self getEmailType:email.type];
}
return @{@"subject" : subject, @"body" : body, @"address" : address, @"emailType" : typeString};
}
- (NSString *)processDate:(NSDate *)date
{
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"dd-MM-YYYY HH:mm:ss"];
return [dateFormatter stringFromDate:date];
}
- (NSDictionary *)processBounds:(CGRect)bounds
{
float width = bounds.size.width * _scaleX;
float height = bounds.size.height * _scaleY;
float originX = bounds.origin.x * _scaleX;
float originY = bounds.origin.y * _scaleY;
NSDictionary *boundsDict = @{
@"size" : @{@"width" : @(width), @"height" : @(height)},
@"origin" : @{@"x" : @(originX), @"y" : @(originY)}
};
return boundsDict;
}
- (NSDictionary *)processPoint:(FIRVisionPoint *)point
{
float originX = [point.x floatValue] * _scaleX;
float originY = [point.y floatValue] * _scaleY;
NSDictionary *pointDict = @{
@"x" : @(originX),
@"y" : @(originY)
};
return pointDict;
}
@end
#else
@interface BarcodeDetectorManagerMlkit ()
@end
@implementation BarcodeDetectorManagerMlkit
- (instancetype)init {
self = [super init];
return self;
}
- (BOOL)isRealDetector {
return false;
}
- (void)findBarcodesInFrame:(UIImage *)image
scaleX:(float)scaleX
scaleY:(float)scaleY
completed:(void (^)(NSArray *result))completed;
{
NSLog(@"BarcodeDetector not installed, stub used!");
NSArray *barcodes = @[ @"Error, Barcode Detector not installed" ];
completed(barcodes);
}
+ (NSDictionary *)constants
{
return @{
@"CODE_128" : @{},
@"CODE_39" : @{},
@"CODE_93" : @{},
@"CODABAR" : @{},
@"EAN_13" : @{},
@"EAN_8" : @{},
@"ITF" : @{},
@"UPC_A" : @{},
@"UPC_E" : @{},
@"QR_CODE" : @{},
@"PDF417" : @{},
@"AZTEC" : @{},
@"DATA_MATRIX" : @{},
};
}
- (void)setType:(id)json queue:(dispatch_queue_t)sessionQueue
{
return;
}
@end
#endif

View File

@ -3,12 +3,15 @@
#import <React/RCTBridgeModule.h>
#import <UIKit/UIKit.h>
#import "TextDetectorManager.h"
#import "FaceDetectorManagerMlkit.h"
#import "BarcodeDetectorManagerMlkit.h"
#import "TextDetectorManager.h"
@class RNCamera;
@interface RNCamera : UIView <AVCaptureMetadataOutputObjectsDelegate, AVCaptureFileOutputRecordingDelegate, AVCaptureVideoDataOutputSampleBufferDelegate>
@interface RNCamera : UIView <AVCaptureMetadataOutputObjectsDelegate,
AVCaptureFileOutputRecordingDelegate,
AVCaptureVideoDataOutputSampleBufferDelegate>
@property(nonatomic, strong) dispatch_queue_t sessionQueue;
@property(nonatomic, strong) AVCaptureSession *session;
@ -20,23 +23,26 @@
@property(nonatomic, strong) id runtimeErrorHandlingObserver;
@property(nonatomic, strong) AVCaptureVideoPreviewLayer *previewLayer;
@property(nonatomic, strong) NSArray *barCodeTypes;
@property(nonatomic, strong) NSArray *googleVisionBarcodeTypes;
@property(nonatomic, assign) NSInteger presetCamera;
@property (assign, nonatomic) NSInteger flashMode;
@property (assign, nonatomic) CGFloat zoom;
@property (assign, nonatomic) NSInteger autoFocus;
@property (copy, nonatomic) NSDictionary *autoFocusPointOfInterest;
@property (assign, nonatomic) float focusDepth;
@property (assign, nonatomic) NSInteger whiteBalance;
@property (assign, nonatomic) AVCaptureSessionPreset pictureSize;
@property (nonatomic, assign) BOOL isReadingBarCodes;
@property (nonatomic, assign) BOOL isRecording;
@property (nonatomic, assign) BOOL isRecordingInterrupted;
@property (nonatomic, assign) BOOL isDetectingFaces;
@property (nonatomic, assign) BOOL canReadText;
@property (nonatomic, assign) BOOL canDetectFaces;
@property(assign, nonatomic) NSInteger flashMode;
@property(assign, nonatomic) CGFloat zoom;
@property(assign, nonatomic) NSInteger autoFocus;
@property(copy, nonatomic) NSDictionary *autoFocusPointOfInterest;
@property(assign, nonatomic) float focusDepth;
@property(assign, nonatomic) NSInteger whiteBalance;
@property(assign, nonatomic) AVCaptureSessionPreset pictureSize;
@property(nonatomic, assign) BOOL isReadingBarCodes;
@property(nonatomic, assign) BOOL isRecording;
@property(nonatomic, assign) BOOL isRecordingInterrupted;
@property(nonatomic, assign) BOOL isDetectingFaces;
@property(nonatomic, assign) BOOL canReadText;
@property(nonatomic, assign) BOOL canDetectFaces;
@property(nonatomic, assign) BOOL canDetectBarcodes;
@property(assign, nonatomic) AVVideoCodecType videoCodecType;
@property (assign, nonatomic) AVCaptureVideoStabilizationMode videoStabilizationMode;
@property(assign, nonatomic)
AVCaptureVideoStabilizationMode videoStabilizationMode;
@property(assign, nonatomic, nullable) NSNumber *defaultVideoQuality;
@property(assign, nonatomic, nullable) NSNumber *deviceOrientation;
@property(assign, nonatomic, nullable) NSNumber *orientation;
@ -55,24 +61,35 @@
- (void)updateFaceDetectionMode:(id)requestedMode;
- (void)updateFaceDetectionLandmarks:(id)requestedLandmarks;
- (void)updateFaceDetectionClassifications:(id)requestedClassifications;
// google Barcode props
- (void)updateGoogleVisionBarcodeType:(id)requestedTypes;
- (void)takePicture:(NSDictionary *)options resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject;
- (void)takePictureWithOrientation:(NSDictionary *)options resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject;
- (void)record:(NSDictionary *)options resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject;
- (void)recordWithOrientation:(NSDictionary *)options resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject;
- (void)takePicture:(NSDictionary *)options
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject;
- (void)takePictureWithOrientation:(NSDictionary *)options
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject;
- (void)record:(NSDictionary *)options
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject;
- (void)recordWithOrientation:(NSDictionary *)options
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject;
- (void)stopRecording;
- (void)resumePreview;
- (void)pausePreview;
- (void)setupOrDisableBarcodeScanner;
- (void)setupOrDisableTextDetector;
- (void)setupOrDisableFaceDetector;
- (void)setupOrDisableBarcodeDetector;
- (void)onReady:(NSDictionary *)event;
- (void)onMountingError:(NSDictionary *)event;
- (void)onCodeRead:(NSDictionary *)event;
- (void)onFacesDetected:(NSDictionary *)event;
- (void)onPictureSaved:(NSDictionary *)event;
- (void)onText:(NSDictionary *)event;
- (void)onBarcodesDetected:(NSDictionary *)event;
- (bool)isRecording;
@end

View File

@ -17,17 +17,21 @@
@property (nonatomic, strong) RCTPromiseRejectBlock videoRecordedReject;
@property (nonatomic, strong) id textDetector;
@property (nonatomic, strong) id faceDetector;
@property (nonatomic, strong) id barcodeDetector;
@property (nonatomic, copy) RCTDirectEventBlock onCameraReady;
@property (nonatomic, copy) RCTDirectEventBlock onMountError;
@property (nonatomic, copy) RCTDirectEventBlock onBarCodeRead;
@property (nonatomic, copy) RCTDirectEventBlock onTextRecognized;
@property (nonatomic, copy) RCTDirectEventBlock onFacesDetected;
@property (nonatomic, copy) RCTDirectEventBlock onGoogleVisionBarcodesDetected;
@property (nonatomic, copy) RCTDirectEventBlock onPictureSaved;
@property (nonatomic, assign) BOOL finishedReadingText;
@property (nonatomic, assign) BOOL finishedDetectingFace;
@property (nonatomic, assign) BOOL finishedDetectingBarcodes;
@property (nonatomic, copy) NSDate *startText;
@property (nonatomic, copy) NSDate *startFace;
@property (nonatomic, copy) NSDate *startBarcode;
@end
@ -44,10 +48,13 @@ static NSDictionary *defaultFaceDetectorOptions = nil;
self.sensorOrientationChecker = [RNSensorOrientationChecker new];
self.textDetector = [self createTextDetector];
self.faceDetector = [self createFaceDetectorMlKit];
self.barcodeDetector = [self createBarcodeDetectorMlKit];
self.finishedReadingText = true;
self.finishedDetectingFace = true;
self.finishedDetectingBarcodes = true;
self.startText = [NSDate date];
self.startFace = [NSDate date];
self.startBarcode = [NSDate date];
#if !(TARGET_IPHONE_SIMULATOR)
self.previewLayer =
[AVCaptureVideoPreviewLayer layerWithSession:self.session];
@ -489,6 +496,9 @@ static NSDictionary *defaultFaceDetectorOptions = nil;
if ([self.faceDetector isRealDetector]) {
[self stopFaceDetection];
}
if ([self.barcodeDetector isRealDetector]) {
[self stopBarcodeDetection];
}
[self setupMovieFileCapture];
}
@ -611,7 +621,7 @@ static NSDictionary *defaultFaceDetectorOptions = nil;
// (see comment in -record), we go ahead and add the AVCaptureMovieFileOutput
// to avoid an exposure rack on some devices that can cause the first few
// frames of the recorded output to be underexposed.
if (![self.faceDetector isRealDetector] && ![self.textDetector isRealDetector]) {
if (![self.faceDetector isRealDetector] && ![self.textDetector isRealDetector] && ![self.barcodeDetector isRealDetector]) {
[self setupMovieFileCapture];
}
[self setupOrDisableBarcodeScanner];
@ -645,6 +655,9 @@ static NSDictionary *defaultFaceDetectorOptions = nil;
if ([self.faceDetector isRealDetector]) {
[self stopFaceDetection];
}
if ([self.barcodeDetector isRealDetector]) {
[self stopBarcodeDetection];
}
[self.previewLayer removeFromSuperlayer];
[self.session commitConfiguration];
[self.session stopRunning];
@ -1022,6 +1035,10 @@ static NSDictionary *defaultFaceDetectorOptions = nil;
[self setupOrDisableFaceDetector];
}
if ([self.barcodeDetector isRealDetector]) {
[self setupOrDisableBarcodeDetector];
}
AVCaptureSessionPreset preset = [RNCameraUtils captureSessionPresetForVideoResolution:[self defaultVideoQuality]];
if (self.session.sessionPreset != preset) {
[self updateSessionPreset: preset == AVCaptureSessionPresetHigh ? AVCaptureSessionPresetPhoto: preset];
@ -1092,7 +1109,7 @@ static NSDictionary *defaultFaceDetectorOptions = nil;
[self stopFaceDetection];
return;
}
// [self updateSessionPreset: AVCaptureSessionPresetMedium];
NSDictionary *rgbOutputSettings = [NSDictionary
dictionaryWithObject:[NSNumber numberWithInt:kCMPixelFormat_32BGRA]
forKey:(id)kCVPixelBufferPixelFormatTypeKey];
@ -1145,6 +1162,64 @@ static NSDictionary *defaultFaceDetectorOptions = nil;
}
}
# pragma mark - BarcodeDetectorMlkit
-(id)createBarcodeDetectorMlKit
{
Class barcodeDetectorManagerClassMlkit = NSClassFromString(@"BarcodeDetectorManagerMlkit");
return [[barcodeDetectorManagerClassMlkit alloc] init];
}
- (void)setupOrDisableBarcodeDetector
{
if (self.canDetectBarcodes && [self.barcodeDetector isRealDetector]){
AVCaptureSessionPreset preset = ([self defaultVideoQuality]) ? [RNCameraUtils captureSessionPresetForVideoResolution:[[self defaultVideoQuality] integerValue]] : AVCaptureSessionPresetHigh;
self.session.sessionPreset = preset;
if (!self.videoDataOutput) {
self.videoDataOutput = [[AVCaptureVideoDataOutput alloc] init];
if (![self.session canAddOutput:_videoDataOutput]) {
NSLog(@"Failed to setup video data output");
[self stopBarcodeDetection];
return;
}
NSDictionary *rgbOutputSettings = [NSDictionary
dictionaryWithObject:[NSNumber numberWithInt:kCMPixelFormat_32BGRA]
forKey:(id)kCVPixelBufferPixelFormatTypeKey];
[self.videoDataOutput setVideoSettings:rgbOutputSettings];
[self.videoDataOutput setAlwaysDiscardsLateVideoFrames:YES];
[self.videoDataOutput setSampleBufferDelegate:self queue:self.sessionQueue];
[self.session addOutput:_videoDataOutput];
}
} else {
[self stopBarcodeDetection];
}
}
- (void)stopBarcodeDetection
{
if (self.videoDataOutput && !self.canReadText) {
[self.session removeOutput:self.videoDataOutput];
}
self.videoDataOutput = nil;
AVCaptureSessionPreset preset = [RNCameraUtils captureSessionPresetForVideoResolution:[self defaultVideoQuality]];
if (self.session.sessionPreset != preset) {
[self updateSessionPreset: preset == AVCaptureSessionPresetHigh ? AVCaptureSessionPresetPhoto: preset];
}
}
- (void)updateGoogleVisionBarcodeType:(id)requestedTypes
{
[self.barcodeDetector setType:requestedTypes queue:self.sessionQueue];
}
- (void)onBarcodesDetected:(NSDictionary *)event
{
if (_onGoogleVisionBarcodesDetected && _session) {
_onGoogleVisionBarcodesDetected(event);
}
}
# pragma mark - TextDetector
-(id)createTextDetector
@ -1190,7 +1265,7 @@ static NSDictionary *defaultFaceDetectorOptions = nil;
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection *)connection
{
if (![self.textDetector isRealDetector] && ![self.faceDetector isRealDetector]) {
if (![self.textDetector isRealDetector] && ![self.faceDetector isRealDetector] && ![self.barcodeDetector isRealDetector]) {
NSLog(@"failing real check");
return;
}
@ -1202,9 +1277,11 @@ static NSDictionary *defaultFaceDetectorOptions = nil;
NSDate *methodFinish = [NSDate date];
NSTimeInterval timePassedSinceSubmittingForText = [methodFinish timeIntervalSinceDate:self.startText];
NSTimeInterval timePassedSinceSubmittingForFace = [methodFinish timeIntervalSinceDate:self.startFace];
NSTimeInterval timePassedSinceSubmittingForBarcode = [methodFinish timeIntervalSinceDate:self.startBarcode];
BOOL canSubmitForTextDetection = timePassedSinceSubmittingForText > 0.5 && _finishedReadingText && self.canReadText && [self.textDetector isRealDetector];
BOOL canSubmitForFaceDetection = timePassedSinceSubmittingForFace > 0.5 && _finishedDetectingFace && self.canDetectFaces && [self.faceDetector isRealDetector];
if (canSubmitForFaceDetection || canSubmitForTextDetection) {
BOOL canSubmitForBarcodeDetection = timePassedSinceSubmittingForBarcode > 0.5 && _finishedDetectingBarcodes && self.canDetectBarcodes && [self.barcodeDetector isRealDetector];
if (canSubmitForFaceDetection || canSubmitForTextDetection || canSubmitForBarcodeDetection) {
CGSize previewSize = CGSizeMake(_previewLayer.frame.size.width, _previewLayer.frame.size.height);
NSInteger position = self.videoCaptureDeviceInput.device.position;
UIImage *image = [RNCameraUtils convertBufferToUIImage:sampleBuffer previewSize:previewSize position:position];
@ -1232,6 +1309,16 @@ static NSDictionary *defaultFaceDetectorOptions = nil;
self.finishedDetectingFace = true;
}];
}
// find barcodes
if (canSubmitForBarcodeDetection) {
_finishedDetectingBarcodes = false;
self.startBarcode = [NSDate date];
[self.barcodeDetector findBarcodesInFrame:image scaleX:scaleX scaleY:scaleY completed:^(NSArray * barcodes) {
NSDictionary *eventBarcode = @{@"type" : @"barcode", @"barcodes" : barcodes};
[self onBarcodesDetected:eventBarcode];
self.finishedDetectingBarcodes = true;
}];
}
}
}

View File

@ -16,6 +16,7 @@ RCT_EXPORT_VIEW_PROPERTY(onCameraReady, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onMountError, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onBarCodeRead, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onFacesDetected, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onGoogleVisionBarcodesDetected, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onPictureSaved, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onTextRecognized, RCTDirectEventBlock);
@ -68,13 +69,16 @@ RCT_EXPORT_VIEW_PROPERTY(onTextRecognized, RCTDirectEventBlock);
@"VideoCodec": [[self class] validCodecTypes],
@"BarCodeType" : [[self class] validBarCodeTypes],
@"FaceDetection" : [[self class] faceDetectorConstants],
@"VideoStabilization": [[self class] validVideoStabilizationModes]
@"VideoStabilization": [[self class] validVideoStabilizationModes],
@"GoogleVisionBarcodeDetection": @{
@"BarcodeType": [[self class] barcodeDetectorConstants],
}
};
}
- (NSArray<NSString *> *)supportedEvents
{
return @[@"onCameraReady", @"onMountError", @"onBarCodeRead", @"onFacesDetected", @"onPictureSaved", @"onTextRecognized"];
return @[@"onCameraReady", @"onMountError", @"onBarCodeRead", @"onFacesDetected", @"onPictureSaved", @"onTextRecognized", @"onGoogleVisionBarcodesDetected"];
}
+ (NSDictionary *)validCodecTypes
@ -149,6 +153,15 @@ RCT_EXPORT_VIEW_PROPERTY(onTextRecognized, RCTDirectEventBlock);
#endif
}
+ (NSDictionary *)barcodeDetectorConstants
{
#if __has_include(<FirebaseMLVision/FirebaseMLVision.h>)
return [BarcodeDetectorManagerMlkit constants];
#else
return [NSDictionary new];
#endif
}
RCT_CUSTOM_VIEW_PROPERTY(type, NSInteger, RNCamera)
{
if (view.presetCamera != [RCTConvert NSInteger:json]) {
@ -238,6 +251,17 @@ RCT_CUSTOM_VIEW_PROPERTY(barCodeTypes, NSArray, RNCamera)
[view setBarCodeTypes:[RCTConvert NSArray:json]];
}
RCT_CUSTOM_VIEW_PROPERTY(googleVisionBarcodeType, NSString, RNCamera)
{
[view updateGoogleVisionBarcodeType:json];
}
RCT_CUSTOM_VIEW_PROPERTY(googleVisionBarcodeDetectorEnabled, BOOL, RNCamera)
{
view.canDetectBarcodes = [RCTConvert BOOL:json];
[view setupOrDisableBarcodeDetector];
}
RCT_CUSTOM_VIEW_PROPERTY(textRecognizerEnabled, BOOL, RNCamera)
{

View File

@ -43,10 +43,10 @@
- (NSArray *)processBlocks:(NSArray *)features
{
NSMutableArray *textBlocks = [[NSMutableArray alloc] init];
for (FIRVisionTextBlock *textBlock in features) {
NSDictionary *textBlockDict =
@{@"type": @"block", @"value" : textBlock.text, @"bounds" : [self processBounds:textBlock.frame], @"components" : [self processLine:textBlock.lines]};
[textBlocks addObject:textBlockDict];
for (FIRVisionTextBlock *textBlock in features) {
NSDictionary *textBlockDict =
@{@"type": @"block", @"value" : textBlock.text, @"bounds" : [self processBounds:textBlock.frame], @"components" : [self processLine:textBlock.lines]};
[textBlocks addObject:textBlockDict];
}
return textBlocks;
}
@ -58,8 +58,8 @@
NSDictionary *textLineDict =
@{@"type": @"line", @"value" : textLine.text, @"bounds" : [self processBounds:textLine.frame], @"components" : [self processElement:textLine.elements]};
[lineBlocks addObject:textLineDict];
}
return lineBlocks;
}
return lineBlocks;
}
-(NSArray *)processElement:(NSArray *)elements
@ -69,8 +69,8 @@
NSDictionary *textElementDict =
@{@"type": @"element", @"value" : textElement.text, @"bounds" : [self processBounds:textElement.frame]};
[elementBlocks addObject:textElementDict];
}
return elementBlocks;
}
return elementBlocks;
}
-(NSDictionary *)processBounds:(CGRect)bounds

View File

@ -36,6 +36,13 @@ Pod::Spec.new do |s|
ss.dependency 'Firebase/MLVision'
ss.dependency 'Firebase/MLVisionFaceModel'
end
s.subspec "BarcodeDetectorMLKit" do |ss|
ss.dependency 'react-native-camera/RN'
ss.dependency 'react-native-camera/RCT'
ss.dependency 'Firebase/MLVision'
ss.dependency 'Firebase/MLVisionBarcodeModel'
end
s.default_subspecs = "RN", "RCT"

View File

@ -125,6 +125,96 @@ type TrackedTextFeature = {
components: Array<TrackedTextFeature>,
};
type TrackedBarcodeFeature = {
bounds: {
size: {
width: number,
height: number,
},
origin: {
x: number,
y: number,
},
},
data: string,
dataRaw: string,
type: BarcodeType,
addresses?: {
addressesType?: 'UNKNOWN' | 'Work' | 'Home',
addressLines?: string[],
}[],
emails?: Email[],
phones?: Phone[],
urls: ?(string[]),
name?: {
firstName?: string,
lastName?: string,
middleName?: string,
prefix?: string,
pronounciation?: string,
suffix?: string,
formattedName?: string,
},
phone?: Phone,
organization?: string,
latitude?: number,
longitude?: number,
ssid?: string,
password?: string,
encryptionType?: string,
title?: string,
url?: string,
firstName?: string,
middleName?: string,
lastName?: string,
gender?: string,
addressCity?: string,
addressState?: string,
addressStreet?: string,
addressZip?: string,
birthDate?: string,
documentType?: string,
licenseNumber?: string,
expiryDate?: string,
issuingDate?: string,
issuingCountry?: string,
eventDescription?: string,
location?: string,
organizer?: string,
status?: string,
summary?: string,
start?: string,
end?: string,
email?: Email,
phoneNumber?: string,
message?: string,
};
type BarcodeType =
| 'EMAIL'
| 'PHONE'
| 'CALENDAR_EVENT'
| 'DRIVER_LICENSE'
| 'GEO'
| 'SMS'
| 'CONTACT_INFO'
| 'WIFI'
| 'TEXT'
| 'ISBN'
| 'PRODUCT';
type Email = {
address?: string,
body?: string,
subject?: string,
emailType?: 'UNKNOWN' | 'Work' | 'Home',
};
type Phone = {
number?: string,
phoneType?: 'UNKNOWN' | 'Work' | 'Home' | 'Fax' | 'Mobile',
};
type RecordingOptions = {
maxDuration?: number,
maxFileSize?: number,
@ -149,7 +239,7 @@ type PropsType = typeof View.props & {
onStatusChange?: Function,
onBarCodeRead?: Function,
onPictureSaved?: Function,
onGoogleVisionBarcodesDetected?: Function,
onGoogleVisionBarcodesDetected?: ({ barcodes: Array<TrackedBarcodeFeature> }) => void,
faceDetectionMode?: number,
trackingEnabled?: boolean,
flashMode?: number | string,
@ -688,9 +778,7 @@ export default class Camera extends React.Component<PropsType, StateType> {
}
if (Platform.OS === 'ios') {
delete newProps.googleVisionBarcodeType;
delete newProps.googleVisionBarcodeMode;
delete newProps.googleVisionBarcodeDetectorEnabled;
delete newProps.ratio;
}

91
types/index.d.ts vendored
View File

@ -80,6 +80,7 @@ type GoogleVisionBarcodeType = Readonly<{
UPC_E: any;
PDF417: any;
AZTEC: any;
ALL: any;
}>;
type GoogleVisionBarcodeMode = Readonly<{ NORMAL: any; ALTERNATE: any; INVERTED: any }>;
@ -141,7 +142,10 @@ export interface RNCameraProps {
captureAudio?: boolean;
onCameraReady?(): void;
onStatusChange?(event: { cameraStatus: CameraStatus, recordAudioPermissionStatus: keyof RecordAudioPermissionStatus }): void;
onStatusChange?(event: {
cameraStatus: CameraStatus;
recordAudioPermissionStatus: keyof RecordAudioPermissionStatus;
}): void;
onMountError?(error: { message: string }): void;
/** Value: float from 0 to 1.0 */
@ -151,7 +155,7 @@ export interface RNCameraProps {
// -- BARCODE PROPS
barCodeTypes?: Array<keyof BarCodeType>;
googleVisionBarcodeType?: keyof GoogleVisionBarcodeType;
googleVisionBarcodeType?: Constants['GoogleVisionBarcodeDetection']['BarcodeType'];
onBarCodeRead?(event: {
data: string;
rawData?: string;
@ -165,10 +169,6 @@ export interface RNCameraProps {
onGoogleVisionBarcodesDetected?(event: {
barcodes: Barcode[];
sourceRotation: number;
sourceHeight: number;
sourceWidth: number;
type: keyof GoogleVisionBarcodeType;
}): void;
// -- FACE DETECTION PROPS
@ -178,7 +178,7 @@ export interface RNCameraProps {
faceDetectionMode?: keyof FaceDetectionMode;
faceDetectionLandmarks?: keyof FaceDetectionLandmarks;
faceDetectionClassifications?: keyof FaceDetectionClassifications;
trackingEnabled?: boolean,
trackingEnabled?: boolean;
onTextRecognized?(response: { textBlocks: TrackedTextFeature[] }): void;
// -- ANDROID ONLY PROPS
@ -211,7 +211,82 @@ interface Barcode {
origin: Point;
};
data: string;
type: string;
dataRaw: string;
type: BarcodeType;
addresses?: {
addressesType?: "UNKNOWN" | "Work" | "Home";
addressLines?: string[];
}[];
emails?: Email[];
phones?: Phone[];
urls:? string[];
name?: {
firstName?: string;
lastName?: string;
middleName?: string;
prefix?:string;
pronounciation?:string;
suffix?:string;
formattedName?: string;
};
phone?: Phone;
organization?: string;
latitude?: number;
longitude?: number;
ssid?: string;
password?: string;
encryptionType?: string;
title?: string;
url?: string;
firstName?: string;
middleName?: string;
lastName?: string;
gender?: string;
addressCity?: string;
addressState?: string;
addressStreet?: string;
addressZip?: string;
birthDate?: string;
documentType?: string;
licenseNumber?: string;
expiryDate?: string;
issuingDate?: string;
issuingCountry?: string;
eventDescription?: string;
location?: string;
organizer?: string;
status?: string;
summary?: string;
start?: string;
end?: string;
email?: Email;
phoneNumber?: string;
message?: string;
}
type BarcodeType =
|"EMAIL"
|"PHONE"
|"CALENDAR_EVENT"
|"DRIVER_LICENSE"
|"GEO"
|"SMS"
|"CONTACT_INFO"
|"WIFI"
|"TEXT"
|"ISBN"
|"PRODUCT"
interface Email {
address?: string;
body?: string;
subject?: string;
emailType?: "UNKNOWN" | "Work" | "Home";
}
interface Phone {
number?: string;
phoneType?: "UNKNOWN" | "Work" | "Home" | "Fax" | "Mobile";
}
interface Face {