Click here to Skip to main content
14,217,582 members

iOS Barcode Scanner with Dynamsoft Mobile Barcode SDK

7 Jul 2016CPOL
Save time and money. Expedite development of iOS barcode apps using Dynamsoft Barcode Reader SDK.

This article is in the Product Showcase section for our sponsors at CodeProject. These articles are intended to provide you with information on products and services that we consider useful and of value to developers.

Introduction

Dynamsoft aims to make barcode SDK available for all mainstream platforms. So far, it has covered Windows, Linux, and macOS for desktop platforms. As for mobile platforms, Dynamsoft has released the mobile barcode SDK for iOS. No matter whether you prefer free or proprietary software, this is a new option. In the following paragraph, we will show you how to use the iOS barcode SDK.

Features of Dynamsoft Barcode Reader for iOS

Compatibility:

  • iOS 7.0 or later
  • Xcode 6.0 or later

Input Data:

  • UIImage or NV21

Supported 1D/2D Barcode Types:

  • 1D: Code 39, Code 93, Code 128, Codabar, EAN-8, EAN-13, UPC-A, UPC-E, Interleaved 2 of 5 (ITF), Industrial 2 of 5 (Code 2 of 5 Industry, Standard 2 of 5, Code 2 of 5), ITF-14
  • 2D: QRCode, DataMatrix, and PDF417

Detected Barcode Information:

  • Barcode type
  • Barcode value as string
  • Barcode raw data as bytes
  • Barcode bounding rectangle
  • Coordinate of four corners

iOS Barcode Scanner Example

Open Xcode 7 and press Shift+Command+N to create a new project with the Single View Application template.

Drag DynamsoftBarcodeReader.framework to your project. Check the option "Copy items if needed":

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:

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.

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

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];
    }
}

App Download

You can install the app from iTunes App Store.

Get iOS Barcode SDK

Do you want to quickly develop iOS barcode apps? Get your hands dirty now:

Dynamsoft iOS Barcode SDK, 30-day Free Trial

Support

If you have any questions about the above sample or the iOS barcode SDK, please feel free to contact support@dynamsoft.com.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Dynamsoft
Canada Canada
Dynamsoft has more than 10 years of experience in TWAIN SDKs, imaging SDKs and version control solutions.

Our products include:

TWAIN SDK
- Dynamic Web TWAIN: a TWAIN scanning SDK optimized for web document management applications.
- Dynamic .NET TWAIN: a .NET TWAIN and Directshow Image Capture SDK for WinForms/WPF applications.

Imaging SDKs
- Barcode Reader for Windows, Linux, macOS, iOS, Android and Raspberry Pi.
- OCR addon for both web and .NET TWAIN SDKs

Version Control
- SourceAnywhere: a SQL server-based source control solution. Both on-premise and hosting options are provided.
Group type: Organisation

22 members


Comments and Discussions

 
-- There are no messages in this forum --
Article
Posted 7 Jul 2016

Tagged as

Stats

9.8K views
2 bookmarked