From 60fe613bd1ad2ad8efca3d22e5219d173eabd6ef Mon Sep 17 00:00:00 2001 From: Lochlan Wansbrough Date: Sun, 19 Apr 2015 15:53:30 -0700 Subject: [PATCH] Added QR code reader functionality --- Camera.ios.js | 12 +++++++++++- RCTCameraManager.h | 3 ++- RCTCameraManager.m | 47 ++++++++++++++++++++++++++++++++++++++++++++++ README.md | 5 +++++ package.json | 9 ++++++--- 5 files changed, 71 insertions(+), 5 deletions(-) diff --git a/Camera.ios.js b/Camera.ios.js index c83869d..d959c1b 100644 --- a/Camera.ios.js +++ b/Camera.ios.js @@ -1,4 +1,5 @@ var React = require('React'); +var DeviceEventEmitter = require('RCTDeviceEventEmitter'); var NativeModules = require('NativeModules'); var ReactIOSViewAttributes = require('ReactIOSViewAttributes'); var StyleSheet = require('StyleSheet'); @@ -37,6 +38,11 @@ var Camera = React.createClass({ this.state.isAuthorized = isAuthorized; this.setState(this.state); }).bind(this)); + this.cameraBarCodeReadListener = DeviceEventEmitter.addListener('CameraBarCodeRead', this._onBarCodeRead); + }, + + componentWillUnmount: function() { + this.cameraBarCodeReadListener.remove(); }, render: function() { @@ -50,12 +56,16 @@ var Camera = React.createClass({ style, aspect: aspect, type: type, - orientation: orientation, + orientation: orientation }); return }, + _onBarCodeRead(e) { + this.props.onBarCodeRead && this.props.onBarCodeRead(e); + }, + switch: function() { this.state.type = this.state.type == 'Back' ? 'Front' : 'Back'; this.setState(this.state); diff --git a/RCTCameraManager.h b/RCTCameraManager.h index 955692a..fb9dc13 100644 --- a/RCTCameraManager.h +++ b/RCTCameraManager.h @@ -3,12 +3,13 @@ @class RCTCamera; -@interface RCTCameraManager : RCTViewManager +@interface RCTCameraManager : RCTViewManager @property (nonatomic) dispatch_queue_t sessionQueue; @property (nonatomic) AVCaptureSession *session; @property (nonatomic) AVCaptureDeviceInput *captureDeviceInput; @property (nonatomic) AVCaptureStillImageOutput *stillImageOutput; +@property (nonatomic) AVCaptureMetadataOutput *metadataOutput; @property (nonatomic) id runtimeErrorHandlingObserver; @property (nonatomic) NSInteger presetCamera; @property (nonatomic) AVCaptureVideoPreviewLayer *previewLayer; diff --git a/RCTCameraManager.m b/RCTCameraManager.m index 1249e52..0b8e563 100644 --- a/RCTCameraManager.m +++ b/RCTCameraManager.m @@ -1,6 +1,7 @@ #import "RCTCameraManager.h" #import "RCTCamera.h" #import "RCTBridge.h" +#import "RCTEventDispatcher.h" #import "RCTUtils.h" #import "RCTLog.h" #import "UIView+React.h" @@ -82,6 +83,14 @@ RCT_EXPORT_VIEW_PROPERTY(orientation, NSInteger); self.stillImageOutput = stillImageOutput; } + AVCaptureMetadataOutput *metadataOutput = [[AVCaptureMetadataOutput alloc] init]; + if ([self.session canAddOutput:metadataOutput]) { + [metadataOutput setMetadataObjectsDelegate:self queue:self.sessionQueue]; + [self.session addOutput:metadataOutput]; + [metadataOutput setMetadataObjectTypes:metadataOutput.availableMetadataObjectTypes]; + self.metadataOutput = metadataOutput; + } + __weak RCTCameraManager *weakSelf = self; [self setRuntimeErrorHandlingObserver:[NSNotificationCenter.defaultCenter addObserverForName:AVCaptureSessionRuntimeErrorNotification object:self.session queue:nil usingBlock:^(NSNotification *note) { RCTCameraManager *strongSelf = weakSelf; @@ -168,6 +177,44 @@ RCT_EXPORT_METHOD(takePicture:(RCTResponseSenderBlock)callback) { }]; } +- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection { + + NSArray *barcodeTypes = @[ + AVMetadataObjectTypeUPCECode, + AVMetadataObjectTypeCode39Code, + AVMetadataObjectTypeCode39Mod43Code, + AVMetadataObjectTypeEAN13Code, + AVMetadataObjectTypeEAN8Code, + AVMetadataObjectTypeCode93Code, + AVMetadataObjectTypeCode128Code, + AVMetadataObjectTypePDF417Code, + AVMetadataObjectTypeQRCode, + AVMetadataObjectTypeAztecCode + ]; + + for (AVMetadataMachineReadableCodeObject *metadata in metadataObjects) { + for (id barcodeType in barcodeTypes) { + if (metadata.type == barcodeType) { + + [self.bridge.eventDispatcher sendDeviceEventWithName:@"CameraBarCodeRead" + body:@{ + @"data": metadata.stringValue, + @"bounds": @{ + @"origin": @{ + @"x": [NSString stringWithFormat:@"%f", metadata.bounds.origin.x], + @"y": [NSString stringWithFormat:@"%f", metadata.bounds.origin.y] + }, + @"size": @{ + @"height": [NSString stringWithFormat:@"%f", metadata.bounds.size.height], + @"width": [NSString stringWithFormat:@"%f", metadata.bounds.size.width], + } + } + }]; + } + } + } +} + - (AVCaptureDevice *)deviceWithMediaType:(NSString *)mediaType preferringPosition:(AVCaptureDevicePosition)position { diff --git a/README.md b/README.md index d39f372..31cff40 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,11 @@ The `orientation` property allows you to specify the current orientation of the TODO: Add support for an `Auto` value to automatically adjust for orientation changes. +#### `onBarCodeRead` + +Will call the specified method when a barcode is detected in the camera's view. + +Event contains `data` (the data in the barcode) and `bounds` (the rectangle which outlines the barcode.) ## Component methods diff --git a/package.json b/package.json index c5ad7cc..52edfe3 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,8 @@ "type" : "git", "url" : "https://github.com/lwansbrough/react-native-camera.git" }, - "version": "0.0.10", - "description": "A Camera element for React Native", + "version": "0.1.0", + "description": "A Camera component for React Native. Also reads barcodes.", "main": "Camera.ios.js", "author": "Lochlan Wansbrough (http://lwansbrough.com)", "dependencies": { @@ -15,6 +15,9 @@ "react-native", "react", "native", - "camera" + "camera", + "qr", + "code", + "barcode" ] }