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 withResult:result];
58 - (void)failedToDecodeImage:(NSString *)reason {
59 [self.delegate decoder:self failedToDecodeImage:self.image reason:reason];
62 - (void) prepareSubset {
63 CGImageRef cgImage = self.image.CGImage;
64 CGSize size = CGSizeMake(CGImageGetWidth(cgImage), CGImageGetHeight(cgImage));
65 NSLog(@"decoding: image is (%.1f x %.1f)", size.width, size.height);
66 float scale = min(1.0f, max(0.25f, (float)max(400.0f / size.width, 400.0f / size.height)));
67 subsetWidth = size.width * scale;
68 subsetHeight = size.height * scale;
70 subsetBytesPerRow = ((subsetWidth + 0xf) >> 4) << 4;
71 NSLog(@"decoding: image to decode is (%d x %d) (%d bytes/row)", subsetWidth, subsetHeight, subsetBytesPerRow);
73 subsetData = (unsigned char *)malloc(subsetBytesPerRow * subsetHeight);
74 NSLog(@"allocated %d bytes of memory", subsetBytesPerRow * subsetHeight);
76 CGColorSpaceRef grayColorSpace = CGColorSpaceCreateDeviceGray();
79 CGBitmapContextCreate(subsetData, subsetWidth, subsetHeight,
80 8, subsetBytesPerRow, grayColorSpace,
82 CGColorSpaceRelease(grayColorSpace);
83 CGContextSetInterpolationQuality(ctx, kCGInterpolationNone);
84 CGContextSetAllowsAntialiasing(ctx, false);
86 NSLog(@"created %dx%d bitmap context", subsetWidth, subsetHeight);
87 CGRect rect = CGRectMake(0, 0, subsetWidth, subsetHeight);
89 CGContextDrawImage(ctx, rect, cgImage);
90 NSLog(@"drew image into %d(%d)x%d bitmap context", subsetWidth, subsetBytesPerRow, subsetHeight);
92 NSLog(@"flushed context");
94 CGImageRef subsetImageRef = CGBitmapContextCreateImage(ctx);
95 NSLog(@"created CGImage from context");
97 self.subsetImage = [UIImage imageWithCGImage:subsetImageRef];
98 CGImageRelease(subsetImageRef);
100 CGContextRelease(ctx);
102 NSLog(@"released context");
105 - (void)decode:(id)arg {
106 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
110 Ref<MonochromeBitmapSource> grayImage
111 (new GrayBytesMonochromeBitmapSource(subsetData, subsetWidth, subsetHeight, subsetBytesPerRow));
112 NSLog(@"grayImage count = %d", grayImage->count());
114 NSLog(@"created GrayBytesMonochromeBitmapSource", subsetWidth, subsetHeight);
116 NSLog(@"created QRCoreReader");
118 TwoDDecoderResult *decoderResult = nil;
121 for (int i = 0; !decoderResult && i < 4; i++) {
125 NSLog(@"decoding gray image");
126 Ref<Result> result(reader.decode(grayImage));
127 NSLog(@"gray image decoed");
129 Ref<String> resultText(result->getText());
130 const char *cString = resultText->getText().c_str();
131 ArrayRef<Ref<ResultPoint> > resultPoints = result->getResultPoints();
132 NSMutableArray *points =
133 [NSMutableArray arrayWithCapacity:resultPoints->size()];
135 for (size_t i = 0; i < resultPoints->size(); i++) {
136 Ref<ResultPoint> rp(resultPoints[i]);
137 CGPoint p = CGPointMake(rp->getX(), rp->getY());
138 [points addObject:[NSValue valueWithCGPoint:p]];
141 NSString *resultString = [NSString stringWithCString:cString
142 encoding:NSUTF8StringEncoding];
144 decoderResult = [TwoDDecoderResult resultWithText:resultString
146 } catch (ReaderException *rex) {
147 NSLog(@"failed to decode, caught ReaderException '%s'",
150 } catch (IllegalArgumentException *iex) {
151 NSLog(@"failed to decode, caught IllegalArgumentException '%s'",
155 NSLog(@"Caught unknown exception, trying again");
159 if (!decoderResult) {
160 NSLog(@"rotating gray image");
161 grayImage = grayImage->rotateCounterClockwise();
162 NSLog(@"gray image rotated");
168 [self performSelectorOnMainThread:@selector(didDecodeImage:)
169 withObject:decoderResult
172 [self performSelectorOnMainThread:@selector(failedToDecodeImage:)
173 withObject:NSLocalizedString(@"No barcode detected.", @"No barcode detected.")
178 self.subsetData = NULL;
181 NSLog(@"finished decoding.");
183 // if this is not the main thread, then we end it
184 if (![NSThread isMainThread]) {
189 - (void) decodeImage:(UIImage *)i {
190 CGRect rect = CGRectMake(0.0f, 0.0f, image.size.width, image.size.height);
191 [self decodeImage:i cropRectangle:rect];
194 - (void) decodeImage:(UIImage *)i cropRectangle:(CGRect)cropRect {
196 [self.delegate decoder:self willDecodeImage:i];
198 [self prepareSubset];
200 [self performSelectorOnMainThread:@selector(progressDecodingImage:)
201 withObject:@"Decoding ..."
204 [NSThread detachNewThreadSelector:@selector(decode:)
211 [subsetImage release];
212 if (subsetData) free(subsetData);