Select one barcode among many

Motivation

The default scan mode provided by the Scandit Barcode Scanner searches barcodes/2d codes in the whole image. This works well when scanning individual codes. However, when scanning codes from sheets with a large number of densely packed barcodes, the full screen scan mode is not optimal as there is little control for the user to decide which code is going to get scanned. With very little code it's possible to implement mechanisms that help selecting the code to be scanned.

Two such "barcode selection modi" have been implemented in the BatchScanSample which is included in the iOS SDK.

Aim and Scan

In the first of the two modi, the camera is started with the barcode scanner in paused state. After positioning the phone such that the barcode is in the center of the image, the user presses the "Scan barcode" button to activate the barcode scanner and scan the code.

Steps

To implement the Aim and Scan mode in your application, you will need to do the following:

  • Enable and set the restrict active area. This will make sure that codes are only scanned in a very thin band in the center of the image.

    Objective-C:

    //Enable restrict area
    [scanSettings setActiveScanningArea:CGRectMake(0, 0.48, 1, 0.04)];

    Swift:

    // Enable restrict area
    scanSettings.setActiveScanningArea(CGRect(x: 0, y: 0.48, width: 1, height: 0.04))
  • Modify the GUI style to have a "laser" line instead of a square view finder and the scan button to the view.

    Objective-C:

    [self.scanditBarcodePicker.overlayController setGuiStyle:SBSGuiStyleLaser];
    //Add scan button
    self.scanButton = [UIButton buttonWithType:UIButtonTypeCustom];
    [self.scanButton setTitle:@"Scan barcode" forState:UIControlStateNormal];
    CGFloat red = 58/255.0, green = 194/255.0, blue = 205/255.0;
    [self.scanButton setBackgroundColor:[UIColor colorWithRed:red green:green blue:blue alpha:1]];
    self.scanButton.layer.cornerRadius = 4.0f;
    [self.scanButton.titleLabel setFont:[UIFont fontWithName:@"Helvetica" size:20.0]];
    self.scanButton.frame = CGRectMake(0, 0, 0, 0);
    [self.scanditBarcodePicker.overlayController.view addSubview:self.scanButton];

    Swift:

    scanditBarcodePicker.overlayController.guiStyle = .laser
    // Add scan button
    scanButton = UIButton(type: .custom)
    scanButton.setTitle("Scan Barcode", for: .normal)
    scanButton.backgroundColor = UIColor(red: 55.0/255.0, green: 194.0/255.0, blue: 205.0/255.0, alpha: 1.0)
    scanButton.layer.cornerRadius = 4.0
    scanButton.frame = CGRect(x: 0, y: 0, width: 0, height: 0)
    scanditBarcodePicker.overlayController.view.addSubview(scanButton)
  • Start scanning in pause state. This will initialize and open the camera but not start barcode scanning until resumeScanning (SBSBarcodePicker) is called.

    Objective-C:

    [self.scanditBarcodePicker startScanningInPausedState:YES];

    Swift:

    scanditBarcodePicker.startScanning(inPausedState: true)
  • Set action to scan button to resume scanning

    Objective-C:

    [self.scanButton addTarget:self
    action:@selector(startScanWithButton)
    forControlEvents:UIControlEventTouchUpInside];
    [self.scanditBarcodePicker resumeScanning];

    Swift:

    scanButton.addTarget(self, action: #selector(startScanWithButton), for: .touchUpInside)
    scanditBarcodePicker.resumeScanning()
  • Pause the scanner when a barcode is detected, show the value decoded and set the user interface to “stop mode”

    Objective-C:

    - (void)barcodePicker:(SBSBarcodePicker *)thePicker didScan:(SBSScanSession *)session {
    // call pauseScanning on the session to immediately pause scanning
    [session pauseScanning];
    SBSCode *code = [session.newlyRecognizedCodes objectAtIndex:0];
    // the barcodePicker:didScan delegate method is invoked from a picker-internal queue. To display
    // the results in the UI, you need to dispatch to the main queue. Note that it's not allowed
    // to use SBSScanSession in the dispatched block as it's only allowed to access the
    // SBSScanSession inside the barcodePicker:didScan callback. It is however safe to use results
    // returned by session.newlyRecognizedCodes etc.
    dispatch_async(dispatch_get_main_queue(), ^{
    NSString *symbology = code.symbologyString;
    NSString *barcode = code.data;
    UIAlertView *alert = [[UIAlertView alloc]
    initWithTitle:[NSString stringWithFormat:@"Scanned %@", symbology]
    message:barcode
    delegate:self
    cancelButtonTitle:@"OK"
    otherButtonTitles:nil];
    [alert show];
    });
    }

    Swift:

    func barcodePicker(_ picker: SBSBarcodePicker, didScan session: SBSScanSession) {
    // call pauseScanning on the session to immediately pause scanning
    session.pauseScanning()
    guard let code = session.newlyRecognizedCodes.first else { return }
    // the barcodePicker:didScan delegate method is invoked from a picker-internal queue. To display
    // the results in the UI, you need to dispatch to the main queue. Note that it's not allowed
    // to use SBSScanSession in the dispatched block as it's only allowed to access the
    // SBSScanSession inside the barcodePicker:didScan callback. It is however safe to use results
    // returned by session.newlyRecognizedCodes etc.
    DispatchQueue.main.async {
    let symbology = code.symbologyString
    let barcode = code.data
    let alertController = UIAlertController(title: "Scanned \(symbology)", message: barcode, preferredStyle: .alert)
    alertController.addAction(UIAlertAction(title: "OK", style: .default))
    self.present(alertController, animated: true)
    }
    }

Scan and Confirm

In this selection mode, the camera is started and the scanner activated to scan codes. When a code is scanned a confirm dialog is shown where the user can tap confirm when the correct code has been scanned.

Steps

To implement the Scan and Confirm mode in your application, you will need to do the following:

  • Enable and set the restrict active area

    Objective-C:

    //Enable restrict area
    [scanSettings setActiveScanningArea:CGRectMake(0, 0.48, 1, 0.04)];

    Swift:

    // Enable restrict area
    scanSettings.setActiveScanningArea(CGRect(x: 0, y: 0.48, width: 1, height: 0.04))
  • Modify the GUI style to have a "laser" line instead of a square view finder

    Objective-C:

    [self.scanditBarcodePicker.overlayController setGuiStyle:SBSGuiStyleLaser];

    Swift:

    scanditBarcodePicker.overlayController.guiStyle = .laser
  • Start the scanning

    Objective-C:

    [self.scanditBarcodePicker startScanning];

    Swift:

    scanditBarcodePicker.startScanning()
  • Show the last barcode scanned on the screen

    Objective-C:

    - (void)barcodePicker:(SBSBarcodePicker*)thePicker didScan:(SBSScanSession*)session {
    [self.dinamLabel removeFromSuperview];
    CGRect screen = [[UIScreen mainScreen] bounds];
    NSString *barcode = code.data;
    NSString *symbology = code.symbologyString;
    NSString *text = [NSString stringWithFormat:@"%@ %@", symbology, barcode];
    UILabel *tmpLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 2 * screen.size.height / 3, screen.size.width, 110)];
    self.dinamLabel = tmpLabel;
    self.dinamLabel.text = text;
    [self.scanditBarcodePicker.overlayController.view addSubview:self.dinamLabel];
    }

    Swift:

    func barcodePicker(_ picker: SBSBarcodePicker, didScan session: SBSScanSession) {
    guard let code = session.newlyRecognizedCodes.first else { return }
    dinamLabel.removeFromSuperview()
    let screen = UIScreen.main.bounds
    let text = "\(code.symbologyString) \(code.data)"
    DispatchQueue.main.async {
    let label = UILabel(frame: CGRect(x: 0, y: 2 * screen.size.height / 3, width: screen.size.width, height: 110))
    self.dinamLabel = label
    self.dinamLabel.text = text
    self.scanditBarcodePicker.overlayController.view.addSubView(dinamLabel)
    }
    }