Search code examples
iosios7avfoundationbarcodebarcode-scanner

Wrong result on Barcode scanning using AVFoundation framework


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 -

enter image description here

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.


Solution

  • 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);