zbar was using a 2010 snapshot of its hg tree. Take a new snapshot to get zbar's improvements. [Imported from Fedora 26 tree]
748 lines
21 KiB
Objective-C
748 lines
21 KiB
Objective-C
//------------------------------------------------------------------------
|
|
// Copyright 2009-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
|
|
//
|
|
// This file is part of the ZBar Bar Code Reader.
|
|
//
|
|
// The ZBar Bar Code Reader is free software; you can redistribute it
|
|
// and/or modify it under the terms of the GNU Lesser Public License as
|
|
// published by the Free Software Foundation; either version 2.1 of
|
|
// the License, or (at your option) any later version.
|
|
//
|
|
// The ZBar Bar Code Reader is distributed in the hope that it will be
|
|
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
|
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Lesser Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser Public License
|
|
// along with the ZBar Bar Code Reader; if not, write to the Free
|
|
// Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
// Boston, MA 02110-1301 USA
|
|
//
|
|
// http://sourceforge.net/projects/zbar
|
|
//------------------------------------------------------------------------
|
|
|
|
#import <ZBarSDK/ZBarReaderController.h>
|
|
#import <ZBarSDK/ZBarHelpController.h>
|
|
#import "debug.h"
|
|
|
|
/* the use of UIGetScreenImage() may no longer be sanctioned, even
|
|
* though it was previously "allowed". define this to 0 to rip it out
|
|
* and fall back to cameraMode=Default (manual capture)
|
|
*/
|
|
#ifndef USE_PRIVATE_APIS
|
|
# define USE_PRIVATE_APIS 0
|
|
#endif
|
|
|
|
#ifndef MIN_QUALITY
|
|
# define MIN_QUALITY 10
|
|
#endif
|
|
|
|
NSString* const ZBarReaderControllerResults = @"ZBarReaderControllerResults";
|
|
|
|
#if USE_PRIVATE_APIS
|
|
// expose undocumented API
|
|
CF_RETURNS_RETAINED
|
|
CGImageRef UIGetScreenImage(void);
|
|
#endif
|
|
|
|
@implementation ZBarReaderController
|
|
|
|
@synthesize scanner, readerDelegate, cameraMode, scanCrop, maxScanDimension,
|
|
showsHelpOnFail, takesPicture, enableCache, tracksSymbols;
|
|
@dynamic showsZBarControls;
|
|
|
|
- (id) init
|
|
{
|
|
if(self = [super init]) {
|
|
showsHelpOnFail = YES;
|
|
hasOverlay = showsZBarControls =
|
|
[self respondsToSelector: @selector(cameraOverlayView)];
|
|
enableCache = tracksSymbols = YES;
|
|
scanCrop = CGRectMake(0, 0, 1, 1);
|
|
maxScanDimension = 640;
|
|
|
|
scanner = [ZBarImageScanner new];
|
|
[scanner setSymbology: 0
|
|
config: ZBAR_CFG_X_DENSITY
|
|
to: 2];
|
|
[scanner setSymbology: 0
|
|
config: ZBAR_CFG_Y_DENSITY
|
|
to: 2];
|
|
|
|
if([UIImagePickerController
|
|
isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera])
|
|
self.sourceType = UIImagePickerControllerSourceTypeCamera;
|
|
|
|
#if USE_PRIVATE_APIS
|
|
cameraMode = ZBarReaderControllerCameraModeSampling;
|
|
#else
|
|
cameraMode = ZBarReaderControllerCameraModeDefault;
|
|
#endif
|
|
}
|
|
return(self);
|
|
}
|
|
|
|
- (void) initOverlay
|
|
{
|
|
CGRect bounds = self.view.bounds;
|
|
overlay = [[UIView alloc] initWithFrame: bounds];
|
|
overlay.backgroundColor = [UIColor clearColor];
|
|
|
|
CGRect r = bounds;
|
|
r.size.height -= 54;
|
|
boxView = [[UIView alloc] initWithFrame: r];
|
|
|
|
boxLayer = [CALayer new];
|
|
boxLayer.frame = r;
|
|
boxLayer.borderWidth = 1;
|
|
boxLayer.borderColor = [UIColor greenColor].CGColor;
|
|
[boxView.layer addSublayer: boxLayer];
|
|
|
|
toolbar = [UIToolbar new];
|
|
toolbar.barStyle = UIBarStyleBlackOpaque;
|
|
r.origin.y = r.size.height;
|
|
r.size.height = 54;
|
|
toolbar.frame = r;
|
|
|
|
cancelBtn = [[UIBarButtonItem alloc]
|
|
initWithBarButtonSystemItem: UIBarButtonSystemItemCancel
|
|
target: self
|
|
action: @selector(cancel)];
|
|
cancelBtn.width = r.size.width / 4 - 16;
|
|
|
|
scanBtn = [[UIBarButtonItem alloc]
|
|
initWithTitle: @"Scan!"
|
|
style: UIBarButtonItemStyleDone
|
|
target: self
|
|
action: @selector(scan)];
|
|
scanBtn.width = r.size.width / 2 - 16;
|
|
|
|
for(int i = 0; i < 2; i++)
|
|
space[i] = [[UIBarButtonItem alloc]
|
|
initWithBarButtonSystemItem:
|
|
UIBarButtonSystemItemFlexibleSpace
|
|
target: nil
|
|
action: nil];
|
|
|
|
space[2] = [[UIBarButtonItem alloc]
|
|
initWithBarButtonSystemItem:
|
|
UIBarButtonSystemItemFixedSpace
|
|
target: nil
|
|
action: nil];
|
|
space[2].width = r.size.width / 4 - 16;
|
|
|
|
infoBtn = [[UIButton buttonWithType: UIButtonTypeInfoLight] retain];
|
|
r.origin.x = r.size.width - 54;
|
|
r.size.width = 54;
|
|
infoBtn.frame = r;
|
|
[infoBtn addTarget: self
|
|
action: @selector(info)
|
|
forControlEvents: UIControlEventTouchUpInside];
|
|
}
|
|
|
|
- (void) viewDidLoad
|
|
{
|
|
[super viewDidLoad];
|
|
[super setDelegate: self];
|
|
if(hasOverlay)
|
|
[self initOverlay];
|
|
}
|
|
|
|
- (void) cleanup
|
|
{
|
|
[overlay release];
|
|
overlay = nil;
|
|
[boxView release];
|
|
boxView = nil;
|
|
[boxLayer release];
|
|
boxLayer = nil;
|
|
[toolbar release];
|
|
toolbar = nil;
|
|
[cancelBtn release];
|
|
cancelBtn = nil;
|
|
[scanBtn release];
|
|
scanBtn = nil;
|
|
for(int i = 0; i < 3; i++) {
|
|
[space[i] release];
|
|
space[i] = nil;
|
|
}
|
|
[infoBtn release];
|
|
infoBtn = nil;
|
|
[help release];
|
|
help = nil;
|
|
}
|
|
|
|
- (void) viewDidUnload
|
|
{
|
|
[self cleanup];
|
|
[super viewDidUnload];
|
|
}
|
|
|
|
- (void) dealloc
|
|
{
|
|
[self cleanup];
|
|
[scanner release];
|
|
scanner = nil;
|
|
[super dealloc];
|
|
}
|
|
|
|
- (void) scan
|
|
{
|
|
scanBtn.enabled = NO;
|
|
self.view.userInteractionEnabled = NO;
|
|
[self takePicture];
|
|
}
|
|
|
|
- (void) cancel
|
|
{
|
|
[self performSelector: @selector(imagePickerControllerDidCancel:)
|
|
withObject: self
|
|
afterDelay: 0.1];
|
|
}
|
|
|
|
- (void) reenable
|
|
{
|
|
scanBtn.enabled = YES;
|
|
self.view.userInteractionEnabled = YES;
|
|
}
|
|
|
|
- (void) initScanning
|
|
{
|
|
if(hasOverlay &&
|
|
self.sourceType == UIImagePickerControllerSourceTypeCamera) {
|
|
if(showsZBarControls || ![self cameraOverlayView])
|
|
[self setCameraOverlayView: overlay];
|
|
|
|
UIView *activeOverlay = [self cameraOverlayView];
|
|
|
|
if(showsZBarControls) {
|
|
if(!toolbar.superview) {
|
|
[overlay addSubview: toolbar];
|
|
[overlay addSubview: infoBtn];
|
|
}
|
|
[self setShowsCameraControls: NO];
|
|
}
|
|
else {
|
|
[toolbar removeFromSuperview];
|
|
[infoBtn removeFromSuperview];
|
|
if(activeOverlay == overlay)
|
|
[self setShowsCameraControls: YES];
|
|
}
|
|
|
|
self.view.userInteractionEnabled = YES;
|
|
|
|
sampling = (cameraMode == ZBarReaderControllerCameraModeSampling ||
|
|
cameraMode == ZBarReaderControllerCameraModeSequence);
|
|
|
|
if(sampling) {
|
|
toolbar.items = [NSArray arrayWithObjects:
|
|
cancelBtn, space[0], nil];
|
|
|
|
t_frame = timer_now();
|
|
dt_frame = 0;
|
|
boxLayer.opacity = 0;
|
|
if(boxView.superview != activeOverlay)
|
|
[boxView removeFromSuperview];
|
|
if(!boxView.superview)
|
|
[activeOverlay insertSubview: boxView atIndex:0];
|
|
scanner.enableCache = enableCache;
|
|
|
|
SEL meth = nil;
|
|
if(cameraMode == ZBarReaderControllerCameraModeSampling) {
|
|
// ensure crop rect does not include controls
|
|
if(scanCrop.origin.x + scanCrop.size.width > .8875)
|
|
scanCrop.size.width = .8875 - scanCrop.origin.x;
|
|
|
|
meth = @selector(scanScreen);
|
|
}
|
|
else
|
|
meth = @selector(takePicture);
|
|
|
|
[self performSelector: meth
|
|
withObject: nil
|
|
afterDelay: 2];
|
|
#ifdef DEBUG_OBJC
|
|
[self performSelector: @selector(dumpFPS)
|
|
withObject: nil
|
|
afterDelay: 4];
|
|
#endif
|
|
}
|
|
else {
|
|
scanBtn.enabled = NO;
|
|
toolbar.items = [NSArray arrayWithObjects:
|
|
cancelBtn, space[0], scanBtn, space[1], space[2], nil];
|
|
|
|
[self performSelector: @selector(reenable)
|
|
withObject: nil
|
|
afterDelay: .5];
|
|
|
|
[boxView removeFromSuperview];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void) viewWillAppear: (BOOL) animated
|
|
{
|
|
[self initScanning];
|
|
[super viewWillAppear: animated];
|
|
}
|
|
|
|
- (void) viewWillDisappear: (BOOL) animated
|
|
{
|
|
sampling = NO;
|
|
scanner.enableCache = NO;
|
|
[super viewWillDisappear: animated];
|
|
}
|
|
|
|
- (BOOL) showsZBarControls
|
|
{
|
|
return(showsZBarControls);
|
|
}
|
|
|
|
- (void) setCameraMode: (ZBarReaderControllerCameraMode) mode
|
|
{
|
|
#if !USE_PRIVATE_APIS
|
|
if(mode == ZBarReaderControllerCameraModeSampling)
|
|
[NSException raise: NSInvalidArgumentException
|
|
format: @"ZBarReaderController cannot set cameraMode=Sampling"
|
|
@" when USE_PRIVATE_APIS=0"];
|
|
#endif
|
|
cameraMode = mode;
|
|
}
|
|
|
|
- (void) setShowsZBarControls: (BOOL) show
|
|
{
|
|
if(show && !hasOverlay)
|
|
[NSException raise: NSInvalidArgumentException
|
|
format: @"ZBarReaderController cannot set showsZBarControls=YES for OS<3.1"];
|
|
|
|
showsZBarControls = show;
|
|
}
|
|
|
|
// intercept delegate as readerDelegate
|
|
|
|
- (void) setDelegate: (id <UINavigationControllerDelegate,
|
|
UIImagePickerControllerDelegate>) delegate
|
|
{
|
|
self.readerDelegate = (id <ZBarReaderDelegate>)delegate;
|
|
}
|
|
|
|
|
|
#ifdef DEBUG_OBJC
|
|
- (void) dumpFPS
|
|
{
|
|
if(!sampling)
|
|
return;
|
|
[self performSelector: @selector(dumpFPS)
|
|
withObject: nil
|
|
afterDelay: 2];
|
|
zlog(@"fps=%g", 1 / dt_frame);
|
|
}
|
|
#endif
|
|
|
|
- (NSInteger) scanImage: (CGImageRef) image
|
|
withScaling: (CGFloat) scale
|
|
{
|
|
uint64_t now = timer_now();
|
|
if(dt_frame)
|
|
dt_frame = (dt_frame + timer_elapsed(t_frame, now)) / 2;
|
|
else
|
|
dt_frame = timer_elapsed(t_frame, now);
|
|
t_frame = now;
|
|
|
|
int w = CGImageGetWidth(image);
|
|
int h = CGImageGetHeight(image);
|
|
CGRect crop;
|
|
if(w >= h)
|
|
crop = CGRectMake(scanCrop.origin.x * w, scanCrop.origin.y * h,
|
|
scanCrop.size.width * w, scanCrop.size.height * h);
|
|
else
|
|
crop = CGRectMake(scanCrop.origin.y * w, scanCrop.origin.x * h,
|
|
scanCrop.size.height * w, scanCrop.size.width * h);
|
|
|
|
CGSize size;
|
|
if(crop.size.width >= crop.size.height &&
|
|
crop.size.width > maxScanDimension)
|
|
size = CGSizeMake(maxScanDimension,
|
|
crop.size.height * maxScanDimension / crop.size.width);
|
|
else if(crop.size.height > maxScanDimension)
|
|
size = CGSizeMake(crop.size.width * maxScanDimension / crop.size.height,
|
|
maxScanDimension);
|
|
else
|
|
size = crop.size;
|
|
|
|
if(scale) {
|
|
size.width *= scale;
|
|
size.height *= scale;
|
|
}
|
|
|
|
if(self.sourceType != UIImagePickerControllerSourceTypeCamera ||
|
|
cameraMode == ZBarReaderControllerCameraModeDefault) {
|
|
// limit the maximum number of scan passes
|
|
int density;
|
|
if(size.width > 720)
|
|
density = (size.width / 240 + 1) / 2;
|
|
else
|
|
density = 1;
|
|
[scanner setSymbology: 0
|
|
config: ZBAR_CFG_X_DENSITY
|
|
to: density];
|
|
|
|
if(size.height > 720)
|
|
density = (size.height / 240 + 1) / 2;
|
|
else
|
|
density = 1;
|
|
[scanner setSymbology: 0
|
|
config: ZBAR_CFG_Y_DENSITY
|
|
to: density];
|
|
}
|
|
|
|
ZBarImage *zimg = [[ZBarImage alloc]
|
|
initWithCGImage: image
|
|
crop: crop
|
|
size: size];
|
|
int nsyms = [scanner scanImage: zimg];
|
|
[zimg release];
|
|
|
|
return(nsyms);
|
|
}
|
|
|
|
- (ZBarSymbol*) extractBestResult: (BOOL) filter
|
|
{
|
|
ZBarSymbol *sym = nil;
|
|
ZBarSymbolSet *results = scanner.results;
|
|
results.filterSymbols = filter;
|
|
for(ZBarSymbol *s in results)
|
|
if(!sym || sym.quality < s.quality)
|
|
sym = s;
|
|
return(sym);
|
|
}
|
|
|
|
- (void) updateBox: (ZBarSymbol*) sym
|
|
imageSize: (CGSize) size
|
|
{
|
|
[CATransaction begin];
|
|
[CATransaction setAnimationDuration: .3];
|
|
[CATransaction setAnimationTimingFunction:
|
|
[CAMediaTimingFunction functionWithName:
|
|
kCAMediaTimingFunctionLinear]];
|
|
|
|
CGFloat alpha = boxLayer.opacity;
|
|
if(sym) {
|
|
CGRect r = sym.bounds;
|
|
if(r.size.width > 16 && r.size.height > 16) {
|
|
r.origin.x += scanCrop.origin.y * size.width;
|
|
r.origin.y += scanCrop.origin.x * size.height;
|
|
r = CGRectInset(r, -16, -16);
|
|
if(alpha > .25) {
|
|
CGRect frame = boxLayer.frame;
|
|
r.origin.x = (r.origin.x * 3 + frame.origin.x) / 4;
|
|
r.origin.y = (r.origin.y * 3 + frame.origin.y) / 4;
|
|
r.size.width = (r.size.width * 3 + frame.size.width) / 4;
|
|
r.size.height = (r.size.height * 3 + frame.size.height) / 4;
|
|
}
|
|
boxLayer.frame = r;
|
|
boxLayer.opacity = 1;
|
|
}
|
|
}
|
|
else {
|
|
if(alpha > .1)
|
|
boxLayer.opacity = alpha / 2;
|
|
else if(alpha)
|
|
boxLayer.opacity = 0;
|
|
}
|
|
[CATransaction commit];
|
|
}
|
|
|
|
#if USE_PRIVATE_APIS
|
|
|
|
- (void) scanScreen
|
|
{
|
|
if(!sampling)
|
|
return;
|
|
|
|
// FIXME ugly hack: use private API to sample screen
|
|
CGImageRef image = UIGetScreenImage();
|
|
|
|
[self scanImage: image
|
|
withScaling: 0];
|
|
CGSize size = CGSizeMake(CGImageGetWidth(image), CGImageGetHeight(image));
|
|
CGImageRelease(image);
|
|
|
|
ZBarSymbol *sym = [self extractBestResult: NO];
|
|
|
|
if(sym && !sym.count) {
|
|
SEL cb = @selector(imagePickerController:didFinishPickingMediaWithInfo:);
|
|
if(takesPicture) {
|
|
symbol = [sym retain];
|
|
[self takePicture];
|
|
}
|
|
else if([readerDelegate respondsToSelector: cb]) {
|
|
symbol = [sym retain];
|
|
|
|
[CATransaction begin];
|
|
[CATransaction setDisableActions: YES];
|
|
boxLayer.opacity = 0;
|
|
[CATransaction commit];
|
|
|
|
// capture preview image and send to delegate
|
|
// after box has been hidden
|
|
[self performSelector: @selector(captureScreen)
|
|
withObject: nil
|
|
afterDelay: 0.001];
|
|
return;
|
|
}
|
|
}
|
|
|
|
// reschedule
|
|
[self performSelector: @selector(scanScreen)
|
|
withObject: nil
|
|
afterDelay: 0.001];
|
|
|
|
if(tracksSymbols)
|
|
[self updateBox: sym
|
|
imageSize: size];
|
|
}
|
|
|
|
- (void) captureScreen
|
|
{
|
|
CGImageRef screen = UIGetScreenImage();
|
|
|
|
CGRect r = CGRectMake(0, 0,
|
|
CGImageGetWidth(screen), CGImageGetHeight(screen));
|
|
if(r.size.width > r.size.height)
|
|
r.size.width -= 54;
|
|
else
|
|
r.size.height -= 54;
|
|
CGImageRef preview = CGImageCreateWithImageInRect(screen, r);
|
|
CGImageRelease(screen);
|
|
|
|
UIImage *image = [UIImage imageWithCGImage: preview];
|
|
CGImageRelease(preview);
|
|
|
|
[readerDelegate
|
|
imagePickerController: self
|
|
didFinishPickingMediaWithInfo:
|
|
[NSDictionary dictionaryWithObjectsAndKeys:
|
|
image, UIImagePickerControllerOriginalImage,
|
|
[NSArray arrayWithObject: symbol],
|
|
ZBarReaderControllerResults,
|
|
nil]];
|
|
[symbol release];
|
|
symbol = nil;
|
|
|
|
// continue scanning until dismissed
|
|
[self performSelector: @selector(scanScreen)
|
|
withObject: nil
|
|
afterDelay: 0.001];
|
|
}
|
|
|
|
#endif /* USE_PRIVATE_APIS */
|
|
|
|
- (void) scanSequence: (UIImage*) image
|
|
{
|
|
if(!sampling) {
|
|
[image release];
|
|
return;
|
|
}
|
|
|
|
int nsyms = [self scanImage: image.CGImage
|
|
withScaling: 0];
|
|
|
|
ZBarSymbol *sym = nil;
|
|
if(nsyms)
|
|
[self extractBestResult: NO];
|
|
|
|
SEL cb = @selector(imagePickerController:didFinishPickingMediaWithInfo:);
|
|
if(sym && !sym.count &&
|
|
[readerDelegate respondsToSelector: cb])
|
|
[readerDelegate
|
|
imagePickerController: self
|
|
didFinishPickingMediaWithInfo:
|
|
[NSDictionary dictionaryWithObjectsAndKeys:
|
|
image, UIImagePickerControllerOriginalImage,
|
|
[NSArray arrayWithObject: sym],
|
|
ZBarReaderControllerResults,
|
|
nil]];
|
|
CGSize size = image.size;
|
|
[image release];
|
|
|
|
// reschedule
|
|
[self performSelector: @selector(takePicture)
|
|
withObject: nil
|
|
afterDelay: 0.001];
|
|
|
|
if(tracksSymbols)
|
|
[self updateBox: sym
|
|
imageSize: size];
|
|
}
|
|
|
|
- (void) showHelpWithReason: (NSString*) reason
|
|
{
|
|
if(help) {
|
|
[help.view removeFromSuperview];
|
|
[help release];
|
|
}
|
|
help = [[ZBarHelpController alloc]
|
|
initWithReason: reason];
|
|
help.delegate = (id<ZBarHelpDelegate>)self;
|
|
|
|
if(self.sourceType != UIImagePickerControllerSourceTypeCamera) {
|
|
[self presentModalViewController: help
|
|
animated: YES];
|
|
return;
|
|
}
|
|
|
|
// show help as overlay view to workaround controller bugs
|
|
sampling = NO;
|
|
scanner.enableCache = NO;
|
|
help.wantsFullScreenLayout = YES;
|
|
help.view.alpha = 0;
|
|
|
|
UIView *activeOverlay = [self cameraOverlayView];
|
|
help.view.frame = [activeOverlay
|
|
convertRect: CGRectMake(0, 0, 320, 480)
|
|
fromView: nil];
|
|
[activeOverlay addSubview: help.view];
|
|
[UIView beginAnimations: @"ZBarHelp"
|
|
context: nil];
|
|
help.view.alpha = 1;
|
|
[UIView commitAnimations];
|
|
}
|
|
|
|
- (void) info
|
|
{
|
|
[self showHelpWithReason: @"INFO"];
|
|
}
|
|
|
|
- (void) imagePickerController: (UIImagePickerController*) picker
|
|
didFinishPickingMediaWithInfo: (NSDictionary*) info
|
|
{
|
|
UIImage *img = [info objectForKey: UIImagePickerControllerOriginalImage];
|
|
|
|
id results = nil;
|
|
if(self.sourceType == UIImagePickerControllerSourceTypeCamera &&
|
|
cameraMode == ZBarReaderControllerCameraModeSequence) {
|
|
if(sampling)
|
|
[self performSelector: @selector(scanSequence:)
|
|
withObject: [img retain]
|
|
afterDelay: 0.001];
|
|
return;
|
|
}
|
|
else if(!sampling)
|
|
results = [self scanImage: img.CGImage];
|
|
else {
|
|
results = [NSArray arrayWithObject: symbol];
|
|
[symbol release];
|
|
symbol = nil;
|
|
}
|
|
|
|
[self performSelector: @selector(reenable)
|
|
withObject: nil
|
|
afterDelay: .25];
|
|
|
|
if(results) {
|
|
NSMutableDictionary *newinfo = [info mutableCopy];
|
|
[newinfo setObject: results
|
|
forKey: ZBarReaderControllerResults];
|
|
SEL cb = @selector(imagePickerController:didFinishPickingMediaWithInfo:);
|
|
if([readerDelegate respondsToSelector: cb])
|
|
[readerDelegate imagePickerController: self
|
|
didFinishPickingMediaWithInfo: newinfo];
|
|
else
|
|
[self dismissModalViewControllerAnimated: YES];
|
|
[newinfo release];
|
|
return;
|
|
}
|
|
|
|
BOOL camera = (self.sourceType == UIImagePickerControllerSourceTypeCamera);
|
|
BOOL retry = !camera || (hasOverlay && ![self showsCameraControls]);
|
|
if(showsHelpOnFail && retry)
|
|
[self showHelpWithReason: @"FAIL"];
|
|
|
|
SEL cb = @selector(readerControllerDidFailToRead:withRetry:);
|
|
if([readerDelegate respondsToSelector: cb])
|
|
// assume delegate dismisses controller if necessary
|
|
[readerDelegate readerControllerDidFailToRead: self
|
|
withRetry: retry];
|
|
else if(!retry)
|
|
// must dismiss stock controller
|
|
[self dismissModalViewControllerAnimated: YES];
|
|
}
|
|
|
|
- (void) imagePickerControllerDidCancel: (UIImagePickerController*) picker
|
|
{
|
|
SEL cb = @selector(imagePickerControllerDidCancel:);
|
|
if([readerDelegate respondsToSelector: cb])
|
|
[readerDelegate imagePickerControllerDidCancel: self];
|
|
else
|
|
[self dismissModalViewControllerAnimated: YES];
|
|
}
|
|
|
|
// ZBarHelpDelegate
|
|
|
|
- (void) helpControllerDidFinish: (ZBarHelpController*) hlp
|
|
{
|
|
if(self.sourceType == UIImagePickerControllerSourceTypeCamera) {
|
|
[UIView beginAnimations: @"ZBarHelp"
|
|
context: nil];
|
|
hlp.view.alpha = 0;
|
|
[UIView commitAnimations];
|
|
[self initScanning];
|
|
}
|
|
else
|
|
[hlp dismissModalViewControllerAnimated: YES];
|
|
}
|
|
|
|
- (id <NSFastEnumeration>) scanImage: (CGImageRef) image
|
|
{
|
|
timer_start;
|
|
|
|
int nsyms = [self scanImage: image
|
|
withScaling: 0];
|
|
|
|
if(!nsyms &&
|
|
CGImageGetWidth(image) >= 640 &&
|
|
CGImageGetHeight(image) >= 640)
|
|
// make one more attempt for close up, grainy images
|
|
nsyms = [self scanImage: image
|
|
withScaling: .5];
|
|
|
|
NSMutableArray *syms = nil;
|
|
if(nsyms) {
|
|
// quality/type filtering
|
|
int max_quality = MIN_QUALITY;
|
|
for(ZBarSymbol *sym in scanner.results) {
|
|
zbar_symbol_type_t type = sym.type;
|
|
int quality;
|
|
if(type == ZBAR_QRCODE)
|
|
quality = INT_MAX;
|
|
else
|
|
quality = sym.quality;
|
|
|
|
if(quality < max_quality) {
|
|
zlog(@" type=%d quality=%d < %d\n",
|
|
type, quality, max_quality);
|
|
continue;
|
|
}
|
|
|
|
if(max_quality < quality) {
|
|
max_quality = quality;
|
|
if(syms)
|
|
[syms removeAllObjects];
|
|
}
|
|
zlog(@" type=%d quality=%d\n", type, quality);
|
|
if(!syms)
|
|
syms = [NSMutableArray arrayWithCapacity: 1];
|
|
|
|
[syms addObject: sym];
|
|
}
|
|
}
|
|
|
|
zlog(@"read %d filtered symbols in %gs total\n",
|
|
(!syms) ? 0 : [syms count], timer_elapsed(t_start, timer_now()));
|
|
return(syms);
|
|
}
|
|
|
|
@end
|