I am using iOS 7 AVFoundation framework for Barcode scanning. It works fine for me but on some Barcodes it gives me wrong result.
I am adding code file and Barcode also to generate the issue. Please take a look and help me to find out the problem.
Code Sample:
ViewController.h Class-
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#interface ViewController : UIViewController <AVCaptureMetadataOutputObjectsDelegate>
{
AVCaptureSession *_session;
AVCaptureDevice *_device;
AVCaptureDeviceInput *_input;
AVCaptureMetadataOutput *_output;
AVCaptureVideoPreviewLayer *_prevLayer;
UIView *_highlightView;
IBOutlet UIView *_viewBg;
IBOutlet UIButton *_btnScanning;
}
#end
ViewController.m Class Methods -
- (void)setScanningVideoOrientation
{
if ([UIDevice currentDevice].orientation == UIInterfaceOrientationPortrait)
{
_prevLayer.connection.videoOrientation = AVCaptureVideoOrientationPortrait;
}
else if ([UIDevice currentDevice].orientation == UIInterfaceOrientationPortraitUpsideDown)
{
_prevLayer.connection.videoOrientation = AVCaptureVideoOrientationPortraitUpsideDown;
}
else if ([UIDevice currentDevice].orientation == UIInterfaceOrientationLandscapeLeft)
{
_prevLayer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeLeft;
}
else if ([UIDevice currentDevice].orientation == UIInterfaceOrientationLandscapeRight)
{
_prevLayer.connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
}
}
- (void)startScanning
{
// Create Session.------------------------------------------------------
_session = nil;
_session = [[AVCaptureSession alloc] init];
_device = nil;
_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
NSError *error = nil;
_input = nil;
_input = [AVCaptureDeviceInput deviceInputWithDevice:_device error:&error];
if (_input)
{
[_session addInput:_input];
_output = nil;
_output = [[AVCaptureMetadataOutput alloc] init];
[_output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
[_session addOutput:_output];
_output.metadataObjectTypes = [_output availableMetadataObjectTypes];
_prevLayer = nil;
_prevLayer = [AVCaptureVideoPreviewLayer layerWithSession:_session];
_prevLayer.frame = _viewBg.frame;
_prevLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[self setScanningVideoOrientation];
[self.view.layer addSublayer:_prevLayer];
[_session startRunning];
} else
{
NSLog(#"Error: %#", error);
}
//----------------------------------------------------------------------
}
In this delegate method. I am getting wrong barcode string. Please take a look on 'detectionString'.
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
{
CGRect highlightViewRect = CGRectZero;
AVMetadataMachineReadableCodeObject *barCodeObject;
NSString *detectionString = nil;
NSArray *barCodeTypes = #[AVMetadataObjectTypeUPCECode, AVMetadataObjectTypeCode39Code, AVMetadataObjectTypeCode39Mod43Code,
AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode93Code, AVMetadataObjectTypeCode128Code,
AVMetadataObjectTypePDF417Code, AVMetadataObjectTypeQRCode, AVMetadataObjectTypeAztecCode];
for (AVMetadataObject *metadata in metadataObjects) {
for (NSString *type in barCodeTypes) {
if ([metadata.type isEqualToString:type])
{
barCodeObject = (AVMetadataMachineReadableCodeObject *)[_prevLayer transformedMetadataObjectForMetadataObject:(AVMetadataMachineReadableCodeObject *)metadata];
highlightViewRect = barCodeObject.bounds;
detectionString = [(AVMetadataMachineReadableCodeObject *)metadata stringValue];
break;
}
}
if (detectionString != nil)
{
NSLog(#"ViewController-->captureOutput-->detectionString = %#",detectionString);
[self stopScanning];
break;
}
}
barCodeObject = nil;
detectionString = nil;
barCodeTypes = nil;
}
Barcode Image -
I am getting result - 0649954006029
But it should be - 649954006029.
As for some other barcodes, i am seeing 'l' before actual barcode scanning string.
Hope it will help you to identify the problem.
Thanks.
The reason you're getting a 13 digit code is because you're trying to scan a UPC-A code (649954..) and iOS doesn't have a separate category for UPC-A codes.
UPC-A codes come scanned in as EAN13 codes, and those are 13 digits long, so they get a prefix of 0.
From AVFoundation/AVMetadata.h
/*! #constant AVMetadataObjectTypeEAN13Code
#abstract An identifier for an instance of
AVMetadataMachineReadableCodeObject having a type
AVMetadataObjectTypeEAN13Code.
#discussion
AVMetadataMachineReadableCodeObject objects generated from EAN-13 (including UPC-A) codes return this constant as their type. */
AVF_EXPORT NSString *const AVMetadataObjectTypeEAN13Code NS_AVAILABLE(NA, 7_0);
Related
I am developing an app where I have displayed the detected data from a QR code but the problem is that QR code is not detected. I have used this code:
NSDictionary *detectorOptions = #{ CIDetectorAccuracy : CIDetectorAccuracyHigh };
CIDetector *faceDetector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:detectorOptions];
NSArray *features = [faceDetector featuresInImage:chosenImage.CIImage];
CIQRCodeFeature *faceFeature;
for(faceFeature in features)
{
qrcodedetected = YES;
self.decodedstr = [NSString stringWithFormat:#"%#",faceFeature.messageString];
break;
}
I have searched a lot but not succeeded. I have used this code from Apple default form. Every time I will get nil in result. If anybody has any solution regarding this then please share with me. It would be appreciated. Thanks in advance.
// initialize
AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];
// create session
AVCaptureMetadataOutput *captureMetadataOutput = [[AVCaptureMetadataOutput alloc] init];
dispatch_queue_t dispatchQueue = dispatch_queue_create("QRCodeQueue", NULL);
[captureMetadataOutput setMetadataObjectsDelegate:self queue:dispatchQueue];
[captureMetadataOutput setMetadataObjectTypes:[captureMetadataOutput availableMetadataObjectTypes]];
[self.captureSession addOutput:captureMetadataOutput];
// add camera view layer
AVCaptureVideoPreviewLayer *captureLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession];
[captureLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
[captureLayer setFrame:self.view.layer.bounds];
[self.view.layer addSublayer:captureLayer];
// delegate method
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
// Specify the barcodes you want to read here:
NSArray *supportedBarcodeTypes = #[AVMetadataObjectTypeUPCECode, AVMetadataObjectTypeCode39Code, AVMetadataObjectTypeCode39Mod43Code, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode93Code, AVMetadataObjectTypeCode128Code, AVMetadataObjectTypePDF417Code, AVMetadataObjectTypeQRCode, AVMetadataObjectTypeAztecCode];
for (AVMetadataObject *barcodeMetadata in metadataObjects) {
for (NSString *supportedBarcode in supportedBarcodeTypes) {
if ([supportedBarcode isEqualToString:barcodeMetadata.type]) {
// get barcode object AVMetadataMachineReadableCodeObject
AVMetadataMachineReadableCodeObject *barcodeObject = (AVMetadataMachineReadableCodeObject *)[self.captureLayer transformedMetadataObjectForMetadataObject:barcodeMetadata];
NSString *capturedBarcode = [barcodeObject stringValue];
// do what you want...
}
}
}
}
I'm struggling with delegate creation and usage. Could someone help me understand what I'm doing wrong? According to all the examples I have read this is correct but my data is not being returned.
ViewController (Parent)
.h
#import <UIKit/UIKit.h>
#import "BarcodeViewController.h"
#interface ViewController: UIViewController <BarcodeViewDelegate> {
IBOutlet UILabel *bcode;
}
#end
.m
-(void)setbarcode:(NSString*)barcode
{
NSLog(#" data %#", barcode);
bcode.text = barcode;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Make sure your segue name in storyboard is the same as this line
if ([[segue identifier] isEqualToString:#"scanbarcode"])
{
BarcodeViewController *cv = [segue destinationViewController];
cv.delegate = self;
}
}
The Barcode view controller (Child view)
.h
#protocol BarcodeViewDelegate <NSObject>
-(void)setbarcode:(NSString*)barcode;
#end
#interface BarcodeViewController : UIViewController
{
id<BarcodeViewDelegate> delegate;
}
#property(nonatomic,assign)id delegate;
#end
.m
#import "BarcodeViewController.h"
#import <AVFoundation/AVFoundation.h>
#interface BarcodeViewController () <AVCaptureMetadataOutputObjectsDelegate>
{
AVCaptureSession *_session;
AVCaptureDevice *_device;
AVCaptureDeviceInput *_input;
AVCaptureMetadataOutput *_output;
AVCaptureVideoPreviewLayer *_prevLayer;
UIView *_highlightView;
UIImageView *_imageOverlay;
}
#end
#implementation BarcodeViewController
- (void)viewDidLoad
{
[super viewDidLoad];
/*
* setup scanner view
*/
_highlightView = [[UIView alloc] init];
_highlightView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin|UIViewAutoresizingFlexibleBottomMargin;
_highlightView.layer.borderColor = [UIColor greenColor].CGColor;
_highlightView.layer.borderWidth = 3;
[self.view addSubview:_highlightView];
/*
* setup a overlay guide
*/
_imageOverlay = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"camera_overlay"]];
[self.view addSubview:_imageOverlay];
_session = [[AVCaptureSession alloc] init];
_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
NSError *error = nil;
_input = [AVCaptureDeviceInput deviceInputWithDevice:_device error:&error];
if (_input) {
[_session addInput:_input];
} else {
NSLog(#"Error: %#", error);
}
_output = [[AVCaptureMetadataOutput alloc] init];
[_output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
[_session addOutput:_output];
_output.metadataObjectTypes = [_output availableMetadataObjectTypes];
_prevLayer = [AVCaptureVideoPreviewLayer layerWithSession:_session];
_prevLayer.frame = self.view.bounds;
_prevLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[self.view.layer addSublayer:_prevLayer];
[_session startRunning];
[self.view bringSubviewToFront:_highlightView];
[self.view bringSubviewToFront:_imageOverlay];
}
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
{
CGRect highlightViewRect = CGRectZero;
AVMetadataMachineReadableCodeObject *barCodeObject;
NSString *detectionString = nil;
NSArray *barCodeTypes = #[AVMetadataObjectTypeUPCECode, AVMetadataObjectTypeCode39Code, AVMetadataObjectTypeCode39Mod43Code,
AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode93Code, AVMetadataObjectTypeCode128Code,
AVMetadataObjectTypePDF417Code, AVMetadataObjectTypeQRCode, AVMetadataObjectTypeAztecCode];
/*
* keep looking around while we look for the barcode
*/
for (AVMetadataObject *metadata in metadataObjects) {
for (NSString *type in barCodeTypes) {
if ([metadata.type isEqualToString:type])
{
barCodeObject = (AVMetadataMachineReadableCodeObject *)[_prevLayer transformedMetadataObjectForMetadataObject:(AVMetadataMachineReadableCodeObject *)metadata];
//highlightViewRect = barCodeObject.bounds;
detectionString = [(AVMetadataMachineReadableCodeObject *)metadata stringValue];
break;
}
}
if (detectionString != nil)
{
/*
* Set the detected barcode so we can use it.
* - perform segway to another view
*/
//barcode = detectionString;
//NSLog(#" data %#", detectionString);
[delegate setbarcode: detectionString];
[self.navigationController popViewControllerAnimated:YES];
break;
}
//else
/*
* Just reset the barcode value for now
*/
//_barcode = false;
}
_highlightView.frame = highlightViewRect;
}
#end
Your problem is simple.
You define an instance variable and a property to hold the delegate:
{
id delegate;
}
#property(nonatomic,assign)id delegate;
You set the delegate via the property:
cv.delegate = self;
Then access it via the instance variable:
[delegate setbarcode: detectionString];
The property is backed by a different instance variable, automatically defined as _delegate, which you should not be accessing. You should always access via the property, as self.delegate. When calling your delegate ivar, it will be nil, so nothing is being sent back.
Remove the unnecessary instance variable declaration, type the property correctly (as id<BarcodeViewDelegate> rather than just id) and always access it via the property, and you'll be fine.
I am trying to scan Aztec code using the Apple native API. But I am not able to scan it. In the Apple guideline, I have read it, you can scan the Aztec code. But it is not working.
Please check the code which i am using.
#import <UIKit/UIKit.h>
#interface igViewController : UIViewController
#end
#import <AVFoundation/AVFoundation.h>
#import "igViewController.h"
#interface igViewController () <AVCaptureMetadataOutputObjectsDelegate>
{
AVCaptureSession *_session;
AVCaptureDevice *_device;
AVCaptureDeviceInput *_input;
AVCaptureMetadataOutput *_output;
AVCaptureVideoPreviewLayer *_prevLayer;
UIView *_highlightView;
UILabel *_label;
}
#end
#implementation igViewController
- (void)viewDidLoad
{
[super viewDidLoad];
_highlightView = [[UIView alloc] init];
_highlightView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin|UIViewAutoresizingFlexibleBottomMargin;
_highlightView.layer.borderColor = [UIColor greenColor].CGColor;
_highlightView.layer.borderWidth = 3;
[self.view addSubview:_highlightView];
_label = [[UILabel alloc] init];
_label.frame = CGRectMake(0, self.view.bounds.size.height - 40, self.view.bounds.size.width, 40);
_label.autoresizingMask = UIViewAutoresizingFlexibleTopMargin;
_label.backgroundColor = [UIColor colorWithWhite:0.15 alpha:0.65];
_label.textColor = [UIColor whiteColor];
_label.textAlignment = NSTextAlignmentCenter;
_label.text = #"(none)";
[self.view addSubview:_label];
_session = [[AVCaptureSession alloc] init];
_device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
NSError *error = nil;
_input = [AVCaptureDeviceInput deviceInputWithDevice:_device error:&error];
if (_input) {
[_session addInput:_input];
} else {
NSLog(#"Error: %#", error);
}
_output = [[AVCaptureMetadataOutput alloc] init];
[_output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
[_session addOutput:_output];
_output.metadataObjectTypes = [_output availableMetadataObjectTypes];
for (NSString* avail in _output.metadataObjectTypes) {
NSLog(#"Avail...%#", avail);
}
_prevLayer = [AVCaptureVideoPreviewLayer layerWithSession:_session];
_prevLayer.frame = self.view.bounds;
_prevLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[self.view.layer addSublayer:_prevLayer];
[_session startRunning];
[self.view bringSubviewToFront:_highlightView];
[self.view bringSubviewToFront:_label];
}
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection
{
NSLog(#"Failed...");
CGRect highlightViewRect = CGRectZero;
AVMetadataMachineReadableCodeObject *barCodeObject;
NSString *detectionString = nil;
NSArray *barCodeTypes = #[AVMetadataObjectTypeAztecCode];
for (AVMetadataObject *metadata in metadataObjects) {
NSLog(#".....%#", metadata.type);
for (NSString *type in barCodeTypes) {
if ([metadata.type isEqualToString:type])
{
barCodeObject = (AVMetadataMachineReadableCodeObject *)[_prevLayer transformedMetadataObjectForMetadataObjectAVMetadataMachineReadableCodeObject *)metadata];
highlightViewRect = barCodeObject.bounds;
detectionString = [(AVMetadataMachineReadableCodeObject *)metadata stringValue];
break;
}
}
if (detectionString != nil)
{
_label.text = detectionString;
break;
}
else
_label.text = #"(none)";
}
//_label.text = #"(nonessss)";
_highlightView.frame = highlightViewRect;
}
#end
This is my first answer on SO and I'm a total beginner with Objective-C and iOS development, so be a little gentle with me, please.
I can't actually help you fix errors in your code, as it is still very hard for me as a beginner to see what's going on, but I wanted to tell you that just a few days ago I successfully followed this tutorial on how to do exactly what you need. I adjusted the tutorials code and added comments where I needed them, so it should be easy to follow in case you'd like to try. As it is seems it is frowned upon to only post a link here, so I'm posting my code.
This is a ViewController that directly opens a scan view and reacts if a barcode (aztec in my case) is found. It should be easy to adjust to your needs. In the tutorial they used AVMetadataObjectTypeQRCode, but to scan Aztec codes, simply replace by AVMetadataObjectTypeAztecCode. I have done that already in my code.
ScanVC.h (in your case igViewController)
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#interface ScanVC : UIViewController <AVCaptureMetadataOutputObjectsDelegate>
#property (retain, nonatomic) UILabel *scannerWindow;
#property (retain, nonatomic) UILabel *statusLabel;
#property (retain, nonatomic) UIButton *cancelButton;
#end
ScanVC.m
#import "ScanVC.h"
#interface ScanVC ()
#property (nonatomic) BOOL isReading;
#property (nonatomic, strong) AVCaptureSession *captureSession;
#property (nonatomic, strong) AVCaptureVideoPreviewLayer *videoPreviewLayer;
#end
#implementation ScanVC
#synthesize cancelButton;
#synthesize statusLabel;
#synthesize scannerWindow;
- (void)viewDidLoad {
[super viewDidLoad];
_isReading = NO;
_captureSession = nil;
//place a close button
cancelButton = [UIButton buttonWithType:UIButtonTypeSystem];
[cancelButton addTarget:self action:#selector(closeScan) forControlEvents:UIControlEventTouchUpInside];
[cancelButton setTitle:#"Close" forState:UIControlStateNormal];
cancelButton.frame = CGRectMake(0, 410, 250, 40);
[self.view addSubview:cancelButton];
//place a status label
statusLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 340, 250, 40)];
statusLabel.text = #"Currently not scanning";
[self.view addSubview:statusLabel];
//place the scanner window (adjust the size)
scannerWindow = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 250, 250)];
scannerWindow.text = #"Camera Capture Window";
[self.view addSubview:scannerWindow];
//start the scan immediately when the view loads
[self startStopScan];
}
- (void)closeScan {
if(_isReading) {
[self stopReading];
}
_isReading = !_isReading;
//dismiss the view controller here?
}];
}
- (void)startStopScan {
if (!_isReading) {
if([self startReading]) {
[statusLabel setText:#"Scanning for Barcode"];
}
} else {
[self stopReading];
}
_isReading = !_isReading;
}
- (BOOL)startReading {
NSError *error;
AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error];
if(!input) {
NSLog(#"%#", [error localizedDescription]);
return NO;
}
_captureSession = [[AVCaptureSession alloc] init];
[_captureSession addInput:input];
AVCaptureMetadataOutput *captureMetadataOutput = [[AVCaptureMetadataOutput alloc] init];
[_captureSession addOutput:captureMetadataOutput];
dispatch_queue_t dispatchQueue;
dispatchQueue = dispatch_queue_create("myQueue", NULL);
[captureMetadataOutput setMetadataObjectsDelegate:self queue:dispatchQueue];
[captureMetadataOutput setMetadataObjectTypes:[NSArray arrayWithObject:AVMetadataObjectTypeAztecCode]];
//show the preview to the user
_videoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];
[_videoPreviewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
[_videoPreviewLayer setFrame:scannerWindow.layer.bounds];
[scannerWindow.layer addSublayer:_videoPreviewLayer];
[_captureSession startRunning];
return YES;
}
-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{
if (metadataObjects != nil && [metadataObjects count] > 0) {
AVMetadataMachineReadableCodeObject *metadataObj = [metadataObjects objectAtIndex:0];
if ([[metadataObj type] isEqualToString:AVMetadataObjectTypeAztecCode]) {
[statusLabel performSelectorOnMainThread:#selector(setText:) withObject:[metadataObj stringValue] waitUntilDone:NO];
[self performSelectorOnMainThread:#selector(stopReading) withObject:nil waitUntilDone:NO];
_isReading = NO;
//do things after a successful scan here
NSLog(#"scanner output %#", [metadataObj stringValue]);
}
}
}
- (void)stopReading {
[_captureSession stopRunning];
_captureSession = nil;
[_videoPreviewLayer removeFromSuperlayer];
}
#end
I'm making an app that has a camera preview in a View, inside this View I want to draw the camera data and also another View that shows a little rectangle when data it's captured, for example, in a BarCode scanning Scenario the Camera is shown in a view, when a BarCode it's found a Rectangle will be drawn showing that it has scanned a Barcode.
My current View Hierarchy it's the following:
View
{
-UIView cameraHolder
{
-UIView highlightView
}
}
I'm managed to get the camera showed and scanning things, but the highlight View it's not being shown, why is this happening?
This is the code for initializing the highlight View:
-(void)setUpHiglightView{
self.highlightView = [[UIView alloc] init];
self.highlightView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin|UIViewAutoresizingFlexibleBottomMargin;
self.highlightView.layer.borderColor = [UIColor greenColor].CGColor;
self.highlightView.layer.borderWidth = 3;
}
and this is the code for when a data it's captured:
-(void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection{
CGRect highlightViewRect = CGRectZero;
AVMetadataMachineReadableCodeObject *barCodeObject;
NSString *detectionString = nil;
NSArray *barCodeTypes = #[AVMetadataObjectTypeUPCECode, AVMetadataObjectTypeCode39Code, AVMetadataObjectTypeCode39Mod43Code,
AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode93Code, AVMetadataObjectTypeCode128Code,
AVMetadataObjectTypePDF417Code, AVMetadataObjectTypeQRCode, AVMetadataObjectTypeAztecCode];
for(AVMetadataObject *metadata in metadataObjects){
for(NSString *type in barCodeTypes){
if([metadata.type isEqualToString:type]){
barCodeObject = (AVMetadataMachineReadableCodeObject *)[prevLayer transformedMetadataObjectForMetadataObject:(AVMetadataMachineReadableCodeObject*)metadata];
highlightViewRect = barCodeObject.bounds;
detectionString = [(AVMetadataMachineReadableCodeObject*)metadata stringValue];
break;
}
}
}
if(detectionString != nil){
[self.itemIdTextField setText:detectionString];
}else{
//NSLog(#"Got Nothing");
}
NSLog(#"Position: [%f,%f][%f,%f]",highlightViewRect.origin.x, highlightViewRect.origin.y,highlightViewRect.size.height, highlightViewRect.size.width);
self.highlightView.frame = highlightViewRect;
}
Also the code that initializes the camera:
-(void)setupBarCodeScanner{
[self setUpHiglightView];
session = [[AVCaptureSession alloc] init];
device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
NSError *error = nil;
input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
if(input){
[session addInput:input];
}else{
[self showAlertDialogWithTitle:#"Error" andMessage:#"There was an error while accessing your camera"];
NSLog(#"Error: %#", error);
}
output = [[AVCaptureMetadataOutput alloc] init];
[output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
[session addOutput:output];
output.metadataObjectTypes = [output availableMetadataObjectTypes];
prevLayer = [AVCaptureVideoPreviewLayer layerWithSession:session];
prevLayer.frame = self.cameraHolder.bounds;
prevLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[self.cameraHolder.layer addSublayer:prevLayer];
}
Thank you very much!
Add self.highlightView to self.view at the end of captureOutput:
[self.view addSubview:self.highlightView];
It doesn't look like you're adding that view anywhere. You create it and set its frame, but I'm not seeing where you're adding to the view hierarchy.
I am trying to write an app that involves both front and rear camera and switching between them. As far as I understand, in the addVideoInput method, I have to change the IDs in
AVCaptureDevice *videoDevice = [AVCaptureDevice deviceWithUniqueID:(NSString *)deviceUniqueID];
But which NSStrings are those IDs?
Or, if it should be done in the other way, please, give a suggestion.
Thank you for help!
Ok, I have managed to find out a solution. I don't know if it's right or wrong, it was taken from http://www.bunnyhero.org/2010/08/15/turn-your-iphone-into-a-vampire-with-avfoundation-and-ios-4/
Just use
AVCaptureDevice *captureDevice = [self frontFacingCameraIfAvailable];
where frontFacingCameraIfAvailable is:
-(AVCaptureDevice *)frontFacingCameraIfAvailable
{
NSArray *videoDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
AVCaptureDevice *captureDevice = nil;
for (AVCaptureDevice *device in videoDevices)
{
if (device.position == AVCaptureDevicePositionFront)
{
captureDevice = device;
break;
}
}
// couldn't find one on the front, so just get the default video device.
if ( ! captureDevice)
{
captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
}
return captureDevice;
}
You can usually get frontal camera using
AVCaptureDevice *frontalCamera = [AVCaptureDevice deviceWithUniqueID:#"com.apple.avfoundation.avcapturedevice.built-in_video:1"];
But I would by all means rather use your accepted method - this one is not safe at all.
I was facing issue scanning QR Code with Front Camera. I looked out for so many resources and libraries in order to do so. Library was not fulfilling my requirement as I needed customised UI for scanner. And the piece of code on the internet to scan QR Code was also deprecated. So by debugging and knowing the device type I applied position of the camera and it worked. I am posting this as an answer so that it will help another peer like me looking for the answer.
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self setupScanner];
[self openScanner:nil];
}
#pragma mark- Actions
- (IBAction)openScanner:(id)sender {
if([UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceFront]){
[self.session startRunning];
}
}
- (IBAction)stopScanner:(id)sender {
[self.session stopRunning];
}
- (void)setupScanner {
#if !(TARGET_OS_SIMULATOR)
//self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
self.device = [self frontFacingCameraIfAvailable];
self.input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:nil];
self.session = [[AVCaptureSession alloc] init];
self.output = [[AVCaptureMetadataOutput alloc] init];
if([self.session canAddOutput:self.output]) {
[self.session addOutput:self.output];
}
if ([self.session canAddInput:self.input]){
[self.session addInput:self.input];
}
[self.output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
[self.output setMetadataObjectTypes:#[AVMetadataObjectTypeQRCode]];
self.preview = [AVCaptureVideoPreviewLayer layerWithSession:self.session];
self.preview.videoGravity = AVLayerVideoGravityResizeAspectFill;
self.preview.frame = CGRectMake(0, 0, CGRectGetWidth(self.pLayer.frame), CGRectGetHeight(self.pLayer.frame));
AVCaptureConnection *con = self.preview.connection;
con.videoOrientation = AVCaptureVideoOrientationLandscapeRight;
//pLayer is a UIView outlet on which the scanner fits or occupies its area to scan QR Code
[self.pLayer.layer insertSublayer:self.preview atIndex:0];
#endif
}
#pragma mark - AVCaptureMetadataOutputObjectsDelegate
- (void)captureOutput:(AVCaptureOutput *)output didOutputMetadataObjects:(NSArray<__kindof AVMetadataObject *> *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
CGRect highlightViewRect = CGRectZero;
AVMetadataMachineReadableCodeObject *barCodeObject;
NSString *detectionString = nil;
NSArray *barCodeTypes = #[AVMetadataObjectTypeUPCECode, AVMetadataObjectTypeCode39Code, AVMetadataObjectTypeCode39Mod43Code,
AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeCode93Code, AVMetadataObjectTypeCode128Code,
AVMetadataObjectTypePDF417Code, AVMetadataObjectTypeQRCode, AVMetadataObjectTypeAztecCode];
for (AVMetadataObject *metadata in metadataObjects) {
for (NSString *type in barCodeTypes) {
if ([metadata.type isEqualToString:type])
{
barCodeObject = (AVMetadataMachineReadableCodeObject *)[self.preview transformedMetadataObjectForMetadataObject:(AVMetadataMachineReadableCodeObject *)metadata];
highlightViewRect = barCodeObject.bounds;
detectionString = [(AVMetadataMachineReadableCodeObject *)metadata stringValue];
break;
}
}
if (detectionString != nil) {
self.codeLabel.text = detectionString;
[self stopScanner:nil];
//Do your work with QR Code String ---
break;
}
else
self.codeLabel.text = #"CODE";
}
}
#pragma mark- Capture Device
-(AVCaptureDevice *)frontFacingCameraIfAvailable {
AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithDeviceType:AVCaptureDeviceTypeBuiltInWideAngleCamera mediaType:AVMediaTypeVideo position:AVCaptureDevicePositionFront];
NSLog(#"capture device %#",captureDevice.description);
NSLog(#"device type %#",captureDevice.deviceType);
NSLog(#"unique Id: %#",captureDevice.uniqueID);
//com.apple.avfoundation.avcapturedevice.built-in_video:1
//Device Position: 2
NSLog(#"frontFacingCameraIfAvailable-> Device Position: %ld",(long)captureDevice.position);
return captureDevice;
}
-(AVCaptureDevice *)backFacingCameraIfAvailable {
AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
NSLog(#"capture device %#",captureDevice.description);
NSLog(#"device type %#",captureDevice.deviceType);
NSLog(#"unique Id: %#",captureDevice.uniqueID);
NSLog(#"backFacingCameraIfAvailable-> Device Position: %ld",(long)captureDevice.position);
return captureDevice;
}