2 // DecoderViewController.m
5 // Created by Christian Brunschen on 22/05/2008.
7 * Copyright 2008 Google Inc.
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
22 #import "DecoderViewController.h"
24 #import "NSString+HTML.h"
25 #import "ParsedResult.h"
26 #import "ResultAction.h"
29 #import "ArchiveController.h"
31 #import "TwoDDecoderResult.h"
34 @implementation DecoderViewController
36 @synthesize cameraBarItem;
37 @synthesize libraryBarItem;
38 @synthesize savedPhotosBarItem;
39 @synthesize archiveBarItem;
40 @synthesize actionBarItem;
42 @synthesize messageView;
43 @synthesize resultView;
44 @synthesize imageView;
51 - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
52 if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
53 // Initialization code
54 self.title = @"ZXing";
56 Decoder *d = [[Decoder alloc] init];
65 // Implement loadView if you want to create a view hierarchy programmatically
69 CGRect mViewFrame = self.resultView.bounds;
70 UITextView *mView = [[UITextView alloc] initWithFrame:mViewFrame];
71 mView.backgroundColor = [UIColor yellowColor];
73 mView.editable = false;
74 mView.scrollEnabled = true;
75 mView.autoresizingMask = UIViewAutoresizingFlexibleHeight |
76 UIViewAutoresizingFlexibleWidth |
77 UIViewAutoresizingFlexibleLeftMargin |
78 UIViewAutoresizingFlexibleRightMargin |
79 UIViewAutoresizingFlexibleTopMargin |
80 UIViewAutoresizingFlexibleBottomMargin;
81 self.messageView = mView;
84 [self.resultView addSubview:self.messageView];
86 [self showMessage:@"Please take or choose a picture containing a barcode"];
89 - (void) updateToolbar {
90 self.cameraBarItem.enabled = [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera];
91 self.savedPhotosBarItem.enabled = [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeSavedPhotosAlbum];
92 self.libraryBarItem.enabled = [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary];
93 self.archiveBarItem.enabled = true;
94 self.actionBarItem.enabled = (self.result != nil) && ([self.result actions] != nil) && ([self.result actions].count > 0);
98 // If you need to do additional setup after loading the view, override viewDidLoad.
104 - (void)pickAndDecodeFromSource:(UIImagePickerControllerSourceType) sourceType {
106 // Create the Image Picker
107 if ([UIImagePickerController isSourceTypeAvailable:sourceType]) {
108 UIImagePickerController* picker = [[UIImagePickerController alloc] init];
109 picker.sourceType = sourceType;
110 picker.delegate = self;
111 picker.allowsImageEditing = [[NSUserDefaults standardUserDefaults]
112 boolForKey:@"allowEditing"];
114 // Picker is displayed asynchronously.
115 [self presentModalViewController:picker animated:YES];
117 NSLog(@"Attempted to pick an image with illegal source type '%d'", sourceType);
121 - (IBAction)pickAndDecode:(id) sender {
122 UIImagePickerControllerSourceType sourceType;
123 int i = [sender tag];
126 case 0: sourceType = UIImagePickerControllerSourceTypeCamera; break;
127 case 1: sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum; break;
128 case 2: sourceType = UIImagePickerControllerSourceTypePhotoLibrary; break;
129 default: sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
131 [self pickAndDecodeFromSource:sourceType];
135 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
136 // Return YES for supported orientations
141 - (void)didReceiveMemoryWarning {
142 [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
143 // Release anything that's not essential, such as cached data
150 [actionBarItem release];
151 [cameraBarItem release];
152 [libraryBarItem release];
153 [savedPhotosBarItem release];
154 [archiveBarItem release];
160 - (void)showMessage:(NSString *)message {
162 self.messageView.text = message;
163 [self.messageView sizeToFit];
166 // DecoderDelegate methods
168 - (void)decoder:(Decoder *)decoder willDecodeImage:(UIImage *)image {
169 [self.imageView setImage:image];
170 [self showMessage:[NSString stringWithFormat:@"Decoding image (%.0fx%.0f) ...", image.size.width, image.size.height]];
173 - (void)decoder:(Decoder *)decoder
174 decodingImage:(UIImage *)image
175 usingSubset:(UIImage *)subset
176 progress:(NSString *)message {
177 [self.imageView setImage:subset];
178 [self showMessage:message];
181 - (void)presentResultForString:(NSString *)resultString {
182 self.result = [ParsedResult parsedResultForString:resultString];
183 [self showMessage:[self.result stringForDisplay]];
184 self.actions = self.result.actions;
185 NSLog(@"result has %d actions", actions ? 0 : actions.count);
186 [self updateToolbar];
189 - (void)decoder:(Decoder *)decoder didDecodeImage:(UIImage *)image withResult:(TwoDDecoderResult *)twoDResult {
190 [self presentResultForString:twoDResult.text];
192 // save the scan to the shared database
193 [[Database sharedDatabase] addScanWithText:twoDResult.text];
195 [self performResultAction:self];
198 - (void)decoder:(Decoder *)decoder failedToDecodeImage:(UIImage *)image reason:(NSString *)reason {
199 [self showMessage:reason];
200 [self updateToolbar];
204 // UIImagePickerControllerDelegate methods
206 - (void)imagePickerController:(UIImagePickerController *)picker
207 didFinishPickingImage:(UIImage *)image
208 editingInfo:(NSDictionary *)editingInfo
210 NSLog(@"picked image size = (%f, %f)", image.size.width, image.size.height);
212 UIImage *originalImage = [editingInfo objectForKey:UIImagePickerControllerOriginalImage];
214 NSLog(@"original image size = (%f, %f)", originalImage.size.width, originalImage.size.height);
216 NSValue *cropRectValue = [editingInfo objectForKey:UIImagePickerControllerCropRect];
218 CGRect cropRect = [cropRectValue CGRectValue];
219 NSLog(@"crop rect = (%f, %f) x (%f, %f)", CGRectGetMinX(cropRect), CGRectGetMinY(cropRect), CGRectGetWidth(cropRect), CGRectGetHeight(cropRect));
223 [[picker parentViewController] dismissModalViewControllerAnimated:YES];
226 [self.decoder decodeImage:image];
228 [self updateToolbar];
231 - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
233 [picker dismissModalViewControllerAnimated:YES];
235 [self updateToolbar];
238 - (void)navigationController:(UINavigationController *)navigationController
239 didShowViewController:(UIViewController *)viewController
240 animated:(BOOL)animated {
244 - (void)navigationController:(UINavigationController *)navigationController
245 willShowViewController:(UIViewController *)viewController
246 animated:(BOOL)animated {
251 - (IBAction)performResultAction:(id)sender {
252 if (self.result == nil) {
253 NSLog(@"no result to perform an action on!");
257 if (self.actions == nil || self.actions.count == 0) {
258 NSLog(@"result has no actions to perform!");
262 if (self.actions.count == 1) {
263 ResultAction *action = [self.actions lastObject];
264 NSLog(@"Result has the single action, (%@) '%@', performing it",
265 NSStringFromClass([action class]), [action title]);
266 [action performSelector:@selector(performActionWithController:)
270 NSLog(@"Result has multiple actions, popping up an action sheet");
271 UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithFrame:self.view.bounds];
273 for (ResultAction *action in self.actions) {
274 [actionSheet addButtonWithTitle:[action title]];
277 int cancelIndex = [actionSheet addButtonWithTitle:@"Cancel"];
278 actionSheet.cancelButtonIndex = cancelIndex;
280 actionSheet.delegate = self;
282 [actionSheet showFromToolbar:self.toolbar];
286 - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
287 if (buttonIndex < self.actions.count) {
288 int actionIndex = buttonIndex;
289 ResultAction *action = [self.actions objectAtIndex:actionIndex];
290 [action performSelector:@selector(performActionWithController:)
296 - (IBAction)showArchive:(id)sender {
297 ArchiveController *archiveController = [[ArchiveController alloc] initWithDecoderViewController:self];
298 [[self navigationController] pushViewController:archiveController animated:true];
299 [archiveController release];
302 - (void)showScan:(Scan *)scan {
303 [[self navigationController] popToViewController:self animated:YES];
304 [self presentResultForString:scan.text];