Demos and Sample Code

Anyline Demo

Warning

With Anyline 4 we have two types of json files. One of them contains also the scan plugin specified in it (e.g. “plugin”: {“id”: “VIN_ID”, …}). With this, all the parameters specific to the scan plugin (e.g. scanMode, charWhitelist) should not be specified in the code anymore, but in the json.
If you explicitly load the scan plugin in your code and/or scan view plugin configuration, please make sure that your json config file does not contain the plugin element.

Meter Plugin Analog/Digital Automatic (Documentation)
{
  "camera":{
    "captureResolution" : "720p"
  },
  "flash" : {
    "mode" : "manual",
    "alignment" : "bottom"
  },
  "viewPlugin" : {
    "plugin" : {
      "id" : "METER_ID",
       "meterPlugin": {
          "scanMode": "AUTO_ANALOG_DIGITAL_METER"
        }
    },
    "cutoutConfig" : {
      "style" : "rect",
      "alignment" : "top_half",
      "strokeWidth" : 2,
      "strokeColor" : "FFFFFF",
      "cornerRadius" : 4,
      "outerColor" : "000000",
      "outerAlpha" : 0.5,
      "feedbackStrokeColor" : "0099FF"
    },
    "scanFeedback" : {
      "style" : "CONTOUR_RECT",
      "strokeColor" : "0099FF",
      "fillColor" : "220099FF",
      "blinkOnResult": true,
      "beepOnResult": true,
      "vibrateOnResult": true
    },
    "cancelOnResult" : true
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;

import androidx.annotation.Nullable;
import io.anyline.plugin.ScanResultListener;
import io.anyline.plugin.meter.MeterScanResult;
import io.anyline.plugin.meter.MeterScanViewPlugin;
import io.anyline.view.ScanView;
import io.anyline.AnylineSDK;


public class ScanAutoAnalogDigitalMeter extends Activity {

    private ScanView scanView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_anyline_test);


        scanView = findViewById(R.id.scan_view);

      	// This must be called before doing anything Anyline-related! 
	// Try/Catch this to check whether or not your license key is valid! 
	try {
    	    AnylineSDK.init(getString(getString(R.string.anyline_license_key)), this);
	} catch (LicenseException e) {
    	    // handle exception
	}

        // initialize Anyline with a Listener that is called if a result is found
        try {
            scanView.init("energy_auto_analog_digital_view_config.json");
        } catch (Exception e) {
            e.printStackTrace();
        }

        MeterScanViewPlugin scanViewPlugin = (MeterScanViewPlugin) scanView.getScanViewPlugin();

        scanViewPlugin.addScanResultListener(new ScanResultListener<MeterScanResult>() {
            @Override
            public void onResult(MeterScanResult result) {
				Toast.makeText(getApplicationContext(), result.getResult(), Toast.LENGTH_LONG).show();
            }

        });
    }

    @Override
    protected void onResume() {
        super.onResume();
        scanView.start();
    }


    @Override
    protected void onPause() {
        super.onPause();
        scanView.stop();
    }
}
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
#import "NSUserDefaults+ALExamplesAdditions.h"
#import "ALAutoAnalogDigitalMeterScanViewController.h"
#import <Anyline/Anyline.h>
#import "ALAppDemoLicenses.h"
#import "ALResultEntry.h"
#import "ALResultViewController.h"



// This is the license key for the examples project used to set up Aynline below
NSString * const kAutoAnalogDigitalMeterScanLicenseKey = kDemoAppLicenseKey;

static const NSInteger padding = 7;

// The controller has to conform to <AnylineEnergyModuleDelegate> to be able to receive results
@interface ALAutoAnalogDigitalMeterScanViewController ()<ALMeterScanPluginDelegate, AnylineNativeBarcodeDelegate>

// The Anyline plugins used to scan
@property (nonatomic, strong) ALMeterScanViewPlugin *meterScanViewPlugin;
@property (nonatomic, strong) ALMeterScanPlugin *meterScanPlugin;
@property (nullable, nonatomic, strong) ALScanView *scanView;

//Native barcode scanning properties
@property (nonatomic, strong) NSString *barcodeResult;

@property (nonatomic, strong) UIView *enableBarcodeView;
@property (nonatomic, strong) UISwitch *enableBarcodeSwitch;
@property (nonatomic, strong) UILabel *enableBarcodeLabel;

@end

@implementation ALAutoAnalogDigitalMeterScanViewController

/*
 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 = @"Analog/Digital Meter";
    
    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);
    
    
    NSError *licenseError = nil;
    //Initialize the Anyline License
    [AnylineSDK setupWithLicenseKey:kDemoAppLicenseKey error:&licenseError];
    if (licenseError) {
        //Handle errors here
    }
    
    //Add Meter Scan Plugin (Scan Process)
    NSError *error = nil;
    self.meterScanPlugin = [[ALMeterScanPlugin alloc] initWithPluginID:@"ENERGY" delegate:self error:&error];
    NSAssert(self.meterScanPlugin, @"Setup Error: %@", error.debugDescription);
    
    //Add Meter Scan View Plugin (Scan UI)
    self.meterScanViewPlugin = [[ALMeterScanViewPlugin alloc] initWithScanPlugin:self.meterScanPlugin];
    
    
    //Set ScanMode to ALAutoAnalogDigitalMeter
    BOOL success = [self.meterScanPlugin setScanMode:ALAutoAnalogDigitalMeter error:&error];
    if( !success ) {
        // Something went wrong. The error object contains the error description
        [[[UIAlertView alloc] initWithTitle:@"Set ScanMode Error"
                                    message:error.debugDescription
                                   delegate:self
                          cancelButtonTitle:@"OK"
                          otherButtonTitles:nil] show];
        
    }
    
    //Add ScanView (Camera and Flashbutton)
    self.scanView = [[ALScanView alloc] initWithFrame:frame scanViewPlugin:self.meterScanViewPlugin];
    
    [self.view addSubview:self.scanView];
    [self.scanView startCamera];
    
    BOOL enableReporting = [NSUserDefaults AL_reportingEnabled];
    [self.meterScanPlugin enableReporting:enableReporting];
    self.meterScanViewPlugin.translatesAutoresizingMaskIntoConstraints = NO;
    
    //After setup is complete we add the module to the view of this view controller
    [[self view] addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scanView]|" options:0 metrics:nil views:@{@"scanView" : self.scanView}]];
    id topGuide = self.topLayoutGuide;
    [[self view] addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[topGuide]-0-[scanView]|" options:0 metrics:nil views:@{@"scanView" : self.scanView, @"topGuide" : topGuide}]];

    
    self.controllerType = ALScanHistoryElectricMeter;

    self.barcodeResult = @"";
    [self.view sendSubviewToBack:self.scanView];
    [self.scanView addSubview:[self createBarcoeSwitchView]];
    [self.scanView bringSubviewToFront:self.enableBarcodeView];
}

/*
 This method will be called once the view controller and its subviews have appeared on screen
 */
- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    /*
     This is the place where we tell Anyline to start receiving and displaying images from the camera.
     Success/error tells us if everything went fine.
     */
    NSError *error = nil;
    BOOL success = [self.meterScanViewPlugin startAndReturnError:&error];
    if( !success ) {
        // Something went wrong. The error object contains the error description
        [[[UIAlertView alloc] initWithTitle:@"Start Scanning Error"
                                    message:error.debugDescription
                                   delegate:self
                          cancelButtonTitle:@"OK"
                          otherButtonTitles:nil] show];
    }
}

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];
        
    [self updateLayoutBarcodeSwitchView];
}

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

#pragma mark - IBAction methods


- (IBAction)toggleBarcodeScanning:(id)sender {
    
    if (self.scanView.captureDeviceManager.barcodeDelegates.count > 0) {
        self.enableBarcodeSwitch.on = false;
        [self.scanView.captureDeviceManager removeBarcodeDelegate:self];
        //reset found barcode
        self.barcodeResult = @"";
    } else {
        self.enableBarcodeSwitch.on = true;
        [self.scanView.captureDeviceManager addBarcodeDelegate:self error:nil];
    }
}

#pragma mark - Barcode View layouting
- (UIView *)createBarcoeSwitchView {
    //Add UISwitch for toggling barcode scanning
    self.enableBarcodeView = [[UIView alloc] init];
    self.enableBarcodeView.frame = CGRectMake(100, 100, 150, 50);
    
    self.enableBarcodeLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 30)];
    self.enableBarcodeLabel.text = @"Barcode Detection";
    UIFont *font = [UIFont systemFontOfSize:14 weight:UIFontWeightThin];
    self.enableBarcodeLabel.font = font;
    self.enableBarcodeLabel.numberOfLines = 0;
    
    self.enableBarcodeLabel.textColor = [UIColor whiteColor];
    [self.enableBarcodeLabel sizeToFit];
    
    self.enableBarcodeSwitch = [[UISwitch alloc] init];
    [self.enableBarcodeSwitch setOn:false];
    self.enableBarcodeSwitch.onTintColor = [UIColor whiteColor];
    [self.enableBarcodeSwitch setOnTintColor:[UIColor colorWithRed:0.0/255.0 green:153.0/255.0 blue:255.0/255.0 alpha:1.0]];
    [self.enableBarcodeSwitch addTarget:self action:@selector(toggleBarcodeScanning:) forControlEvents:UIControlEventValueChanged];
    
    [self.enableBarcodeView addSubview:self.enableBarcodeLabel];
    [self.enableBarcodeView addSubview:self.enableBarcodeSwitch];
    
    return self.enableBarcodeView;
}

- (void)updateLayoutBarcodeSwitchView {
    self.enableBarcodeLabel.center = CGPointMake(self.enableBarcodeLabel.frame.size.width/2,
                                                 self.enableBarcodeView.frame.size.height/2);

    self.enableBarcodeSwitch.center = CGPointMake(self.enableBarcodeLabel.frame.size.width + self.enableBarcodeSwitch.frame.size.width/2 + padding,
                                                  self.enableBarcodeView.frame.size.height/2);

    CGFloat width = self.enableBarcodeSwitch.frame.size.width + padding + self.enableBarcodeLabel.frame.size.width;
    self.enableBarcodeView.frame = CGRectMake(self.scanView.frame.size.width-width-15,
                                              self.scanView.frame.size.height-self.enableBarcodeView.frame.size.height-55,
                                              width,
                                              50);
}

#pragma mark - ALMeterScanPluginDelegate methods
/*
 The main delegate method Anyline uses to report its scanned codes
 */
- (void)anylineMeterScanPlugin:(ALMeterScanPlugin *)anylineMeterScanPlugin
                 didFindResult:(ALMeterResult *)scanResult {
    
    [self anylineDidFindResult:scanResult.result barcodeResult:self.barcodeResult image:(UIImage*)scanResult.image scanPlugin:anylineMeterScanPlugin viewPlugin:self.meterScanViewPlugin  completion:^{
        //Display the result
        NSMutableArray <ALResultEntry*> *resultData = [[NSMutableArray alloc] init];
        [resultData addObject:[[ALResultEntry alloc] initWithTitle:@"Meter Reading" value:scanResult.result]];
        [resultData addObject:[[ALResultEntry alloc] initWithTitle:@"Barcode" value:self.barcodeResult]];
        
        ALResultViewController *vc = [[ALResultViewController alloc] initWithResultData:resultData image:scanResult.image];
        [self.navigationController pushViewController:vc animated:YES];
    }];
    
    //reset found barcodes
    self.barcodeResult = @"";
}

#pragma mark - AnylineNativeBarcodeDelegate methods
/*
 An additional delegate which will add all found, and unique, barcodes to a Dictionary simultaneously.
 */
- (void)anylineCaptureDeviceManager:(ALCaptureDeviceManager *)captureDeviceManager didFindBarcodeResult:(NSString *)scanResult type:(NSString *)barcodeType {
    dispatch_async(dispatch_get_main_queue(), ^{
        if ([scanResult length] > 0 && ![self.barcodeResult isEqualToString:scanResult]) {
            self.barcodeResult = scanResult;
        }
    });
}


@end
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
using Anyline.SDK.Models;
using Anyline.SDK.Plugins;
using Anyline.SDK.Plugins.Meter;
using Anyline.SDK.Util;
using Anyline.SDK.ViewPlugins;
using Anyline.SDK.Views;
using Anyline_Windows_UWP_Examples.Model;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Windows.Foundation;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;


namespace Anyline_Windows_UWP_Examples
{
    /// <summary>
    /// This page is used to setup the plugin, open the camera and start scanning
    /// it has to implement the IScanResultListener for each Plugin that will be used
    /// </summary>
    public sealed partial class ScanPage : Page, IScanResultListener<MeterScanResult>, IPhotoCaptureListener
	{
		string myLicenseKey = "INSERT LICENSE KEY HERE";

		protected override async void OnNavigatedTo(NavigationEventArgs e)
		{
			base.OnNavigatedTo(e);

			// register camera events
			AnylineScanView.CameraView.CameraOpened += CameraView_CameraOpened;
			AnylineScanView.CameraView.CameraClosed += CameraView_CameraClosed;

			// register visibility changed event
			Window.Current.VisibilityChanged += Current_VisibilityChanged;

			// make sure the license is initalized (needs only to be done once in the app lifetime)
			AnylineSDK.Init(myLicenseKey);
			// initialize Anyline
			await AnylineScanView.InitAsync("Assets/energy_config_analog_digital.json");

			var scanViewPlugin = AnylineScanView?.ScanViewPlugin as MeterScanViewPlugin; 
			
			if(scanViewPlugin != null)
			{
				// attach the result listener to the ScanViewPlugin to receive scanning results
				scanViewPlugin.AddScanResultListener(this);
				scanViewPlugin.PhotoCaptureListener = this;
				scanViewPlugin.PhotoCaptureTarget = PhotoCaptureTarget.File;
			}

			// opens the camera
			AnylineScanView.StartCamera();
		}

		private async void Current_VisibilityChanged(object sender, Windows.UI.Core.VisibilityChangedEventArgs args)
		{
			if (AnylineScanView == null) return;

			if (args.Visible == false)
			{
				await AnylineScanView.StopCameraAsync();
			}
			if (args.Visible == true)
			{
				AnylineScanView.StartCamera();
			}
		}

		private void CameraView_CameraOpened(object sender, Size args)
		{
			AnylineScanView.StartScanning();
		}

		private void CameraView_CameraClosed(object sender, bool success)
		{
			AnylineScanView.StopScanning();
		}

		public void OnResult(ScanResult<MeterScanResult> result)
		{
			Debug.WriteLine($"(APP) Scan result: {result.Result}");
		}
		
		public void OnPhotoCaptured(AnylineImage anylineImage)
        {
			// do something with the image
        }

        public async void OnPhotoToFile(StorageFile file)
        {
            BitmapImage bitmapImage = new BitmapImage();
            FileRandomAccessStream stream = (FileRandomAccessStream)await file.OpenAsync(FileAccessMode.Read);
            bitmapImage.SetSource(stream);
			// do something with the bitmapImage
        }

	}
}
Dial Meter (Alpha) (Documentation)
{
  "camera": {
    "captureResolution": "720p"
  },
  "flash": {
    "mode": "manual",
    "alignment": "top_left"
  },
  "viewPlugin": {
    "plugin": {
      "id": "DIAL_METER",
      "meterPlugin": {
        "scanMode": "DIAL_METER"
      }
    },
    "cutoutConfig": {
      "style": "rect",
      "maxWidthPercent": "90%",
      "maxHeightPercent": "90%",
      "alignment": "top_half",
      "ratioFromSize": {
        "width": 125,
        "height": 85
      },
      "offset": {
        "x": 0,
        "y": 15
      },
      "cropPadding": {
        "x": 0,
        "y": 0
      },
      "cropOffset": {
        "x": 0,
        "y": 0
      },
      "strokeWidth": 2,
      "cornerRadius": 4,
      "strokeColor": "FFFFFF",
      "outerColor": "000000",
      "outerAlpha": 0.3,
      "feedbackStrokeColor": "0099FF"
    },
    "scanFeedback": {
      "style": "CONTOUR_RECT",
      "strokeColor": "0099FF",
      "fillColor": "220099FF",
      "blinkOnResult": true,
      "beepOnResult": true,
      "vibrateOnResult": true
    },
    "cancelOnResult": true
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;

import androidx.annotation.Nullable;
import io.anyline.plugin.ScanResultListener;
import io.anyline.plugin.meter.MeterScanResult;
import io.anyline.plugin.meter.MeterScanViewPlugin;
import io.anyline.view.ScanView;
import io.anyline.AnylineSDK;


public class ScanDialMeter extends Activity {

    private ScanView scanView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_anyline_test);


        scanView = findViewById(R.id.scan_view);

      	// This must be called before doing anything Anyline-related! 
	// Try/Catch this to check whether or not your license key is valid! 
	try {
    	    AnylineSDK.init(getString(getString(R.string.anyline_license_key)), this);
	} catch (LicenseException e) {
    	    // handle exception
	}

        // initialize Anyline with a Listener that is called if a result is found
        try {
            scanView.init("energy_dial_view_config.json");
        } catch (Exception e) {
            e.printStackTrace();
        }

        MeterScanViewPlugin scanViewPlugin = (MeterScanViewPlugin) scanView.getScanViewPlugin();

        scanViewPlugin.addScanResultListener(new ScanResultListener<MeterScanResult>() {
            @Override
            public void onResult(MeterScanResult result) {
		Toast.makeText(getApplicationContext(), result.getResult(), Toast.LENGTH_LONG).show();
            }

        });
    }

    @Override
    protected void onResume() {
        super.onResume();
        scanView.start();
    }


    @Override
    protected void onPause() {
        super.onPause();
        scanView.stop();
    }
}
ID Plugin MRZ (Documentation)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
{
  "camera": {
    "captureResolution": "720",
    "defaultCamera": "BACK"
  },
  "flash": {
    "mode": "manual",
    "alignment": "bottom_right"
  },

  "viewPlugin": {
    "plugin": {
      "id": "ID_PLUGIN",
      "idPlugin": {
        "mrzConfig": {
          "strictMode" : false,
          "cropAndTransformID" : false,
          "mrzFieldScanOptions": {
            "vizAddress": "mandatory"
          },
          "mrzMinFieldConfidences": {
            "surname": 70,
            "givenNames":80,
	    "vizAddress":30
          },
          "minConfidence": 50
        }
      }
    },
    "cutoutConfig": {
      "style": "rect",
      "maxWidthPercent": "99%",
      "maxHeightPercent": "100%",
      "alignment": "center",
      "ratioFromSize": {
        "width": 560,
        "height": 354
      },
      "strokeWidth": 2,
      "cornerRadius": 4,
      "strokeColor": "FFFFFF",
      "outerColor": "000000",
      "outerAlpha": 0.3,
      "feedbackStrokeColor": "0099FF"
    },
    "scanFeedback": {
      "fillColor": "220099FF",
      "style": "CONTOUR_POINT",
      "strokeColor": "0099FF",
      "strokeWidth": 2,
      "blinkOnResult": true,
      "beepOnResult": true,
      "vibrateOnResult": true
    },
    "cancelOnResult": true,
    "delayStartScanTime" : 1000
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package at.nineyards.anyline.test;

import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;

import io.anyline.plugin.ScanResult;
import io.anyline.plugin.ScanResultListener;
import io.anyline.plugin.id.ID;
import io.anyline.plugin.id.IdScanViewPlugin;
import io.anyline.plugin.id.MrzIdentification;
import io.anyline.view.ScanView;
import io.anyline.AnylineSDK;


public class ScanMRZActivity extends Activity {

    private ScanView scanView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_anyline4_test);

        scanView = findViewById(R.id.scan_view);

      	// This must be called before doing anything Anyline-related! 
	// Try/Catch this to check whether or not your license key is valid! 
	try {
    	    AnylineSDK.init(getString(getString(R.string.anyline_license_key)), this);
	} catch (LicenseException e) {
    	    // handle exception
	}

        //init the scan view
        scanView.init("mrz_view_config.json");
        
        IdScanViewPlugin scanViewPlugin = (IdScanViewPlugin) scanView.getScanViewPlugin();

        scanView.setScanViewPlugin(scanViewPlugin);

        // add the result listener
        scanViewPlugin.addScanResultListener(new ScanResultListener<ScanResult<ID>>() {
            @Override
            public void onResult(ScanResult<ID> result) {
                MrzIdentification identification = (MrzIdentification) result.getResult();
                Toast.makeText(getApplicationContext(), identification.toString(), Toast.LENGTH_LONG).show();

            }


        });

    }

    @Override
    protected void onResume() {
        super.onResume();
        scanView.start();
    }


    @Override
    protected void onPause() {
        super.onPause();
        scanView.stop();
        scanView.releaseCameraInBackground();
    }
}
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
#import "ALMRZScanViewController.h"
#import "ALIdentificationView.h"
#import <Anyline/Anyline.h>
#import "NSUserDefaults+ALExamplesAdditions.h"
#import "ALAppDemoLicenses.h"
#import "ALResultViewController.h"

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

// The Anyline module used to scan machine readable zones
@property (nonatomic, strong) ALIDScanViewPlugin *mrzScanViewPlugin;
@property (nonatomic, strong) ALIDScanPlugin *mrzScanPlugin;
@property (nullable, nonatomic, strong) ALScanView *scanView;

@end

@implementation ALMRZScanViewController
/*
 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 = @"MRZ";
    
    // 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);
    
    NSError *licenseError = nil;
    //Initialize the Anyline License
    [AnylineSDK setupWithLicenseKey:kMRZLicenseKey error:&licenseError];
    if (licenseError) {
        //Handle errors here
    }
    
    ALMRZConfig *mrzConfig = [[ALMRZConfig alloc] init];
    
    NSError *error = nil;

    self.mrzScanPlugin = [[ALIDScanPlugin alloc] initWithPluginID:@"ModuleID" delegate:self idConfig:mrzConfig error:&error];
    NSAssert(self.mrzScanPlugin, @"Setup Error: %@", error.debugDescription);
    [self.mrzScanPlugin addInfoDelegate:self];
    
    self.mrzScanViewPlugin = [[ALIDScanViewPlugin alloc] initWithScanPlugin:self.mrzScanPlugin];
    NSAssert(self.mrzScanViewPlugin, @"Setup Error: %@", error.debugDescription);
    
    self.scanView = [[ALScanView alloc] initWithFrame:frame scanViewPlugin:self.mrzScanViewPlugin];
    
    self.scanView.flashButtonConfig.flashAlignment = ALFlashAlignmentTopLeft;
    self.mrzScanViewPlugin.translatesAutoresizingMaskIntoConstraints = NO;
    
    self.controllerType = ALScanHistoryMrz;
    
    // 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 view] addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scanView]|" options:0 metrics:nil views:@{@"scanView" : self.scanView}]];
    
    id topGuide = self.topLayoutGuide;
    [[self view] addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[topGuide]-0-[scanView]|" options:0 metrics:nil views:@{@"scanView" : self.scanView, @"topGuide" : topGuide}]];
    
    [self startListeningForMotion];
}

/*
 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.mrzScanViewPlugin.cutoutRect.origin.y +
     self.mrzScanViewPlugin.cutoutRect.size.height +
     self.mrzScanViewPlugin.frame.origin.y +
     120];
}

/*
 Cancel scanning to allow the module to clean up
 */
- (void)viewWillDisappear:(BOOL)animated {
    [self.mrzScanViewPlugin 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.mrzScanViewPlugin startAndReturnError:&error];
    if( !success ) {
        // Something went wrong. The error object contains the error description
        [[[UIAlertView alloc] initWithTitle:@"Start Scanning Error"
                                    message:error.debugDescription
                                   delegate:self
                          cancelButtonTitle:@"OK"
                          otherButtonTitles:nil] show];
    }
    
    self.startTime = CACurrentMediaTime();
}

#pragma mark -- AnylineMRZModuleDelegate

/*
 This is the main delegate method Anyline uses to report its results
 */
- (void)anylineIDScanPlugin:(ALIDScanPlugin *)anylineIDScanPlugin didFindResult:(ALIDResult *)scanResult {
    [self.mrzScanViewPlugin stopAndReturnError:nil];
    NSMutableString * result = [NSMutableString string];
    [result appendString:[NSString stringWithFormat:@"Document Type: %@\n", [scanResult.result documentType]]];
    [result appendString:[NSString stringWithFormat:@"Document Number: %@\n", [scanResult.result documentNumber]]];
    [result appendString:[NSString stringWithFormat:@"Surnames: %@\n", [scanResult.result surNames]]];
    [result appendString:[NSString stringWithFormat:@"Given Names: %@\n", [scanResult.result givenNames]]];
    [result appendString:[NSString stringWithFormat:@"Issuing Country Code: %@\n", [scanResult.result issuingCountryCode]]];
    [result appendString:[NSString stringWithFormat:@"Nationality Country Code: %@\n", [scanResult.result nationalityCountryCode]]];
    [result appendString:[NSString stringWithFormat:@"Day Of Birth: %@\n", [scanResult.result dayOfBirth]]];
    [result appendString:[NSString stringWithFormat:@"Expiration Date: %@\n", [scanResult.result expirationDate]]];
    [result appendString:[NSString stringWithFormat:@"Sex: %@\n", [scanResult.result sex]]];
    [result appendString:[NSString stringWithFormat:@"Check Digit Number: %@\n", [scanResult.result checkdigitNumber]]];
    [result appendString:[NSString stringWithFormat:@"Check Digit Expiration Date: %@\n", [scanResult.result checkdigitExpirationDate]]];
    [result appendString:[NSString stringWithFormat:@"Check Digit Day Of Birth: %@\n", [scanResult.result checkdigitDayOfBirth]]];
    [result appendString:[NSString stringWithFormat:@"Check Digit Final: %@\n", [scanResult.result checkdigitFinal]]];
    [result appendString:[NSString stringWithFormat:@"Personal Number: %@\n", [scanResult.result personalNumber]]];
    [result appendString:[NSString stringWithFormat:@"Check Digit Personal Number: %@\n", [scanResult.result checkDigitPersonalNumber]]];
    
    [super anylineDidFindResult:result barcodeResult:@"" image:scanResult.image scanPlugin:anylineIDScanPlugin viewPlugin:self.mrzScanViewPlugin completion:^{
        
        NSMutableArray <ALResultEntry*> *resultData = [[NSMutableArray alloc] init];
        [resultData addObject:[[ALResultEntry alloc] initWithTitle:@"Given Name" value:[scanResult.result givenNames]]];
        [resultData addObject:[[ALResultEntry alloc] initWithTitle:@"Surname" value:[scanResult.result surNames]]];
        [resultData addObject:[[ALResultEntry alloc] initWithTitle:@"Sex" value:[scanResult.result sex]]];
        [resultData addObject:[self resultEntryWithDate:[scanResult.result dayOfBirthDateObject] dateString:[scanResult.result dayOfBirth] title:@"Date of Birth"]];
        [resultData addObject:[[ALResultEntry alloc] initWithTitle:@"Document Type" value:[scanResult.result documentType]]];
        [resultData addObject:[[ALResultEntry alloc] initWithTitle:@"Document Number" value:[scanResult.result documentNumber]]];
        [resultData addObject:[self resultEntryWithDate:[scanResult.result expirationDateObject] dateString:[((ALMRZIdentification *)scanResult.result) expirationDate] title:@"Expiration Date"]];
        [resultData addObject:[[ALResultEntry alloc] initWithTitle:@"Nationality" value:[scanResult.result nationalityCountryCode]]];
        
        ALResultViewController *vc = [[ALResultViewController alloc] initWithResultData:resultData image:scanResult.image optionalImageTitle:@"Detected Face Image" optionalImage:[scanResult.result faceImage]];
        [self.navigationController pushViewController:vc animated:YES];
    }];
}

- (ALResultEntry *)resultEntryWithDate:(NSDate *)date dateString:(NSString *)dateString title:(NSString *)title {
    if (![self checkDateIfAvailable:date dateString:dateString]) {
        return [[ALResultEntry alloc] initWithTitle:title value:nil];
    }
    
    NSString *value = [self formatDate:date];
    return [[ALResultEntry alloc] initWithTitle:title value:value isAvailable:(date)];
}

- (BOOL)checkDateIfAvailable:(NSDate *)date dateString:(NSString *)dateString {
    if (!date && dateString.length == 0) {
        return NO;
    }
    return YES;
}

- (NSString *)formatDate:(NSDate *)date {
    if (!date) {
        return @"Date not valid";
    }
    return [NSDateFormatter localizedStringFromDate:date dateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterNoStyle];
}

@end
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
using Anyline.SDK.Models;
using Anyline.SDK.Plugins;
using Anyline.SDK.Plugins.ID;
using Anyline.SDK.Util;
using Anyline.SDK.ViewPlugins;
using Anyline.SDK.Views;
using Anyline_Windows_UWP_Examples.Model;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Windows.Foundation;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;


namespace Anyline_Windows_UWP_Examples
{
    /// <summary>
    /// This page is used to setup the plugin, open the camera and start scanning
    /// it has to implement the IScanResultListener for each Plugin that will be used
    /// </summary>
    public sealed partial class ScanPage : Page, IScanResultListener<ScanResult<ID>>
	{
		string myLicenseKey = "INSERT LICENSE KEY HERE";

		protected override async void OnNavigatedTo(NavigationEventArgs e)
		{
			base.OnNavigatedTo(e);

			// register camera events
			AnylineScanView.CameraView.CameraOpened += CameraView_CameraOpened;
			AnylineScanView.CameraView.CameraClosed += CameraView_CameraClosed;

			// register visibility changed event
			Window.Current.VisibilityChanged += Current_VisibilityChanged;

			// make sure the license is initalized (needs only to be done once in the app lifetime)
			AnylineSDK.Init(myLicenseKey);
			// initialize Anyline
			await AnylineScanView.InitAsync("Assets/myconfig.json");

			// attach the result listener to the ScanViewPlugin to receive scanning results
			(AnylineScanView.ScanViewPlugin as IDScanViewPlugin)?.AddScanResultListener(this);

			// opens the camera
			AnylineScanView.StartCamera();
		}

		private async void Current_VisibilityChanged(object sender, Windows.UI.Core.VisibilityChangedEventArgs args)
		{
			if (AnylineScanView == null) return;

			if (args.Visible == false)
			{
				await AnylineScanView.StopCameraAsync();
			}
			if (args.Visible == true)
			{
				AnylineScanView.StartCamera();
			}
		}

		private void CameraView_CameraOpened(object sender, Size args)
		{
			AnylineScanView.StartScanning();
		}

		private void CameraView_CameraClosed(object sender, bool success)
		{
			AnylineScanView.StopScanning();
		}

		public void OnResult(ScanResult<ID> result)
		{
			Debug.WriteLine($"(APP) Scan result: {result.Result}");
			var mrzIdentification = result.Result as MrzIdentification;
			Debug.WriteLine($"(APP) Given Names result: {mrzIdentification.GivenNames}");
		}
	}
}
ID Plugin Universal ID (Documentation)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
{
  "camera" : {
    "captureResolution" : "1080p",
    "zoomGesture": true
  },
  "flash" : {
    "mode": "manual",
    "alignment": "top_left"
  },
  "viewPlugin" : {
    "plugin":{
      "id":"ID",
      "idPlugin": {
        "universalIdConfig": {
          "allowedLayouts": {
            "mrz": [],
            "drivingLicense": [],
            "idFront": [],
            "insuranceCard" : []
          },
          "drivingLicense": {
            "surname": {"scanOption": 0, "minConfidence": 40},
            "givenNames": {"scanOption": 0, "minConfidence": 40},
            "dateOfBirth": {"scanOption": 0, "minConfidence": 50},
            "placeOfBirth": {"scanOption": 1, "minConfidence": 50},
            "dateOfIssue": {"scanOption": 0, "minConfidence": 50},
            "dateOfExpiry": {"scanOption": 1, "minConfidence": 50},
            "authority": {"scanOption": 1, "minConfidence": 30},
            "documentNumber": {"scanOption": 0, "minConfidence": 40},
            "categories": {"scanOption": 1, "minConfidence": 30},
            "address": {"scanOption": 1}
          },
          "idFront": {
            "surname": {"scanOption": 0, "minConfidence": 60},
            "givenNames": {"scanOption": 0, "minConfidence": 60},
            "dateOfBirth": {"scanOption": 0, "minConfidence": 60},
            "placeOfBirth": {"scanOption": 1, "minConfidence": 60},
            "dateOfExpiry": {"scanOption": 1, "minConfidence": 60},
            "cardAccessNumber": {"scanOption": 1, "minConfidence": 60},
            "documentNumber": {"scanOption": 0, "minConfidence": 60},
            "nationality": {"scanOption": 1, "minConfidence": 60}
          },
          "insuranceCard": {
            "nationality": {"scanOption": 0, "minConfidence": 50},
            "surname": {"scanOption": 0, "minConfidence": 50},
            "givenNames": {"scanOption": 0, "minConfidence": 50},
            "dateOfBirth": {"scanOption": 0, "minConfidence": 50},
            "personalNumber": {"scanOption": 0, "minConfidence": 50},
            "authority": {"scanOption": 0, "minConfidence": 50},
            "documentNumber": {"scanOption": 0, "minConfidence": 50},
            "dateOfExpiry": {"scanOption": 0, "minConfidence": 50}
          }
        }
      }
    },
    "cutoutConfig" : {
      "style": "animated_rect",
      "maxWidthPercent": "90%",
      "maxHeightPercent": "90%",
      "alignment": "center",
      "strokeWidth": 3,
      "cornerRadius": 4,
      "strokeColor": "FFFFFF",
      "outerColor": "000000",
      "outerAlpha": 0.3,
      "ratioFromSize" : {
        "width": 50,
        "height": 31
      },
      "cropPadding": {
        "x": -50,
        "y": -50
      },
      "cropOffset": {
        "x": 0,
        "y": 0
      },
      "feedbackStrokeColor": "0099FF"
    },
    "scanFeedback" : {
      "style": "CONTOUR_RECT",
      "visualFeedbackRedrawTimeout": 100,
      "strokeColor": "0099FF",
      "fillColor" : "220099FF",
      "beepOnResult": true,
      "vibrateOnResult": true,
      "strokeWidth": 3
    },
    "cancelOnResult" : true
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public class ScanUniversalIdActivity extends AppCompatActivity implements ScanRunSkippedListener {

    ScanView scanView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_universal_id);
        init();
    }

    void init(){
        scanView = findViewById(R.id.scan_view);
        
        // This must be called before doing anything Anyline-related! 
        // Try/Catch this to check whether or not your license key is valid!
        try {
            AnylineSDK.init(getString(getString(R.string.anyline_license_key)), this);
        } catch (LicenseException e) {
            // handle exception
        }

        scanView.init("myConfig.json");

        IdScanViewPlugin idScanViewPlugin = (IdScanViewPlugin) scanView.getScanViewPlugin();
        scanView.getScanViewPlugin().addScanRunSkippedListener(this);

        idScanViewPlugin.addScanResultListener((ScanResultListener<ScanResult<ID>>) idScanResult -> {
            Identification identification = (Identification) idScanResult.getResult();
            HashMap<String, String> data = (HashMap<String, String>) identification.getResultData();
        });
    }

    @Override
    protected void onResume() {
        super.onResume();
        scanView.start();
    }

    @Override
    protected void onStop() {
        super.onStop();
        scanView.stop();
    }

    @Override
    public void onRunSkipped(ScanRunSkippedReason reason) {
        if(reason.getCode() == 5555){
            Toast.makeText(this, (reason.getText()), Toast.LENGTH_SHORT).show();
        }
    }
}
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//
//  ALUniversalIDViewController.m
//  AnylineExamples
//
//  Created by Aldrich Co on 08.12.21.
//

#import "ALUniversalIDViewController.h"

// This is the license key for the examples project used to set up Anyline below
NSString * const kUniversalIDLicenseKey = @"ADD YOUR LICENSE KEY";

@interface ALUniversalIDScanViewControllerFrontAndBack ()<ALIDPluginDelegate>

@property (nonatomic, strong) ALIDScanViewPlugin *scanViewPlugin;
@property (nonatomic, strong) ALIDScanPlugin *scanPlugin;
@property (nullable, nonatomic, strong) ALScanView *scanView;

@end

@implementation ALUniversalIDViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    // Set the background color to black to have a nicer transition
    self.view.backgroundColor = [UIColor blackColor];
    
    // Initialise the Anyline License
    NSError *licenseError = nil;
    [AnylineSDK setupWithLicenseKey:kUniversalIDLicenseKey error:&licenseError];
    if (licenseError) {
        // Handle the error. You would be unable to use the scan view and scan plugin
        // in the event of an error, so it may be a good idea to make an early return.
    }
    
    NSError *error = nil;
    NSString *jsonFilePath = [[NSBundle mainBundle] pathForResource:@"universal_id_config"
                                                             ofType:@"json"];
    NSData *jsonFile = [NSData dataWithContentsOfFile:jsonFilePath];
    NSDictionary *configDict = [NSJSONSerialization JSONObjectWithData:jsonFile
                                                               options:NSJSONReadingMutableContainers
                                                                 error:&error];
    
    // Initialise the scan view plugin using the JSON configuration file and setting oneself
    // as its ALIDPluginDelegate
    self.scanViewPlugin = (ALIDScanViewPlugin *)[ALAbstractScanViewPlugin scanViewPluginForConfigDict:configDict delegate:self error:&error];

    NSAssert(self.scanViewPlugin, @"Setup Error: %@", error.debugDescription);

    self.scanPlugin = self.scanViewPlugin.idScanPlugin;
    
    // Implement ALScanViewPluginDelegate for its `anylineScanViewPlugin:updatedCutout:` method
    // [self.scanViewPlugin addScanViewPluginDelegate:self];
    
    // Implement ALInfoDelegate if interested in meta-variables reported while scanning
    // [self.scanPlugin addInfoDelegate:self];
    
    // Set the scanView's frame to fill the whole screen
    CGRect frame = [self scanViewFrame];
    self.scanView = [[ALScanView alloc] initWithFrame:frame scanViewPlugin:self.scanViewPlugin];
    
    // You can still configure the scan view config until the plugin is started;
    // here we set the flash button position within the scan view
    self.scanView.flashButtonConfig.flashAlignment = ALFlashAlignmentTopLeft;
    
    // After setup is complete we add the scanView to the view of this view controller
    [self.view addSubview:self.scanView];
    
    [self.scanView startCamera];
}

/*
 Start the scanning process once the view hierarchy has appeared onscreen.
 */
- (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];
}

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

/*
 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:).
 */
- (void)startAnyline {
    NSError *error = nil;
    [self.scanViewPlugin startAndReturnError:&error];
    // Handle if error is not null here
}


// MARK: - ALIDPluginDelegate
/*
 This is the main delegate method Anyline uses to report its results.
 */
- (void)anylineIDScanPlugin:(ALIDScanPlugin *)anylineIDScanPlugin
              didFindResult:(ALIDResult *)scanResult {
    ALUniversalIDIdentification *identification = (ALUniversalIDIdentification *)scanResult.result;
    NSArray<NSString *> *fieldNames = identification.fieldNames;
    ALLayoutDefinition *layoutDefinition = identification.layoutDefinition;
    ALUniversalIDFieldConfidences *fieldConfidences = identification.fieldConfidences;
    UIImage *faceImage = identification.faceImage;
    
    // Handle your result here
    // ...
}

@end
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
using Anyline.SDK.Models;
using Anyline.SDK.Plugins;
using Anyline.SDK.Plugins.Barcode;
using Anyline.SDK.Plugins.ID;
using Anyline.SDK.Plugins.LicensePlate;
using Anyline.SDK.Plugins.Meter;
using Anyline.SDK.Plugins.OCR;
using Anyline.SDK.Plugins.ViewPlugins;
using Anyline.SDK.Util;
using Anyline.SDK.ViewPlugins;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using Windows.Foundation;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;
using Anyline.SDK.Views;
using Anyline.SDK.Plugins.ID;

namespace Anyline_Windows_UWP_Examples
{
    public sealed partial class ScanViewPage : Page,
        IScanResultListener<ScanResult<ID>>
    {
        private ScanView anylineScanView;
        private IViewPluginBase scanViewPlugin;

        public ScanViewPage()
        {
            // We don't want to keep multiple instances of the scan views that we're navigating to.
            NavigationCacheMode = NavigationCacheMode.Required;
            ((Frame)Window.Current.Content).CacheSize = 0;

            this.InitializeComponent();

            anylineScanView = AnylineScanView;
        }

        private void CameraView_CameraOpened(object sender, Size args)
        {
            Debug.WriteLine($"(APP) Camera Opened: {args.Width}x{args.Height}");

            try
            {
                anylineScanView?.StartScanning();
            }
            catch (Exception e)
            {
                Debug.WriteLine($"(APP) {e.Message}");
            }
        }

        private void CameraView_CameraClosed(object sender, bool success)
        {
            Debug.WriteLine($"(APP) Camera Closed: {success}");

            try
            {
                anylineScanView?.StopScanning();
            }
            catch (Exception e)
            {
                Debug.WriteLine($"(APP) {e.Message}");
            }
        }

        private void CameraView_CameraError(object sender, Exception exception)
        {
            Debug.WriteLine($"(APP) Camera Error: {exception.Message}");
        }

        // important because the UWP camera stream automatically shuts down when a window is minimized
        private async void Current_VisibilityChanged(object sender, Windows.UI.Core.VisibilityChangedEventArgs args)
        {
            if (args.Visible == false)
            {
                if (anylineScanView != null)
                {
                    await anylineScanView.StopCameraAsync();
                }
            }
            if (args.Visible == true)
            {
                anylineScanView?.StartCamera();
            }
        }

        protected override async void OnNavigatedFrom(NavigationEventArgs e)
        {
            base.OnNavigatedFrom(e);
            
            Window.Current.VisibilityChanged -= Current_VisibilityChanged;
            
            if (anylineScanView != null)
            {
                anylineScanView.CameraView.CameraOpened -= CameraView_CameraOpened;
                anylineScanView.CameraView.CameraClosed -= CameraView_CameraClosed;
                anylineScanView.CameraView.CameraError -= CameraView_CameraError;

                await anylineScanView.StopCameraAsync();

                anylineScanView.Dispose();
            }
        }

        protected override async void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);

            if (anylineScanView == null) return;

            // register events
            if (anylineScanView != null)
            {
                anylineScanView.CameraView.CameraOpened -= CameraView_CameraOpened;
                anylineScanView.CameraView.CameraClosed -= CameraView_CameraClosed;
                anylineScanView.CameraView.CameraError -= CameraView_CameraError;

                anylineScanView.CameraView.CameraOpened += CameraView_CameraOpened;
                anylineScanView.CameraView.CameraClosed += CameraView_CameraClosed;
                anylineScanView.CameraView.CameraError += CameraView_CameraError;

                Window.Current.VisibilityChanged -= Current_VisibilityChanged;
                Window.Current.VisibilityChanged += Current_VisibilityChanged;
            }

            string jsonConfig = (e.Parameter as ExamplePlugin).JSONConfigFile;
            
			// make sure the license is initalized (needs only to be done once in the app lifetime)
			AnylineSDK.Init(myLicenseKey);
			// initialize Anyline
			await AnylineScanView.InitAsync("Assets/myconfig.json");
			
			// the correct plugin is loaded according to the .json config file informed
            scanViewPlugin = anylineScanView.ScanViewPlugin;

            scanViewPlugin.AddScanResultListener(this);
            anylineScanView?.StartCamera();
        }

        public void OnResult(ScanResult<ID> result)
        {
            if (result.Result is Identification id) {
				
				// get layout definition here:
				var layoutDefinition = id.LayoutDefinition;
				
				// iterate through values of the id, because it is enumerable
				foreach(var parameter in id) {
					Debug.WriteLine($"Parameter name: {parameter.Key}, value: {parameter.Value}, Confidence: {id.FieldConfidences[parameter.Key]}");
				}
			}
        }
    }
}
Japanese Landing Permission (Documentation)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
{
  "camera": {
    "captureResolution": "1080p",
    "zoomGesture": true
  },
  "flash": {
    "mode": "manual",
    "alignment": "bottom_right"
  },
  "viewPlugin" : {
    "plugin": {
      "id": "ID",
      "idPlugin": {
        "japaneseLandingPermissionConfig": {
          "miscellaneous": {
            "dateOfIssue": {"scanOption": 0,"minConfidence": 35},
            "dateOfExpiry": {"scanOption": 0,"minConfidence": 35},
            "status": {"scanOption": 1,"minConfidence": 35},
            "duration": {"scanOption": 0,"minConfidence": 35},
            "airport": {"scanOption": 0,"minConfidence": 35}
          }
        }
      }
    },
    "cutoutConfig": {
      "style": "rect",
      "maxWidthPercent": "70%",
      "maxHeightPercent": "70%",
      "alignment": "center",
      "strokeWidth": 2,
      "cornerRadius": 4,
      "strokeColor": "FFFFFF",
      "outerColor": "000000",
      "outerAlpha": 0.3,
      "ratioFromSize": {
        "width": 440,
        "height": 615
      },
      "feedbackStrokeColor": "0099FF"
    },
    "scanFeedback": {
      "style": "RECT",
      "visualFeedbackRedrawTimeout": 100,
      "strokeColor": "0099FF",
      "fillColor": "220099FF",
      "beepOnResult": true,
      "vibrateOnResult": true,
      "strokeWidth": 2
    },
    "cancelOnResult": true
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public class ScanUniversalIdActivity extends AppCompatActivity implements ScanRunSkippedListener {

    ScanView scanView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_universal_id);
        init();
    }

    void init(){
        scanView = findViewById(R.id.scan_view);
        
        // This must be called before doing anything Anyline-related! 
        // Try/Catch this to check whether or not your license key is valid!
        try {
            AnylineSDK.init(getString(getString(R.string.anyline_license_key)), this);
        } catch (LicenseException e) {
            // handle exception
        }

        scanView.init("myConfig.json");

        IdScanViewPlugin idScanViewPlugin = (IdScanViewPlugin) scanView.getScanViewPlugin();
        scanView.getScanViewPlugin().addScanRunSkippedListener(this);

        idScanViewPlugin.addScanResultListener((ScanResultListener<ScanResult<ID>>) idScanResult -> {
            Identification identification = (Identification) idScanResult.getResult();
            HashMap<String, String> data = (HashMap<String, String>) identification.getResultData();
        });
    }

    @Override
    protected void onResume() {
        super.onResume();
        scanView.start();
    }

    @Override
    protected void onStop() {
        super.onStop();
        scanView.stop();
    }

    @Override
    public void onRunSkipped(ScanRunSkippedReason reason) {
        if(reason.getCode() == 5555){
            Toast.makeText(this, (reason.getText()), Toast.LENGTH_SHORT).show();
        }
    }
}
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//
//  ALUniversalIDViewController.m
//  AnylineExamples
//
//  Created by Aldrich Co on 08.12.21.
//

#import "ALUniversalIDViewController.h"

// This is the license key for the examples project used to set up Anyline below
NSString * const kUniversalIDLicenseKey = @"ADD YOUR LICENSE KEY";

@interface ALUniversalIDScanViewControllerFrontAndBack ()<ALIDPluginDelegate>

@property (nonatomic, strong) ALIDScanViewPlugin *scanViewPlugin;
@property (nonatomic, strong) ALIDScanPlugin *scanPlugin;
@property (nullable, nonatomic, strong) ALScanView *scanView;

@end

@implementation ALUniversalIDViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    // Set the background color to black to have a nicer transition
    self.view.backgroundColor = [UIColor blackColor];
    
    // Initialise the Anyline License
    NSError *licenseError = nil;
    [AnylineSDK setupWithLicenseKey:kUniversalIDLicenseKey error:&licenseError];
    if (licenseError) {
        // Handle the error. You would be unable to use the scan view and scan plugin
        // in the event of an error, so it may be a good idea to make an early return.
    }
    
    NSError *error = nil;
    NSString *jsonFilePath = [[NSBundle mainBundle] pathForResource:@"universal_id_config"
                                                             ofType:@"json"];
    NSData *jsonFile = [NSData dataWithContentsOfFile:jsonFilePath];
    NSDictionary *configDict = [NSJSONSerialization JSONObjectWithData:jsonFile
                                                               options:NSJSONReadingMutableContainers
                                                                 error:&error];
    
    // Initialise the scan view plugin using the JSON configuration file and setting oneself
    // as its ALIDPluginDelegate
    self.scanViewPlugin = (ALIDScanViewPlugin *)[ALAbstractScanViewPlugin scanViewPluginForConfigDict:configDict delegate:self error:&error];

    NSAssert(self.scanViewPlugin, @"Setup Error: %@", error.debugDescription);

    self.scanPlugin = self.scanViewPlugin.idScanPlugin;
    
    // Implement ALScanViewPluginDelegate for its `anylineScanViewPlugin:updatedCutout:` method
    // [self.scanViewPlugin addScanViewPluginDelegate:self];
    
    // Implement ALInfoDelegate if interested in meta-variables reported while scanning
    // [self.scanPlugin addInfoDelegate:self];
    
    // Set the scanView's frame to fill the whole screen
    CGRect frame = [self scanViewFrame];
    self.scanView = [[ALScanView alloc] initWithFrame:frame scanViewPlugin:self.scanViewPlugin];
    
    // You can still configure the scan view config until the plugin is started;
    // here we set the flash button position within the scan view
    self.scanView.flashButtonConfig.flashAlignment = ALFlashAlignmentTopLeft;
    
    // After setup is complete we add the scanView to the view of this view controller
    [self.view addSubview:self.scanView];
    
    [self.scanView startCamera];
}

/*
 Start the scanning process once the view hierarchy has appeared onscreen.
 */
- (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];
}

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

/*
 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:).
 */
- (void)startAnyline {
    NSError *error = nil;
    [self.scanViewPlugin startAndReturnError:&error];
    // Handle if error is not null here
}


// MARK: - ALIDPluginDelegate
/*
 This is the main delegate method Anyline uses to report its results.
 */
- (void)anylineIDScanPlugin:(ALIDScanPlugin *)anylineIDScanPlugin
              didFindResult:(ALIDResult *)scanResult {
    ALUniversalIDIdentification *identification = (ALUniversalIDIdentification *)scanResult.result;
    NSArray<NSString *> *fieldNames = identification.fieldNames;
    ALLayoutDefinition *layoutDefinition = identification.layoutDefinition;
    ALUniversalIDFieldConfidences *fieldConfidences = identification.fieldConfidences;
    UIImage *faceImage = identification.faceImage;
    
    // Handle your result here
    // ...
}

@end
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
using Anyline.SDK.Models;
using Anyline.SDK.Plugins;
using Anyline.SDK.Plugins.Barcode;
using Anyline.SDK.Plugins.ID;
using Anyline.SDK.Plugins.LicensePlate;
using Anyline.SDK.Plugins.Meter;
using Anyline.SDK.Plugins.OCR;
using Anyline.SDK.Plugins.ViewPlugins;
using Anyline.SDK.Util;
using Anyline.SDK.ViewPlugins;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using Windows.Foundation;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;
using Anyline.SDK.Views;
using Anyline.SDK.Plugins.ID;

namespace Anyline_Windows_UWP_Examples
{
    public sealed partial class ScanViewPage : Page,
        IScanResultListener<ScanResult<ID>>
    {
        private ScanView anylineScanView;
        private IViewPluginBase scanViewPlugin;

        public ScanViewPage()
        {
            // We don't want to keep multiple instances of the scan views that we're navigating to.
            NavigationCacheMode = NavigationCacheMode.Required;
            ((Frame)Window.Current.Content).CacheSize = 0;

            this.InitializeComponent();

            anylineScanView = AnylineScanView;
        }

        private void CameraView_CameraOpened(object sender, Size args)
        {
            Debug.WriteLine($"(APP) Camera Opened: {args.Width}x{args.Height}");

            try
            {
                anylineScanView?.StartScanning();
            }
            catch (Exception e)
            {
                Debug.WriteLine($"(APP) {e.Message}");
            }
        }

        private void CameraView_CameraClosed(object sender, bool success)
        {
            Debug.WriteLine($"(APP) Camera Closed: {success}");

            try
            {
                anylineScanView?.StopScanning();
            }
            catch (Exception e)
            {
                Debug.WriteLine($"(APP) {e.Message}");
            }
        }

        private void CameraView_CameraError(object sender, Exception exception)
        {
            Debug.WriteLine($"(APP) Camera Error: {exception.Message}");
        }

        // important because the UWP camera stream automatically shuts down when a window is minimized
        private async void Current_VisibilityChanged(object sender, Windows.UI.Core.VisibilityChangedEventArgs args)
        {
            if (args.Visible == false)
            {
                if (anylineScanView != null)
                {
                    await anylineScanView.StopCameraAsync();
                }
            }
            if (args.Visible == true)
            {
                anylineScanView?.StartCamera();
            }
        }

        protected override async void OnNavigatedFrom(NavigationEventArgs e)
        {
            base.OnNavigatedFrom(e);
            
            Window.Current.VisibilityChanged -= Current_VisibilityChanged;
            
            if (anylineScanView != null)
            {
                anylineScanView.CameraView.CameraOpened -= CameraView_CameraOpened;
                anylineScanView.CameraView.CameraClosed -= CameraView_CameraClosed;
                anylineScanView.CameraView.CameraError -= CameraView_CameraError;

                await anylineScanView.StopCameraAsync();

                anylineScanView.Dispose();
            }
        }

        protected override async void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);

            if (anylineScanView == null) return;

            // register events
            if (anylineScanView != null)
            {
                anylineScanView.CameraView.CameraOpened -= CameraView_CameraOpened;
                anylineScanView.CameraView.CameraClosed -= CameraView_CameraClosed;
                anylineScanView.CameraView.CameraError -= CameraView_CameraError;

                anylineScanView.CameraView.CameraOpened += CameraView_CameraOpened;
                anylineScanView.CameraView.CameraClosed += CameraView_CameraClosed;
                anylineScanView.CameraView.CameraError += CameraView_CameraError;

                Window.Current.VisibilityChanged -= Current_VisibilityChanged;
                Window.Current.VisibilityChanged += Current_VisibilityChanged;
            }

            string jsonConfig = (e.Parameter as ExamplePlugin).JSONConfigFile;
            
			// make sure the license is initalized (needs only to be done once in the app lifetime)
			AnylineSDK.Init(myLicenseKey);
			// initialize Anyline
			await AnylineScanView.InitAsync("Assets/myconfig.json");
			
			// the correct plugin is loaded according to the .json config file informed
            scanViewPlugin = anylineScanView.ScanViewPlugin;

            scanViewPlugin.AddScanResultListener(this);
            anylineScanView?.StartCamera();
        }

        public void OnResult(ScanResult<ID> result)
        {
            if (result.Result is Identification id) {
				
				// get layout definition here:
				var layoutDefinition = id.LayoutDefinition;
				
				// iterate through values of the id, because it is enumerable
				foreach(var parameter in id) {
					Debug.WriteLine($"Parameter name: {parameter.Key}, value: {parameter.Value}, Confidence: {id.FieldConfidences[parameter.Key]}");
				}
			}
        }
    }
}
Vehicle Registration Certificate (Documentation)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
{
  "camera" : {
    "captureResolution" : "1080p"
  },
  "flash" : {
    "mode": "manual",
    "alignment": "bottom_right",
    "imageOn": "flash_on",
    "imageOff": "flash_off"
  },
  "viewPlugin" : {
    "plugin":{
      "id":"ID",
      "idPlugin": {
        "vehicleRegistrationCertificateConfig": {
          "layoutVehicleCertificate": {
            "documentNumber": {"scanOption": 1, "minConfidence": 40},
            "licensePlate": {"scanOption": 0, "minConfidence": 40},
            "lastName": {"scanOption": 0, "minConfidence": 60},
            "firstName": {"scanOption": 1, "minConfidence": 40},
            "address": {"scanOption": 0, "minConfidence": 50},
            "firstIssued": {"scanOption": 0, "minConfidence": 60},
            "manufacturerCode": {"scanOption": 0, "minConfidence": 50},
            "vehicleTypeCode": {"scanOption": 0, "minConfidence": 50},
            "vehicleIdentificationNumber": {"scanOption": 0, "minConfidence": 60},
            "brand": {"scanOption": 1, "minConfidence": 40},
            "vehicleType": {"scanOption": 1, "minConfidence": 40},
            "displacement": {"scanOption": 1, "minConfidence": 40},
            "tire": {"scanOption": 1, "minConfidence": 50}
          }
        }
      }
    },
    "cutoutConfig" : {
      "style": "animated_rect",
      "maxWidthPercent": "90%",
      "maxHeightPercent": "90%",
      "alignment": "center",
      "strokeWidth": 3,
      "cornerRadius": 8,
      "strokeColor": "FFFFFF",
      "outerColor": "000000",
      "outerAlpha": 0.3,
      "ratioFromSize": {
        "width": 90,
        "height": 46
      },
      "cropPadding": {
        "x": -50,
        "y": -50
      },
      "cropOffset": {
        "x": 0,
        "y": 0
      },
      "feedbackStrokeColor": "0099FF"
    },
    "scanFeedback" : {
      "style": "CONTOUR_RECT",
      "visualFeedbackRedrawTimeout": 100,
      "strokeColor": "0099FF",
      "fillColor" : "220099FF",
      "beepOnResult": true,
      "vibrateOnResult": true,
      "strokeWidth": 2
    },
    "cancelOnResult" : true
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class ScanVehicleRegistrationCertificate extends AppCompatActivity {

    ScanView scanView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_vehicle_registration);
        init();
    }

    void init(){
        scanView = findViewById(R.id.scan_view);
        
        // This must be called before doing anything Anyline-related! 
        // Try/Catch this to check whether or not your license key is valid!
        try {
            AnylineSDK.init(getString(getString(R.string.anyline_license_key)), this);
        } catch (LicenseException e) {
            // handle exception
        }

        scanView.init("vehicle_registration_certificate_view_config.json");

        IdScanViewPlugin idScanViewPlugin = (IdScanViewPlugin) scanView.getScanViewPlugin();

        idScanViewPlugin.addScanResultListener((ScanResultListener<ScanResult<ID>>) idScanResult -> {
            Identification identification = (Identification) idScanResult.getResult();
            HashMap<String, String> data = (HashMap<String, String>) identification.getResultData();
        });
    }

    @Override
    protected void onResume() {
        super.onResume();
        scanView.start();
    }

    @Override
    protected void onStop() {
        super.onStop();
        scanView.stop();
    }
}
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//
//  ALUniversalIDViewController.m
//  AnylineExamples
//
//  Created by Aldrich Co on 08.12.21.
//

#import "ALUniversalIDViewController.h"

// This is the license key for the examples project used to set up Anyline below
NSString * const kUniversalIDLicenseKey = @"ADD YOUR LICENSE KEY";

@interface ALUniversalIDScanViewControllerFrontAndBack ()<ALIDPluginDelegate>

@property (nonatomic, strong) ALIDScanViewPlugin *scanViewPlugin;
@property (nonatomic, strong) ALIDScanPlugin *scanPlugin;
@property (nullable, nonatomic, strong) ALScanView *scanView;

@end

@implementation ALUniversalIDViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    // Set the background color to black to have a nicer transition
    self.view.backgroundColor = [UIColor blackColor];
    
    // Initialise the Anyline License
    NSError *licenseError = nil;
    [AnylineSDK setupWithLicenseKey:kUniversalIDLicenseKey error:&licenseError];
    if (licenseError) {
        // Handle the error. You would be unable to use the scan view and scan plugin
        // in the event of an error, so it may be a good idea to make an early return.
    }
    
    NSError *error = nil;
    NSString *jsonFilePath = [[NSBundle mainBundle] pathForResource:@"universal_id_config"
                                                             ofType:@"json"];
    NSData *jsonFile = [NSData dataWithContentsOfFile:jsonFilePath];
    NSDictionary *configDict = [NSJSONSerialization JSONObjectWithData:jsonFile
                                                               options:NSJSONReadingMutableContainers
                                                                 error:&error];
    
    // Initialise the scan view plugin using the JSON configuration file and setting oneself
    // as its ALIDPluginDelegate
    self.scanViewPlugin = (ALIDScanViewPlugin *)[ALAbstractScanViewPlugin scanViewPluginForConfigDict:configDict delegate:self error:&error];

    NSAssert(self.scanViewPlugin, @"Setup Error: %@", error.debugDescription);

    self.scanPlugin = self.scanViewPlugin.idScanPlugin;
    
    // Implement ALScanViewPluginDelegate for its `anylineScanViewPlugin:updatedCutout:` method
    // [self.scanViewPlugin addScanViewPluginDelegate:self];
    
    // Implement ALInfoDelegate if interested in meta-variables reported while scanning
    // [self.scanPlugin addInfoDelegate:self];
    
    // Set the scanView's frame to fill the whole screen
    CGRect frame = [self scanViewFrame];
    self.scanView = [[ALScanView alloc] initWithFrame:frame scanViewPlugin:self.scanViewPlugin];
    
    // You can still configure the scan view config until the plugin is started;
    // here we set the flash button position within the scan view
    self.scanView.flashButtonConfig.flashAlignment = ALFlashAlignmentTopLeft;
    
    // After setup is complete we add the scanView to the view of this view controller
    [self.view addSubview:self.scanView];
    
    [self.scanView startCamera];
}

/*
 Start the scanning process once the view hierarchy has appeared onscreen.
 */
- (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];
}

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

/*
 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:).
 */
- (void)startAnyline {
    NSError *error = nil;
    [self.scanViewPlugin startAndReturnError:&error];
    // Handle if error is not null here
}


// MARK: - ALIDPluginDelegate
/*
 This is the main delegate method Anyline uses to report its results.
 */
- (void)anylineIDScanPlugin:(ALIDScanPlugin *)anylineIDScanPlugin
              didFindResult:(ALIDResult *)scanResult {
    ALUniversalIDIdentification *identification = (ALUniversalIDIdentification *)scanResult.result;
    NSArray<NSString *> *fieldNames = identification.fieldNames;
    ALLayoutDefinition *layoutDefinition = identification.layoutDefinition;
    ALUniversalIDFieldConfidences *fieldConfidences = identification.fieldConfidences;
    UIImage *faceImage = identification.faceImage;
    
    // Handle your result here
    // ...
}

@end
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
using Anyline.SDK.Models;
using Anyline.SDK.Plugins;
using Anyline.SDK.Plugins.Barcode;
using Anyline.SDK.Plugins.ID;
using Anyline.SDK.Plugins.LicensePlate;
using Anyline.SDK.Plugins.Meter;
using Anyline.SDK.Plugins.OCR;
using Anyline.SDK.Plugins.ViewPlugins;
using Anyline.SDK.Util;
using Anyline.SDK.ViewPlugins;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using Windows.Foundation;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;
using Anyline.SDK.Views;
using Anyline.SDK.Plugins.ID;

namespace Anyline_Windows_UWP_Examples
{
    public sealed partial class ScanViewPage : Page,
        IScanResultListener<ScanResult<ID>>
    {
        private ScanView anylineScanView;
        private IViewPluginBase scanViewPlugin;

        public ScanViewPage()
        {
            // We don't want to keep multiple instances of the scan views that we're navigating to.
            NavigationCacheMode = NavigationCacheMode.Required;
            ((Frame)Window.Current.Content).CacheSize = 0;

            this.InitializeComponent();

            anylineScanView = AnylineScanView;
        }

        private void CameraView_CameraOpened(object sender, Size args)
        {
            Debug.WriteLine($"(APP) Camera Opened: {args.Width}x{args.Height}");

            try
            {
                anylineScanView?.StartScanning();
            }
            catch (Exception e)
            {
                Debug.WriteLine($"(APP) {e.Message}");
            }
        }

        private void CameraView_CameraClosed(object sender, bool success)
        {
            Debug.WriteLine($"(APP) Camera Closed: {success}");

            try
            {
                anylineScanView?.StopScanning();
            }
            catch (Exception e)
            {
                Debug.WriteLine($"(APP) {e.Message}");
            }
        }

        private void CameraView_CameraError(object sender, Exception exception)
        {
            Debug.WriteLine($"(APP) Camera Error: {exception.Message}");
        }

        // important because the UWP camera stream automatically shuts down when a window is minimized
        private async void Current_VisibilityChanged(object sender, Windows.UI.Core.VisibilityChangedEventArgs args)
        {
            if (args.Visible == false)
            {
                if (anylineScanView != null)
                {
                    await anylineScanView.StopCameraAsync();
                }
            }
            if (args.Visible == true)
            {
                anylineScanView?.StartCamera();
            }
        }

        protected override async void OnNavigatedFrom(NavigationEventArgs e)
        {
            base.OnNavigatedFrom(e);
            
            Window.Current.VisibilityChanged -= Current_VisibilityChanged;
            
            if (anylineScanView != null)
            {
                anylineScanView.CameraView.CameraOpened -= CameraView_CameraOpened;
                anylineScanView.CameraView.CameraClosed -= CameraView_CameraClosed;
                anylineScanView.CameraView.CameraError -= CameraView_CameraError;

                await anylineScanView.StopCameraAsync();

                anylineScanView.Dispose();
            }
        }

        protected override async void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);

            if (anylineScanView == null) return;

            // register events
            if (anylineScanView != null)
            {
                anylineScanView.CameraView.CameraOpened -= CameraView_CameraOpened;
                anylineScanView.CameraView.CameraClosed -= CameraView_CameraClosed;
                anylineScanView.CameraView.CameraError -= CameraView_CameraError;

                anylineScanView.CameraView.CameraOpened += CameraView_CameraOpened;
                anylineScanView.CameraView.CameraClosed += CameraView_CameraClosed;
                anylineScanView.CameraView.CameraError += CameraView_CameraError;

                Window.Current.VisibilityChanged -= Current_VisibilityChanged;
                Window.Current.VisibilityChanged += Current_VisibilityChanged;
            }

            string jsonConfig = (e.Parameter as ExamplePlugin).JSONConfigFile;
            
			// make sure the license is initalized (needs only to be done once in the app lifetime)
			AnylineSDK.Init(myLicenseKey);
			// initialize Anyline
			await AnylineScanView.InitAsync("Assets/myconfig.json");
			
			// the correct plugin is loaded according to the .json config file informed
            scanViewPlugin = anylineScanView.ScanViewPlugin;

            scanViewPlugin.AddScanResultListener(this);
            anylineScanView?.StartCamera();
        }

        public void OnResult(ScanResult<ID> result)
        {
            if (result.Result is Identification id) {
				
				// get layout definition here:
				var layoutDefinition = id.LayoutDefinition;
				
				// iterate through values of the id, because it is enumerable
				foreach(var parameter in id) {
					Debug.WriteLine($"Parameter name: {parameter.Key}, value: {parameter.Value}, Confidence: {id.FieldConfidences[parameter.Key]}");
				}
			}
        }
    }
}
License Plate Plugin (Documentation)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
{
  "camera": {
    "captureResolution": "1080p",
    "zoomGesture": true
  },
  "flash": {
    "mode": "manual",
    "alignment": "top_left"
  },
  "viewPlugin": {
    "plugin": {
      "id": "LicensePlate_ID",
      "licensePlatePlugin": {
      }
    },
    "cutoutConfig": {
      "style": "rect",
      "maxWidthPercent": "80%",
      "maxHeightPercent": "80%",
      "alignment": "top_half",
      "width": 720,
      "ratioFromSize": {
        "width": 2,
        "height": 1
      },
      "strokeWidth": 2,
      "cornerRadius": 10,
      "strokeColor": "FFFFFF",
      "outerColor": "000000",
      "outerAlpha": 0.3,
      "feedbackStrokeColor": "0099FF"
    },
    "scanFeedback": {
      "animationDuration": 0,
      "style": "RECT",
      "strokeWidth": 2,
      "strokeColor": "0099FF",
      "blinkOnResult": true,
      "beepOnResult": true,
      "vibrateOnResult": true
    },
    "cancelOnResult": true,
    "delayStartScanTime": 2000
  }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;

import io.anyline.plugin.ScanResultListener;
import io.anyline.plugin.licenseplate.LicensePlateScanResult;
import io.anyline.plugin.licenseplate.LicensePlateScanViewPlugin;
import io.anyline.view.ScanView;
import io.anyline.AnylineSDK;


public class ScanLicensePlateActivity extends Activity {

    private ScanView scanView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.anyline_scan_view);

        scanView = findViewById(R.id.scan_view);

      	// This must be called before doing anything Anyline-related! 
	// Try/Catch this to check whether or not your license key is valid! 
	try {
    	    AnylineSDK.init(getString(getString(R.string.anyline_license_key)), this);
	} catch (LicenseException e) {
    	    // handle exception
	}

        //init the scan view
        scanView.init("license_plate_view_config.json");

        LicensePlateScanViewPlugin scanViewPlugin = (LicensePlateScanViewPlugin) scanView.getScanViewPlugin();

        scanView.setScanViewPlugin(scanViewPlugin);

        // add the result listener
        scanViewPlugin.addScanResultListener(new ScanResultListener<LicensePlateScanResult>() {
            @Override
            public void onResult(LicensePlateScanResult result) {
                Toast.makeText(getApplicationContext(), result.getCountry(), Toast.LENGTH_LONG).show();
            }

        });

    }

    @Override
    protected void onResume() {
        super.onResume();
        scanView.start();
    }


    @Override
    protected void onPause() {
        super.onPause();
        scanView.stop();
        scanView.releaseCameraInBackground();
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#import "ALLicensePlateViewController.h"
#import <Anyline/Anyline.h>
#import "NSUserDefaults+ALExamplesAdditions.h"
#import "ALAppDemoLicenses.h"
#import "ALResultEntry.h"
#import "ALResultViewController.h"
#import "Anyline/ALMeterScanPlugin.h"
#import "Anyline/ALMeterScanViewPlugin.h"




// This is the license key for the examples project used to set up Aynline below
NSString * const kLicensePlateLicenseKey = kDemoAppLicenseKey;
// The controller has to conform to <AnylineOCRModuleDelegate> to be able to receive results
@interface ALLicensePlateViewController ()<ALLicensePlateScanPluginDelegate, ALInfoDelegate>
// The Anyline module used for OCR
@property (nonatomic, strong) ALLicensePlateScanViewPlugin *licensePlateScanViewPlugin;
@property (nonatomic, strong) ALLicensePlateScanPlugin *licensePlateScanPlugin;
@property (nullable, nonatomic, strong) ALScanView *scanView;

@end

@implementation ALLicensePlateViewController
/*
 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 = @"License Plate";
    
    // 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);

    NSError *licenseError = nil;
    //Initialize the Anyline License
    [AnylineSDK setupWithLicenseKey:kDemoAppLicenseKey error:&licenseError];
    if (licenseError) {
        //Handle errors here
    }
    
    NSError *error = nil;
    self.licensePlateScanPlugin = [[ALLicensePlateScanPlugin alloc] initWithPluginID:@"LICENSE_PLATE" delegate:self error:&error];
    NSAssert(self.licensePlateScanPlugin, @"Setup Error: %@", error.debugDescription);
    [self.licensePlateScanPlugin addInfoDelegate:self];
    
    self.licensePlateScanViewPlugin = [[ALLicensePlateScanViewPlugin alloc] initWithScanPlugin:self.licensePlateScanPlugin];
    NSAssert(self.licensePlateScanViewPlugin, @"Setup Error: %@", error.debugDescription);
    
    self.scanView = [[ALScanView alloc] initWithFrame:frame scanViewPlugin:self.licensePlateScanViewPlugin];
    
    self.controllerType = ALScanHistoryLicensePlates;
    
    // 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];
}

/*
 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.
    NSError *error;
    BOOL success = [self.licensePlateScanViewPlugin startAndReturnError:&error];
    if( !success ) {
        // Something went wrong. The error object contains the error description
        NSAssert(success, @"Start Scanning Error: %@", error.debugDescription);
    }
}

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

#pragma mark -- AnylineOCRModuleDelegate

/*
 This is the main delegate method Anyline uses to report its results
 */
- (void)anylineLicensePlateScanPlugin:(ALLicensePlateScanPlugin *)anylineLicensePlateScanPlugin
                        didFindResult:(ALLicensePlateResult *)result {

    //Handle the returned scan Result here.
}

@end
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
using Anyline.SDK.Models;
using Anyline.SDK.Plugins;
using Anyline.SDK.Plugins.LicensePlate;
using Anyline.SDK.Util;
using Anyline.SDK.ViewPlugins;
using Anyline.SDK.Views;
using Anyline_Windows_UWP_Examples.Model;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Windows.Foundation;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;


namespace Anyline_Windows_UWP_Examples
{
    /// <summary>
    /// This page is used to setup the plugin, open the camera and start scanning
    /// it has to implement the IScanResultListener for each Plugin that will be used
    /// </summary>
    public sealed partial class ScanPage : Page, IScanResultListener<LicensePlateScanResult>
	{
		string myLicenseKey = "INSERT LICENSE KEY HERE";

		protected override async void OnNavigatedTo(NavigationEventArgs e)
		{
			base.OnNavigatedTo(e);

			// register camera events
			AnylineScanView.CameraView.CameraOpened += CameraView_CameraOpened;
			AnylineScanView.CameraView.CameraClosed += CameraView_CameraClosed;

			// register visibility changed event
			Window.Current.VisibilityChanged += Current_VisibilityChanged;

			// make sure the license is initalized (needs only to be done once in the app lifetime)
			AnylineSDK.Init(myLicenseKey);
			// initialize Anyline
			await AnylineScanView.InitAsync("Assets/myconfig.json");
			
			// attach the result listener to the ScanViewPlugin to receive scanning results
			(AnylineScanView.ScanViewPlugin as LicensePlateScanViewPlugin)?.AddScanResultListener(this);

			// opens the camera
			AnylineScanView.StartCamera();
		}

		private async void Current_VisibilityChanged(object sender, Windows.UI.Core.VisibilityChangedEventArgs args)
		{
			if (AnylineScanView == null) return;

			if (args.Visible == false)
			{
				await AnylineScanView.StopCameraAsync();
			}
			if (args.Visible == true)
			{
				AnylineScanView.StartCamera();
			}
		}

		private void CameraView_CameraOpened(object sender, Size args)
		{
			AnylineScanView.StartScanning();
		}

		private void CameraView_CameraClosed(object sender, bool success)
		{
			AnylineScanView.StopScanning();
		}

		public void OnResult(LicensePlateScanResult result)
		{
			Debug.WriteLine($"(APP) Scan result: {result.Result}");
		}
	}
}
Tire Plugin : TIN Scan Mode (Documentation)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
{
  "camera": {
    "captureResolution": "720"
  },
  "flash": {
    "mode": "manual",
    "alignment": "bottom_left"
  },
  "viewPlugin": {
    "plugin": {
      "id": "TIN_ID",
      "tirePlugin": {
        "tinConfig": {
          "scanMode": "UNIVERSAL",
          "upsideDownMode": "auto"
        }
      }
    },
    "cutoutConfig": {
      "style": "rect",
      "width": 720,
      "alignment": "center",
      "maxWidthPercent": "80%",
      "ratioFromSize": {
        "width": 720,
        "height": 144
      },
      "strokeWidth": 2,
      "strokeColor": "FFFFFF",
      "cornerRadius": 4,
      "outerColor": "000000",
      "outerAlpha": 0.5,
      "feedbackStrokeColor": "0099FF",
      "offset": {
        "x": 0,
        "y": -15
      }
    },
    "scanFeedback": {
      "animation": "traverse_multi",
      "animationDuration": 250,
      "style": "contour_rect",
      "strokeWidth": 2,
      "strokeColor": "0099FF",
      "beepOnResult": false,
      "vibrateOnResult": true,
      "blinkAnimationOnResult": true,
      "cancelOnResult": true
    },
    "cancelOnResult": true
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package com.anyline.examples.demo;

import android.os.Bundle;
import android.view.WindowManager;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import io.anyline.plugin.ScanResultListener;
import io.anyline.plugin.tire.TINConfig;
import io.anyline.plugin.tire.TireScanResult;
import io.anyline.plugin.tire.TireScanViewPlugin;
import io.anyline.view.BaseScanViewConfig;
import io.anyline.view.ScanView;
import io.anyline.view.ScanViewPluginConfig;
import io.anyline.AnylineSDK;

import at.nineyards.anyline.core.LicenseException;

public class ScanTINActivity extends AppCompatActivity {
    private static final String TAG = ScanTINActivity.class.getSimpleName();
    private ScanView scanView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Set the flag to keep the screen on (otherwise the screen may go dark during scanning)
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        setContentView(R.layout.activity_scan_tire);

        String lic = getString(R.string.anyline_license_key);
        scanView = (ScanView) findViewById(R.id.scan_view);

        // This must be called before doing anything Anyline-related! 
        // Try/Catch this to check whether or not your license key is valid! 
        try {
            AnylineSDK.init(getString(lic), this);
        } catch (LicenseException e) {
            // handle exception
        }

        //init the scanView with the JSON config file
        scanView.init("tire_config.json");
        //add the scan result listener
        scanView.getScanViewPlugin().addScanResultListener(new ScanResultListener<TireScanResult>() {
            @Override
            public void onResult(TireScanResult result) {

                if (!result.toString().isEmpty()) {
                    Toast.makeText(getApplicationContext(), result.getResult(), Toast.LENGTH_LONG).show();
                }
            }
        });
    }

    @Override
    protected void onResume() {
        super.onResume();
        //start the scanning
        //internally scanView is calling the scanPlugin which is starting the scanning part
        scanView.start();
    }

    @Override
    protected void onPause() {
        super.onPause();

        scanView.stop();
        scanView.releaseCameraInBackground();
    }
}
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
#import "ALTINScanViewController.h"

@interface ALTINScanViewController() <ALTireScanPluginDelegate, ALScanViewPluginDelegate>

// The Anyline plugin used for tire scanning
@property (nonatomic, strong) ALTireScanPlugin *tireScanPlugin;
@property (nonatomic, strong) ALTireScanViewPlugin *tireScanViewPlugin;
@property (nullable, nonatomic, strong) ALScanView *scanView;

@end


@implementation ALTINScanViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.title = @"Tire Identification Number";

    // We will be setting up the tire plugin with the TIN Config: Universal TIN scan mode. Other
    // scan modes for the TIN Config include: ALTINDotStrict and ALTINDotStrict.
    //
    // Apart from ALTINConfig, other tire plugin configs are available: ALTireSizeConfig and
    // ALCommercialTireIdConfig
    ALTINConfig *config = [[ALTINConfig alloc] init];
    [config setScanMode:ALTINUniversal];

    // Initialize the tire plugin here. If there is an error, scanning would not be possible.
    // This case will need to be handled in the appropriate manner.
    NSError *error = nil;
    self.tireScanPlugin = [[ALTireScanPlugin alloc] initWithPluginID:@"TIRE"
                                                           delegate:self
                                                         tireConfig:config
                                                              error:&error];
    NSAssert(self.tireScanPlugin, @"Setup Error: %@", error.debugDescription);

    // Configure the scan view config, setting it up using the tireScanPlugin initialized
    // previously.
    ALScanViewPluginConfig *viewPluginConfig = [ALScanViewPluginConfig defaultTINConfig];
    viewPluginConfig.delayStartScanTime = 2000;
    self.tireScanViewPlugin = [[ALTireScanViewPlugin alloc] initWithScanPlugin:self.tireScanPlugin
                                                          scanViewPluginConfig:viewPluginConfig];

    // Set the delegate for the scan view plugin to be notified when a result has been found.
    [self.tireScanViewPlugin addScanViewPluginDelegate:self];

    // Finally, initialize the scan view, which is a UIView subclass, with the scan view plugin.
    // We set the frame initially to CGRectZero, but later use autolayout constraints to allow
    // the scan view to fill the entire screen.
    self.scanView = [[ALScanView alloc] initWithFrame:CGRectZero scanViewPlugin:self.tireScanViewPlugin];

    // After setup is complete we add the scanView to the view of this view controller.
    [self.view addSubview:self.scanView];

    [self setupConstraints];

    // Start the camera.
    [self.scanView startCamera];
}

/*
 This method will be called once the view controller and its subviews have appeared on screen
 */
- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    // Start the tire scan plugin to begin scanning, the moment the scan view appears.
    [self startPlugin:self.tireScanViewPlugin];
}

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

- (void)setupConstraints {
    self.scanView.translatesAutoresizingMaskIntoConstraints = NO;
    
    NSArray *constraints = @[[self.scanView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor],
                             [self.scanView.leftAnchor constraintEqualToAnchor:self.view.leftAnchor],
                             [self.scanView.rightAnchor constraintEqualToAnchor:self.view.rightAnchor],
                             [self.scanView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor]];
    
    
    [self.view addConstraints:constraints];
    [NSLayoutConstraint activateConstraints:constraints];
}

// MARK: - ALTireScanPluginDelegate

- (void)anylineTireScanPlugin:(ALTireScanPlugin * _Nonnull)anylineTireScanPlugin
                didFindResult:(ALTireResult * _Nonnull)tireScanResult {

    // The plugin is stopped when the result is returned. You may at some later
    // point decide to start the plugin again, depending on your needs. Here,
    // the tire scan result is used.
    NSLog(@"Tire Scan Result: %@", tireScanResult.result);
}

@end
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
using Anyline.SDK.Models;
using Anyline.SDK.Plugins;
using Anyline.SDK.Plugins.Tire;
using Anyline.SDK.Util;
using Anyline.SDK.ViewPlugins;
using Anyline.SDK.Views;
using Anyline_Windows_UWP_Examples.Model;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Windows.Foundation;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;


namespace Anyline_Windows_UWP_Examples
{
    /// <summary>
    /// This page is used to setup the plugin, open the camera and start scanning
    /// it has to implement the IScanResultListener for each Plugin that will be used
    /// </summary>
    public sealed partial class ScanPage : Page, IScanResultListener<TireScanResult>
	{
		string myLicenseKey = "INSERT LICENSE KEY HERE";

		protected override async void OnNavigatedTo(NavigationEventArgs e)
		{
			base.OnNavigatedTo(e);

			// register camera events
			AnylineScanView.CameraView.CameraOpened += CameraView_CameraOpened;
			AnylineScanView.CameraView.CameraClosed += CameraView_CameraClosed;

			// register visibility changed event
			Window.Current.VisibilityChanged += Current_VisibilityChanged;

			// make sure the license is initalized (needs only to be done once in the app lifetime)
			AnylineSDK.Init(myLicenseKey);
			// initialize Anyline
			await AnylineScanView.InitAsync("Assets/myconfig.json");

			// attach the result listener to the ScanViewPlugin to receive scanning results
			(AnylineScanView.ScanViewPlugin as TireScanViewPlugin)?.AddScanResultListener(this);

			// opens the camera
			AnylineScanView.StartCamera();
		}

		private async void Current_VisibilityChanged(object sender, Windows.UI.Core.VisibilityChangedEventArgs args)
		{
			if (AnylineScanView == null) return;

			if (args.Visible == false)
			{
				await AnylineScanView.StopCameraAsync();
			}
			if (args.Visible == true)
			{
				AnylineScanView.StartCamera();
			}
		}

		private void CameraView_CameraOpened(object sender, Size args)
		{
			AnylineScanView.StartScanning();
		}

		private void CameraView_CameraClosed(object sender, bool success)
		{
			AnylineScanView.StopScanning();
		}

		public void OnResult(ScanResult<TireScanResult> result)
		{
			Debug.WriteLine($"(APP) Scan result: {result.Result}");
		}
	}
}
Tire Plugin : Tire Size Specifications Scan Mode (Documentation)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
{
  "camera": {
    "captureResolution": "1080"
  },
  "flash": {
    "mode": "manual",
    "alignment": "bottom_left"
  },
  "viewPlugin": {
    "plugin": {
      "id": "TIRE_SIZE_ID",
      "tirePlugin": {
        "tireSizeConfig": {
        }
      }
    },
    "cutoutConfig": {
      "style": "rect",
      "width": 720,
      "alignment": "center",
      "maxWidthPercent": "80%",
      "ratioFromSize": {
        "width": 720,
        "height": 144
      },
      "strokeWidth": 2,
      "strokeColor": "FFFFFF",
      "cornerRadius": 4,
      "outerColor": "000000",
      "outerAlpha": 0.5,
      "feedbackStrokeColor": "0099FF",
      "offset": {
        "x": 0,
        "y": -15
      }
    },
    "scanFeedback": {
      "animation": "traverse_multi",
      "animationDuration": 250,
      "style": "rect",
      "strokeWidth": 2,
      "strokeColor": "0099FF",
      "beepOnResult": false,
      "vibrateOnResult": true,
      "blinkAnimationOnResult": true,
      "cancelOnResult": true
    },
    "cancelOnResult": true
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package com.anyline.examples.demo;

import android.os.Bundle;
import android.view.WindowManager;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import io.anyline.plugin.ScanResultListener;
import io.anyline.plugin.tire.TINConfig;
import io.anyline.plugin.tire.TireScanResult;
import io.anyline.plugin.tire.TireScanViewPlugin;
import io.anyline.view.BaseScanViewConfig;
import io.anyline.view.ScanView;
import io.anyline.view.ScanViewPluginConfig;
import io.anyline.AnylineSDK;

import at.nineyards.anyline.core.LicenseException;

public class ScanTINActivity extends AppCompatActivity {
    private static final String TAG = ScanTINActivity.class.getSimpleName();
    private ScanView scanView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Set the flag to keep the screen on (otherwise the screen may go dark during scanning)
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        setContentView(R.layout.activity_scan_tire);

        String lic = getString(R.string.anyline_license_key);
        scanView = (ScanView) findViewById(R.id.scan_view);

        // This must be called before doing anything Anyline-related! 
        // Try/Catch this to check whether or not your license key is valid! 
        try {
            AnylineSDK.init(getString(lic), this);
        } catch (LicenseException e) {
            // handle exception
        }

        //init the scanView with the JSON config file
        scanView.init("tire_config.json");
        //add the scan result listener
        scanView.getScanViewPlugin().addScanResultListener(new ScanResultListener<TireScanResult>() {
            @Override
            public void onResult(TireScanResult result) {

                if (!result.toString().isEmpty()) {
                    Toast.makeText(getApplicationContext(), result.getResult(), Toast.LENGTH_LONG).show();
                }
            }
        });
    }

    @Override
    protected void onResume() {
        super.onResume();
        //start the scanning
        //internally scanView is calling the scanPlugin which is starting the scanning part
        scanView.start();
    }

    @Override
    protected void onPause() {
        super.onPause();

        scanView.stop();
        scanView.releaseCameraInBackground();
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#import "ALTINScanViewController.h"

@interface ALTINScanViewController() <ALTireScanPluginDelegate, ALScanViewPluginDelegate>

// The Anyline plugin used for tire scanning
@property (nonatomic, strong) ALTireScanPlugin *tireScanPlugin;
@property (nonatomic, strong) ALTireScanViewPlugin *tireScanViewPlugin;
@property (nullable, nonatomic, strong) ALScanView *scanView;

@end


@implementation ALTINScanViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.title = @"Tire Size Specification";

    ALTireSizeConfig *config = [[ALTireSizeConfig alloc] init];

    // Initialize the tire plugin here. If there is an error, scanning would not be possible.
    // This case will need to be handled in the appropriate manner.
    NSError *error = nil;
    self.tireScanPlugin = [[ALTireScanPlugin alloc] initWithPluginID:@"TIRE"
                                                           delegate:self
                                                         tireConfig:config
                                                              error:&error];
    NSAssert(self.tireScanPlugin, @"Setup Error: %@", error.debugDescription);

    // Configure the scan view config, setting it up using the tireScanPlugin initialized
    // previously.
    ALScanViewPluginConfig *viewPluginConfig = [ALScanViewPluginConfig defaultTINConfig];
    viewPluginConfig.delayStartScanTime = 2000;
    self.tireScanViewPlugin = [[ALTireScanViewPlugin alloc] initWithScanPlugin:self.tireScanPlugin
                                                          scanViewPluginConfig:viewPluginConfig];

    // Set the delegate for the scan view plugin to be notified when a result has been found.
    [self.tireScanViewPlugin addScanViewPluginDelegate:self];

    // Finally, initialize the scan view, which is a UIView subclass, with the scan view plugin.
    // We set the frame initially to CGRectZero, but later use autolayout constraints to allow
    // the scan view to fill the entire screen.
    self.scanView = [[ALScanView alloc] initWithFrame:CGRectZero scanViewPlugin:self.tireScanViewPlugin];

    // After setup is complete we add the scanView to the view of this view controller.
    [self.view addSubview:self.scanView];

    [self setupConstraints];

    // Start the camera.
    [self.scanView startCamera];
}

/*
 This method will be called once the view controller and its subviews have appeared on screen
 */
- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    // Start the tire scan plugin to begin scanning, the moment the scan view appears.
    [self startPlugin:self.tireScanViewPlugin];
}

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

- (void)setupConstraints {
    self.scanView.translatesAutoresizingMaskIntoConstraints = NO;

    NSArray *constraints = @[[self.scanView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor],
                             [self.scanView.leftAnchor constraintEqualToAnchor:self.view.leftAnchor],
                             [self.scanView.rightAnchor constraintEqualToAnchor:self.view.rightAnchor],
                             [self.scanView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor]];


    [self.view addConstraints:constraints];
    [NSLayoutConstraint activateConstraints:constraints];
}

// MARK: - ALTireScanPluginDelegate

- (void)anylineTireScanPlugin:(ALTireScanPlugin * _Nonnull)anylineTireScanPlugin
                didFindResult:(ALTireResult * _Nonnull)tireScanResult {

    // The plugin is stopped when the result is returned. You may at some later
    // point decide to start the plugin again, depending on your needs. Here,
    // the tire scan result is used.
    NSLog(@"Tire Scan Result: %@", tireScanResult.result);
}

@end
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
using Anyline.SDK.Models;
using Anyline.SDK.Plugins;
using Anyline.SDK.Plugins.Tire;
using Anyline.SDK.Util;
using Anyline.SDK.ViewPlugins;
using Anyline.SDK.Views;
using Anyline_Windows_UWP_Examples.Model;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Windows.Foundation;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;


namespace Anyline_Windows_UWP_Examples
{
    /// <summary>
    /// This page is used to setup the plugin, open the camera and start scanning
    /// it has to implement the IScanResultListener for each Plugin that will be used
    /// </summary>
    public sealed partial class ScanPage : Page, IScanResultListener<TireScanResult>
	{
		string myLicenseKey = "INSERT LICENSE KEY HERE";

		protected override async void OnNavigatedTo(NavigationEventArgs e)
		{
			base.OnNavigatedTo(e);

			// register camera events
			AnylineScanView.CameraView.CameraOpened += CameraView_CameraOpened;
			AnylineScanView.CameraView.CameraClosed += CameraView_CameraClosed;

			// register visibility changed event
			Window.Current.VisibilityChanged += Current_VisibilityChanged;

			// make sure the license is initalized (needs only to be done once in the app lifetime)
			AnylineSDK.Init(myLicenseKey);
			// initialize Anyline
			await AnylineScanView.InitAsync("Assets/myconfig.json");

			// attach the result listener to the ScanViewPlugin to receive scanning results
			(AnylineScanView.ScanViewPlugin as TireScanViewPlugin)?.AddScanResultListener(this);

			// opens the camera
			AnylineScanView.StartCamera();
		}

		private async void Current_VisibilityChanged(object sender, Windows.UI.Core.VisibilityChangedEventArgs args)
		{
			if (AnylineScanView == null) return;

			if (args.Visible == false)
			{
				await AnylineScanView.StopCameraAsync();
			}
			if (args.Visible == true)
			{
				AnylineScanView.StartCamera();
			}
		}

		private void CameraView_CameraOpened(object sender, Size args)
		{
			AnylineScanView.StartScanning();
		}

		private void CameraView_CameraClosed(object sender, bool success)
		{
			AnylineScanView.StopScanning();
		}

		public void OnResult(ScanResult<TireScanResult> result)
		{
			Debug.WriteLine($"(APP) Scan result: {result.Result}");
		}
	}
}
Tire Plugin : Commercial Tire ID Scan Mode (Documentation)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
{
  "camera": {
    "captureResolution": "1080"
  },
  "flash": {
    "mode": "manual",
    "alignment": "bottom_left"
  },
  "viewPlugin": {
    "plugin": {
      "id": "COMMERCIAL_TIRE_ID",
      "tirePlugin": {
        "commercialTireIdConfig": {
        }
      }
    },
    "cutoutConfig": {
      "style": "rect",
      "width": 720,
      "alignment": "center",
      "maxWidthPercent": "80%",
      "ratioFromSize": {
        "width": 720,
        "height": 144
      },
      "strokeWidth": 2,
      "strokeColor": "FFFFFF",
      "cornerRadius": 4,
      "outerColor": "000000",
      "outerAlpha": 0.5,
      "feedbackStrokeColor": "0099FF",
      "offset": {
        "x": 0,
        "y": -15
      }
    },
    "scanFeedback": {
      "animation": "traverse_multi",
      "animationDuration": 250,
      "style": "contour_rect",
      "strokeWidth": 2,
      "strokeColor": "0099FF",
      "beepOnResult": false,
      "vibrateOnResult": true,
      "blinkAnimationOnResult": true,
      "cancelOnResult": true
    },
    "cancelOnResult": true
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package com.anyline.examples.demo;

import android.os.Bundle;
import android.view.WindowManager;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import io.anyline.plugin.ScanResultListener;
import io.anyline.plugin.tire.TINConfig;
import io.anyline.plugin.tire.TireScanResult;
import io.anyline.plugin.tire.TireScanViewPlugin;
import io.anyline.view.BaseScanViewConfig;
import io.anyline.view.ScanView;
import io.anyline.view.ScanViewPluginConfig;
import io.anyline.AnylineSDK;

import at.nineyards.anyline.core.LicenseException;

public class ScanTINActivity extends AppCompatActivity {
    private static final String TAG = ScanTINActivity.class.getSimpleName();
    private ScanView scanView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Set the flag to keep the screen on (otherwise the screen may go dark during scanning)
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        setContentView(R.layout.activity_scan_tire);

        String lic = getString(R.string.anyline_license_key);
        scanView = (ScanView) findViewById(R.id.scan_view);

        // This must be called before doing anything Anyline-related! 
        // Try/Catch this to check whether or not your license key is valid! 
        try {
            AnylineSDK.init(getString(lic), this);
        } catch (LicenseException e) {
            // handle exception
        }

        //init the scanView with the JSON config file
        scanView.init("tire_config.json");
        //add the scan result listener
        scanView.getScanViewPlugin().addScanResultListener(new ScanResultListener<TireScanResult>() {
            @Override
            public void onResult(TireScanResult result) {

                if (!result.toString().isEmpty()) {
                    Toast.makeText(getApplicationContext(), result.getResult(), Toast.LENGTH_LONG).show();
                }
            }
        });
    }

    @Override
    protected void onResume() {
        super.onResume();
        //start the scanning
        //internally scanView is calling the scanPlugin which is starting the scanning part
        scanView.start();
    }

    @Override
    protected void onPause() {
        super.onPause();

        scanView.stop();
        scanView.releaseCameraInBackground();
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#import "ALTINScanViewController.h"

@interface ALTINScanViewController() <ALTireScanPluginDelegate, ALScanViewPluginDelegate>

// The Anyline plugin used for tire scanning
@property (nonatomic, strong) ALTireScanPlugin *tireScanPlugin;
@property (nonatomic, strong) ALTireScanViewPlugin *tireScanViewPlugin;
@property (nullable, nonatomic, strong) ALScanView *scanView;

@end


@implementation ALTINScanViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.title = @"Commercial Tire ID";

    ALCommercialTireIdConfig *config = [[ALCommercialTireIdConfig alloc] init];

    // Initialize the tire plugin here. If there is an error, scanning would not be possible.
    // This case will need to be handled in the appropriate manner.
    NSError *error = nil;
    self.tireScanPlugin = [[ALTireScanPlugin alloc] initWithPluginID:@"TIRE"
                                                           delegate:self
                                                         tireConfig:config
                                                              error:&error];
    NSAssert(self.tireScanPlugin, @"Setup Error: %@", error.debugDescription);

    // Configure the scan view config, setting it up using the tireScanPlugin initialized
    // previously.
    ALScanViewPluginConfig *viewPluginConfig = [ALScanViewPluginConfig defaultTINConfig];
    viewPluginConfig.delayStartScanTime = 2000;
    self.tireScanViewPlugin = [[ALTireScanViewPlugin alloc] initWithScanPlugin:self.tireScanPlugin
                                                          scanViewPluginConfig:viewPluginConfig];

    // Set the delegate for the scan view plugin to be notified when a result has been found.
    [self.tireScanViewPlugin addScanViewPluginDelegate:self];

    // Finally, initialize the scan view, which is a UIView subclass, with the scan view plugin.
    // We set the frame initially to CGRectZero, but later use autolayout constraints to allow
    // the scan view to fill the entire screen.
    self.scanView = [[ALScanView alloc] initWithFrame:CGRectZero scanViewPlugin:self.tireScanViewPlugin];

    // After setup is complete we add the scanView to the view of this view controller.
    [self.view addSubview:self.scanView];

    [self setupConstraints];

    // Start the camera.
    [self.scanView startCamera];
}

/*
 This method will be called once the view controller and its subviews have appeared on screen
 */
- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    // Start the tire scan plugin to begin scanning, the moment the scan view appears.
    [self startPlugin:self.tireScanViewPlugin];
}

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

- (void)setupConstraints {
    self.scanView.translatesAutoresizingMaskIntoConstraints = NO;

    NSArray *constraints = @[[self.scanView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor],
                             [self.scanView.leftAnchor constraintEqualToAnchor:self.view.leftAnchor],
                             [self.scanView.rightAnchor constraintEqualToAnchor:self.view.rightAnchor],
                             [self.scanView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor]];


    [self.view addConstraints:constraints];
    [NSLayoutConstraint activateConstraints:constraints];
}

// MARK: - ALTireScanPluginDelegate

- (void)anylineTireScanPlugin:(ALTireScanPlugin * _Nonnull)anylineTireScanPlugin
                didFindResult:(ALTireResult * _Nonnull)tireScanResult {

    // The plugin is stopped when the result is returned. You may at some later
    // point decide to start the plugin again, depending on your needs. Here,
    // the tire scan result is used.
    NSLog(@"Tire Scan Result: %@", tireScanResult.result);
}

@end
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
using Anyline.SDK.Models;
using Anyline.SDK.Plugins;
using Anyline.SDK.Plugins.Tire;
using Anyline.SDK.Util;
using Anyline.SDK.ViewPlugins;
using Anyline.SDK.Views;
using Anyline_Windows_UWP_Examples.Model;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Windows.Foundation;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;


namespace Anyline_Windows_UWP_Examples
{
    /// <summary>
    /// This page is used to setup the plugin, open the camera and start scanning
    /// it has to implement the IScanResultListener for each Plugin that will be used
    /// </summary>
    public sealed partial class ScanPage : Page, IScanResultListener<TireScanResult>
	{
		string myLicenseKey = "INSERT LICENSE KEY HERE";

		protected override async void OnNavigatedTo(NavigationEventArgs e)
		{
			base.OnNavigatedTo(e);

			// register camera events
			AnylineScanView.CameraView.CameraOpened += CameraView_CameraOpened;
			AnylineScanView.CameraView.CameraClosed += CameraView_CameraClosed;

			// register visibility changed event
			Window.Current.VisibilityChanged += Current_VisibilityChanged;

			// make sure the license is initalized (needs only to be done once in the app lifetime)
			AnylineSDK.Init(myLicenseKey);
			// initialize Anyline
			await AnylineScanView.InitAsync("Assets/myconfig.json");

			// attach the result listener to the ScanViewPlugin to receive scanning results
			(AnylineScanView.ScanViewPlugin as TireScanViewPlugin)?.AddScanResultListener(this);

			// opens the camera
			AnylineScanView.StartCamera();
		}

		private async void Current_VisibilityChanged(object sender, Windows.UI.Core.VisibilityChangedEventArgs args)
		{
			if (AnylineScanView == null) return;

			if (args.Visible == false)
			{
				await AnylineScanView.StopCameraAsync();
			}
			if (args.Visible == true)
			{
				AnylineScanView.StartCamera();
			}
		}

		private void CameraView_CameraOpened(object sender, Size args)
		{
			AnylineScanView.StartScanning();
		}

		private void CameraView_CameraClosed(object sender, bool success)
		{
			AnylineScanView.StopScanning();
		}

		public void OnResult(ScanResult<TireScanResult> result)
		{
			Debug.WriteLine($"(APP) Scan result: {result.Result}");
		}
	}
}
AnylineOCR Plugin : Universal Serial Number Scan Mode (Documentation)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
{
  "camera": {
    "captureResolution": "720"
  },
  "flash": {
    "mode": "manual",
    "alignment": "bottom_right"
  },
  "viewPlugin": {
    "plugin": {
      "id": "USNR_ID",
      "ocrPlugin": {
        "ocrConfig" : {
          "scanMode" : "AUTO"
        }
      }
    },
    "cutoutConfig": {
      "style": "rect",
      "width": 720,
      "alignment": "top_half",
      "maxWidthPercent": "80%",
      "ratioFromSize": {
        "width": 720,
        "height": 144
      },
      "strokeWidth": 2,
      "strokeColor": "FFFFFF",
      "cornerRadius": 4,
      "outerColor": "000000",
      "outerAlpha": 0.5,
      "feedbackStrokeColor": "0099FF",
      "offset": {
        "x": 0,
        "y": -15
      }
    },
    "scanFeedback": {
      "style": "CONTOUR_RECT",
      "strokeColor": "0099FF",
      "fillColor": "220099FF",
      "beepOnResult": true,
      "vibrateOnResult": true,
      "blinkAnimationOnResult": true
    },
    "cancelOnResult": true
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;

import io.anyline.plugin.ScanResultListener;
import io.anyline.plugin.ocr.OcrScanResult;
import io.anyline.plugin.ocr.OcrScanViewPlugin;
import io.anyline.view.ScanView;
import io.anyline.AnylineSDK;


public class ScanUSNrActiviy extends Activity {

    private ScanView scanView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.anyline_scan_view);

        scanView = findViewById(R.id.scan_view);

      	// This must be called before doing anything Anyline-related! 
	// Try/Catch this to check whether or not your license key is valid! 
	try {
    	    AnylineSDK.init(getString(getString(R.string.anyline_license_key)), this);
	} catch (LicenseException e) {
    	    // handle exception
	}

        try {
            scanView.init("usnr_view_config.json");
        } catch (Exception e) {
            e.printStackTrace();
        }

        OcrScanViewPlugin scanViewPlugin = (OcrScanViewPlugin) scanView.getScanViewPlugin();

        scanViewPlugin.addScanResultListener(new ScanResultListener<OcrScanResult>() {
            @Override
            public void onResult(OcrScanResult anylineOcrResult) {

                String result = anylineOcrResult.getResult();
                Toast.makeText(getApplicationContext(), result.toString(), Toast.LENGTH_LONG).show();
            }

        });

    }

    @Override
    protected void onResume() {
        super.onResume();
        scanView.start();
    }


    @Override
    protected void onPause() {
        super.onPause();
        scanView.stop();
        scanView.releaseCameraInBackground();
    }
}
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
using Anyline.SDK.Models;
using Anyline.SDK.Plugins;
using Anyline.SDK.Plugins.Barcode;
using Anyline.SDK.Plugins.ID;
using Anyline.SDK.Plugins.LicensePlate;
using Anyline.SDK.Plugins.Meter;
using Anyline.SDK.Plugins.OCR;
using Anyline.SDK.Plugins.ViewPlugins;
using Anyline.SDK.Util;
using Anyline.SDK.ViewPlugins;
using Anyline.SDK.Views;
using Anyline_Windows_UWP_Examples.Model;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Windows.Foundation;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;


namespace Anyline_Windows_UWP_Examples
{
    /// <summary>
    /// This page is used to setup the plugin, open the camera and start scanning
    /// it has to implement the IScanResultListener for each Plugin that will be used
    /// </summary>
    public sealed partial class ScanViewPage : Page,
        IScanResultListener<BarcodeScanResult>,
        IScanResultListener<ScanResult<ID>>,
        IScanResultListener<LicensePlateScanResult>,
        IScanResultListener<MeterScanResult>,
        IScanResultListener<OCRScanResult>,
        IPhotoCaptureListener
    {
        private ScanView anylineScanView;
        private IViewPluginBase scanViewPlugin;

        public ScanViewPage()
        {
			// make sure the license is initalized (needs only to be done once in the app lifetime)
			AnylineSDK.Init(MY_LICENSE_KEY);
			
            // We don't want to keep multiple instances of the scan views that we're navigating to.
            NavigationCacheMode = NavigationCacheMode.Required;
            ((Frame)Window.Current.Content).CacheSize = 0;

            ApplicationView.GetForCurrentView().Title = "Anyline Examples";

            this.InitializeComponent();

            //AnylineDebug.SetVerbosity(Verbosity.Diagnostic);

            anylineScanView = AnylineScanView;
        }

        private void CameraView_CameraOpened(object sender, Size args)
        {
            Debug.WriteLine($"(APP) Camera Opened: {args.Width}x{args.Height}");

            try
            {
                anylineScanView?.StartScanning();
            }
            catch (Exception e)
            {
                Debug.WriteLine($"(APP) {e.Message}");
            }
        }

        private void CameraView_CameraClosed(object sender, bool success)
        {
            Debug.WriteLine($"(APP) Camera Closed: {success}");

            try
            {
                anylineScanView?.StopScanning();
            }
            catch (Exception e)
            {
                Debug.WriteLine($"(APP) {e.Message}");
            }
        }

        private void CameraView_CameraError(object sender, Exception exception)
        {
            Debug.WriteLine($"(APP) Camera Error: {exception.Message}");
        }

        // important because the UWP camera stream automatically shuts down when a window is minimized
        private async void Current_VisibilityChanged(object sender, Windows.UI.Core.VisibilityChangedEventArgs args)
        {
            if (args.Visible == false)
            {
                if (anylineScanView != null)
                {
                    await anylineScanView.StopCameraAsync();
                }
            }
            if (args.Visible == true)
            {
                anylineScanView?.StartCamera();
            }
        }

        protected override async void OnNavigatedFrom(NavigationEventArgs e)
        {
            base.OnNavigatedFrom(e);
            
            Window.Current.VisibilityChanged -= Current_VisibilityChanged;
            
            if (anylineScanView != null)
            {
                anylineScanView.CameraView.CameraOpened -= CameraView_CameraOpened;
                anylineScanView.CameraView.CameraClosed -= CameraView_CameraClosed;
                anylineScanView.CameraView.CameraError -= CameraView_CameraError;

                await anylineScanView.StopCameraAsync();

                anylineScanView.Dispose();
            }
        }

        protected override async void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);

            if (anylineScanView == null) return;

            // register events
            if (anylineScanView != null)
            {
                anylineScanView.CameraView.CameraOpened -= CameraView_CameraOpened;
                anylineScanView.CameraView.CameraClosed -= CameraView_CameraClosed;
                anylineScanView.CameraView.CameraError -= CameraView_CameraError;

                anylineScanView.CameraView.CameraOpened += CameraView_CameraOpened;
                anylineScanView.CameraView.CameraClosed += CameraView_CameraClosed;
                anylineScanView.CameraView.CameraError += CameraView_CameraError;

                Window.Current.VisibilityChanged -= Current_VisibilityChanged;
                Window.Current.VisibilityChanged += Current_VisibilityChanged;
            }

            ApplicationView.GetForCurrentView().Title = (e.Parameter as ExamplePlugin).Name;

            string jsonConfig = (e.Parameter as ExamplePlugin).JSONConfigFile;
            
			// initialize Anyline
			await AnylineScanView.InitAsync("Assets/myconfig.json");
			
            // the correct plugin is loaded according to the .json config file informed
            scanViewPlugin = anylineScanView.ScanViewPlugin;

            scanViewPlugin.AddScanResultListener(this);

            if (scanViewPlugin is PhotoCaptureViewPlugin photoCapturePlugin)
            {
                photoCapturePlugin.PhotoCaptureListener = this;
                photoCapturePlugin.PhotoCaptureTarget = PhotoCaptureTarget.File;
            }

            anylineScanView?.StartCamera();
        }

        public void OnResult(LicensePlateScanResult result)
        {
            OpenResultsPage(result.CreatePropertyDictionary());
        }

        public void OnResult(BarcodeScanResult result)
        {
            OpenResultsPage(result.CreatePropertyDictionary());
        }

        public void OnResult(MeterScanResult result)
        {
            OpenResultsPage(result.CreatePropertyDictionary());
        }

        public void OnResult(OCRScanResult result)
        {
            OpenResultsPage(result.CreatePropertyDictionary());
        }

        public void OnResult(ScanResult<ID> result)
        {
            OpenResultsPage(result.CreatePropertyDictionary());
        }

        private void OpenResultsPage(Dictionary<string, object> dictionary)
        {
            /// in our example app, we dynamically extract result values from the object via reflection.
            /// Usually, you can just use the result on the object type that matches your ScanPlugin type (e.g. ALMeterResult for ALMeterScanPlugin etc.) and access the properties directly
            (Window.Current.Content as Frame).Navigate(typeof(ResultsPage), dictionary);
        }

        public void OnPhotoCaptured(AnylineImage anylineImage)
        {
            var result = new Dictionary<string, object> { };
            result.Add("Image result", anylineImage);
            (Window.Current.Content as Frame).Navigate(typeof(ResultsPage), result);
        }

        public async void OnPhotoToFile(StorageFile file)
        {
            BitmapImage bitmapImage = new BitmapImage();
            FileRandomAccessStream stream = (FileRandomAccessStream)await file.OpenAsync(FileAccessMode.Read);
            bitmapImage.SetSource(stream);

            var result = new Dictionary<string, object> { };
            result.Add("Image result", bitmapImage);
            (Window.Current.Content as Frame).Navigate(typeof(ResultsPage), result);
        }
    }
}
AnylineOCR Plugin : VIN Scan Mode (Documentation)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
{
  "camera": {
    "captureResolution": "1080p",
    "zoomGesture": true
  },
  "flash": {
    "mode": "manual",
    "alignment": "bottom_right",
    "imageOn": "flash_on",
    "imageOff": "flash_off"
  },
  "viewPlugin": {
    "plugin": {
      "id": "VIN_ID",
      "ocrPlugin": {
        "vinConfig":{
        }
      }
    },
    "cutoutConfig": {
      "style": "rect",
      "maxWidthPercent": "70%",
      "alignment": "top_half",
      "ratioFromSize": {
        "width": 62,
        "height": 9
      },
      "strokeWidth": 2,
      "strokeColor": "FFFFFF",
      "cornerRadius": 4,
      "outerColor": "000000",
      "outerAlpha": 0.3,
      "feedbackStrokeColor": "0099FF"
    },
    "scanFeedback": {
      "animation": "traverse_multi",
      "animationDuration": 250,
      "style": "contour_rect",
      "strokeWidth": 2,
      "strokeColor": "0099FF",
      "fillColor": "220099FF",
      "beepOnResult": true,
      "vibrateOnResult": true,
      "blinkAnimationOnResult": true
    },
    "cancelOnResult": true,
    "reportingEnabled": true
  }

}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;

import io.anyline.plugin.ScanResultListener;
import io.anyline.plugin.ocr.OcrScanResult;
import io.anyline.plugin.ocr.OcrScanViewPlugin;
import io.anyline.view.ScanView;
import io.anyline.AnylineSDK;


public class ScanVINActiviy extends Activity {

    private ScanView scanView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.anyline_scan_view);

        scanView = findViewById(R.id.scan_view);

      	// This must be called before doing anything Anyline-related! 
	// Try/Catch this to check whether or not your license key is valid! 
	try {
    	    AnylineSDK.init(getString(getString(R.string.anyline_license_key)), this);
	} catch (LicenseException e) {
    	    // handle exception
	}

        try {
            scanView.init("vin_view_config.json");
        } catch (Exception e) {
            e.printStackTrace();
        }

        OcrScanViewPlugin scanViewPlugin = (OcrScanViewPlugin) scanView.getScanViewPlugin();

        scanViewPlugin.addScanResultListener(new ScanResultListener<OcrScanResult>() {
            @Override
            public void onResult(OcrScanResult anylineOcrResult) {

                String result = anylineOcrResult.getResult();
                Toast.makeText(getApplicationContext(), result.toString(), Toast.LENGTH_LONG).show();
            }

        });

    }

    @Override
    protected void onResume() {
        super.onResume();
        scanView.start();
    }


    @Override
    protected void onPause() {
        super.onPause();
        scanView.stop();
        scanView.releaseCameraInBackground();
    }
}
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// The Anyline plugin used for OCR
@property (nonatomic, strong) ALOCRScanViewPlugin *vinScanViewPlugin;
@property (nonatomic, strong) ALOCRScanPlugin *vinScanPlugin;
@property (nullable, nonatomic, strong) ALScanView *scanView;

@end

@implementation ALVINScanViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Set the background color to black to have a nicer transition
    self.view.backgroundColor = [UIColor blackColor];
    self.title = @"VIN";
    // 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);
    
    NSError *licenseError = nil;
    //Initialize the Anyline License
    [AnylineSDK setupWithLicenseKey:kVINLicenseKey error:&licenseError];
    if (licenseError) {
        //Handle errors here
    }
    
    ALVINConfig *config = [[ALVINConfig alloc] init];
    
    NSError *error = nil;
    
    self.vinScanPlugin = [[ALOCRScanPlugin alloc] initWithPluginID:@"ANYLINE_OCR"
                                                          delegate:self
                                                         ocrConfig:config
                                                             error:&error];
    NSAssert(self.vinScanPlugin, @"Setup Error: %@", error.debugDescription);
    [self.vinScanPlugin addInfoDelegate:self];
    
    //Set a custom Anyline JSON config
    NSString *confPath = [[NSBundle mainBundle] pathForResource:@"vin_capture_config" ofType:@"json"];
    ALScanViewPluginConfig *scanViewPluginConfig = [ALScanViewPluginConfig configurationFromJsonFilePath:confPath];
    
    self.vinScanViewPlugin = [[ALOCRScanViewPlugin alloc] initWithScanPlugin:self.vinScanPlugin
                                                        scanViewPluginConfig:scanViewPluginConfig];
    NSAssert(self.vinScanViewPlugin, @"Setup Error: %@", error.debugDescription);
    
    self.scanView = [[ALScanView alloc] initWithFrame:frame scanViewPlugin:self.vinScanViewPlugin];
    
    //Enable Zoom Gesture
    [self.scanView enableZoomPinchGesture:YES];
    
    // After setup is complete we add the scanView to the view of this view controller
    [self.view addSubview:self.scanView];
    [self.view sendSubviewToBack:self.scanView];
    
    //Start Camera:
    [self.scanView startCamera];
    [self startListeningForMotion];
}

/*
 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.
    NSError *error;
    BOOL success = [self.vinScanViewPlugin startAndReturnError:&error];
    if( !success ) {
        // Something went wrong. The error object contains the error description
        NSAssert(success, @"Start Scanning Error: %@", error.debugDescription);
    }
}

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

#pragma mark -- anylineOCRScanPlugin

/*
 This is the main delegate method Anyline uses to report its results
 */
- (void)anylineOCRScanPlugin:(ALOCRScanPlugin *)anylineOCRScanPlugin
               didFindResult:(ALOCRResult *)result {
    //Handle the result here:
    NSLog(@"Result: %@", result.result);
}

- (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
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
using Anyline.SDK.Models;
using Anyline.SDK.Plugins;
using Anyline.SDK.Plugins.Ocr;
using Anyline.SDK.Util;
using Anyline.SDK.ViewPlugins;
using Anyline.SDK.Views;
using Anyline_Windows_UWP_Examples.Model;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Windows.Foundation;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;


namespace Anyline_Windows_UWP_Examples
{
    /// <summary>
    /// This page is used to setup the plugin, open the camera and start scanning
    /// it has to implement the IScanResultListener for each Plugin that will be used
    /// </summary>
    public sealed partial class ScanPage : Page, IScanResultListener<OcrScanResult>
	{
		string myLicenseKey = "INSERT LICENSE KEY HERE";

		protected override async void OnNavigatedTo(NavigationEventArgs e)
		{
			base.OnNavigatedTo(e);

			// register camera events
			AnylineScanView.CameraView.CameraOpened += CameraView_CameraOpened;
			AnylineScanView.CameraView.CameraClosed += CameraView_CameraClosed;

			// register visibility changed event
			Window.Current.VisibilityChanged += Current_VisibilityChanged;
			
			// make sure the license is initalized (needs only to be done once in the app lifetime)
			AnylineSDK.Init(myLicenseKey);
			// initialize Anyline
			await AnylineScanView.InitAsync("Assets/myconfig.json");

			// attach the result listener to the ScanViewPlugin to receive scanning results
			(AnylineScanView.ScanViewPlugin as OcrScanViewPlugin)?.AddScanResultListener(this);

			// opens the camera
			AnylineScanView.StartCamera();
		}

		private async void Current_VisibilityChanged(object sender, Windows.UI.Core.VisibilityChangedEventArgs args)
		{
			if (AnylineScanView == null) return;

			if (args.Visible == false)
			{
				await AnylineScanView.StopCameraAsync();
			}
			if (args.Visible == true)
			{
				AnylineScanView.StartCamera();
			}
		}

		private void CameraView_CameraOpened(object sender, Size args)
		{
			AnylineScanView.StartScanning();
		}

		private void CameraView_CameraClosed(object sender, bool success)
		{
			AnylineScanView.StopScanning();
		}

		public void OnResult(ScanResult<OcrScanResult> result)
		{
			Debug.WriteLine($"(APP) Scan result: {result.Result}");
		}
	}
}
AnylineOCR Plugin : Shipping Container Scan Mode (Documentation)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
{
  "camera": {
    "captureResolution": "1080",
    "zoomGesture": true
  },
  "flash": {
    "mode": "manual",
    "alignment": "bottom_right",
    "imageOn": "flash_on",
    "imageOff": "flash_off"
  },
  "viewPlugin": {
    "plugin" : {
      "id" : "CONTAINER",
      "ocrPlugin" : {
        "containerConfig":{
          "scanMode": "horizontal"
        }
      }
    },
    "cutoutConfig": {
      "style": "rect",
      "maxWidthPercent": "80%",
      "alignment": "top_half",
      "width": 720,
      "ratioFromSize": {
        "width": 720,
        "height": 144
      },
      "strokeWidth": 2,
      "cornerRadius": 4,
      "strokeColor": "FFFFFF",
      "outerColor": "000000",
      "outerAlpha": 0.3,
      "feedbackStrokeColor": "0099FF",
      "offset": {
        "x": 0,
        "y": -15
      }
    },
    "scanFeedback": {
      "style": "CONTOUR_RECT",
      "strokeWidth": 2,
      "strokeColor": "0099FF",
      "fillColor" : "220099FF",
      "beepOnResult": true,
      "vibrateOnResult": true,
      "blinkAnimationOnResult": true
    },
    "cancelOnResult": true
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;

import io.anyline.plugin.ScanResultListener;
import io.anyline.plugin.ocr.OcrScanResult;
import io.anyline.plugin.ocr.OcrScanViewPlugin;
import io.anyline.view.ScanView;
import io.anyline.AnylineSDK;


public class ScanShippingContainerActiviy extends Activity {

    private ScanView scanView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.anyline_scan_view);

        scanView = findViewById(R.id.scan_view);

      	// This must be called before doing anything Anyline-related! 
	// Try/Catch this to check whether or not your license key is valid! 
	try {
    	    AnylineSDK.init(getString(getString(R.string.anyline_license_key)), this);
	} catch (LicenseException e) {
    	    // handle exception
	}

        try {
            scanView.init("shipping_container_view_config.json");
        } catch (Exception e) {
            e.printStackTrace();
        }

        OcrScanViewPlugin scanViewPlugin = (OcrScanViewPlugin) scanView.getScanViewPlugin();

        scanViewPlugin.addScanResultListener(new ScanResultListener<OcrScanResult>() {
            @Override
            public void onResult(OcrScanResult anylineOcrResult) {

                String result = anylineOcrResult.getResult();
                Toast.makeText(getApplicationContext(), result.toString(), Toast.LENGTH_LONG).show();
            }

        });

    }

    @Override
    protected void onResume() {
        super.onResume();
        scanView.start();
    }


    @Override
    protected void onPause() {
        super.onPause();
        scanView.stop();
        scanView.releaseCameraInBackground();
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
using Anyline.SDK.Models;
using Anyline.SDK.Plugins;
using Anyline.SDK.Plugins.Ocr;
using Anyline.SDK.Util;
using Anyline.SDK.ViewPlugins;
using Anyline.SDK.Views;
using Anyline_Windows_UWP_Examples.Model;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Windows.Foundation;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;


namespace Anyline_Windows_UWP_Examples
{
    /// <summary>
    /// This page is used to setup the plugin, open the camera and start scanning
    /// it has to implement the IScanResultListener for each Plugin that will be used
    /// </summary>
    public sealed partial class ScanPage : Page, IScanResultListener<OcrScanResult>
	{
		string myLicenseKey = "INSERT LICENSE KEY HERE";

		protected override void OnNavigatedTo(NavigationEventArgs e)
		{
			base.OnNavigatedTo(e);

			// register camera events
			AnylineScanView.CameraView.CameraOpened += CameraView_CameraOpened;
			AnylineScanView.CameraView.CameraClosed += CameraView_CameraClosed;

			// register visibility changed event
			Window.Current.VisibilityChanged += Current_VisibilityChanged;

			// make sure the license is initalized (needs only to be done once in the app lifetime)
			AnylineSDK.Init(myLicenseKey);
			// initialize Anyline
			await AnylineScanView.InitAsync("Assets/mro_config_shipping_container.json");

			// attach the result listener to the ScanViewPlugin to receive scanning results
			(AnylineScanView.ScanViewPlugin as OcrScanViewPlugin)?.AddScanResultListener(this);

			// opens the camera
			AnylineScanView.StartCamera();
		}

		private async void Current_VisibilityChanged(object sender, Windows.UI.Core.VisibilityChangedEventArgs args)
		{
			if (AnylineScanView == null) return;

			if (args.Visible == false)
			{
				await AnylineScanView.StopCameraAsync();
			}
			if (args.Visible == true)
			{
				AnylineScanView.StartCamera();
			}
		}

		private void CameraView_CameraOpened(object sender, Size args)
		{
			AnylineScanView.StartScanning();
		}

		private void CameraView_CameraClosed(object sender, bool success)
		{
			AnylineScanView.StopScanning();
		}

		public void OnResult(ScanResult<OcrScanResult> result)
		{
			Debug.WriteLine($"(APP) Scan result: {result.Result}");
		}
	}
}
AnylineOCR Plugin : Cattle Tag Scan Mode (Documentation)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
{
  "camera": {
    "captureResolution": "720",
    "zoomGesture": true
  },
  "flash": {
    "mode": "manual",
    "alignment": "bottom_right"
  },
  "viewPlugin": {
    "plugin": {
      "id": "CATTLE_TAG",
        "ocrPlugin": {
          "cattleTagConfig":{
          }
        }
    },
    "cutoutConfig": {
      "style": "rect",
      "maxWidthPercent": "80%",
      "maxHeightPercent": "80%",
      "alignment": "center",
      "width": 600,
      "ratioFromSize": {
        "width": 1,
        "height": 1
      },
      "strokeWidth": 2,
      "cornerRadius": 10,
      "strokeColor": "FFFFFF",
      "outerColor": "000000",
      "outerAlpha": 0.3,
      "feedbackStrokeColor": "0099FF",
      "cropPadding": {
        "x": 60,
        "y": 60
      },
      "cropOffset": {
        "x": 0,
        "y": 0
      }
    },
    "cancelOnResult": false,
    "scanFeedback": {
      "style": "rect",
      "strokeWidth": 2,
      "strokeColor": "0099FF",
      "fillColor": "330099FF",
      "cornerRadius": 0,
      "beepOnResult": true,
      "vibrateOnResult": true,
      "blinkAnimationOnResult": true
    }
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;

import io.anyline.plugin.ScanResultListener;
import io.anyline.plugin.ocr.OcrScanResult;
import io.anyline.plugin.ocr.OcrScanViewPlugin;
import io.anyline.view.ScanView;
import io.anyline.AnylineSDK;


public class ScanCattleTagActiviy extends Activity {

    private ScanView scanView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.anyline_scan_view);

        scanView = findViewById(R.id.scan_view);

      	// This must be called before doing anything Anyline-related! 
	// Try/Catch this to check whether or not your license key is valid! 
	try {
    	    AnylineSDK.init(getString(getString(R.string.anyline_license_key)), this);
	} catch (LicenseException e) {
    	    // handle exception
	}

        try {
            scanView.init("cattle_tag_view_config.json");
        } catch (Exception e) {
            e.printStackTrace();
        }

        OcrScanViewPlugin scanViewPlugin = (OcrScanViewPlugin) scanView.getScanViewPlugin();

        scanViewPlugin.addScanResultListener(new ScanResultListener<OcrScanResult>() {
            @Override
            public void onResult(OcrScanResult anylineOcrResult) {

                String result = anylineOcrResult.getResult();
                Toast.makeText(getApplicationContext(), result.toString(), Toast.LENGTH_LONG).show();
            }

        });

    }

    @Override
    protected void onResume() {
        super.onResume();
        scanView.start();
    }


    @Override
    protected void onPause() {
        super.onPause();
        scanView.stop();
        scanView.releaseCameraInBackground();
    }
}
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// The Anyline plugin used for OCR
@property (nonatomic, strong) ALOCRScanViewPlugin *cattleTagScanViewPlugin;
@property (nonatomic, strong) ALOCRScanPlugin *cattleTagScanPlugin;
@property (nullable, nonatomic, strong) ALScanView *scanView;

@end

@implementation ALCattleTagScanViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Set the background color to black to have a nicer transition
    self.view.backgroundColor = [UIColor blackColor];
    self.title = @"CattleTag";
    // 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);
    
    NSError *licenseError = nil;
    //Initialize the Anyline License
    [AnylineSDK setupWithLicenseKey:kCattleTagLicenseKey error:&licenseError];
    if (licenseError) {
        //Handle errors here
    }
    
    ALCattleTagConfig *config = [[ALCattleTagConfig alloc] init];
    
    NSError *error = nil;
    
    self.cattleTagScanPlugin = [[ALOCRScanPlugin alloc] initWithPluginID:@"ANYLINE_OCR"
                                                                delegate:self
                                                               ocrConfig:config
                                                                   error:&error];
    NSAssert(self.cattleTagScanPlugin, @"Setup Error: %@", error.debugDescription);
    [self.cattleTagScanPlugin addInfoDelegate:self];
    
    //Set a custom Anyline JSON config
    NSString *confPath = [[NSBundle mainBundle] pathForResource:@"cattle_tag_capture_config" ofType:@"json"];
    ALScanViewPluginConfig *scanViewPluginConfig = [ALScanViewPluginConfig configurationFromJsonFilePath:confPath];
    
    self.cattleTagScanViewPlugin = [[ALOCRScanViewPlugin alloc] initWithScanPlugin:self.cattleTagScanPlugin
                                                              scanViewPluginConfig:scanViewPluginConfig];
    NSAssert(self.cattleTagScanViewPlugin, @"Setup Error: %@", error.debugDescription);
    
    self.scanView = [[ALScanView alloc] initWithFrame:frame scanViewPlugin:self.cattleTagScanViewPlugin];
    
    //Enable Zoom Gesture
    [self.scanView enableZoomPinchGesture:YES];
    
    // After setup is complete we add the scanView to the view of this view controller
    [self.view addSubview:self.scanView];
    [self.view sendSubviewToBack:self.scanView];
    
    //Start Camera:
    [self.scanView startCamera];
    [self startListeningForMotion];
}

/*
 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.
    NSError *error;
    BOOL success = [self.cattleTagScanViewPlugin startAndReturnError:&error];
    if( !success ) {
        // Something went wrong. The error object contains the error description
        NSAssert(success, @"Start Scanning Error: %@", error.debugDescription);
    }
}

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

#pragma mark -- anylineOCRScanPlugin

/*
 This is the main delegate method Anyline uses to report its results
 */
- (void)anylineOCRScanPlugin:(ALOCRScanPlugin *)anylineOCRScanPlugin
               didFindResult:(ALOCRResult *)result {
    //Handle the result here:
    NSLog(@"Result: %@", result.result);
}

- (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
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
using Anyline.SDK.Models;
using Anyline.SDK.Plugins;
using Anyline.SDK.Plugins.Ocr;
using Anyline.SDK.Util;
using Anyline.SDK.ViewPlugins;
using Anyline.SDK.Views;
using Anyline_Windows_UWP_Examples.Model;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Windows.Foundation;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;


namespace Anyline_Windows_UWP_Examples
{
    /// <summary>
    /// This page is used to setup the plugin, open the camera and start scanning
    /// it has to implement the IScanResultListener for each Plugin that will be used
    /// </summary>
    public sealed partial class ScanPage : Page, IScanResultListener<OcrScanResult>
	{
		string myLicenseKey = "INSERT LICENSE KEY HERE";

		protected async override void OnNavigatedTo(NavigationEventArgs e)
		{
			base.OnNavigatedTo(e);

			// register camera events
			AnylineScanView.CameraView.CameraOpened += CameraView_CameraOpened;
			AnylineScanView.CameraView.CameraClosed += CameraView_CameraClosed;

			// register visibility changed event
			Window.Current.VisibilityChanged += Current_VisibilityChanged;

			// make sure the license is initalized (needs only to be done once in the app lifetime)
			AnylineSDK.Init(myLicenseKey);
			// initialize Anyline
			await AnylineScanView.InitAsync("Assets/others_config_cow_tag.json");

			// attach the result listener to the ScanViewPlugin to receive scanning results
			(AnylineScanView.ScanViewPlugin as OcrScanViewPlugin)?.AddScanResultListener(this);

			// opens the camera
			AnylineScanView.StartCamera();
		}

		private async void Current_VisibilityChanged(object sender, Windows.UI.Core.VisibilityChangedEventArgs args)
		{
			if (AnylineScanView == null) return;

			if (args.Visible == false)
			{
				await AnylineScanView.StopCameraAsync();
			}
			if (args.Visible == true)
			{
				AnylineScanView.StartCamera();
			}
		}

		private void CameraView_CameraOpened(object sender, Size args)
		{
			AnylineScanView.StartScanning();
		}

		private void CameraView_CameraClosed(object sender, bool success)
		{
			AnylineScanView.StopScanning();
		}

		public void OnResult(ScanResult<OcrScanResult> result)
		{
			Debug.WriteLine($"(APP) Scan result: {result.Result}");
		}
	}
}
AnylineOCR Plugin AUTO: Scrabble
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
{
  "camera": {
    "captureResolution": "720"
  },
  "flash": {
    "mode": "manual",
    "alignment": "bottom_right",
    "imageOn": "flash_on",
    "imageOff": "flash_off"
  },
  "viewPlugin": {
    "cutoutConfig": {
      "style": "rect",
      "maxWidthPercent": "80%",
      "maxHeightPercent": "80%",
      "alignment": "center",
      "width": 600,
      "ratioFromSize": {
        "width": 4,
        "height": 1
      },
      "strokeWidth": 2,
      "cornerRadius": 4,
      "strokeColor": "FFFFFF",
      "outerColor": "000000",
      "outerAlpha": 0.3,
      "feedbackStrokeColor": "0099FF"
    },
    "scanFeedback": {
      "style": "contour_point",
      "strokeWidth": 2,
      "strokeColor": "0099FF",
      "fillColor": "220099FF",
      "beepOnResult": true,
      "vibrateOnResult": true,
      "blinkAnimationOnResult": true
    },
    "cancelOnResult": true
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;

import io.anyline.plugin.ScanResultListener;
import io.anyline.plugin.ocr.OcrScanResult;
import io.anyline.plugin.ocr.OcrScanViewPlugin;
import io.anyline.view.ScanView;
import io.anyline.AnylineSDK;


public class ScanScrabbleActiviy extends Activity {

    private ScanView scanView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.anyline_scan_view);

        scanView = findViewById(R.id.scan_view);

      	// This must be called before doing anything Anyline-related! 
	// Try/Catch this to check whether or not your license key is valid! 
	try {
    	    AnylineSDK.init(getString(getString(R.string.anyline_license_key)), this);
	} catch (LicenseException e) {
    	    // handle exception
	}

        try {
            scanView.init("scrable_view_config.json");
        } catch (Exception e) {
            e.printStackTrace();
        }

        OcrScanViewPlugin scanViewPlugin = (OcrScanViewPlugin) scanView.getScanViewPlugin();

        scanViewPlugin.addScanResultListener(new ScanResultListener<OcrScanResult>() {
            @Override
            public void onResult(OcrScanResult anylineOcrResult) {

                String result = anylineOcrResult.getResult();
                Toast.makeText(getApplicationContext(), result.toString(), Toast.LENGTH_LONG).show();
            }

        });

    }

    @Override
    protected void onResume() {
        super.onResume();
        scanView.start();
    }


    @Override
    protected void onPause() {
        super.onPause();
        scanView.stop();
        scanView.releaseCameraInBackground();
    }
}
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#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);
    
    NSError *licenseError = nil;
    //Initialize the Anyline License
    [AnylineSDK setupWithLicenseKey:kScrabbleLicenseKey error:&licenseError];
    if (licenseError) {
        //Handle errors here
    }
    
    ALOCRConfig *config = [[ALOCRConfig alloc] init];
    config.scanMode = ALAuto;
    config.charWhiteList = @"ABCDEFGHIJKLMNOPQRSTUVWXYZÄÜÖ";
    config.validationRegex = @"^[A-ZÄÜÖ]{7,10}$";
    
    NSError *error = nil;
    
    self.scrabbleScanPlugin = [[ALOCRScanPlugin alloc] initWithPluginID:@"ANYLINE_OCR"
                                                               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
AnylineOCR Plugin LINE: Record Numbers
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
{
  "camera": {
    "captureResolution": "720"
  },
  "flash": {
    "mode": "manual",
    "alignment": "bottom_right",
    "imageOn": "flash_on",
    "imageOff": "flash_off"
  },
  "viewPlugin": {
    "plugin" : {
      "id" : "OCR_RECORD",
      "ocrPlugin" : {
        "ocrConfig": {
          "scanMode" : "LINE",
          "languages" : ["eng_no_dict.traineddata", "deu.traineddata"],
          "charWhitelist": "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-.",
          "minCharHeight":15,
          "maxCharHeight":70,
          "minConfidence": 75,
          "removeSmallContours":false
        }
      }
    },
    "cutoutConfig": {
      "style": "rect",
      "maxWidthPercent": "80%",
      "maxHeightPercent": "80%",
      "alignment": "center",
      "width": 340,
      "ratioFromSize": {
        "width": 4,
        "height": 1
      },
      "strokeWidth": 2,
      "cornerRadius": 10,
      "strokeColor": "FFFFFF",
      "outerColor": "000000",
      "outerAlpha": 0.3,
      "feedbackStrokeColor": "0099FF"
    },
    "scanFeedback": {
      "animationDuration": 400,
      "style": "contour_point",
      "strokeWidth": 2,
      "strokeColor": "0099FF",
      "fillColor": "220099FF",
      "beepOnResult": true,
      "vibrateOnResult": true,
      "blinkAnimationOnResult": true
    },
    "cancelOnResult": true
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;

import io.anyline.plugin.ScanResultListener;
import io.anyline.plugin.ocr.OcrScanResult;
import io.anyline.plugin.ocr.OcrScanViewPlugin;
import io.anyline.view.ScanView;
import io.anyline.AnylineSDK;


public class ScanRecordActiviy extends Activity {

    private ScanView scanView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.anyline_scan_view);

        scanView = findViewById(R.id.scan_view);

      	// This must be called before doing anything Anyline-related! 
	// Try/Catch this to check whether or not your license key is valid! 
	try {
    	    AnylineSDK.init(getString(getString(R.string.anyline_license_key)), this);
	} catch (LicenseException e) {
    	    // handle exception
	}

        try {
            scanView.init("record_view_config.json");
        } catch (Exception e) {
            e.printStackTrace();
        }

        OcrScanViewPlugin scanViewPlugin = (OcrScanViewPlugin) scanView.getScanViewPlugin();

        scanViewPlugin.addScanResultListener(new ScanResultListener<OcrScanResult>() {
            @Override
            public void onResult(OcrScanResult anylineOcrResult) {

                String result = anylineOcrResult.getResult();
                Toast.makeText(getApplicationContext(), result.toString(), Toast.LENGTH_LONG).show();
            }

        });

    }

    @Override
    protected void onResume() {
        super.onResume();
        scanView.start();
    }


    @Override
    protected void onPause() {
        super.onPause();
        scanView.stop();
        scanView.releaseCameraInBackground();
    }
}
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#import "ALRecordNumberScanViewController.h"
#import <Anyline/Anyline.h>
#import "ALBaseViewController.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 kRecordNumberLicenseKey = kDemoAppLicenseKey;
// The controller has to conform to <AnylineOCRModuleDelegate> to be able to receive results
@interface ALRecordNumberScanViewController ()<ALOCRScanPluginDelegate, ALInfoDelegate>

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

@end

@implementation ALRecordNumberScanViewController
/*
 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 = @"Record Number";
    
    // 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);
    
    NSError *licenseError = nil;
    //Initialize the Anyline License
    [AnylineSDK setupWithLicenseKey:kVoucherCodeLicenseKey error:&licenseError];
    if (licenseError) {
        //Handle errors here
    }
    
    ALOCRConfig *config = [[ALOCRConfig alloc] init];
    config.charHeight = ALRangeMake(22, 105);
    config.charWhiteList = @"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-.";
    config.minConfidence = 70;
    config.validationRegex = @"^([A-Z]+\\s*-*\\s*)?[0-9A-Z-\\s\\.]{3,}$";
    config.scanMode = ALLine;
    
    NSError *error = nil;
    
    self.recordScanPlugin = [[ALOCRScanPlugin alloc] initWithPluginID:@"ANYLINE_OCR"
                                                             delegate:self
                                                            ocrConfig:config
                                                                error:&error];
    NSAssert(self.recordScanPlugin, @"Setup Error: %@", error.debugDescription);
    [self.recordScanPlugin addInfoDelegate:self];
    
    NSString *confPath = [[NSBundle mainBundle] pathForResource:@"record_number_config" ofType:@"json"];
    ALScanViewPluginConfig *scanViewPluginConfig = [ALScanViewPluginConfig configurationFromJsonFilePath:confPath];
    
    self.recordScanViewPlugin = [[ALOCRScanViewPlugin alloc] initWithScanPlugin:self.recordScanPlugin
                                                           scanViewPluginConfig:scanViewPluginConfig];
    NSAssert(self.recordScanViewPlugin, @"Setup Error: %@", error.debugDescription);
    
    self.scanView = [[ALScanView alloc] initWithFrame:frame scanViewPlugin:self.recordScanViewPlugin];
    
    // After setup is complete we add the module to the view of this view controller
    [self.view addSubview:self.scanView];
    [self.view sendSubviewToBack:self.scanView];
    
    //Start Camera:
    [self.scanView startCamera];
    [self startListeningForMotion];
    
    self.controllerType = ALScanHistoryRecordNumber;
}

/*
 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.recordScanViewPlugin.cutoutRect.origin.y +
     self.recordScanViewPlugin.cutoutRect.size.height +
     self.recordScanViewPlugin.frame.origin.y +
     120];
}

/*
 Cancel scanning to allow the module to clean up
 */
- (void)viewWillDisappear:(BOOL)animated {
    [self.recordScanViewPlugin 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.recordScanViewPlugin startAndReturnError:&error];
    if( !success ) {
        // Something went wrong. The error object contains the error description
        NSAssert(success, @"Start Scanning Error: %@", error.debugDescription);
    }
    
    self.startTime = CACurrentMediaTime();
}

#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.recordScanViewPlugin completion:^{
        ALBaseViewController *vc = [[ALBaseViewController alloc] init];
        vc.result = result.result;
        NSString *url = [NSString stringWithFormat:@"https://www.google.at/search?q=\"%@\" site:discogs.com OR site:musbrainz.org OR site:allmusic.com", result.result];
        [vc startWebSearchWithURL:url];
        [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.recordScanViewPlugin];
    }
}


@end
Barcode Plugin
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
{
  "camera": {
    "captureResolution": "1080p"
  },
  "flash": {
    "mode": "auto",
    "alignment": "bottom_right"
  },
  "viewPlugin": {
    "plugin": {
      "id": "Barcode_ID",
      "barcodePlugin": {
      }
    },
    "cutoutConfig": {
      "style": "rect",
      "maxWidthPercent": "80%",
      "maxHeightPercent": "80%",
      "alignment": "center",
      "ratioFromSize": {
        "width": 100,
        "height": 80
      },
      "strokeWidth": 1,
      "cornerRadius": 3,
      "strokeColor": "FFFFFF",
      "outerColor": "000000",
      "outerAlpha": 0.3,
      "feedbackStrokeColor": "0099FF"
    },
    "scanFeedback": {
      "style": "rect",
      "strokeColor": "0099FF",
      "fillColor": "220099FF",
      "animationDuration": 150,
      "blinkOnResult": true,
      "beepOnResult": true,
      "vibrateOnResult": true
    },
    "cancelOnResult": true
  }}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import android.app.Activity;
import android.os.Bundle;
import android.widget.Toast;

import io.anyline.plugin.ScanResultListener;
import io.anyline.plugin.barcode.BarcodeScanResult;
import io.anyline.plugin.barcode.BarcodeScanViewPlugin;
import io.anyline.view.ScanView;
import io.anyline.AnylineSDK;


public class ScanBarcodeActivity extends Activity {

    private ScanView scanView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_anyline_scan_view);

        scanView = findViewById(R.id.scan_view);

      	// This must be called before doing anything Anyline-related! 
	// Try/Catch this to check whether or not your license key is valid! 
	try {
    	    AnylineSDK.init(getString(getString(R.string.anyline_license_key)), this);
	} catch (LicenseException e) {
    	    // handle exception
	}

        try {
            scanView.init("barcode_view_config.json");
        } catch (Exception e) {
            e.printStackTrace();
        }

        BarcodeScanViewPlugin scanViewPlugin = (BarcodeScanViewPlugin) scanView.getScanViewPlugin();

        scanViewPlugin.addScanResultListener(new ScanResultListener<BarcodeScanResult>() {
            @Override
            public void onResult(BarcodeScanResult result) {
                Toast.makeText(getApplicationContext(), result.toString(), Toast.LENGTH_LONG).show();
            }

        });

    }

    @Override
    protected void onResume() {
        super.onResume();
        scanView.start();
    }


    @Override
    protected void onPause() {
        super.onPause();
        scanView.stop();
        scanView.releaseCameraInBackground();
    }
}
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
// This is the license key for the examples project used to set up Anyline below
NSString * const kBarcodeScanLicenseKey = kDemoAppLicenseKey;

// The controller has to conform to <AnylineBarcodeModuleDelegate> to be able to receive results
@interface ALMultiformatBarcodeScanViewController() <ALBarcodeScanPluginDelegate, ALScanViewPluginDelegate>
// The Anyline plugin used to scan barcodes
@property (nonatomic, strong) ALBarcodeScanPlugin *barcodeScanPlugin;
@property (nonatomic, strong) ALBarcodeScanViewPlugin *barcodeScanViewPlugin;
@property (nullable, nonatomic, strong) ALScanView *scanView;

// A debug label to show scanned results
@property (nonatomic, strong) UILabel *resultLabel;
@end

@implementation ALMultiformatBarcodeScanViewController

/*
 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 = @"Barcodes";

    CGRect frame = [self scanViewFrame];

    NSError *licenseError = nil;
    
    //Initialize Anyline
    [AnylineSDK setupWithLicenseKey:kBarcodeScanLicenseKey error:&licenseError];
    if (licenseError) {
        //Handle errors here
        NSLog(@" *** Error: setup error: %@", licenseError);
    }

    //Add Barcode Scan Plugin (Scan Process)
    NSError *error = nil;

    self.barcodeScanPlugin = [[ALBarcodeScanPlugin alloc] initWithPluginID:@"BARCODE" delegate:self error:&error];
    NSAssert(self.barcodeScanPlugin, @"Setup Error: %@", error.debugDescription);

    //Set Barcode Formats
    [self.barcodeScanPlugin setBarcodeFormatOptions:@[kCodeTypePDF417]];

    //Add Barcode Scan View Plugin (Scan UI)
    self.barcodeScanViewPlugin = [[ALBarcodeScanViewPlugin alloc] initWithScanPlugin:self.barcodeScanPlugin];
    NSAssert(self.barcodeScanViewPlugin, @"Setup Error: %@", error.debugDescription);
    [self.barcodeScanViewPlugin addScanViewPluginDelegate:self];

    //Add ScanView (Camera and Flashbutton)
    self.scanView = [[ALScanView alloc] initWithFrame:frame scanViewPlugin:self.barcodeScanViewPlugin];
    
    [self.view addSubview:self.scanView];
    [self.scanView startCamera];

    self.barcodeScanViewPlugin.translatesAutoresizingMaskIntoConstraints = NO;

    [[self view] addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scanView]|" options:0 metrics:nil views:@{@"scanView" : self.scanView}]];
    id topGuide = self.topLayoutGuide;
    [[self view] addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[topGuide]-0-[scanView]|" options:0 metrics:nil views:@{@"scanView" : self.scanView, @"topGuide" : topGuide}]];

    // The resultLabel is used as a debug view to see the scanned results. We set its text
    // in anylineBarcodeModuleView:didFindScanResult:atImage below
    self.resultLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height - 100, self.view.frame.size.width, 50)];
    self.resultLabel.textAlignment = NSTextAlignmentCenter;
    self.resultLabel.textColor = [UIColor whiteColor];
    self.resultLabel.font = [UIFont fontWithName:@"HelveticaNeue-UltraLight" size:35.0];
    self.resultLabel.adjustsFontSizeToFitWidth = YES;

    [self.view addSubview:self.resultLabel];

    self.barcodeScanPlugin.multiBarcode = YES;
}

/*
 This method will be called once the view controller and its subviews have appeared on screen
 */
- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [self startPlugin:self.barcodeScanViewPlugin];
}

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


#pragma mark -- AnylineBarcodeModuleDelegate

- (void)anylineBarcodeScanPlugin:(ALBarcodeScanPlugin *)anylineBarcodeScanPlugin didFindResult:(ALBarcodeResult *)scanResult {
    ALBarcodeResult * result = scanResult;
    self.resultLabel.text = [result firstObject].value;
}


// This is called every frame
- (void)anylineBarcodeScanPlugin:(ALBarcodeScanPlugin *)anylineBarcodeScanPlugin scannedBarcodes:(ALBarcodeResult*)scanResult {
	NSLog(@"Visible barcodes: %@", scanResult.result);
}

@end
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
using Anyline.SDK.Models;
using Anyline.SDK.Plugins;
using Anyline.SDK.Plugins.Barcode;
using Anyline.SDK.Util;
using Anyline.SDK.ViewPlugins;
using Anyline.SDK.Views;
using Anyline_Windows_UWP_Examples.Model;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Windows.Foundation;
using Windows.Storage;
using Windows.Storage.Streams;
using Windows.UI.ViewManagement;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;


namespace Anyline_Windows_UWP_Examples
{
    /// <summary>
    /// This page is used to setup the plugin, open the camera and start scanning
    /// it has to implement the IScanResultListener for each Plugin that will be used
    /// </summary>
    public sealed partial class ScanPage : Page, IScanResultListener<BarcodeScanResult>
	{
		string myLicenseKey = "INSERT LICENSE KEY HERE";

		protected override async void OnNavigatedTo(NavigationEventArgs e)
		{
			base.OnNavigatedTo(e);

			// register camera events
			AnylineScanView.CameraView.CameraOpened += CameraView_CameraOpened;
			AnylineScanView.CameraView.CameraClosed += CameraView_CameraClosed;

			// register visibility changed event
			Window.Current.VisibilityChanged += Current_VisibilityChanged;

			// make sure the license is initalized (needs only to be done once in the app lifetime)
			AnylineSDK.Init(myLicenseKey);
			// initialize Anyline
			await AnylineScanView.InitAsync("Assets/myconfig.json");

			// attach the result listener to the ScanViewPlugin to receive scanning results
			(AnylineScanView.ScanViewPlugin as BarcodeScanViewPlugin)?.AddScanResultListener(this);

			// opens the camera
			AnylineScanView.StartCamera();
		}

		private async void Current_VisibilityChanged(object sender, Windows.UI.Core.VisibilityChangedEventArgs args)
		{
			if (AnylineScanView == null) return;

			if (args.Visible == false)
			{
				await AnylineScanView.StopCameraAsync();
			}
			if (args.Visible == true)
			{
				AnylineScanView.StartCamera();
			}
		}

		private void CameraView_CameraOpened(object sender, Size args)
		{
			AnylineScanView.StartScanning();
		}

		private void CameraView_CameraClosed(object sender, bool success)
		{
			AnylineScanView.StopScanning();
		}

		public void OnResult(BarcodeScanResult result)
		{
			Debug.WriteLine($"(APP) Scan result: {result.Result}");
		}
	}
}
Document Plugin
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
{
    "captureResolution":"720p",
    "pictureResolution":"1080p",
    "cutout": {
        "style": "rect",
        "maxWidthPercent": "100%",
        "maxHeightPercent": "100%",
        "width": 720,
        "ratioFromSize": {
            "width": 10,
            "height": 15
        },
        "alignment": "center",
        "strokeWidth": 2,
        "cornerRadius": 0,
        "strokeColor": "00000000"
    },
    "flash": {
        "mode": "manual",
        "alignment": "bottom_left",
        "offset": {
            "x": 10,
            "y": 0
        }
    },
    "beepOnResult": true,
    "vibrateOnResult": true,
    "blinkAnimationOnResult": true,
    "cancelOnResult": false
}
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
package io.anyline.examples.document;

import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.PointF;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.ScaleAnimation;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Toast;

import java.io.File;
import java.io.IOException;
import java.util.List;

import at.nineyards.anyline.camera.CameraController;
import at.nineyards.anyline.camera.CameraOpenListener;
import at.nineyards.anyline.models.AnylineImage;
import at.nineyards.anyline.modules.AnylineBaseModuleView;
import io.anyline.examples.R;
import io.anyline.examples.ScanActivity;
import io.anyline.examples.ScanModuleEnum;
import io.anyline.plugin.ScanResult;
import io.anyline.plugin.document.DocumentScanResultListener;
import io.anyline.plugin.document.DocumentScanViewPlugin;
import io.anyline.view.BaseScanViewConfig;
import io.anyline.view.ScanView;
import io.anyline.view.ScanViewPluginConfig;
import io.anyline.AnylineSDK;


/**
 * Example activity for the Anyline-Document-Detection-Module
 */
public class ScanDocumentActivity extends AppCompatActivity implements CameraOpenListener {

	private static final String TAG = ScanDocumentActivity.class.getSimpleName();
	private ScanView documentScanView;
	private Toast notificationToast;
	private ImageView imageViewResult;
	private ProgressDialog progressDialog;
	private ImageView imageViewFull;
	private List<PointF> lastOutline;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		getLayoutInflater().inflate(R.layout.document_scan_view, (ViewGroup) findViewById(R.id.scan_view_placeholder));

		imageViewFull = (ImageView) findViewById(R.id.image_result);

		imageViewResult = (ImageView) findViewById(R.id.full_image);

		documentScanView = (ScanView) findViewById(R.id.scan_view);
		
		// This must be called before doing anything Anyline-related! 
	        // Try/Catch this to check whether or not your license key is valid! 
		try {
    	    	    AnylineSDK.init(getString(getString(R.string.anyline_license_key)), this);
	        } catch (LicenseException e) {
    	    	    // handle exception
		}

		// add a camera open listener that will be called when the camera is opened or an error occurred
		//  this is optional (if not set a RuntimeException will be thrown if an error occurs)
		documentScanView.setCameraOpenListener(this);
		//init the scanViewPluginConfig
		ScanViewPluginConfig documentScanViewPluginConfig = new ScanViewPluginConfig(getApplicationContext(), "document_view_config.json");
		//init the Document Scan View Plugin
		final DocumentScanViewPlugin documentScanViewPlugin = new DocumentScanViewPlugin(getApplicationContext(), documentScanViewPluginConfig, "Document");
		//init the base config for camera and flash
		BaseScanViewConfig documentBaseScanViewconfig  = new BaseScanViewConfig(getApplicationContext(), "document_view_config.json");
		//set the base config to the scan view
		documentScanView.setScanViewConfig(documentBaseScanViewconfig);
		//set the scan view plugin to the scan view
		documentScanView.setScanViewPlugin(documentScanViewPlugin);

		//set cancel on result on true
		documentScanViewPlugin.getScanViewPluginConfig().setCancelOnResult(true);
		documentScanViewPlugin.cancelOnResult();

		documentScanViewPlugin.addScanResultListener(new DocumentScanResultListener() {

			@Override
			public void onPreviewProcessingSuccess(AnylineImage anylineImage) {

				notificationToast = Toast.makeText(ScanDocumentActivity.this, "Scanning full document. Please hold " +
						"still", Toast.LENGTH_LONG);
				notificationToast.show();

				showToast(getString(R.string.document_preview_success));
			}

			@Override
			public void onPreviewProcessingFailure(DocumentScanViewPlugin.DocumentError error) {
				// this is called on any error while processing the document image
				// Note: this is called every time an error occurs in a run, so that might be quite often
				// An error message should only be presented to the user after some time
				Log.d("Callback", "onPictureProcessingFailure: " + error.name());

			}

			@Override
			public void onPictureProcessingFailure(DocumentScanViewPlugin.DocumentError error) {

				// handle an error while processing the full picture here
				// the preview will be restarted automatically
				String text = getString(R.string.document_picture_error);
				switch (error) {
					case DOCUMENT_NOT_SHARP:
						text += getString(R.string.document_error_not_sharp);
						break;
					case DOCUMENT_SKEW_TOO_HIGH:
						text += getString(R.string.document_error_skew_too_high);
						break;
					case DOCUMENT_OUTLINE_NOT_FOUND:
						text += getString(R.string.document_error_outline_not_found);
						break;
					case GLARE_DETECTED:
						text += getString(R.string.document_error_glare_detected);
						break;
					case IMAGE_TOO_DARK:
						text += getString(R.string.document_error_too_dark);
						break;
				}

				showToast(text);
				if (progressDialog != null && progressDialog.isShowing()) {
					progressDialog.dismiss();
				}

				AnylineImage image = documentScanViewPlugin.getCurrentFullImage();

				if (image != null) {
					File outDir = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "error");
					outDir.mkdir();
					File outFile = new File(outDir, "" + System.currentTimeMillis() + error.name() + ".jpg");
					Log.d(TAG, "saved image to: " + outFile.getAbsolutePath());
					try {
						image.save(outFile, 100);
						Log.d(TAG, "error image saved to " + outFile.getAbsolutePath());
					} catch (IOException e) {
						e.printStackTrace();
					}
					image.release();
				}
			}

			@Override
			public void onTakePictureSuccess() {
				progressDialog = ProgressDialog.show(ScanDocumentActivity.this, "Processing", "Processing the picture" +
						". Please wait", true);

				if (notificationToast != null) {
					notificationToast.cancel();
				}

			}

			@Override
			public void onTakePictureError(Throwable error) {
				Log.d("Callback", "onTakePictureError: " + error.getMessage());
			}

			@Override
			public void onPictureTransformed(AnylineImage transformedImage) {
				Log.d("Callback", "onPictureTransformed");
			}

			@Override
			public void onPictureTransformError(DocumentScanViewPlugin.DocumentError error) {
				Log.d("Callback", "onPictureTransformError: " + error.name());
			}

			@Override
			public void onPictureCornersDetected(AnylineImage fullFrame, List corners) {
				Log.d("Callback", "onPictureCornersDetected");
			}


			@Override
			public boolean onDocumentOutlineDetected(List rect, boolean documentShapeAndBrightnessValid) {

				lastOutline = rect;
				return true;

			}

			@Override
			public void onResult(ScanResult result) {
				if (progressDialog != null && progressDialog.isShowing()) {
					progressDialog.dismiss();
				}

				// handle the result document images here
				if (progressDialog != null && progressDialog.isShowing()) {
					progressDialog.dismiss();
				}

				AnylineImage transformedImage = (AnylineImage) result.getResult();
				AnylineImage fullFrame = result.getFullImage();

				showToast(getString(R.string.document_picture_success));


				// show the picture on the screen
				displayPicture(transformedImage);

				/**
				 * IMPORTANT: cache provided frames here, and release them at the end of this onResult. Because
				 * keeping them in memory (e.g. setting the full frame to an ImageView)
				 * will result in a OutOfMemoryError soon. This error is reported in {@link #onTakePictureError
				 * (Throwable)}
				 *
				 * Use a DiskCache http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html#disk-cache
				 * for example
				 *
				 */
				File outDir = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "ok");
				outDir.mkdir();
				File outFile = new File(outDir, "" + System.currentTimeMillis() + ".jpg");
				try {
					transformedImage.save(outFile, 100);
					showToast("image saved to " + outFile.getAbsolutePath());
				} catch (IOException e) {
					e.printStackTrace();
				}

				// release the images
				transformedImage.release();
				fullFrame.release();
			}
		});
	}

	/**
	 * Performs an animation after the final image was successfully processed. This is just an example.
	 *
	 * @param transformedImage The transformed final image
	 */
	private void displayPicture(AnylineImage transformedImage) {

		imageViewResult.setImageBitmap(Bitmap.createScaledBitmap(transformedImage.getBitmap(), imageViewResult.getWidth(), imageViewResult.getHeight(), false));
		imageViewResult.setVisibility(View.VISIBLE);

		imageViewResult.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View view) {
				resetScanning();
			}
		});

	}


	@Override
	protected AnylineBaseModuleView getScanView() {
		return null;
	}


	private void showToast(String text) {
		try {
			notificationToast.setText(text);
		} catch (Exception e) {
			notificationToast = Toast.makeText(this, text, Toast.LENGTH_LONG);
		}
		notificationToast.show();
	}

	@Override
	protected void onResume() {
		super.onResume();
		//start the actual scanning
		documentScanView.start();
	}

	@Override
	protected void onPause() {
		super.onPause();
		//stop the scanning
		documentScanView.stop();
		//release the camera (must be called in onPause, because there are situations where
		// it cannot be auto-detected that the camera should be released)
		documentScanView.releaseCameraInBackground();
	}

	@Override
	public void onCameraOpened(CameraController cameraController, int width, int height) {
		//the camera is opened async and this is called when the opening is finished
		Log.d(TAG, "Camera opened successfully. Frame resolution " + width + " x " + height);
	}

	@Override
	public void onCameraError(Exception e) {
		//This is called if the camera could not be opened.
		// (e.g. If there is no camera or the permission is denied)
		// This is useful to present an alternative way to enter the required data if no camera exists.
		throw new RuntimeException(e);
	}

	@Override
	protected ScanModuleEnum.ScanModule getScanModule() {
		return ScanModuleEnum.ScanModule.DOCUMENT;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {

		if (item.getItemId() == android.R.id.home) {
			if(imageViewResult.getVisibility() == View.VISIBLE){
				resetScanning();
			}else {
				onBackPressed();
			}
			return true;
		}

		return false;
	}

	@Override
	public void onBackPressed() {
		if(imageViewResult.getVisibility() == View.VISIBLE){
			resetScanning();
		}else {
			super.onBackPressed();
			overridePendingTransition(R.anim.fade_in, R.anim.activity_close_translate);
		}
	}

	private void resetScanning(){
		if(imageViewResult.getVisibility() == View.VISIBLE){
			imageViewResult.setVisibility(View.GONE);
			if(documentScanView.getScanViewPlugin() != null && !documentScanView.getScanViewPlugin().isRunning() ){
				documentScanView.start();
			}
		}
	}
}
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
#import "ALDocumentScanViewController.h"
#import <Anyline/Anyline.h>
#import "NSUserDefaults+ALExamplesAdditions.h"
#import "ALRoundedView.h"
#import "ALAppDemoLicenses.h"

NSString * const kDocumentScanLicenseKey = kDemoAppLicenseKey;

@class AnylineDocumentModuleView;

@interface ALDocumentScanViewController () <ALDocumentScanPluginDelegate, ALInfoDelegate, ALDocumentInfoDelegate>

// The Anyline plugins used for Document
@property (nonatomic, strong) ALDocumentScanViewPlugin *documentScanViewPlugin;
@property (nonatomic, strong) ALDocumentScanPlugin *documentScanPlugin;
@property (nullable, nonatomic, strong) ALScanView *scanView;

@property (nonatomic, strong) ALRoundedView *roundedView;
@property (nonatomic, assign) NSInteger showingLabel;

@end

@implementation ALDocumentScanViewController

/*
 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];
   
    [super viewDidLoad];
    // Set the background color to black to have a nicer transition
    self.view.backgroundColor = [UIColor blackColor];
    self.title = NSLocalizedString(@"Scan Document", @"Scan Document");
    // 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);

    NSError *licenseError = nil;
    //Initialize the Anyline License
    [AnylineSDK setupWithLicenseKey:kDocumentScanLicenseKey error:&licenseError];
    if (licenseError) {
        //Handle errors here
    }
    
    NSError *error = nil;
    self.documentScanPlugin = [[ALDocumentScanPlugin alloc] initWithPluginID:@"DOCUMENT" delegate:self error:&error];;
    NSAssert(self.documentScanPlugin, @"Setup Error: %@", error.debugDescription);

    [self.documentScanPlugin addInfoDelegate:self];
    
    [self.documentScanPlugin setDocumentRatios:@[@(ALDocumentRatioLetterPortrait), @(ALDocumentRatioLetterLandscape)]];
    self.documentScanPlugin.maxDocumentRatioDeviation = @(0.15);
    
    self.documentScanViewPlugin = [[ALDocumentScanViewPlugin alloc] initWithScanPlugin:self.documentScanPlugin];
    NSAssert(self.documentScanViewPlugin, @"Setup Error: %@", error.debugDescription);
    
    self.scanView = [[ALScanView alloc] initWithFrame:frame
                                       scanViewPlugin:self.documentScanViewPlugin
                                         cameraConfig:[ALCameraConfig defaultDocumentCameraConfig]
                                    flashButtonConfig:[ALFlashButtonConfig defaultFlashConfig]];
    
    // Enable PostProcessing
    [self.documentScanPlugin setPostProcessingEnabled:YES];
    // Disable justDetectCornersIfPossible
    self.documentScanPlugin.justDetectCornersIfPossible = NO;
    
    [self.documentScanPlugin enableReporting:[NSUserDefaults AL_reportingEnabled]];
    self.controllerType = ALScanHistoryDocument;
    self.documentScanViewPlugin.translatesAutoresizingMaskIntoConstraints = NO;
    
    // 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];

    // This view notifies the user of any problems that occur while he is scanning
    self.roundedView = [[ALRoundedView alloc] initWithFrame:CGRectMake(20, 115, self.view.bounds.size.width - 40, 30)];
    self.roundedView.fillColor = [UIColor colorWithRed:98.0/255.0 green:39.0/255.0 blue:232.0/255.0 alpha:0.6];
    self.roundedView.textLabel.text = @"";
    self.roundedView.alpha = 0;
    [self.view addSubview:self.roundedView];
}

/*
 This method will be called once the view controller and its subviews have appeared on screen
 */
-(void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    /*
     This is the place where we tell Anyline to start receiving and displaying images from the camera.
     Success/error tells us if everything went fine.
     */
    NSError *error;
    BOOL success = [self.documentScanViewPlugin startAndReturnError:&error];
    if( !success ) {
        // Something went wrong. The error object contains the error description
        [[[UIAlertView alloc] initWithTitle:@"Start Scanning Error"
                                    message:error.debugDescription
                                   delegate:self
                          cancelButtonTitle:@"OK"
                          otherButtonTitles:nil] show];
    }
    
    //Update Position of Warning Indicator
    [self updateWarningPosition:
     self.documentScanViewPlugin.cutoutRect.origin.y +
     self.documentScanViewPlugin.cutoutRect.size.height +
     self.documentScanViewPlugin.frame.origin.y - 100];
}

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

#pragma mark -- AnylineDocumentModuleDelegate

/*
 This is the main delegate method Anyline uses to report its scanned codes
 */
- (void)anylineDocumentScanPlugin:(ALDocumentScanPlugin *)anylineDocumentScanPlugin
                        hasResult:(UIImage *)transformedImage
                        fullImage:(UIImage *)fullFrame
                  documentCorners:(ALSquare *)corners {
    UIViewController *viewController = [[UIViewController alloc] init];
    UIImageView *imageView = [[UIImageView alloc] initWithFrame:viewController.view.bounds];
    imageView.center = CGPointMake(imageView.center.x, imageView.center.y + 30);
    imageView.contentMode = UIViewContentModeScaleAspectFit;
    imageView.image = transformedImage;
    [viewController.view addSubview:imageView];
    [self.navigationController pushViewController:viewController animated:YES];
}

/*
 This method receives errors that occured during the scan.
 */
- (void)anylineDocumentScanPlugin:(ALDocumentScanPlugin *)anylineDocumentScanPlugin
  reportsPictureProcessingFailure:(ALDocumentError)error {
    [self showUserLabel:error];
}

/*
 This method receives errors that occured during the scan.
 */
- (void)anylineDocumentScanPlugin:(ALDocumentScanPlugin *)anylineDocumentScanPlugin
  reportsPreviewProcessingFailure:(ALDocumentError)error {
    [self showUserLabel:error];
}

/**
 *  Crops an arbitrary rectangle (e.g. trapezoid) of the input image and perspectively transforms it to a rectangle (e.g. square).
 *  After the transformation is complete the result delegate anylineDocumentScanPlugin:hasResult:fullImage:documentCorners will be triggered.
 *  In any case call [AnylineDocumentModuleView cancelScanningAndReturnError:] before using this method.
 *
 *  Return value indicating the success / failure of the call.
 *
 *
 */
- (BOOL)transformImageWithSquare:(ALSquare *)square
                           image:(UIImage *)image
                           error:(NSError * *)error {
    [self.scanViewPlugin transformImageWithSquare:square image:image error:&error];
}

- (BOOL)transformALImageWithSquare:(ALSquare *)square
                             image:(ALImage *)image
                             error:(NSError * *)error {
    [self.scanViewPlugin transformALImageWithSquare:square image:image error:&error];
}

/**
 *  A manual picture will be taken. Anyline tries to detected any document corners and will report the result
 *  with the delegate method anylineDocumentModuleView:detectedPictureCorners:inImage:
 */
- (BOOL)triggerPictureCornerDetectionAndReturnError:(NSError **)error {
    [self.documentModuleView triggerPictureCornerDetectionAndReturnError:&error];
}

#pragma mark -- Helper Methods

/*
 Shows a little round label at the bottom of the screen to inform the user what happended
 */
- (void)showUserLabel:(ALDocumentError)error {
    NSString *helpString = nil;
    switch (error) {
        case ALDocumentErrorNotSharp:
            helpString = @"Document not Sharp";
            break;
        case ALDocumentErrorSkewTooHigh:
            helpString = @"Wrong Perspective";
            break;
        case ALDocumentErrorImageTooDark:
            helpString = @"Too Dark";
            break;
        case ALDocumentErrorShakeDetected:
            helpString = @"Shake";
            break;
        default:
            break;
    }
    
    //Display Error to indicate what the User should do.
}

@end

Tutorials and How To Guides

You can check more tutorials on our Youtube channel at https://www.youtube.com/playlist?list=PLFr-jBATSsLyH1PbsVc3pWsBegbyUI8bx