Skip to content
This repository was archived by the owner on Jun 16, 2023. It is now read-only.

Commit fa61fce

Browse files
feat(ios): Add ability to scan inverted-color barcodes on iOS using Google Vision (#2851)
* Add required plumbing for supporiting inverted colors * Update package.json * Update package.json * Update RNCamera.js * Update package.json * Update RNCameraManager.m * Read barcode detection mode * Update package.json * Declare invertImageData as a property * Access the property correctly * Refer to the property correctly * Update RNCamera.m * Update RNCamera.md * Set default scan mode to Alternate * Update package.json * Set the default barcode detection mode to normal * Update package.json * Make the property type consistent * Update RNCamera.h * Update package.json * Rename variables for readability * Update package.json * Add barcode mode usage * Revert version update Co-authored-by: Manish Kumar <mkumar@acvauctions.com>
1 parent ee88b38 commit fa61fce

File tree

12 files changed

+107
-18
lines changed

12 files changed

+107
-18
lines changed

docs/RNCamera.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class ExampleApp extends PureComponent {
2020
return (
2121
<View style={styles.container}>
2222
<RNCamera
23-
ref={ref => {
23+
ref={(ref) => {
2424
this.camera = ref;
2525
}}
2626
style={styles.preview}
@@ -144,7 +144,7 @@ class ExampleApp extends PureComponent {
144144
);
145145
}
146146

147-
takePicture = async function(camera) {
147+
takePicture = async function (camera) {
148148
const options = { quality: 0.5, base64: true };
149149
const data = await camera.takePictureAsync(options);
150150
// eslint-disable-next-line
@@ -436,13 +436,15 @@ Function to be called when native code stops recording video, but before all vid
436436
Function to be called when a touch within the camera view is recognized.
437437
The function is also called on the first touch of double tap.
438438
Event will contain the following fields:
439+
439440
- `x`
440441
- `y`
441442

442443
### `onDoubleTap`
443444

444445
Function to be called when a double touch within the camera view is recognized.
445446
Event will contain the following fields:
447+
446448
- `x`
447449
- `y`
448450

@@ -537,7 +539,7 @@ Available settings:
537539
- DATA_MATRIX
538540
- ALL
539541

540-
### `Android` `googleVisionBarcodeMode`
542+
### `googleVisionBarcodeMode`
541543

542544
Change the mode in order to scan "inverted" barcodes. You can either change it to `alternate`, which will inverted the image data every second screen and be able to read both normal and inverted barcodes, or `inverted`, which will only read inverted barcodes. Default is `normal`, which only reads "normal" barcodes. Note: this property only applies to the Google Vision barcode detector.
543545
Example: `<RNCamera googleVisionBarcodeMode={RNCamera.Constants.GoogleVisionBarcodeDetection.BarcodeMode.ALTERNATE} />`

examples/mlkit/App.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,14 @@ export default class CameraScreen extends React.Component {
8787
});
8888
}
8989

90-
takePicture = async function() {
90+
takePicture = async function () {
9191
if (this.camera) {
9292
const data = await this.camera.takePictureAsync();
9393
console.warn('takePicture ', data);
9494
}
9595
};
9696

97-
takeVideo = async function() {
97+
takeVideo = async function () {
9898
if (this.camera) {
9999
try {
100100
const promise = this.camera.recordAsync(this.state.recordOptions);
@@ -111,7 +111,7 @@ export default class CameraScreen extends React.Component {
111111
}
112112
};
113113

114-
toggle = value => () => this.setState(prevState => ({ [value]: !prevState[value] }));
114+
toggle = (value) => () => this.setState((prevState) => ({ [value]: !prevState[value] }));
115115

116116
facesDetected = ({ faces }) => this.setState({ faces });
117117

@@ -139,7 +139,7 @@ export default class CameraScreen extends React.Component {
139139
);
140140

141141
renderLandmarksOfFace(face) {
142-
const renderLandmark = position =>
142+
const renderLandmark = (position) =>
143143
position && (
144144
<View
145145
style={[
@@ -204,7 +204,7 @@ export default class CameraScreen extends React.Component {
204204
</React.Fragment>
205205
);
206206

207-
textRecognized = object => {
207+
textRecognized = (object) => {
208208
const { textBlocks } = object;
209209
this.setState({ textBlocks });
210210
};
@@ -238,7 +238,7 @@ export default class CameraScreen extends React.Component {
238238
const { canDetectFaces, canDetectText, canDetectBarcode } = this.state;
239239
return (
240240
<RNCamera
241-
ref={ref => {
241+
ref={(ref) => {
242242
this.camera = ref;
243243
}}
244244
style={{
@@ -272,6 +272,7 @@ export default class CameraScreen extends React.Component {
272272
onTextRecognized={canDetectText ? this.textRecognized : null}
273273
onGoogleVisionBarcodesDetected={canDetectBarcode ? this.barcodeRecognized : null}
274274
googleVisionBarcodeType={RNCamera.Constants.GoogleVisionBarcodeDetection.BarcodeType.ALL}
275+
googleVisionBarcodeMode={RNCamera.Constants.GoogleVisionBarcodeMode.ALTERNATE}
275276
>
276277
<View
277278
style={{

ios/RN/BarcodeDetectorManagerMlkit.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ typedef void(^postRecognitionBlock)(NSArray *barcodes);
1010
- (instancetype)init;
1111

1212
-(BOOL)isRealDetector;
13+
-(NSInteger)fetchDetectionMode;
1314
-(void)setType:(id)json queue:(dispatch_queue_t)sessionQueue;
15+
-(void)setMode:(id)json queue:(dispatch_queue_t)sessionQueue;
1416
-(void)findBarcodesInFrame:(UIImage *)image scaleX:(float)scaleX scaleY:(float)scaleY completed:(postRecognitionBlock)completed;
1517
+(NSDictionary *)constants;
1618

ios/RN/BarcodeDetectorManagerMlkit.m

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ @interface BarcodeDetectorManagerMlkit ()
66
@property(nonatomic, strong) FIRVisionBarcodeDetector *barcodeRecognizer;
77
@property(nonatomic, strong) FIRVision *vision;
88
@property(nonatomic, assign) FIRVisionBarcodeFormat setOption;
9+
@property(nonatomic, assign) NSInteger detectionMode;
910
@property(nonatomic, assign) float scaleX;
1011
@property(nonatomic, assign) float scaleY;
1112
@end
@@ -26,6 +27,11 @@ - (BOOL)isRealDetector
2627
return true;
2728
}
2829

30+
-(NSInteger)fetchDetectionMode
31+
{
32+
return self.detectionMode;
33+
}
34+
2935
+ (NSDictionary *)constants
3036
{
3137
return @{
@@ -63,6 +69,12 @@ - (void)setType:(id)json queue:(dispatch_queue_t)sessionQueue
6369
}
6470
}
6571

72+
-(void)setMode:(id)json queue:(dispatch_queue_t)sessionQueue
73+
{
74+
NSInteger requestedValue = [RCTConvert NSInteger:json];
75+
self.detectionMode = requestedValue;
76+
}
77+
6678
- (void)findBarcodesInFrame:(UIImage *)uiImage
6779
scaleX:(float)scaleX
6880
scaleY:(float)scaleY

ios/RN/RNCamera.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
@property(nonatomic, strong) NSArray *barCodeTypes;
2727
@property(nonatomic, strong) NSArray *googleVisionBarcodeTypes;
2828

29+
@property(nonatomic, assign) NSInteger *googleVisionBarcodeMode;
2930
@property(nonatomic, assign) NSInteger presetCamera;
3031
@property(nonatomic, copy) NSString *cameraId; // copy required for strings/pointers
3132
@property(assign, nonatomic) NSInteger flashMode;
@@ -76,6 +77,7 @@
7677
- (void)updateRectOfInterest;
7778
// google Barcode props
7879
- (void)updateGoogleVisionBarcodeType:(id)requestedTypes;
80+
- (void)updateGoogleVisionBarcodeMode:(id)requestedMode;
7981

8082
- (void)takePicture:(NSDictionary *)options
8183
resolve:(RCTPromiseResolveBlock)resolve

ios/RN/RNCamera.m

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ @interface RNCamera ()
4343
@property (nonatomic, copy) RCTDirectEventBlock onSubjectAreaChanged;
4444
@property (nonatomic, assign) BOOL isFocusedOnPoint;
4545
@property (nonatomic, assign) BOOL isExposedOnPoint;
46+
@property (nonatomic, assign) BOOL invertImageData;
4647

4748
@end
4849

@@ -89,6 +90,7 @@ - (id)initWithBridge:(RCTBridge *)bridge
8990
self.cameraId = nil;
9091
self.isFocusedOnPoint = NO;
9192
self.isExposedOnPoint = NO;
93+
self.invertImageData = false;
9294
_recordRequested = NO;
9395
_sessionInterrupted = NO;
9496

@@ -2175,6 +2177,11 @@ - (void)updateGoogleVisionBarcodeType:(id)requestedTypes
21752177
[self.barcodeDetector setType:requestedTypes queue:self.sessionQueue];
21762178
}
21772179

2180+
- (void)updateGoogleVisionBarcodeMode:(id)requestedMode
2181+
{
2182+
[self.barcodeDetector setMode:requestedMode queue:self.sessionQueue];
2183+
}
2184+
21782185
- (void)onBarcodesDetected:(NSDictionary *)event
21792186
{
21802187
if (_onGoogleVisionBarcodesDetected && _session) {
@@ -2275,6 +2282,27 @@ - (void)captureOutput:(AVCaptureOutput *)captureOutput
22752282
if (canSubmitForBarcodeDetection) {
22762283
_finishedDetectingBarcodes = false;
22772284
self.startBarcode = [NSDate date];
2285+
2286+
// Check for the barcode detection mode (Normal, Alternate, Inverted)
2287+
switch ([self.barcodeDetector fetchDetectionMode]) {
2288+
case RNCameraGoogleVisionBarcodeModeNormal:
2289+
self.invertImageData = false;
2290+
break;
2291+
case RNCameraGoogleVisionBarcodeModeAlternate:
2292+
self.invertImageData = !self.invertImageData;
2293+
break;
2294+
case RNCameraGoogleVisionBarcodeModeInverted:
2295+
self.invertImageData = true;
2296+
break;
2297+
default:
2298+
self.invertImageData = false;
2299+
break;
2300+
}
2301+
2302+
if (self.invertImageData) {
2303+
image = [RNImageUtils invertColors:image];
2304+
}
2305+
22782306
[self.barcodeDetector findBarcodesInFrame:image scaleX:scaleX scaleY:scaleY completed:^(NSArray * barcodes) {
22792307
NSDictionary *eventBarcode = @{@"type" : @"barcode", @"barcodes" : barcodes};
22802308
[self onBarcodesDetected:eventBarcode];

ios/RN/RNCameraManager.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ typedef NS_ENUM(NSInteger, RNCameraVideoResolution) {
5555
RNCameraVideo288p = 4,
5656
};
5757

58+
typedef NS_ENUM(NSInteger, RNCameraGoogleVisionBarcodeMode) {
59+
RNCameraGoogleVisionBarcodeModeNormal = 0,
60+
RNCameraGoogleVisionBarcodeModeAlternate = 1,
61+
RNCameraGoogleVisionBarcodeModeInverted = 2,
62+
};
63+
5864
@interface RNCameraManager : RCTViewManager <RCTBridgeModule>
5965

6066
+ (NSDictionary *)validBarCodeTypes;

ios/RN/RNCameraManager.m

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,12 @@ - (NSDictionary *)constantsToExport
8181
@"VideoStabilization": [[self class] validVideoStabilizationModes],
8282
@"GoogleVisionBarcodeDetection": @{
8383
@"BarcodeType": [[self class] barcodeDetectorConstants],
84-
}
84+
},
85+
@"GoogleVisionBarcodeMode" : @{
86+
@"NORMAL" : @(RNCameraGoogleVisionBarcodeModeNormal),
87+
@"ALTERNATE" : @(RNCameraGoogleVisionBarcodeModeAlternate),
88+
@"INVERTED" : @(RNCameraGoogleVisionBarcodeModeInverted),
89+
},
8590
};
8691
}
8792

@@ -297,6 +302,11 @@ + (NSDictionary *)barcodeDetectorConstants
297302
[view updateGoogleVisionBarcodeType:json];
298303
}
299304

305+
RCT_CUSTOM_VIEW_PROPERTY(googleVisionBarcodeMode, NSInteger, RNCamera)
306+
{
307+
[view updateGoogleVisionBarcodeMode:json];
308+
}
309+
300310
RCT_CUSTOM_VIEW_PROPERTY(googleVisionBarcodeDetectorEnabled, BOOL, RNCamera)
301311
{
302312
view.canDetectBarcodes = [RCTConvert BOOL:json];

ios/RN/RNImageUtils.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
+ (NSString *)writeImage:(NSData *)image toPath:(NSString *)path;
1919
+ (UIImage *) scaleImage:(UIImage*)image toWidth:(NSInteger)width;
2020
+ (void)updatePhotoMetadata:(CMSampleBufferRef)imageSampleBuffer withAdditionalData:(NSDictionary *)additionalData inResponse:(NSMutableDictionary *)response;
21+
+ (UIImage *)invertColors:(UIImage *)image;
2122

2223
@end
2324

ios/RN/RNImageUtils.m

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,5 +115,23 @@ + (void)updatePhotoMetadata:(CMSampleBufferRef)imageSampleBuffer withAdditionalD
115115
response[@"exif"] = metadata;
116116
}
117117

118+
+ (UIImage *)invertColors:(UIImage *)image
119+
{
120+
CIImage *inputCIImage = [[CIImage alloc] initWithImage:image];
121+
122+
// Invert colors
123+
CIFilter *filterColorInvert = [CIFilter filterWithName:@"CIColorInvert"];
124+
[filterColorInvert setValue:inputCIImage forKey:kCIInputImageKey];
125+
CIImage *outputCIImage = [filterColorInvert valueForKey:kCIOutputImageKey];
126+
127+
// A UIImage initialized directly from CIImage has its CGImage property set to NULL. So it has
128+
// to be converted to a CGImage first.
129+
CIContext *context = [CIContext context];
130+
CGImageRef outputCGImage = [context createCGImage:outputCIImage fromRect:[outputCIImage extent]];
131+
132+
UIImage *outputUIImage = [UIImage imageWithCGImage:outputCGImage];
133+
return outputUIImage;
134+
}
135+
118136
@end
119137

0 commit comments

Comments
 (0)