Korean translation from Chang Hyun Park
[zxing.git] / iphone / ZXingWidget / Classes / Decoder.mm
1 //
2 //  Decoder.m
3 //  ZXing
4 //
5 //  Created by Christian Brunschen on 31/03/2008.
6 //
7 /*
8  * Copyright 2008 ZXing authors
9  *
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
13  *
14  *      http://www.apache.org/licenses/LICENSE-2.0
15  *
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.
21  */
22
23 #import "Decoder.h"
24 #import "TwoDDecoderResult.h"
25 #import "FormatReader.h"
26
27 #include <zxing/BinaryBitmap.h>
28 #include <zxing/ReaderException.h>
29 #include <zxing/common/IllegalArgumentException.h>
30 #include <zxing/common/HybridBinarizer.h>
31 #include <zxing/common/GreyscaleLuminanceSource.h>
32
33 using namespace zxing;
34
35 class ZXingWidgetControllerCallback : public zxing::ResultPointCallback {
36 private:
37   Decoder* decoder;
38 public:
39   ZXingWidgetControllerCallback(Decoder* _decoder) : decoder(_decoder) {}
40   void foundPossibleResultPoint(ResultPoint const& result) {
41     CGPoint point;
42     point.x = result.getX();
43     point.y = result.getY();
44     [decoder resultPointCallback:point];
45   }
46 };
47
48 @implementation Decoder
49
50 @synthesize image;
51 @synthesize cropRect;
52 @synthesize subsetImage;
53 @synthesize subsetData;
54 @synthesize subsetWidth;
55 @synthesize subsetHeight;
56 @synthesize subsetBytesPerRow;
57 @synthesize delegate;
58 @synthesize readers;
59
60
61 - (void)willDecodeImage {
62   if ([self.delegate respondsToSelector:@selector(decoder:willDecodeImage:usingSubset:)]) {
63     [self.delegate decoder:self willDecodeImage:self.image usingSubset:self.subsetImage];
64   }
65 }
66
67 - (void)didDecodeImage:(TwoDDecoderResult *)result {
68   if ([self.delegate respondsToSelector:@selector(decoder:didDecodeImage:usingSubset:withResult:)]) {
69     [self.delegate decoder:self didDecodeImage:self.image usingSubset:self.subsetImage withResult:result];
70   }
71         
72   [result release];
73 }
74
75 - (void)failedToDecodeImage:(NSString *)reason {
76   if ([self.delegate respondsToSelector:@selector(decoder:failedToDecodeImage:usingSubset:reason:)]) {
77     [self.delegate decoder:self failedToDecodeImage:self.image usingSubset:self.subsetImage reason:reason];
78   }
79 }
80
81 - (void)resultPointCallback:(CGPoint)point {
82   if ([self.delegate respondsToSelector:@selector(decoder:foundPossibleResultPoint:)]) {
83     [self.delegate decoder:self foundPossibleResultPoint:point];
84   }
85 }
86
87 #define SUBSET_SIZE 360
88 - (void) prepareSubset {
89   CGSize size = [image size];
90 #ifdef DEBUG
91   NSLog(@"decoding: image is (%.1f x %.1f), cropRect is (%.1f,%.1f)x(%.1f,%.1f)", size.width, size.height,
92       cropRect.origin.x, cropRect.origin.y, cropRect.size.width, cropRect.size.height);
93 #endif
94   float scale = fminf(1.0f, fmaxf(SUBSET_SIZE / cropRect.size.width, SUBSET_SIZE / cropRect.size.height));
95   CGPoint offset = CGPointMake(-cropRect.origin.x, -cropRect.origin.y);
96 #ifdef DEBUG
97   NSLog(@"  offset = (%.1f, %.1f), scale = %.3f", offset.x, offset.y, scale);
98 #endif
99   
100   subsetWidth = cropRect.size.width * scale;
101   subsetHeight = cropRect.size.height * scale;
102   
103   subsetBytesPerRow = ((subsetWidth + 0xf) >> 4) << 4;
104 #ifdef DEBUG
105   NSLog(@"decoding: image to decode is (%d x %d) (%d bytes/row)", subsetWidth, subsetHeight, subsetBytesPerRow);
106 #endif
107   
108   subsetData = (unsigned char *)malloc(subsetBytesPerRow * subsetHeight);
109 #ifdef DEBUG
110   NSLog(@"allocated %d bytes of memory", subsetBytesPerRow * subsetHeight);
111 #endif
112   
113   CGColorSpaceRef grayColorSpace = CGColorSpaceCreateDeviceGray();
114   
115   CGContextRef ctx = 
116   CGBitmapContextCreate(subsetData, subsetWidth, subsetHeight, 
117               8, subsetBytesPerRow, grayColorSpace, 
118               kCGImageAlphaNone);
119   CGColorSpaceRelease(grayColorSpace);
120   CGContextSetInterpolationQuality(ctx, kCGInterpolationNone);
121   CGContextSetAllowsAntialiasing(ctx, false);
122   // adjust the coordinate system
123   CGContextTranslateCTM(ctx, 0.0, subsetHeight);
124   CGContextScaleCTM(ctx, 1.0, -1.0);  
125   
126 #ifdef DEBUG
127   NSLog(@"created %dx%d bitmap context", subsetWidth, subsetHeight);
128 #endif
129   
130   UIGraphicsPushContext(ctx);
131   CGRect rect = CGRectMake(offset.x * scale, offset.y * scale, scale * size.width, scale * size.height);
132 #ifdef DEBUG
133   NSLog(@"rect for image = (%.1f,%.1f)x(%.1f,%.1f)", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
134 #endif
135   [image drawInRect:rect];
136   UIGraphicsPopContext();
137   
138 #ifdef DEBUG
139   NSLog(@"drew image into %d(%d)x%d  bitmap context", subsetWidth, subsetBytesPerRow, subsetHeight);
140 #endif
141   CGContextFlush(ctx);
142 #ifdef DEBUG
143   NSLog(@"flushed context");
144 #endif
145     
146   CGImageRef subsetImageRef = CGBitmapContextCreateImage(ctx);
147 #ifdef DEBUG
148   NSLog(@"created CGImage from context");
149 #endif
150   
151   self.subsetImage = [UIImage imageWithCGImage:subsetImageRef];
152   CGImageRelease(subsetImageRef);
153   
154   CGContextRelease(ctx);
155 #ifdef DEBUG
156   NSLog(@"released context");  
157 #endif
158 }  
159
160 - (BOOL)decode {
161   NSAutoreleasePool* mainpool = [[NSAutoreleasePool alloc] init];
162   TwoDDecoderResult *decoderResult = nil;
163     
164   { 
165     //NSSet *formatReaders = [FormatReader formatReaders];
166     NSSet *formatReaders = self.readers;
167     Ref<LuminanceSource> source 
168         (new GreyscaleLuminanceSource(subsetData, subsetBytesPerRow, subsetHeight, 0, 0, subsetWidth, subsetHeight));
169
170     Ref<Binarizer> binarizer (new HybridBinarizer(source));
171     source = 0;
172     Ref<BinaryBitmap> grayImage (new BinaryBitmap(binarizer));
173     binarizer = 0;
174 #ifdef DEBUG
175     NSLog(@"created GreyscaleLuminanceSource(%p,%d,%d,%d,%d,%d,%d)",
176           subsetData, subsetBytesPerRow, subsetHeight, 0, 0, subsetWidth, subsetHeight);
177     NSLog(@"grayImage count = %d", grayImage->count());
178 #endif
179     
180 #ifdef TRY_ROTATIONS
181     for (int i = 0; !decoderResult && i < 4; i++) {
182 #endif
183       for (FormatReader *reader in formatReaders) {
184         NSAutoreleasePool *secondarypool = [[NSAutoreleasePool alloc] init];
185         try {
186   #ifdef DEBUG
187           NSLog(@"decoding gray image");
188   #endif  
189           ResultPointCallback* callback_pointer(new ZXingWidgetControllerCallback(self));
190           Ref<ResultPointCallback> callback(callback_pointer);
191           Ref<Result> result([reader decode:grayImage andCallback:callback]);
192   #ifdef DEBUG
193           NSLog(@"gray image decoded");
194   #endif
195           
196           Ref<String> resultText(result->getText());
197           const char *cString = resultText->getText().c_str();
198           const std::vector<Ref<ResultPoint> > &resultPoints = result->getResultPoints();
199           NSMutableArray *points = 
200             [[NSMutableArray alloc ] initWithCapacity:resultPoints.size()];
201           
202           for (size_t i = 0; i < resultPoints.size(); i++) {
203             const Ref<ResultPoint> &rp = resultPoints[i];
204             CGPoint p = CGPointMake(rp->getX(), rp->getY());
205             [points addObject:[NSValue valueWithCGPoint:p]];
206           }
207           
208           NSString *resultString = [NSString stringWithCString:cString
209                                                         encoding:NSUTF8StringEncoding];
210
211           decoderResult = [[TwoDDecoderResult resultWithText:resultString points:points] retain];
212           [points release];
213         } catch (ReaderException &rex) {
214           NSLog(@"failed to decode, caught ReaderException '%s'",
215               rex.what());
216         } catch (IllegalArgumentException &iex) {
217           NSLog(@"failed to decode, caught IllegalArgumentException '%s'", 
218               iex.what());
219         } catch (...) {
220           NSLog(@"Caught unknown exception!");
221         }
222         [secondarypool release];
223       }
224       
225 #ifdef TRY_ROTATIONS
226       if (!decoderResult) {
227 #ifdef DEBUG
228         NSLog(@"rotating gray image");
229 #endif
230         grayImage = grayImage->rotateCounterClockwise();
231 #ifdef DEBUG
232         NSLog(@"gray image rotated");
233 #endif
234       }
235     }
236 #endif
237           
238         free(subsetData);
239         self.subsetData = NULL;
240           
241         // DONT COMMIT
242         // [decoderResult release];
243         // decoderResult = nil;
244         
245
246     if (decoderResult) {
247       [self performSelectorOnMainThread:@selector(didDecodeImage:)
248                    withObject:decoderResult
249                 waitUntilDone:NO];
250     } else {
251       [self performSelectorOnMainThread:@selector(failedToDecodeImage:)
252                    withObject:NSLocalizedString(@"Decoder BarcodeDetectionFailure", @"No barcode detected.")
253                 waitUntilDone:NO];
254     }
255   }
256   
257   
258 #ifdef DEBUG
259   NSLog(@"finished decoding.");
260 #endif
261   [mainpool release];
262
263   return decoderResult == nil ? NO : YES;
264 }
265
266 - (BOOL) decodeImage:(UIImage *)i {
267   return [self decodeImage:i cropRect:CGRectMake(0.0f, 0.0f, i.size.width, i.size.height)];
268 }
269
270 - (BOOL) decodeImage:(UIImage *)i cropRect:(CGRect)cr {
271   self.image = i;
272   self.cropRect = cr;
273   [self prepareSubset];
274   [self willDecodeImage];
275   return [self decode];
276 }
277
278 - (void) dealloc {
279   [image release];
280   [subsetImage release];
281   free(subsetData);
282   [readers release];
283   [super dealloc];
284 }
285
286 @end