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();
32 @implementation ZXingWidgetController
33 @synthesize result, actions, showCancel, delegate, soundToPlay, oneDMode;
35 - (id)initWithDelegate:(id<ZXingDelegate>)scanDelegate {
36 if (self = [super init]) {
37 [self setDelegate:scanDelegate];
39 self.wantsFullScreenLayout = YES;
40 if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
41 self.sourceType = UIImagePickerControllerSourceTypeCamera;
42 float zoomFactor = CAMERA_SCALAR;
43 if ([self fixedFocus]) {
46 if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
47 self.cameraViewTransform = CGAffineTransformScale(
48 self.cameraViewTransform, zoomFactor, zoomFactor);
49 overlayView = [OverlayView alloc];
50 [overlayView setOneDMode:oneDMode];
51 overlayView = [overlayView initWithCancelEnabled:showCancel frame:[UIScreen mainScreen].bounds];
52 [overlayView setDelegate:self];
53 if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
55 self.showsCameraControls = NO;
56 self.cameraOverlayView = overlayView;
57 self.allowsEditing = NO; // [[NSUserDefaults standardUserDefaults] boolForKey:@"allowEditing"];
65 if (beepSound != -1) {
66 AudioServicesDisposeSystemSoundID(beepSound);
68 [overlayView dealloc];
73 NSLog(@"cancelled called in ZXingWidgetController");
75 if (delegate != nil) {
80 - (NSString *)getPlatform {
82 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
83 char *machine = malloc(size);
84 sysctlbyname("hw.machine", machine, &size, NULL, 0);
85 NSString *platform = [NSString stringWithCString:machine encoding:NSASCIIStringEncoding];
91 NSString *platform = [self getPlatform];
92 if ([platform isEqualToString:@"iPhone1,1"] ||
93 [platform isEqualToString:@"iPhone1,2"]) return true;
97 - (void)viewWillAppear:(BOOL)animated {
98 [super viewWillAppear:animated];
99 if ([self soundToPlay] != nil) {
100 OSStatus error = AudioServicesCreateSystemSoundID((CFURLRef)[self soundToPlay], &beepSound);
101 if (error != kAudioServicesNoError) {
102 NSLog(@"Problem loading nearSound.caf");
107 - (void)viewDidAppear:(BOOL)animated {
108 [super viewDidAppear:animated];
109 [overlayView setPoints:nil];
110 wasCancelled = false;
111 [NSTimer scheduledTimerWithTimeInterval: FIRST_TAKE_DELAY
113 selector: @selector(takePicture:)
118 - (CGImageRef)CGImageRotated90:(CGImageRef)imgRef
120 CGFloat angleInRadians = -90 * (M_PI / 180);
121 CGFloat width = CGImageGetWidth(imgRef);
122 CGFloat height = CGImageGetHeight(imgRef);
124 CGRect imgRect = CGRectMake(0, 0, width, height);
125 CGAffineTransform transform = CGAffineTransformMakeRotation(angleInRadians);
126 CGRect rotatedRect = CGRectApplyAffineTransform(imgRect, transform);
128 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
129 CGContextRef bmContext = CGBitmapContextCreate(NULL,
130 rotatedRect.size.width,
131 rotatedRect.size.height,
135 kCGImageAlphaPremultipliedFirst);
136 CGContextSetAllowsAntialiasing(bmContext, FALSE);
137 CGContextSetInterpolationQuality(bmContext, kCGInterpolationNone);
138 CGColorSpaceRelease(colorSpace);
139 // CGContextTranslateCTM(bmContext,
140 // +(rotatedRect.size.width/2),
141 // +(rotatedRect.size.height/2));
142 CGContextScaleCTM(bmContext, rotatedRect.size.width/rotatedRect.size.height, 1.0);
143 CGContextTranslateCTM(bmContext, 0.0, rotatedRect.size.height);
144 CGContextRotateCTM(bmContext, angleInRadians);
145 // CGContextTranslateCTM(bmContext,
146 // -(rotatedRect.size.width/2),
147 // -(rotatedRect.size.height/2));
148 CGContextDrawImage(bmContext, CGRectMake(0, 0,
149 rotatedRect.size.width,
150 rotatedRect.size.height),
153 CGImageRef rotatedImage = CGBitmapContextCreateImage(bmContext);
154 CFRelease(bmContext);
155 [(id)rotatedImage autorelease];
160 - (CGImageRef)CGImageRotated180:(CGImageRef)imgRef
162 CGFloat angleInRadians = M_PI;
163 CGFloat width = CGImageGetWidth(imgRef);
164 CGFloat height = CGImageGetHeight(imgRef);
166 CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
167 CGContextRef bmContext = CGBitmapContextCreate(NULL,
173 kCGImageAlphaPremultipliedFirst);
174 CGContextSetAllowsAntialiasing(bmContext, FALSE);
175 CGContextSetInterpolationQuality(bmContext, kCGInterpolationNone);
176 CGColorSpaceRelease(colorSpace);
177 CGContextTranslateCTM(bmContext,
180 CGContextRotateCTM(bmContext, angleInRadians);
181 CGContextTranslateCTM(bmContext,
184 CGContextDrawImage(bmContext, CGRectMake(0, 0, width, height), imgRef);
186 CGImageRef rotatedImage = CGBitmapContextCreateImage(bmContext);
187 CFRelease(bmContext);
188 [(id)rotatedImage autorelease];
193 - (void)takePicture:(NSTimer*)theTimer {
194 CGImageRef capture = UIGetScreenImage();
195 CGRect cropRect = [overlayView cropRect];
197 // let's just give the decoder a vertical band right above the red line
198 cropRect.origin.x = cropRect.origin.x + (cropRect.size.width / 2) - (ONE_D_BAND_HEIGHT + 1);
199 cropRect.size.width = ONE_D_BAND_HEIGHT;
201 CGImageRef croppedImg = CGImageCreateWithImageInRect(capture, cropRect);
202 capture = [self CGImageRotated90:croppedImg];
203 capture = [self CGImageRotated180:capture];
204 // UIImageWriteToSavedPhotosAlbum([UIImage imageWithCGImage:capture], nil, nil, nil);
205 CGImageRelease(croppedImg);
206 cropRect.origin.x = 0.0;
207 cropRect.origin.y = 0.0;
208 cropRect.size.width = CGImageGetWidth(capture);
209 cropRect.size.height = CGImageGetHeight(capture);
211 CGImageRef newImage = CGImageCreateWithImageInRect(capture, cropRect);
212 CGImageRelease(capture);
213 //UIImage *scrn = [UIImage imageWithCGImage:newImage];
214 UIImage *scrn = [[UIImage alloc] initWithCGImage:newImage];
215 CGImageRelease(newImage);
216 Decoder *d = [[Decoder alloc] init];
218 cropRect.origin.x = 0.0;
219 cropRect.origin.y = 0.0;
220 [d decodeImage:scrn cropRect:cropRect];
224 // DecoderDelegate methods
226 - (void)decoder:(Decoder *)decoder willDecodeImage:(UIImage *)image usingSubset:(UIImage *)subset{
228 NSLog(@"DecoderViewController MessageWhileDecodingWithDimensions: Decoding image (%.0fx%.0f) ...", image.size.width, image.size.height);
232 - (void)decoder:(Decoder *)decoder
233 decodingImage:(UIImage *)image
234 usingSubset:(UIImage *)subset
235 progress:(NSString *)message {
238 - (void)presentResultForString:(NSString *)resultString {
239 self.result = [ResultParser parsedResultForString:resultString];
241 if (beepSound != -1) {
242 AudioServicesPlaySystemSound(beepSound);
245 NSLog(@"result string = %@", resultString);
246 NSLog(@"result has %d actions", actions ? 0 : actions.count);
248 // [self updateToolbar];
251 - (void)presentResultPoints:(NSArray *)resultPoints
252 forImage:(UIImage *)image
253 usingSubset:(UIImage *)subset {
254 // simply add the points to the image view
255 [overlayView setPoints:resultPoints];
258 - (void)decoder:(Decoder *)decoder didDecodeImage:(UIImage *)image usingSubset:(UIImage *)subset withResult:(TwoDDecoderResult *)twoDResult {
259 [self presentResultForString:[twoDResult text]];
260 [self presentResultPoints:[twoDResult points] forImage:image usingSubset:subset];
261 // now, in a selector, call the delegate to give this overlay time to show the points
262 [self performSelector:@selector(alertDelegate:) withObject:[[twoDResult text] copy] afterDelay:1.0];
263 decoder.delegate = nil;
267 - (void)alertDelegate:(id)text {
268 if (delegate != nil) {
269 [delegate scanResult:text];
273 - (void)decoder:(Decoder *)decoder failedToDecodeImage:(UIImage *)image usingSubset:(UIImage *)subset reason:(NSString *)reason {
274 decoder.delegate = nil;
276 [overlayView setPoints:nil];
278 [self takePicture:nil];
280 //[self updateToolbar];