2

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
rmaddy
  • 314,917
  • 42
  • 532
  • 579
Kapil Kumar
  • 104
  • 8

1 Answers1

3

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
oelna
  • 2,210
  • 3
  • 22
  • 40
  • Hey oelna, did you try this against some Aztec barcodes? Did it successfully scan the Aztec barcodes? I have code similar to the above but I'm not able to scan Aztec barcodes despite `AVMetadataObjectTypeAztecCode` being in the `NSArray` which is assigned to my `AVCaptureMetadataOutput` instance via the `setMetadataObjectTypes` method... – Adil Hussain Sep 04 '14 at 15:21
  • 1
    Sorry, I take that back. I just generated a new Aztec 2D barcode and it scanned fine. Must have been something wrong the barcode I had before. – Adil Hussain Sep 04 '14 at 15:23