#import "DecoderViewController.h"
#import "Decoder.h"
#import "NSString+HTML.h"
+#import "ResultParser.h"
#import "ParsedResult.h"
#import "ResultAction.h"
#import "Database.h"
#import "ArchiveController.h"
+#import "MessageViewController.h"
#import "Scan.h"
#import "TwoDDecoderResult.h"
-
@implementation DecoderViewController
@synthesize cameraBarItem;
@synthesize actionBarItem;
@synthesize messageView;
-@synthesize resultView;
+@synthesize messageTextView;
+@synthesize messageHelpButton;
@synthesize imageView;
@synthesize toolbar;
@synthesize result;
@synthesize actions;
+@synthesize resultPointViews;
+
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
// Initialization code
- self.title = @"ZXing";
+ self.title = NSLocalizedString(@"DecoderViewController AppTitle", @"Barcode Scanner");
Decoder *d = [[Decoder alloc] init];
self.decoder = d;
d.delegate = self;
[d release];
+ resultPointViews = [[NSMutableArray alloc] init];
}
return self;
}
+- (void) messageReady:(id)sender {
+ MessageViewController *messageController = sender;
+ [[self navigationController] pushViewController:messageController animated:true];
+ [messageController release];
+}
+
+- (void) messageFailed:(id)sender {
+ MessageViewController *messageController = sender;
+ NSLog(@"Failed to load message!");
+ [messageController release];
+}
+
+- (void) showHints:(id)sender {
+ NSLog(@"Showing Hints!");
+
+ MessageViewController *hintsController =
+ [[MessageViewController alloc] initWithMessageFilename:@"Hints"
+ target:self
+ onSuccess:@selector(messageReady:)
+ onFailure:@selector(messageFailed:)];
+ hintsController.title = NSLocalizedString(@"DecoderViewController Hints MessageViewController title", @"Hints");
+ hintsController.view;
+}
+
+- (void) showAbout:(id)sender {
+ NSLog(@"Showing About!");
+
+ MessageViewController *aboutController =
+ [[MessageViewController alloc] initWithMessageFilename:@"About"
+ target:self
+ onSuccess:@selector(messageReady:)
+ onFailure:@selector(messageFailed:)];
+ aboutController.title = NSLocalizedString(@"DecoderViewController About MessageViewController title", @"About");
+ aboutController.view;
+}
+
+
+#define HELP_BUTTON_WIDTH (44.0)
+#define HELP_BUTTON_HEIGHT (55.0)
+
+
+#define FONT_NAME @"TimesNewRomanPSMT"
+#define FONT_SIZE 16.0
+
+- (void) reset {
+ self.result = nil;
+ [self clearImageView];
+ [self updateToolbar];
+ [self showMessage:NSLocalizedString(@"DecoderViewController take or choose picture", @"Please take or choose a picture containing a barcode") helpButton:YES];
+}
// Implement loadView if you want to create a view hierarchy programmatically
- (void)loadView {
[super loadView];
- CGRect mViewFrame = self.resultView.bounds;
- UITextView *mView = [[UITextView alloc] initWithFrame:mViewFrame];
- mView.backgroundColor = [UIColor yellowColor];
- mView.alpha = 0.95;
- mView.editable = false;
- mView.scrollEnabled = true;
+ CGRect messageViewFrame = imageView.frame;
+ UIView *mView = [[UIView alloc] initWithFrame:messageViewFrame];
+ mView.backgroundColor = [UIColor darkGrayColor];
+ mView.alpha = 0.9;
mView.autoresizingMask = UIViewAutoresizingFlexibleHeight |
- UIViewAutoresizingFlexibleWidth |
- UIViewAutoresizingFlexibleLeftMargin |
- UIViewAutoresizingFlexibleRightMargin |
- UIViewAutoresizingFlexibleTopMargin |
- UIViewAutoresizingFlexibleBottomMargin;
+ UIViewAutoresizingFlexibleWidth |
+ UIViewAutoresizingFlexibleTopMargin;
+
+ UITextView *mTextView = [[UITextView alloc] initWithFrame:messageViewFrame];
+ mTextView.autoresizingMask = UIViewAutoresizingFlexibleHeight |
+ UIViewAutoresizingFlexibleWidth;
+ mTextView.editable = false;
+ mTextView.scrollEnabled = true;
+ mTextView.font = [UIFont fontWithName:FONT_NAME size:FONT_SIZE];
+ mTextView.textColor = [UIColor whiteColor];
+ mTextView.backgroundColor = [[UIColor lightGrayColor] colorWithAlphaComponent:0.0];
+ mTextView.textAlignment = UITextAlignmentLeft;
+ mTextView.alpha = 1.0;
+ [mView addSubview:mTextView];
+
+ UIButton *mHelpButton = [[UIButton buttonWithType:UIButtonTypeInfoLight] retain];
+ mHelpButton.frame = CGRectMake(messageViewFrame.size.width - HELP_BUTTON_WIDTH, 0.0, HELP_BUTTON_WIDTH, HELP_BUTTON_HEIGHT);
+
+ mHelpButton.backgroundColor = [UIColor clearColor];
+ [mHelpButton setUserInteractionEnabled:YES];
+ [mHelpButton addTarget:self action:@selector(showHints:) forControlEvents:UIControlEventTouchUpInside];
+
+ self.messageHelpButton = mHelpButton;
+ [mHelpButton release];
+
+ self.messageTextView = mTextView;
+ [mTextView release];
+
self.messageView = mView;
[mView release];
- [self.resultView addSubview:self.messageView];
- [self updateToolbar];
- [self showMessage:NSLocalizedString(@"Please take or choose a picture containing a barcode", @"")];
+ [self.view addSubview:self.messageView];
+
+ // add the 'About' button at the top-right of the navigation bar
+ UIBarButtonItem *aboutButton =
+ [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"DecoderViewController about button title", @"About")
+ style:UIBarButtonItemStyleBordered
+ target:self
+ action:@selector(showAbout:)];
+ self.navigationItem.rightBarButtonItem = aboutButton;
+ [aboutButton release];
+
+ [self reset];
}
- (void) updateToolbar {
}
+- (void)clearImageView {
+ imageView.image = nil;
+ for (UIView *view in resultPointViews) {
+ [view removeFromSuperview];
+ }
+ [resultPointViews removeAllObjects];
+}
+
- (void)pickAndDecodeFromSource:(UIImagePickerControllerSourceType) sourceType {
- self.result = nil;
+ [self reset];
+ \
// Create the Image Picker
if ([UIImagePickerController isSourceTypeAvailable:sourceType]) {
UIImagePickerController* picker = [[UIImagePickerController alloc] init];
picker.sourceType = sourceType;
picker.delegate = self;
- picker.allowsImageEditing = [[NSUserDefaults standardUserDefaults]
- boolForKey:@"allowEditing"];
+ picker.allowsImageEditing = YES; // [[NSUserDefaults standardUserDefaults] boolForKey:@"allowEditing"];
// Picker is displayed asynchronously.
[self presentModalViewController:picker animated:YES];
// Release anything that's not essential, such as cached data
}
-
- (void)dealloc {
[decoder release];
+ [self clearImageView];
[imageView release];
[actionBarItem release];
[cameraBarItem release];
[savedPhotosBarItem release];
[archiveBarItem release];
[toolbar release];
+ [actions dealloc];
+ [resultPointViews dealloc];
[super dealloc];
}
-- (void)showMessage:(NSString *)message {
+- (void)showMessage:(NSString *)message helpButton:(BOOL)showHelpButton {
#ifdef DEBUG
- NSLog(@"Showing message '%@'", message);
+ NSLog(@"Showing message '%@' %@ help Button", message, showHelpButton ? @"with" : @"without");
#endif
- self.messageView.text = message;
- [self.messageView sizeToFit];
+
+ CGSize maxSize = imageView.bounds.size;
+ if (showHelpButton) {
+ maxSize.width -= messageHelpButton.frame.size.width;
+ }
+ CGSize size = [message sizeWithFont:messageTextView.font constrainedToSize:maxSize lineBreakMode:UILineBreakModeWordWrap];
+ float height = 20.0 + fmin(100.0, size.height);
+ if (showHelpButton) {
+ height = fmax(HELP_BUTTON_HEIGHT, height);
+ }
+
+ CGRect messageFrame = imageView.bounds;
+ messageFrame.origin.y = CGRectGetMaxY(messageFrame) - height;
+ messageFrame.size.height = height;
+ [self.messageView setFrame:messageFrame];
+ messageView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth;
+ CGRect messageViewBounds = [messageView bounds];
+
+ self.messageTextView.text = message;
+ messageTextView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+ if (showHelpButton) {
+ CGRect textViewFrame;
+ CGRect helpButtonFrame;
+
+ CGRectDivide(messageViewBounds, &helpButtonFrame, &textViewFrame, HELP_BUTTON_WIDTH, CGRectMaxXEdge);
+ [self.messageTextView setFrame:textViewFrame];
+
+ [messageHelpButton setFrame:helpButtonFrame];
+ messageHelpButton.alpha = 1.0;
+ messageHelpButton.enabled = YES;
+ messageHelpButton.autoresizingMask =
+ UIViewAutoresizingFlexibleLeftMargin |
+ UIViewAutoresizingFlexibleTopMargin;
+ [messageView addSubview:messageHelpButton];
+ } else {
+ [messageHelpButton removeFromSuperview];
+ messageHelpButton.alpha = 0.0;
+ messageHelpButton.enabled = NO;
+
+ [self.messageTextView setFrame:messageViewBounds];
+ }
}
// DecoderDelegate methods
- (void)decoder:(Decoder *)decoder willDecodeImage:(UIImage *)image {
+ [self clearImageView];
[self.imageView setImage:image];
- [self showMessage:[NSString stringWithFormat:NSLocalizedString(@"Decoding image (%.0fx%.0f) ...", @"shown while image is decoding"), image.size.width, image.size.height]];
+ [self showMessage:[NSString stringWithFormat:NSLocalizedString(@"DecoderViewController MessageWhileDecodingWithDimensions", @"Decoding image (%.0fx%.0f) ..."), image.size.width, image.size.height]
+ helpButton:NO];
}
- (void)decoder:(Decoder *)decoder
decodingImage:(UIImage *)image
usingSubset:(UIImage *)subset
progress:(NSString *)message {
+ [self clearImageView];
[self.imageView setImage:subset];
- [self showMessage:message];
+ [self showMessage:message helpButton:NO];
}
- (void)presentResultForString:(NSString *)resultString {
- self.result = [ParsedResult parsedResultForString:resultString];
- [self showMessage:[self.result stringForDisplay]];
+ self.result = [ResultParser parsedResultForString:resultString];
+ [self showMessage:[self.result stringForDisplay] helpButton:NO];
self.actions = self.result.actions;
#ifdef DEBUG
NSLog(@"result has %d actions", actions ? 0 : actions.count);
#endif
[self updateToolbar];
-}
+}
+
+- (void)presentResultPoints:(NSArray *)resultPoints
+ forImage:(UIImage *)image
+ usingSubset:(UIImage *)subset {
+ // simply add the points to the image view
+ imageView.image = subset;
+ for (NSValue *pointValue in resultPoints) {
+ [imageView addResultPoint:[pointValue CGPointValue]];
+ }
+}
-- (void)decoder:(Decoder *)decoder didDecodeImage:(UIImage *)image withResult:(TwoDDecoderResult *)twoDResult {
+- (void)decoder:(Decoder *)decoder didDecodeImage:(UIImage *)image usingSubset:(UIImage *)subset withResult:(TwoDDecoderResult *)twoDResult {
[self presentResultForString:twoDResult.text];
+ [self presentResultPoints:twoDResult.points forImage:image usingSubset:subset];
+
// save the scan to the shared database
[[Database sharedDatabase] addScanWithText:twoDResult.text];
[self performResultAction:self];
}
-- (void)decoder:(Decoder *)decoder failedToDecodeImage:(UIImage *)image reason:(NSString *)reason {
- [self showMessage:reason];
+- (void)decoder:(Decoder *)decoder failedToDecodeImage:(UIImage *)image usingSubset:(UIImage *)subset reason:(NSString *)reason {
+ [self showMessage:reason helpButton:YES];
[self updateToolbar];
}
+- (void)willAnimateFirstHalfOfRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
+ [super willAnimateFirstHalfOfRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];
+
+ if (imageView.image) {
+ /*
+ CGRect viewBounds = imageView.bounds;
+ CGSize imageSize = imageView.image.size;
+ float scale = fmin(viewBounds.size.width / imageSize.width,
+ viewBounds.size.height / imageSize.height);
+ float xOffset = (viewBounds.size.width - scale * imageSize.width) / 2.0;
+ float yOffset = (viewBounds.size.height - scale * imageSize.height) / 2.0;
+ */
+
+ for (UIView *view in resultPointViews) {
+ view.alpha = 0.0;
+ }
+ }
+}
+
+- (void)willAnimateSecondHalfOfRotationFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation duration:(NSTimeInterval)duration {
+ [super willAnimateSecondHalfOfRotationFromInterfaceOrientation:fromInterfaceOrientation duration:duration];
+
+ if (imageView.image) {
+ /*
+ CGRect viewBounds = imageView.bounds;
+ CGSize imageSize = imageView.image.size;
+ float scale = fmin(viewBounds.size.width / imageSize.width,
+ viewBounds.size.height / imageSize.height);
+ float xOffset = (viewBounds.size.width - scale * imageSize.width) / 2.0;
+ float yOffset = (viewBounds.size.height - scale * imageSize.height) / 2.0;
+ */
+
+ for (UIView *view in resultPointViews) {
+ view.alpha = 1.0;
+ }
+ }
+}
+
// UIImagePickerControllerDelegate methods
- (void)imagePickerController:(UIImagePickerController *)picker
didFinishPickingImage:(UIImage *)image
editingInfo:(NSDictionary *)editingInfo
{
+ UIImage *imageToDecode = image;
#ifdef DEBUG
NSLog(@"picked image size = (%f, %f)", image.size.width, image.size.height);
+#endif
if (editingInfo) {
UIImage *originalImage = [editingInfo objectForKey:UIImagePickerControllerOriginalImage];
if (originalImage) {
+#ifdef DEBUG
NSLog(@"original image size = (%f, %f)", originalImage.size.width, originalImage.size.height);
- }
- NSValue *cropRectValue = [editingInfo objectForKey:UIImagePickerControllerCropRect];
- if (cropRectValue) {
- CGRect cropRect = [cropRectValue CGRectValue];
- NSLog(@"crop rect = (%f, %f) x (%f, %f)", CGRectGetMinX(cropRect), CGRectGetMinY(cropRect), CGRectGetWidth(cropRect), CGRectGetHeight(cropRect));
+#endif
+ NSValue *cropRectValue = [editingInfo objectForKey:UIImagePickerControllerCropRect];
+ if (cropRectValue) {
+ CGRect cropRect = [cropRectValue CGRectValue];
+#ifdef DEBUG
+ NSLog(@"crop rect = (%f, %f) x (%f, %f)", CGRectGetMinX(cropRect), CGRectGetMinY(cropRect), CGRectGetWidth(cropRect), CGRectGetHeight(cropRect));
+#endif
+ UIGraphicsBeginImageContext(cropRect.size);
+
+ [originalImage drawAtPoint:CGPointMake(-CGRectGetMinX(cropRect),
+ -CGRectGetMinY(cropRect))];
+
+ imageToDecode = UIGraphicsGetImageFromCurrentImageContext();
+ UIGraphicsEndImageContext();
+ }
}
}
-#endif
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
- [image retain];
+ [imageToDecode retain];
[picker release];
- [self.decoder decodeImage:image];
- [image release];
+ [self.decoder decodeImage:imageToDecode];
+ [imageToDecode release];
[self updateToolbar];
}
[actionSheet addButtonWithTitle:[action title]];
}
- int cancelIndex = [actionSheet addButtonWithTitle:NSLocalizedString(@"Cancel", @"")];
+ int cancelIndex = [actionSheet addButtonWithTitle:NSLocalizedString(@"DecoderViewController cancel button title", @"Cancel")];
actionSheet.cancelButtonIndex = cancelIndex;
actionSheet.delegate = self;
}
- (void)showScan:(Scan *)scan {
- [self.imageView setImage:nil];
+ [self clearImageView];
[self presentResultForString:scan.text];
[[self navigationController] popToViewController:self animated:YES];
}