2 * Copyright 2009 Jeff Verkoeyen
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #import "ZXingWidgetController.h"
19 #import "NSString+HTML.h"
20 #import "ResultParser.h"
21 #import "ParsedResult.h"
22 #import "ResultAction.h"
23 #include <sys/types.h>
24 #include <sys/sysctl.h>
26 #define CAMERA_SCALAR 1.12412 // scalar = (480 / (2048 / 480))
27 #define FIRST_TAKE_DELAY 1.0
28 #define ONE_D_BAND_HEIGHT 10.0
30 CGImageRef UIGetScreenImage(void);
32 @interface ZXingWidgetController ()
34 @property BOOL showCancel;
35 @property BOOL oneDMode;
37 @property (nonatomic, retain) UIImagePickerController* imagePicker;
45 @implementation ZXingWidgetController
46 @synthesize result, actions, delegate, soundToPlay;
47 @synthesize overlayView;
48 @synthesize oneDMode, showCancel;
49 @synthesize imagePicker;
53 -(void)loadImagePicker {
56 [imagePicker release];
59 UIImagePickerController* imController = [[UIImagePickerController alloc] init];
60 self.imagePicker = imController;
61 imagePicker.delegate = self;
62 [imController release];
63 imagePicker.wantsFullScreenLayout = YES;
64 if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
65 imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
66 float zoomFactor = CAMERA_SCALAR;
67 if ([self fixedFocus]) {
70 if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
71 imagePicker.cameraViewTransform = CGAffineTransformScale(
72 imagePicker.cameraViewTransform, zoomFactor, zoomFactor);
73 if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
75 imagePicker.showsCameraControls = NO;
76 imagePicker.cameraOverlayView = overlayView;
77 imagePicker.allowsEditing = NO;
81 - (id)initWithDelegate:(id<ZXingDelegate>)scanDelegate showCancel:(BOOL)shouldShowCancel OneDMode:(BOOL)shouldUseoOneDMode {
82 if (self = [super init]) {
83 [self setDelegate:scanDelegate];
84 self.oneDMode = shouldUseoOneDMode;
85 self.showCancel = shouldShowCancel;
86 self.wantsFullScreenLayout = YES;
88 OverlayView *theOverLayView = [[OverlayView alloc] initWithFrame:[UIScreen mainScreen].bounds
89 cancelEnabled:showCancel
91 [theOverLayView setDelegate:self];
92 self.overlayView = theOverLayView;
93 [theOverLayView release];
100 if (beepSound != -1) {
101 AudioServicesDisposeSystemSoundID(beepSound);
103 imagePicker.cameraOverlayView = nil;
104 [imagePicker release];
105 [overlayView release];
111 NSLog(@"cancelled called in ZXingWidgetController");
112 [[UIApplication sharedApplication] setStatusBarHidden:NO];
114 if (delegate != nil) {
115 [delegate cancelled];
119 - (NSString *)getPlatform {
121 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
122 char *machine = malloc(size);
123 sysctlbyname("hw.machine", machine, &size, NULL, 0);
124 NSString *platform = [NSString stringWithCString:machine encoding:NSASCIIStringEncoding];
130 NSString *platform = [self getPlatform];
131 if ([platform isEqualToString:@"iPhone1,1"] ||
132 [platform isEqualToString:@"iPhone1,2"]) return true;
136 - (void)viewWillAppear:(BOOL)animated {
137 [super viewWillAppear:animated];
138 self.wantsFullScreenLayout = YES;
139 //[[UIApplication sharedApplication] setStatusBarHidden:YES];
140 if ([self soundToPlay] != nil) {
141 OSStatus error = AudioServicesCreateSystemSoundID((CFURLRef)[self soundToPlay], &beepSound);
142 if (error != kAudioServicesNoError) {
143 NSLog(@"Problem loading nearSound.caf");
148 - (void)viewDidAppear:(BOOL)animated {
149 NSLog(@"View did appear");
150 [super viewDidAppear:animated];
151 [[UIApplication sharedApplication] setStatusBarHidden:YES];
152 //self.wantsFullScreenLayout = YES;
153 [self loadImagePicker];
154 self.view = imagePicker.view;
156 [overlayView setPoints:nil];
157 wasCancelled = false;
158 if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
160 [NSTimer scheduledTimerWithTimeInterval: FIRST_TAKE_DELAY
162 selector: @selector(takePicture:)
168 - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
169 //self.wantsFullScreenLayout = NO;
170 [UIApplication sharedApplication].statusBarHidden = NO;
175 - (CGImageRef)CGImageRotated90:(CGImageRef)imgRef
177 CGFloat angleInRadians = -90 * (M_PI / 180);
178 CGFloat width = CGImageGetWidth(imgRef);
179 CGFloat height = CGImageGetHeight(imgRef);
181 CGRect imgRect = CGRectMake(0, 0, width, height);
182 CGAffineTransform transform = CGAffineTransformMakeRotation(angleInRadians);
183 CGRect rotatedRect = CGRectApplyAffineTransform(imgRect, transform);
185 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
186 CGContextRef bmContext = CGBitmapContextCreate(NULL,
187 rotatedRect.size.width,
188 rotatedRect.size.height,
192 kCGImageAlphaPremultipliedFirst);
193 CGContextSetAllowsAntialiasing(bmContext, FALSE);
194 CGContextSetInterpolationQuality(bmContext, kCGInterpolationNone);
195 CGColorSpaceRelease(colorSpace);
196 // CGContextTranslateCTM(bmContext,
197 // +(rotatedRect.size.width/2),
198 // +(rotatedRect.size.height/2));
199 CGContextScaleCTM(bmContext, rotatedRect.size.width/rotatedRect.size.height, 1.0);
200 CGContextTranslateCTM(bmContext, 0.0, rotatedRect.size.height);
201 CGContextRotateCTM(bmContext, angleInRadians);
202 // CGContextTranslateCTM(bmContext,
203 // -(rotatedRect.size.width/2),
204 // -(rotatedRect.size.height/2));
205 CGContextDrawImage(bmContext, CGRectMake(0, 0,
206 rotatedRect.size.width,
207 rotatedRect.size.height),
210 CGImageRef rotatedImage = CGBitmapContextCreateImage(bmContext);
211 CFRelease(bmContext);
212 [(id)rotatedImage autorelease];
217 - (CGImageRef)CGImageRotated180:(CGImageRef)imgRef
219 CGFloat angleInRadians = M_PI;
220 CGFloat width = CGImageGetWidth(imgRef);
221 CGFloat height = CGImageGetHeight(imgRef);
223 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
224 CGContextRef bmContext = CGBitmapContextCreate(NULL,
230 kCGImageAlphaPremultipliedFirst);
231 CGContextSetAllowsAntialiasing(bmContext, FALSE);
232 CGContextSetInterpolationQuality(bmContext, kCGInterpolationNone);
233 CGColorSpaceRelease(colorSpace);
234 CGContextTranslateCTM(bmContext,
237 CGContextRotateCTM(bmContext, angleInRadians);
238 CGContextTranslateCTM(bmContext,
241 CGContextDrawImage(bmContext, CGRectMake(0, 0, width, height), imgRef);
243 CGImageRef rotatedImage = CGBitmapContextCreateImage(bmContext);
244 CFRelease(bmContext);
245 [(id)rotatedImage autorelease];
250 - (void)takePicture:(NSTimer*)theTimer {
251 CGImageRef capture = UIGetScreenImage();
252 CGRect cropRect = [overlayView cropRect];
254 // let's just give the decoder a vertical band right above the red line
255 cropRect.origin.x = cropRect.origin.x + (cropRect.size.width / 2) - (ONE_D_BAND_HEIGHT + 1);
256 cropRect.size.width = ONE_D_BAND_HEIGHT;
258 CGImageRef croppedImg = CGImageCreateWithImageInRect(capture, cropRect);
259 capture = [self CGImageRotated90:croppedImg];
260 capture = [self CGImageRotated180:capture];
261 // UIImageWriteToSavedPhotosAlbum([UIImage imageWithCGImage:capture], nil, nil, nil);
262 CGImageRelease(croppedImg);
263 cropRect.origin.x = 0.0;
264 cropRect.origin.y = 0.0;
265 cropRect.size.width = CGImageGetWidth(capture);
266 cropRect.size.height = CGImageGetHeight(capture);
268 CGImageRef newImage = CGImageCreateWithImageInRect(capture, cropRect);
269 CGImageRelease(capture);
270 //UIImage *scrn = [UIImage imageWithCGImage:newImage];
271 UIImage *scrn = [[UIImage alloc] initWithCGImage:newImage];
272 CGImageRelease(newImage);
273 Decoder *d = [[Decoder alloc] init];
276 cropRect.origin.x = 0.0;
277 cropRect.origin.y = 0.0;
278 [d decodeImage:scrn cropRect:cropRect];
282 // DecoderDelegate methods
284 - (void)decoder:(Decoder *)decoder willDecodeImage:(UIImage *)image usingSubset:(UIImage *)subset{
286 NSLog(@"DecoderViewController MessageWhileDecodingWithDimensions: Decoding image (%.0fx%.0f) ...", image.size.width, image.size.height);
290 - (void)decoder:(Decoder *)decoder
291 decodingImage:(UIImage *)image
292 usingSubset:(UIImage *)subset
293 progress:(NSString *)message {
296 - (void)presentResultForString:(NSString *)resultString {
297 self.result = [ResultParser parsedResultForString:resultString];
299 if (beepSound != -1) {
300 AudioServicesPlaySystemSound(beepSound);
303 NSLog(@"result string = %@", resultString);
304 NSLog(@"result has %d actions", actions ? 0 : actions.count);
306 // [self updateToolbar];
309 - (void)presentResultPoints:(NSArray *)resultPoints
310 forImage:(UIImage *)image
311 usingSubset:(UIImage *)subset {
312 // simply add the points to the image view
313 [overlayView setPoints:resultPoints];
316 - (void)decoder:(Decoder *)decoder didDecodeImage:(UIImage *)image usingSubset:(UIImage *)subset withResult:(TwoDDecoderResult *)twoDResult {
317 [self presentResultForString:[twoDResult text]];
318 [self presentResultPoints:[twoDResult points] forImage:image usingSubset:subset];
319 // now, in a selector, call the delegate to give this overlay time to show the points
320 [self performSelector:@selector(alertDelegate:) withObject:[[twoDResult text] copy] afterDelay:1.0];
321 decoder.delegate = nil;
325 - (void)alertDelegate:(id)text {
326 if (delegate != nil) {
327 [delegate scanResult:text];
331 - (void)decoder:(Decoder *)decoder failedToDecodeImage:(UIImage *)image usingSubset:(UIImage *)subset reason:(NSString *)reason {
332 decoder.delegate = nil;
334 [overlayView setPoints:nil];
336 [self takePicture:nil];
338 //[self updateToolbar];