How to Build a Simple iOS Barcode Scanner App

Dynamsoft has released the mobile barcode SDK for iOS. In this post, let’s see how to use the SDK to quickly build an iOS barcode scanner app.

iOS barcode scanner result

iOS Barcode Scanner with Dynamsoft Barcode Reader SDK

SDK

Download

Xcode Project Configuration

  1. Open Xcode 7 and press Shift+Command+N to create a new project with the Single View Application template.
  2. Drag DynamsoftBarcodeReader.framework to your project. Check the option “Copy items if needed”:drag framework to Xcode

    The framework will be copied to your project folder. Why do you need to do this? Open project properties and select Build Settings > Search Paths:

    Xcode search path

    If you do not copy the Framework into your project, you have to change the Framework Search Path. Otherwise, it will fail to find the framework.

  3. Add dependencies. Select Build Phases > Link Binary With Libraries to add DynamsoftBarcodeReader.framework and libc++.tbd(libc++.dylib for Xcode 6):
    Xcode link binary

How-to

Create an instance of DbrManager in ViewDidLoad:

- (void)viewDidLoad {

    [super viewDidLoad];



    [[UIApplication sharedApplication] setIdleTimerDisabled: YES];



    //register notification for UIApplicationDidBecomeActiveNotification

    [[NSNotificationCenter defaultCenter] addObserver:self

                                             selector:@selector(didBecomeActive:)

                                                 name:UIApplicationDidBecomeActiveNotification

                                               object:nil];



    //init DbrManager with Dynamsoft Barcode Reader mobile license

    dbrManager = [[DbrManager alloc] initWithLicense:@"<license>"];

    [dbrManager setRecognitionCallback:self :@selector(onReadImageBufferComplete:)];

    [dbrManager beginVideoSession];



    [self configInterface];

}

Initialize Dynamsoft Barcode Reader with a valid license:

-(id)initWithLicense:(NSString *)license{

    self = [super init];



    if(self)

    {

        m_videoCaptureSession = nil;

        m_barcodeReader = [[BarcodeReader alloc] initWithLicense:license];



        isPauseFramesComing = NO;

        isCurrentFrameDecodeFinished = YES;



        barcodeFormat = [Barcode UNKNOWN];

        startRecognitionDate = nil;



        m_recognitionReceiver = nil;

    }



    return self;

}

Use back-facing camera as the capture device:

-(AVCaptureDevice *)getAvailableCamera {

    NSArray *videoDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];

    AVCaptureDevice *captureDevice = nil;

    for (AVCaptureDevice *device in videoDevices) {

        if (device.position == AVCaptureDevicePositionBack) {

            captureDevice = device;

            break;

        }

    }



    if (!captureDevice)

        captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];



    return captureDevice;

}

Create a video capture session:

-(void)beginVideoSession {

    AVCaptureDevice *inputDevice = [self getAvailableCamera];



    AVCaptureDeviceInput *captureInput = [AVCaptureDeviceInput

                                          deviceInputWithDevice:inputDevice

                                          error:nil];



    AVCaptureVideoDataOutput *captureOutput = [[AVCaptureVideoDataOutput alloc] init];



    captureOutput.alwaysDiscardsLateVideoFrames = YES;



    dispatch_queue_t queue;

    queue = dispatch_queue_create("dbrCameraQueue", NULL);

    [captureOutput setSampleBufferDelegate:self queue:queue];



    // Enable continuous autofocus

    if ([inputDevice isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]) {

        NSError *error = nil;

        if ([inputDevice lockForConfiguration:&error]) {

            inputDevice.focusMode = AVCaptureFocusModeContinuousAutoFocus;

            [inputDevice unlockForConfiguration];

        }

    }



    // Enable AutoFocusRangeRestriction

     if([inputDevice respondsToSelector:@selector(isAutoFocusRangeRestrictionSupported)] &&

        inputDevice.autoFocusRangeRestrictionSupported) {

         if([inputDevice lockForConfiguration:nil]) {

             inputDevice.autoFocusRangeRestriction = AVCaptureAutoFocusRangeRestrictionNear;

             [inputDevice unlockForConfiguration];

         }

     }



    [captureOutput setVideoSettings:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarFullRange] forKey:(id)kCVPixelBufferPixelFormatTypeKey]];



    if(captureInput == nil || captureOutput == nil)

    {

        return;

    }



    m_videoCaptureSession = [[AVCaptureSession alloc] init];

    [m_videoCaptureSession addInput:captureInput];

    [m_videoCaptureSession addOutput:captureOutput];



    if ([m_videoCaptureSession canSetSessionPreset:AVCaptureSessionPreset1920x1080])

    {

        [m_videoCaptureSession setSessionPreset :AVCaptureSessionPreset1920x1080];

        cameraResolution.width = 1920;

        cameraResolution.height = 1080;

    }

    else if ([m_videoCaptureSession canSetSessionPreset:AVCaptureSessionPreset1280x720])

    {

        [m_videoCaptureSession setSessionPreset :AVCaptureSessionPreset1280x720];

        cameraResolution.width = 1280;

        cameraResolution.height = 720;

    }

    else if([m_videoCaptureSession canSetSessionPreset:AVCaptureSessionPreset640x480])

    {

        [m_videoCaptureSession setSessionPreset :AVCaptureSessionPreset640x480];

        cameraResolution.width = 640;

        cameraResolution.height = 480;

    }



    [m_videoCaptureSession startRunning];

}

Display video on preview layer:

AVCaptureSession* captureSession = [dbrManager getVideoSession];

    if(captureSession == nil)

        return;



    previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:captureSession];

    [previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];

        previewLayer.frame = mainScreenLandscapeBoundary;

    cameraPreview = [[UIView alloc] init];

    [cameraPreview.layer addSublayer:previewLayer];

    [self.view insertSubview:cameraPreview atIndex:0];

According to the environment brightness, toggle flash:

- (void) turnFlashOn: (BOOL) on {

    // validate whether flashlight is available

    Class captureDeviceClass = NSClassFromString(@"AVCaptureDevice");

    if (captureDeviceClass != nil) {

        AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];

        if (device != nil && [device hasTorch] && [device hasFlash]){

            [device lockForConfiguration:nil];



            if (on == YES) {

                [device setTorchMode:AVCaptureTorchModeOn];

                [device setFlashMode:AVCaptureFlashModeOn];

                [flashButton setImage:[UIImage imageNamed:@"flash_on"] forState:UIControlStateNormal];

                [flashButton setTitle:NSLocalizedString(@"flash-on", @"flash on string") forState:UIControlStateNormal];



            } else {

                [device setTorchMode:AVCaptureTorchModeOff];

                [device setFlashMode:AVCaptureFlashModeOff];

                [flashButton setImage:[UIImage imageNamed:@"flash_off"] forState:UIControlStateNormal];

                [flashButton setTitle:NSLocalizedString(@"flash-off", @"flash off string") forState:UIControlStateNormal];

            }



            [device unlockForConfiguration];

        }

    }

}

Keep camera automatically focused:

if ([inputDevice isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]) {

        NSError *error = nil;

        if ([inputDevice lockForConfiguration:&error]) {

            inputDevice.focusMode = AVCaptureFocusModeContinuousAutoFocus;

            [inputDevice unlockForConfiguration];

        }

    }

     if([inputDevice respondsToSelector:@selector(isAutoFocusRangeRestrictionSupported)] &&

        inputDevice.autoFocusRangeRestrictionSupported) {

         if([inputDevice lockForConfiguration:nil]) {

             inputDevice.autoFocusRangeRestriction = AVCaptureAutoFocusRangeRestrictionNear;

             [inputDevice unlockForConfiguration];

         }

}

Receive captured video with AVCaptureVideoDataOutputSampleBufferDelegate and read barcode in captureOutput:

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection;

{

    @autoreleasepool {

        if(isPauseFramesComing == YES || isCurrentFrameDecodeFinished == NO) return;



        isCurrentFrameDecodeFinished = NO;



        void *imageData = NULL;

        uint8_t *copyToAddress;



        CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);



        OSType pixelFormat = CVPixelBufferGetPixelFormatType(imageBuffer);



        if (!(pixelFormat == '420v' || pixelFormat == '420f'))

        {

            isCurrentFrameDecodeFinished = YES;

            return;

        }



        CVPixelBufferLockBaseAddress(imageBuffer, 0);

        int numPlanes = (int)CVPixelBufferGetPlaneCount(imageBuffer);

        int bufferSize = (int)CVPixelBufferGetDataSize(imageBuffer);

        int imgWidth = (int)CVPixelBufferGetWidthOfPlane(imageBuffer, 0);

        int imgHeight = (int)CVPixelBufferGetHeightOfPlane(imageBuffer, 0);



        if(numPlanes < 1)

        {

            isCurrentFrameDecodeFinished = YES;

            return;

        }



        uint8_t *baseAddress = (uint8_t *) CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0);

        size_t bytesToCopy = CVPixelBufferGetHeightOfPlane(imageBuffer, 0) * CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, 0);

        imageData = malloc(bytesToCopy);

        copyToAddress = (uint8_t *) imageData;

        memcpy(copyToAddress, baseAddress, bytesToCopy);



        CVPixelBufferUnlockBaseAddress(imageBuffer, 0);



        NSData *buffer = [NSData dataWithBytesNoCopy:imageData length:bufferSize freeWhenDone:YES];



        startRecognitionDate = [NSDate date];



        // read frame using Dynamsoft Barcode Reader in async manner

        [m_barcodeReader readSingleAsync:buffer width:imgWidth height:imgHeight barcodeFormat: barcodeFormat sender:m_recognitionReceiver onComplete:m_recognitionCallback];

    }

}

Video of iOS Barcode Scanner

App Installation

You can download the app from iTunes App Store.

Source Code

https://github.com/dynamsoft-dbr/iOS-barcode-scanner