[iphone] temporary fix because still not valid for app store. ScanTest now builds...
[zxing.git] / iphone / ZXingWidget / Classes / ZXingWidgetController.m
1 /**
2  * Copyright 2009 Jeff Verkoeyen
3  *
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
7  *
8  *    http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #import "ZXingWidgetController.h"
18 #import "Decoder.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>
25
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
29
30 CGImageRef UIGetScreenImage(void);
31
32 @interface ZXingWidgetController ()
33
34 @property BOOL showCancel;
35 @property BOOL oneDMode;
36
37 @property (nonatomic, retain) UIImagePickerController* imagePicker;
38
39 @end
40
41
42
43
44
45 @implementation ZXingWidgetController
46 @synthesize result, actions, delegate, soundToPlay;
47 @synthesize overlayView;
48 @synthesize oneDMode, showCancel;
49 @synthesize imagePicker;
50 @synthesize readers;
51
52
53 -(void)loadImagePicker {
54   if (self.imagePicker)
55   {
56     [imagePicker release];
57     imagePicker = nil;
58   }
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]) {
68     zoomFactor *= 2.0;
69   }
70   if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
71     imagePicker.cameraViewTransform = CGAffineTransformScale(
72                                                              imagePicker.cameraViewTransform, zoomFactor, zoomFactor);
73   if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
74   {
75     imagePicker.showsCameraControls = NO;
76     imagePicker.cameraOverlayView = overlayView;
77     imagePicker.allowsEditing = NO;
78   }
79 }
80
81 - (void)unloadImagePicker {
82   if (self.imagePicker)
83   {
84     [imagePicker release];
85     imagePicker = nil;
86   }
87 }
88
89 - (id)initWithDelegate:(id<ZXingDelegate>)scanDelegate showCancel:(BOOL)shouldShowCancel OneDMode:(BOOL)shouldUseoOneDMode {
90   if (self = [super init]) {
91     [self setDelegate:scanDelegate];
92     self.oneDMode = shouldUseoOneDMode;
93     self.showCancel = shouldShowCancel;
94     self.wantsFullScreenLayout = YES;
95     beepSound = -1;
96     OverlayView *theOverLayView = [[OverlayView alloc] initWithFrame:[UIScreen mainScreen].bounds 
97                                                        cancelEnabled:showCancel 
98                                                             oneDMode:oneDMode];
99     [theOverLayView setDelegate:self];
100     self.overlayView = theOverLayView;
101     [theOverLayView release];
102   }
103   
104   return self;
105 }
106
107 - (void)dealloc {
108   if (beepSound != -1) {
109     AudioServicesDisposeSystemSoundID(beepSound);
110   }
111   imagePicker.cameraOverlayView = nil;
112   [imagePicker release];
113   [overlayView release];
114   [readers release];
115   [super dealloc];
116 }
117
118 - (void)cancelled {
119   [[UIApplication sharedApplication] setStatusBarHidden:NO];
120   wasCancelled = YES;
121   if (delegate != nil) {
122     [delegate zxingControllerDidCancel:self];
123   }
124 }
125
126 - (NSString *)getPlatform {
127   size_t size;
128   sysctlbyname("hw.machine", NULL, &size, NULL, 0);
129   char *machine = malloc(size);
130   sysctlbyname("hw.machine", machine, &size, NULL, 0);
131   NSString *platform = [NSString stringWithCString:machine encoding:NSASCIIStringEncoding];
132   free(machine);
133   return platform;
134 }
135
136 - (BOOL)fixedFocus {
137   NSString *platform = [self getPlatform];
138   if ([platform isEqualToString:@"iPhone1,1"] ||
139       [platform isEqualToString:@"iPhone1,2"]) return YES;
140   return NO;
141 }
142
143 - (void)viewWillAppear:(BOOL)animated {
144   [super viewWillAppear:animated];
145   self.wantsFullScreenLayout = YES;
146   //[[UIApplication sharedApplication] setStatusBarHidden:YES];
147   if ([self soundToPlay] != nil) {
148     OSStatus error = AudioServicesCreateSystemSoundID((CFURLRef)[self soundToPlay], &beepSound);
149     if (error != kAudioServicesNoError) {
150       NSLog(@"Problem loading nearSound.caf");
151     }
152   }
153 }
154
155 - (void)viewDidAppear:(BOOL)animated {
156   NSLog(@"View did appear");
157   [super viewDidAppear:animated];
158   [[UIApplication sharedApplication] setStatusBarHidden:YES];
159   //self.wantsFullScreenLayout = YES;
160   [self loadImagePicker];
161   self.view = imagePicker.view;
162   
163   [overlayView setPoints:nil];
164   wasCancelled = NO;
165   if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
166
167     [NSTimer scheduledTimerWithTimeInterval: FIRST_TAKE_DELAY
168                                      target: self
169                                    selector: @selector(takePicture:)
170                                    userInfo: nil
171                                     repeats: NO];
172   }
173 }
174
175 - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {
176   //self.wantsFullScreenLayout = NO;
177   [UIApplication sharedApplication].statusBarHidden = NO;
178   [self cancelled];
179 }
180
181
182 - (CGImageRef)CGImageRotated90:(CGImageRef)imgRef
183 {
184   CGFloat angleInRadians = -90 * (M_PI / 180);
185   CGFloat width = CGImageGetWidth(imgRef);
186   CGFloat height = CGImageGetHeight(imgRef);
187   
188   CGRect imgRect = CGRectMake(0, 0, width, height);
189   CGAffineTransform transform = CGAffineTransformMakeRotation(angleInRadians);
190   CGRect rotatedRect = CGRectApplyAffineTransform(imgRect, transform);
191   
192   CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
193   CGContextRef bmContext = CGBitmapContextCreate(NULL,
194                                                  rotatedRect.size.width,
195                                                  rotatedRect.size.height,
196                                                  8,
197                                                  0,
198                                                  colorSpace,
199                                                  kCGImageAlphaPremultipliedFirst);
200   CGContextSetAllowsAntialiasing(bmContext, FALSE);
201   CGContextSetInterpolationQuality(bmContext, kCGInterpolationNone);
202   CGColorSpaceRelease(colorSpace);
203   //      CGContextTranslateCTM(bmContext,
204   //                                                +(rotatedRect.size.width/2),
205   //                                                +(rotatedRect.size.height/2));
206   CGContextScaleCTM(bmContext, rotatedRect.size.width/rotatedRect.size.height, 1.0);
207   CGContextTranslateCTM(bmContext, 0.0, rotatedRect.size.height);
208   CGContextRotateCTM(bmContext, angleInRadians);
209   //      CGContextTranslateCTM(bmContext,
210   //                                                -(rotatedRect.size.width/2),
211   //                                                -(rotatedRect.size.height/2));
212   CGContextDrawImage(bmContext, CGRectMake(0, 0,
213                                            rotatedRect.size.width,
214                                            rotatedRect.size.height),
215                      imgRef);
216   
217   CGImageRef rotatedImage = CGBitmapContextCreateImage(bmContext);
218   CFRelease(bmContext);
219   [(id)rotatedImage autorelease];
220   
221   return rotatedImage;
222 }
223
224 - (CGImageRef)CGImageRotated180:(CGImageRef)imgRef
225 {
226   CGFloat angleInRadians = M_PI;
227   CGFloat width = CGImageGetWidth(imgRef);
228   CGFloat height = CGImageGetHeight(imgRef);
229   
230   CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
231   CGContextRef bmContext = CGBitmapContextCreate(NULL,
232                                                  width,
233                                                  height,
234                                                  8,
235                                                  0,
236                                                  colorSpace,
237                                                  kCGImageAlphaPremultipliedFirst);
238   CGContextSetAllowsAntialiasing(bmContext, FALSE);
239   CGContextSetInterpolationQuality(bmContext, kCGInterpolationNone);
240   CGColorSpaceRelease(colorSpace);
241   CGContextTranslateCTM(bmContext,
242                         +(width/2),
243                         +(height/2));
244   CGContextRotateCTM(bmContext, angleInRadians);
245   CGContextTranslateCTM(bmContext,
246                         -(width/2),
247                         -(height/2));
248   CGContextDrawImage(bmContext, CGRectMake(0, 0, width, height), imgRef);
249   
250   CGImageRef rotatedImage = CGBitmapContextCreateImage(bmContext);
251   CFRelease(bmContext);
252   [(id)rotatedImage autorelease];
253   
254   return rotatedImage;
255 }
256
257 - (void)takePicture:(NSTimer*)theTimer {
258   CGImageRef capture = UIGetScreenImage();
259   static int cpt = 0;
260   if (cpt%10 == 0)
261     UIImageWriteToSavedPhotosAlbum([UIImage imageWithCGImage:capture], nil, nil,nil);
262   CGRect cropRect = [overlayView cropRect];
263   if (oneDMode) {
264     // let's just give the decoder a vertical band right above the red line
265     cropRect.origin.x = cropRect.origin.x + (cropRect.size.width / 2) - (ONE_D_BAND_HEIGHT + 1);
266     cropRect.size.width = ONE_D_BAND_HEIGHT;
267     // do a rotate
268     CGImageRef croppedImg = CGImageCreateWithImageInRect(capture, cropRect);
269     capture = [self CGImageRotated90:croppedImg];
270     capture = [self CGImageRotated180:capture];
271     //              UIImageWriteToSavedPhotosAlbum([UIImage imageWithCGImage:capture], nil, nil, nil);
272     CGImageRelease(croppedImg);
273     cropRect.origin.x = 0.0;
274     cropRect.origin.y = 0.0;
275     cropRect.size.width = CGImageGetWidth(capture);
276     cropRect.size.height = CGImageGetHeight(capture);
277   }
278   CGImageRef newImage = CGImageCreateWithImageInRect(capture, cropRect);
279   CGImageRelease(capture);
280   //UIImage *scrn = [UIImage imageWithCGImage:newImage];
281   UIImage *scrn = [[UIImage alloc] initWithCGImage:newImage];
282   CGImageRelease(newImage);
283   Decoder *d = [[Decoder alloc] init];
284   d.readers = readers;
285   d.delegate = self;
286   cropRect.origin.x = 0.0;
287   cropRect.origin.y = 0.0;
288   [d decodeImage:scrn cropRect:cropRect];
289   [scrn release];
290 }
291
292 // DecoderDelegate methods
293
294 - (void)decoder:(Decoder *)decoder willDecodeImage:(UIImage *)image usingSubset:(UIImage *)subset{
295 #ifdef DEBUG
296   NSLog(@"DecoderViewController MessageWhileDecodingWithDimensions: Decoding image (%.0fx%.0f) ...", image.size.width, image.size.height);
297 #endif
298 }
299
300 - (void)decoder:(Decoder *)decoder
301   decodingImage:(UIImage *)image
302     usingSubset:(UIImage *)subset
303        progress:(NSString *)message {
304 }
305
306 - (void)presentResultForString:(NSString *)resultString {
307   self.result = [ResultParser parsedResultForString:resultString];
308   
309   if (beepSound != -1) {
310     AudioServicesPlaySystemSound(beepSound);
311   }
312 #ifdef DEBUG
313   NSLog(@"result string = %@", resultString);
314   NSLog(@"result has %d actions", actions ? 0 : actions.count);
315 #endif
316   //      [self updateToolbar];
317 }
318
319 - (void)presentResultPoints:(NSArray *)resultPoints
320                    forImage:(UIImage *)image
321                 usingSubset:(UIImage *)subset {
322   // simply add the points to the image view
323   [overlayView setPoints:resultPoints];
324 }
325
326 - (void)decoder:(Decoder *)decoder didDecodeImage:(UIImage *)image usingSubset:(UIImage *)subset withResult:(TwoDDecoderResult *)twoDResult {
327   [self presentResultForString:[twoDResult text]];
328   [self presentResultPoints:[twoDResult points] forImage:image usingSubset:subset];
329   // now, in a selector, call the delegate to give this overlay time to show the points
330   [self performSelector:@selector(alertDelegate:) withObject:[[twoDResult text] copy] afterDelay:1.0];
331   decoder.delegate = nil;
332   [decoder release];
333 }
334
335 - (void)alertDelegate:(id)text {        
336   [[UIApplication sharedApplication] setStatusBarHidden:NO];
337   if (delegate != nil) {
338     [delegate zxingController:self didScanResult:text];
339   }
340 }
341
342 - (void)decoder:(Decoder *)decoder failedToDecodeImage:(UIImage *)image usingSubset:(UIImage *)subset reason:(NSString *)reason {
343   decoder.delegate = nil;
344   [decoder release];
345   [overlayView setPoints:nil];
346   if (!wasCancelled) {
347     [self takePicture:nil];
348   }
349   //[self updateToolbar];
350 }
351
352 @end