5 // Created by Christian Brunschen on 31/03/2008.
8 * Copyright 2008 ZXing authors
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
24 #import "TwoDDecoderResult.h"
26 #include "QRCodeReader.h"
27 #include "ReaderException.h"
28 #include "IllegalArgumentException.h"
29 #include "GrayBytesMonochromeBitmapSource.h"
31 using namespace qrcode;
33 @implementation Decoder
36 @synthesize subsetImage;
37 @synthesize subsetData;
38 @synthesize subsetWidth;
39 @synthesize subsetHeight;
40 @synthesize subsetBytesPerRow;
43 - (void)willDecodeImage {
44 [self.delegate decoder:self willDecodeImage:self.image];
47 - (void)progressDecodingImage:(NSString *)progress {
48 [self.delegate decoder:self
49 decodingImage:self.image
50 usingSubset:self.subsetImage
54 - (void)didDecodeImage:(TwoDDecoderResult *)result {
55 [self.delegate decoder:self didDecodeImage:self.image usingSubset:self.subsetImage withResult:result];
58 - (void)failedToDecodeImage:(NSString *)reason {
59 [self.delegate decoder:self failedToDecodeImage:self.image usingSubset:self.subsetImage reason:reason];
62 #define SUBSET_SIZE 320.0
63 - (void) prepareSubset {
64 CGImageRef cgImage = self.image.CGImage;
65 CGSize size = CGSizeMake(CGImageGetWidth(cgImage), CGImageGetHeight(cgImage));
67 NSLog(@"decoding: image is (%.1f x %.1f)", size.width, size.height);
69 float scale = fminf(1.0f, fmaxf(SUBSET_SIZE / size.width, SUBSET_SIZE / size.height));
70 subsetWidth = size.width * scale;
71 subsetHeight = size.height * scale;
73 subsetBytesPerRow = ((subsetWidth + 0xf) >> 4) << 4;
75 NSLog(@"decoding: image to decode is (%d x %d) (%d bytes/row)", subsetWidth, subsetHeight, subsetBytesPerRow);
78 subsetData = (unsigned char *)malloc(subsetBytesPerRow * subsetHeight);
80 NSLog(@"allocated %d bytes of memory", subsetBytesPerRow * subsetHeight);
83 CGColorSpaceRef grayColorSpace = CGColorSpaceCreateDeviceGray();
86 CGBitmapContextCreate(subsetData, subsetWidth, subsetHeight,
87 8, subsetBytesPerRow, grayColorSpace,
89 CGColorSpaceRelease(grayColorSpace);
90 CGContextSetInterpolationQuality(ctx, kCGInterpolationNone);
91 CGContextSetAllowsAntialiasing(ctx, false);
94 NSLog(@"created %dx%d bitmap context", subsetWidth, subsetHeight);
96 CGRect rect = CGRectMake(0, 0, subsetWidth, subsetHeight);
98 CGContextDrawImage(ctx, rect, cgImage);
100 NSLog(@"drew image into %d(%d)x%d bitmap context", subsetWidth, subsetBytesPerRow, subsetHeight);
104 NSLog(@"flushed context");
107 CGImageRef subsetImageRef = CGBitmapContextCreateImage(ctx);
109 NSLog(@"created CGImage from context");
112 self.subsetImage = [UIImage imageWithCGImage:subsetImageRef];
113 CGImageRelease(subsetImageRef);
115 CGContextRelease(ctx);
117 NSLog(@"released context");
121 - (void)decode:(id)arg {
122 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
126 NSLog(@"created QRCoreReader");
129 Ref<MonochromeBitmapSource> grayImage
130 (new GrayBytesMonochromeBitmapSource(subsetData, subsetWidth, subsetHeight, subsetBytesPerRow));
132 NSLog(@"created GrayBytesMonochromeBitmapSource", subsetWidth, subsetHeight);
133 NSLog(@"grayImage count = %d", grayImage->count());
136 TwoDDecoderResult *decoderResult = nil;
139 for (int i = 0; !decoderResult && i < 4; i++) {
144 NSLog(@"decoding gray image");
146 Ref<Result> result(reader.decode(grayImage));
148 NSLog(@"gray image decoded");
151 Ref<String> resultText(result->getText());
152 const char *cString = resultText->getText().c_str();
153 ArrayRef<Ref<ResultPoint> > resultPoints = result->getResultPoints();
154 NSMutableArray *points =
155 [NSMutableArray arrayWithCapacity:resultPoints->size()];
157 for (size_t i = 0; i < resultPoints->size(); i++) {
158 Ref<ResultPoint> rp(resultPoints[i]);
159 CGPoint p = CGPointMake(rp->getX(), rp->getY());
160 [points addObject:[NSValue valueWithCGPoint:p]];
163 NSString *resultString = [NSString stringWithCString:cString
164 encoding:NSUTF8StringEncoding];
166 decoderResult = [TwoDDecoderResult resultWithText:resultString
168 } catch (ReaderException *rex) {
169 NSLog(@"failed to decode, caught ReaderException '%s'",
172 } catch (IllegalArgumentException *iex) {
173 NSLog(@"failed to decode, caught IllegalArgumentException '%s'",
177 NSLog(@"Caught unknown exception!");
181 if (!decoderResult) {
183 NSLog(@"rotating gray image");
185 grayImage = grayImage->rotateCounterClockwise();
187 NSLog(@"gray image rotated");
194 [self performSelectorOnMainThread:@selector(didDecodeImage:)
195 withObject:decoderResult
198 [self performSelectorOnMainThread:@selector(failedToDecodeImage:)
199 withObject:NSLocalizedString(@"No barcode detected.", @"No barcode detected.")
204 self.subsetData = NULL;
208 NSLog(@"finished decoding.");
211 // if this is not the main thread, then we end it
212 if (![NSThread isMainThread]) {
217 - (void) decodeImage:(UIImage *)i {
218 CGRect rect = CGRectMake(0.0f, 0.0f, image.size.width, image.size.height);
219 [self decodeImage:i cropRectangle:rect];
222 - (void) decodeImage:(UIImage *)i cropRectangle:(CGRect)cropRect {
224 [self.delegate decoder:self willDecodeImage:i];
226 [self prepareSubset];
228 [self performSelectorOnMainThread:@selector(progressDecodingImage:)
229 withObject:@"Decoding ..."
232 [NSThread detachNewThreadSelector:@selector(decode:)
239 [subsetImage release];
240 if (subsetData) free(subsetData);