Anyline OCR Plugin


Examples Source Code

The source code of all example use cases of the Anyline OCR Plugin can be found in the iOS SDK Bundle

Plugin Description

Simultaneous Barcode Scanning

Starting from SDK 3.8 Anyline supports simultaneous barcode scanning for any plugin. Additional Information on how to implement this on iOS can be found at Simultaneous Barcode Scanning

The Anyline OCR Plugin can be used to create plenty of different use cases. It offers a generic interface, which can be used to scan a variety of texts, from IBAN codes to Scrabble letters.

The description of all parameters can be found at Plugins > AnylineOCR

How to implement the Anyline OCR Plugins

This is a step by step guide on how to implement the Anyline OCR Plugin in iOS.

Add the Anyline OCR Plugins to your UIViewController

The first step is to add the three main components of every Anyline use case: the Scan Plugin (handling the scanning part), the Scan View Plugin (handling the UI) and the Scan View (handling camera, flash and overall communication between Anyline components).

Add the Anyline OCR Plugins
// The Anyline plugin used for OCR
@property (nonatomic, strong) ALOCRScanViewPlugin *scrabbleScanViewPlugin;
@property (nonatomic, strong) ALOCRScanPlugin *scrabbleScanPlugin;
@property (nullable, nonatomic, strong) ALScanView *scanView;

Anyline ScanPlugin

Initialise the Scan Plugin

You have to initialise the plugin with your Anyline License Key Generation, an ID (String) and the delegate inside viewDidLoad.

Initialise the Scan Plugin
    self.scrabbleScanPlugin = [[ALOCRScanPlugin alloc] initWithPluginID:@"ANYLINE_OCR"
                                                             licenseKey:kScrabbleLicenseKey
                                                               delegate:self
                                                              ocrConfig:config
                                                                  error:&error];
    NSAssert(self.scrabbleScanPlugin, @"Setup Error: %@", error.debugDescription);
    [self.scrabbleScanPlugin addInfoDelegate:self];

Anyline ScanViewPlugin

Option 1: Set your parameters manually

New in version 3.12.0: Predefined Regular Expressions and Character White Lists are now available for some use cases. For instance ISBN. viewDidLoad: create an ALOCRConfig object and set your parameters

Set the plugin parameters
    ALOCRConfig *config = [[ALOCRConfig alloc] init];
    config.scanMode = ALAuto;
    NSString *anylineTraineddata = [[NSBundle mainBundle] pathForResource:@"scrabble" ofType:@"traineddata"];
    [config setLanguages:@[anylineTraineddata] error:nil];
    config.charWhiteList = @"ABCDEFGHIJKLMNOPQRSTUVWXYZÄÜÖ";
    config.validationRegex = @"^[A-ZÄÜÖ]{7,10}$";

Option 2: Load your Custom Command File

If you are provided with a custom command file by Anyline, you can load the file with an instance of ALOCRConfig

Load a Custom Command File
ALOCRConfig *config = [[ALOCRConfig alloc] init];
config.customCmdFilePath = @"license_plates.ale";
// set the ocr config when creating the ScanPlugin

Initialise the Scan View Plugin

After initialising the scanPlugin, the next step is to create the scanViewPlugin with the scanPlugin you just created. The ScanViewPlugin will handle and display the UI used for scanning.

Initialise the Scan View Plugin
    self.scrabbleScanViewPlugin = [[ALOCRScanViewPlugin alloc] initWithScanPlugin:self.scrabbleScanPlugin
                                                             scanViewPluginConfig:scanViewPluginConfig];

Set the ScanViewPluginConfig

The View Configuration configurates the look and feel of the scanning process. You can set it the following way:

Set the ScanViewPluginConfig
NSString *confPath = [[NSBundle mainBundle] pathForResource:@"scrabble_config" ofType:@"json"];
ALScanViewPluginConfig *scanViewPluginConfig = [ALScanViewPluginConfig configurationFromJsonFilePath:confPath];

self.scrabbleScanViewPlugin = [[ALOCRScanViewPlugin alloc] initWithScanPlugin:self.scrabbleScanPlugin
                                                     scanViewPluginConfig:scanViewPluginConfig];

Anyline ScanView

Initialise the Scan View

The last Anyline Object you have to create is the so called scanView, it will handle the camera, the flash and manage the previously created ScanViewPlugin and ScanPlugin. You need to instantiate the scanView with the previous created scanViewPlugin and the frame it should occupy. Usually, that’s the bounds of the screen.

Initialise the Scan View
    self.scanView = [[ALScanView alloc] initWithFrame:frame scanViewPlugin:self.scrabbleScanViewPlugin];

Adding the Scan View to the View Hierarchy and start the Camera Feed

To add the scanView to your view hierarchy add the following in viewDidLoad:

Adding the view and starting the camera
    // After setup is complete we add the module to the view of this view controller
    [self.view addSubview:self.scanView];
    //Start Camera:
    [self.scanView startCamera];

Final steps to configure and use the Anyline OCR Plugin

The Anyline OCR Delegate

In the Anyline SDK, you will be provided final and intermediate results via a delegate call. The delegate is set on initialisation with scanPlugin initWithPluginID:licenseKey:delegate:ocrConfig:error

In case of the Anyline OCR plugin, the delegate protocol is called ALOCRScanPluginDelegate. This section describes the ALOCRScanPluginDelegate calls in detail.

anylineOCRScanPlugin:didFindResult:

This is the main callback method for the Anyline OCR Plugin. It is called once a valid result according to the Parameters has been found.

The result is an instance of ALOCRResult, which holds the detected text, the image that was processed, as well as a thresholded image.

Getting a result
/*
 This is the main delegate method Anyline uses to report its results
 */
- (void)anylineOCRScanPlugin:(ALOCRScanPlugin *)anylineOCRScanPlugin didFindResult:(ALOCRResult *)result {
    [self anylineDidFindResult:result.result barcodeResult:@"" image:result.image scanPlugin:anylineOCRScanPlugin viewPlugin:self.scrabbleScanViewPlugin completion:^{
        [self stopAnyline];
        ALScrabbleViewController *vc = [[ALScrabbleViewController alloc] init];
        [vc setResult:result.result];
        [self.navigationController pushViewController:vc animated:YES];
    }];
}
  • ALOCRResult result
Field Type Nullable Description
result NSString The actual result of the scanning process
image UIImage The image the result was found on. The image is cropped to the cutout
fullImage UIImage The full image the result was found on.
thresholdedImage UIImage Thresholded result image.
confidence NSInteger The confidence of the SDK in the detected result

anylineScanPlugin:runSkipped:

Optional

This Protocol method is optional

This is called if a run (on one image) was aborted because an error occurred. An error can occur if the environment is too dark, the image is too blurry, or other reasons.

Important

The SDK will not stop scanning when this callback is called, but process the next frame.
This means that this callback is solely for information purposes.

Getting run failures
- (void)anylineScanPlugin:(ALAbstractScanPlugin *)anylineScanPlugin runSkipped:(ALRunSkippedReason *)runSkippedReason {
    
    //Handle run skipped reasons here:
    switch (runSkippedReason.reason) {
        case ALRunFailureResultNotValid:
            break;
        case ALRunFailureConfidenceNotReached:
            break;
        case ALRunFailureNoLinesFound:
            break;
        case ALRunFailureNoTextFound:
            break;
        case ALRunFailureUnkown:
            break;
        default:
            break;
    }
}

reportsVariable:reportInfo:

Optional

This Protocol method is optional

This callback delivers intermediate information from the scanning process. This can be the brightness of a frame, a thresholded, or the confidence of the following result. The returned ALScanInfo contains a variableName and the corresponding value.

All values are reported named with a proceeding $. So for example, the brighntess value is reported as $brightness.
The value itself is reported as an Objective-C id

Tip

Because of the value being an id, checking for the actual class with isKindOfClass: is advised

Getting reported variables
- (void)anylineScanPlugin:(ALAbstractScanPlugin *)anylineScanPlugin reportInfo:(ALScanInfo *)info{
    if ([info.variableName isEqualToString:@"$brightness"]) {
        [self updateBrightness:[info.value floatValue] forModule:self.scrabbleScanViewPlugin];
    }
    
}

Enabling or Disabling the Reporting

The reporting of the (intermediate) results (including an image) helps us to improve the accuracy of the SDK and detect potential shortcomings.

However, you can easily turn the reporting off (viewDidLoad())

Enabling or disabling of the Reporting
[self.ocrScanPlugin enableReporting:YES];

Reporting & License

Depending, on your license, the reporting may not be turned on or off.

Multiple Scan Use Cases

If you have multiple scan use cases in your application, and you want different reporting for each usee case, you have to set enableReporting for each use case seperately. I.e. setting reporting to on means that it is turned on for your whole application.

Starting Scanning

Hint

Use [scanView startCamera] within viewDidload before starting Anyline.

After everything is initialised, you can start the scanning process, by calling startAndReturnError: on the plugin.

It is advised to place this call in the viewDidAppear: lifecycle method of the UIViewController.

Stop Scanning

To stop the scanning process, call stopAndReturnError: on the plugin.

To make sure the SDK is properly stopped upon leaving the Activity, make sure to place stopAndReturnError: in the viewWillDisappear: lifecycle method of the UIViewController.

Stopping the plugin
    if (self.scrabbleScanPlugin.isRunning) {
        [self.scrabbleScanViewPlugin stopAndReturnError:nil];
    }

Full Example

Full Anyline OCR iOS Example
#import "ALScrabbleScanViewController.h"
#import <Anyline/Anyline.h>
#import "ALScrabbleViewController.h"
#import "ALCustomBarButton.h"
#import "ScanHistory.h"
#import "NSUserDefaults+ALExamplesAdditions.h"
#import "ALAppDemoLicenses.h"

// This is the license key for the examples project used to set up Aynline below
NSString * const kScrabbleLicenseKey = kDemoAppLicenseKey;
// The controller has to conform to <AnylineOCRModuleDelegate> to be able to receive results
@interface ALScrabbleScanViewController ()<ALOCRScanPluginDelegate, ALInfoDelegate>

// The Anyline plugin used for OCR
@property (nonatomic, strong) ALOCRScanViewPlugin *scrabbleScanViewPlugin;
@property (nonatomic, strong) ALOCRScanPlugin *scrabbleScanPlugin;
@property (nullable, nonatomic, strong) ALScanView *scanView;

@end

@implementation ALScrabbleScanViewController
/*
 We will do our main setup in viewDidLoad. Its called once the view controller is getting ready to be displayed.
 */
- (void)viewDidLoad {
    [super viewDidLoad];

    // Set the background color to black to have a nicer transition
    self.view.backgroundColor = [UIColor blackColor];
    self.title = @"Scrabble";
    // Initializing the module. Its a UIView subclass. We set the frame to fill the whole screen
    CGRect frame = [[UIScreen mainScreen] applicationFrame];
    frame = CGRectMake(frame.origin.x, frame.origin.y + self.navigationController.navigationBar.frame.size.height, frame.size.width, frame.size.height - self.navigationController.navigationBar.frame.size.height);
    
    ALOCRConfig *config = [[ALOCRConfig alloc] init];
    config.scanMode = ALAuto;
    NSString *anylineTraineddata = [[NSBundle mainBundle] pathForResource:@"scrabble" ofType:@"traineddata"];
    [config setLanguages:@[anylineTraineddata] error:nil];
    config.charWhiteList = @"ABCDEFGHIJKLMNOPQRSTUVWXYZÄÜÖ";
    config.validationRegex = @"^[A-ZÄÜÖ]{7,10}$";
    
    NSError *error = nil;
    
    self.scrabbleScanPlugin = [[ALOCRScanPlugin alloc] initWithPluginID:@"ANYLINE_OCR"
                                                             licenseKey:kScrabbleLicenseKey
                                                               delegate:self
                                                              ocrConfig:config
                                                                  error:&error];
    NSAssert(self.scrabbleScanPlugin, @"Setup Error: %@", error.debugDescription);
    [self.scrabbleScanPlugin addInfoDelegate:self];
    
    NSString *confPath = [[NSBundle mainBundle] pathForResource:@"scrabble_config" ofType:@"json"];
    ALScanViewPluginConfig *scanViewPluginConfig = [ALScanViewPluginConfig configurationFromJsonFilePath:confPath];
    
    self.scrabbleScanViewPlugin = [[ALOCRScanViewPlugin alloc] initWithScanPlugin:self.scrabbleScanPlugin
                                                             scanViewPluginConfig:scanViewPluginConfig];
    NSAssert(self.scrabbleScanViewPlugin, @"Setup Error: %@", error.debugDescription);
    
    self.scanView = [[ALScanView alloc] initWithFrame:frame scanViewPlugin:self.scrabbleScanViewPlugin];
    
    // After setup is complete we add the module to the view of this view controller
    [self.view addSubview:self.scanView];
    //Start Camera:
    [self.scanView startCamera];
    
    [self.view sendSubviewToBack:self.scanView];
    [self startListeningForMotion];
    self.controllerType = ALScanHistoryScrabble;

}

/*
 This method will be called once the view controller and its subviews have appeared on screen
 */
-(void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    
    // We use this subroutine to start Anyline. The reason it has its own subroutine is
    // so that we can later use it to restart the scanning process.
    [self startAnyline];
    
    //Update Position of Warning Indicator
    [self updateWarningPosition:
     self.scrabbleScanViewPlugin.cutoutRect.origin.y +
     self.scrabbleScanViewPlugin.cutoutRect.size.height +
     self.scrabbleScanViewPlugin.frame.origin.y +
     120];
}

/*
 Cancel scanning to allow the module to clean up
 */
- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    
    [self.scrabbleScanViewPlugin stopAndReturnError:nil];
}

/*
 This method is used to tell Anyline to start scanning. It gets called in
 viewDidAppear to start scanning the moment the view appears. Once a result
 is found scanning will stop automatically (you can change this behaviour
 with cancelOnResult:). When the user dismisses self.identificationView this
 method will get called again.
 */
- (void)startAnyline {
    NSError *error;
    BOOL success = [self.scrabbleScanViewPlugin startAndReturnError:&error];
    if( !success ) {
        // Something went wrong. The error object contains the error description
        NSAssert(success, @"Start Scanning Error: %@", error.debugDescription);
    }
    
    self.startTime = CACurrentMediaTime();
}

- (void)stopAnyline {
    if (self.scrabbleScanPlugin.isRunning) {
        [self.scrabbleScanViewPlugin stopAndReturnError:nil];
    }
}

#pragma mark -- AnylineOCRModuleDelegate
/*
 This is the main delegate method Anyline uses to report its results
 */
- (void)anylineOCRScanPlugin:(ALOCRScanPlugin *)anylineOCRScanPlugin didFindResult:(ALOCRResult *)result {
    [self anylineDidFindResult:result.result barcodeResult:@"" image:result.image scanPlugin:anylineOCRScanPlugin viewPlugin:self.scrabbleScanViewPlugin completion:^{
        [self stopAnyline];
        ALScrabbleViewController *vc = [[ALScrabbleViewController alloc] init];
        [vc setResult:result.result];
        [self.navigationController pushViewController:vc animated:YES];
    }];
}

- (void)anylineScanPlugin:(ALAbstractScanPlugin *)anylineScanPlugin reportInfo:(ALScanInfo *)info{
    if ([info.variableName isEqualToString:@"$brightness"]) {
        [self updateBrightness:[info.value floatValue] forModule:self.scrabbleScanViewPlugin];
    }
    
}

- (void)anylineScanPlugin:(ALAbstractScanPlugin *)anylineScanPlugin runSkipped:(ALRunSkippedReason *)runSkippedReason {
    
    //Handle run skipped reasons here:
    switch (runSkippedReason.reason) {
        case ALRunFailureResultNotValid:
            break;
        case ALRunFailureConfidenceNotReached:
            break;
        case ALRunFailureNoLinesFound:
            break;
        case ALRunFailureNoTextFound:
            break;
        case ALRunFailureUnkown:
            break;
        default:
            break;
    }
}

@end