improved image cropping, also work around iPhone OS 2.1 bug when picking from photo...
authorchristian.brunschen <christian.brunschen@59b500cc-1b3d-0410-9834-0bbf25fbcc57>
Mon, 13 Oct 2008 16:09:09 +0000 (16:09 +0000)
committerchristian.brunschen <christian.brunschen@59b500cc-1b3d-0410-9834-0bbf25fbcc57>
Mon, 13 Oct 2008 16:09:09 +0000 (16:09 +0000)
git-svn-id: http://zxing.googlecode.com/svn/trunk@614 59b500cc-1b3d-0410-9834-0bbf25fbcc57

iphone/Classes/Decoder.h
iphone/Classes/Decoder.m
iphone/Classes/DecoderDelegate.h
iphone/Classes/DecoderViewController.h
iphone/Classes/DecoderViewController.m
iphone/ZXing.xcodeproj/project.pbxproj

index 8d2c161..4b28141 100644 (file)
@@ -25,6 +25,7 @@
 
 @interface Decoder : NSObject {
        UIImage *image;
+       CGRect cropRect;
   UIImage *subsetImage;
   unsigned char *subsetData;
   size_t subsetWidth;
@@ -34,6 +35,7 @@
 }
 
 @property(nonatomic, retain) UIImage *image;
+@property(nonatomic, assign) CGRect cropRect;
 @property(nonatomic, retain) UIImage *subsetImage;
 @property(nonatomic, assign) unsigned char *subsetData;
 @property(assign) size_t subsetWidth;
@@ -42,6 +44,6 @@
 @property(nonatomic, assign) id<DecoderDelegate> delegate;
 
 - (void) decodeImage:(UIImage *)image;
-- (void) decodeImage:(UIImage *)image cropRectangle:(CGRect)cropRect;
+- (void) decodeImage:(UIImage *)image cropRect:(CGRect)cropRect;
 
 @end
index 74bb6ed..0cac002 100644 (file)
@@ -33,6 +33,7 @@ using namespace qrcode;
 @implementation Decoder
 
 @synthesize image;
+@synthesize cropRect;
 @synthesize subsetImage;
 @synthesize subsetData;
 @synthesize subsetWidth;
@@ -41,7 +42,7 @@ using namespace qrcode;
 @synthesize delegate;
 
 - (void)willDecodeImage {
-  [self.delegate decoder:self willDecodeImage:self.image];
+  [self.delegate decoder:self willDecodeImage:self.image usingSubset:self.subsetImage];
 }
 
 - (void)progressDecodingImage:(NSString *)progress {
@@ -61,14 +62,19 @@ using namespace qrcode;
 
 #define SUBSET_SIZE 320.0
 - (void) prepareSubset {
-  CGImageRef cgImage = self.image.CGImage;
-  CGSize size = CGSizeMake(CGImageGetWidth(cgImage), CGImageGetHeight(cgImage));
+  CGSize size = [image size];
 #ifdef DEBUG
-  NSLog(@"decoding: image is (%.1f x %.1f)", size.width, size.height);
+  NSLog(@"decoding: image is (%.1f x %.1f), cropRect is (%.1f,%.1f)x(%.1f,%.1f)", size.width, size.height,
+                               cropRect.origin.x, cropRect.origin.y, cropRect.size.width, cropRect.size.height);
 #endif
-  float scale = fminf(1.0f, fmaxf(SUBSET_SIZE / size.width, SUBSET_SIZE / size.height));
-  subsetWidth = size.width * scale;
-  subsetHeight = size.height * scale;
+  float scale = fminf(1.0f, fmaxf(SUBSET_SIZE / cropRect.size.width, SUBSET_SIZE / cropRect.size.height));
+       CGPoint offset = CGPointMake(-cropRect.origin.x, -cropRect.origin.y);
+#ifdef DEBUG
+       NSLog(@"  offset = (%.1f, %.1f), scale = %.3f", offset.x, offset.y, scale);
+#endif
+       
+  subsetWidth = cropRect.size.width * scale;
+  subsetHeight = cropRect.size.height * scale;
   
   subsetBytesPerRow = ((subsetWidth + 0xf) >> 4) << 4;
 #ifdef DEBUG
@@ -89,13 +95,22 @@ using namespace qrcode;
   CGColorSpaceRelease(grayColorSpace);
   CGContextSetInterpolationQuality(ctx, kCGInterpolationNone);
   CGContextSetAllowsAntialiasing(ctx, false);
+       // adjust the coordinate system
+       CGContextTranslateCTM(ctx, 0.0, subsetHeight);
+       CGContextScaleCTM(ctx, 1.0, -1.0);      
   
 #ifdef DEBUG
   NSLog(@"created %dx%d bitmap context", subsetWidth, subsetHeight);
 #endif
-  CGRect rect = CGRectMake(0, 0, subsetWidth, subsetHeight);
+       
+       UIGraphicsPushContext(ctx);
+       CGRect rect = CGRectMake(offset.x * scale, offset.y * scale, scale * size.width, scale * size.height);
+#ifdef DEBUG
+       NSLog(@"rect for image = (%.1f,%.1f)x(%.1f,%.1f)", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
+#endif
+       [image drawInRect:rect];
+       UIGraphicsPopContext();
   
-  CGContextDrawImage(ctx, rect, cgImage);
 #ifdef DEBUG
   NSLog(@"drew image into %d(%d)x%d  bitmap context", subsetWidth, subsetBytesPerRow, subsetHeight);
 #endif
@@ -215,15 +230,16 @@ using namespace qrcode;
 }
 
 - (void) decodeImage:(UIImage *)i {
-  CGRect rect = CGRectMake(0.0f, 0.0f, image.size.width, image.size.height);
-  [self decodeImage:i cropRectangle:rect];
+  [self decodeImage:i cropRect:CGRectMake(0.0f, 0.0f, image.size.width, image.size.height)];
 }
 
-- (void) decodeImage:(UIImage *)i cropRectangle:(CGRect)cropRect {
+- (void) decodeImage:(UIImage *)i cropRect:(CGRect)cr {
        self.image = i;
-       [self.delegate decoder:self willDecodeImage:i];
+       self.cropRect = cr;
   
   [self prepareSubset];
+       [self.delegate decoder:self willDecodeImage:i usingSubset:self.subsetImage];
+
   
   [self performSelectorOnMainThread:@selector(progressDecodingImage:)
                          withObject:NSLocalizedString(@"Decoder MessageWhileDecoding", @"Decoding ...")
index a2db608..35d454e 100644 (file)
@@ -26,7 +26,7 @@
 
 @protocol DecoderDelegate
 
-- (void)decoder:(Decoder *)decoder willDecodeImage:(UIImage *)image;
+- (void)decoder:(Decoder *)decoder willDecodeImage:(UIImage *)image usingSubset:(UIImage *)subset;
 - (void)decoder:(Decoder *)decoder decodingImage:(UIImage *)image usingSubset:(UIImage *)subset progress:(NSString *)message;
 - (void)decoder:(Decoder *)decoder didDecodeImage:(UIImage *)image usingSubset:(UIImage *)subset withResult:(TwoDDecoderResult *)result;
 - (void)decoder:(Decoder *)decoder failedToDecodeImage:(UIImage *)image usingSubset:(UIImage *)subset reason:(NSString *)reason;
index 1274536..a941eb3 100644 (file)
@@ -79,7 +79,7 @@
 
 /* DecoderDelegate methods */
 
-- (void)decoder:(Decoder *)decoder willDecodeImage:(UIImage *)image;
+- (void)decoder:(Decoder *)decoder willDecodeImage:(UIImage *)image usingSubset:(UIImage *)subset;
 - (void)decoder:(Decoder *)decoder decodingImage:(UIImage *)image usingSubset:(UIImage *)subset progress:(NSString *) message;
 - (void)decoder:(Decoder *)decoder didDecodeImage:(UIImage *)image usingSubset:(UIImage *)subset withResult:(TwoDDecoderResult *)result;
 
index 0e92b75..02dc731 100644 (file)
 
 - (void)pickAndDecodeFromSource:(UIImagePickerControllerSourceType) sourceType {
   [self reset];
-  \
+
   // Create the Image Picker
   if ([UIImagePickerController isSourceTypeAvailable:sourceType]) {
     UIImagePickerController* picker = [[UIImagePickerController alloc] init];
 
 // DecoderDelegate methods
 
-- (void)decoder:(Decoder *)decoder willDecodeImage:(UIImage *)image {
+- (void)decoder:(Decoder *)decoder willDecodeImage:(UIImage *)image usingSubset:(UIImage *)subset{
   [self clearImageView];
-  [self.imageView setImage:image];
+  [self.imageView setImage:subset];
   [self showMessage:[NSString stringWithFormat:NSLocalizedString(@"DecoderViewController MessageWhileDecodingWithDimensions", @"Decoding image (%.0fx%.0f) ..."), image.size.width, image.size.height]
      helpButton:NO];
 }
                   editingInfo:(NSDictionary *)editingInfo
 {
   UIImage *imageToDecode = image;
+       CGSize size = [image size];
+       CGRect cropRect = CGRectMake(0.0, 0.0, size.width, size.height);
+       
 #ifdef DEBUG
-  NSLog(@"picked image size = (%f, %f)", image.size.width, image.size.height);
+  NSLog(@"picked image size = (%f, %f)", size.width, size.height);
 #endif
+  NSString *systemVersion = [[UIDevice currentDevice] systemVersion];
+  
   if (editingInfo) {
     UIImage *originalImage = [editingInfo objectForKey:UIImagePickerControllerOriginalImage];
     if (originalImage) {
 #endif
       NSValue *cropRectValue = [editingInfo objectForKey:UIImagePickerControllerCropRect];
       if (cropRectValue) {
-        CGRect cropRect = [cropRectValue CGRectValue];
+        cropRect = [cropRectValue CGRectValue];
 #ifdef DEBUG
         NSLog(@"crop rect = (%f, %f) x (%f, %f)", CGRectGetMinX(cropRect), CGRectGetMinY(cropRect), CGRectGetWidth(cropRect), CGRectGetHeight(cropRect));
 #endif
-        UIGraphicsBeginImageContext(cropRect.size);
-        
-        [originalImage drawAtPoint:CGPointMake(-CGRectGetMinX(cropRect),
-                                               -CGRectGetMinY(cropRect))];
-        
-        imageToDecode = UIGraphicsGetImageFromCurrentImageContext();
-        UIGraphicsEndImageContext();
+        if (([picker sourceType] == UIImagePickerControllerSourceTypeSavedPhotosAlbum) &&
+                                               [@"2.1" isEqualToString:systemVersion]) {
+          // adjust crop rect to work around bug in iPhone OS 2.1 when selecting from the photo roll
+          cropRect.origin.x *= 2.5;
+          cropRect.origin.y *= 2.5;
+          cropRect.size.width *= 2.5;
+          cropRect.size.height *= 2.5;
+#ifdef DEBUG
+          NSLog(@"2.1-adjusted crop rect = (%f, %f) x (%f, %f)", CGRectGetMinX(cropRect), CGRectGetMinY(cropRect), CGRectGetWidth(cropRect), CGRectGetHeight(cropRect));
+#endif
+        }
+                               
+                               imageToDecode = originalImage;
       }
     }
   }
   [[picker parentViewController] dismissModalViewControllerAnimated:YES];
   [imageToDecode retain];
   [picker release];
-  [self.decoder decodeImage:imageToDecode];
+  [self.decoder decodeImage:imageToDecode cropRect:cropRect];
   [imageToDecode release];
   [self updateToolbar];
 }
index ac26f7a..3fda9cf 100755 (executable)
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
+                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: Christian Brunschen";
                                COPY_PHASE_STRIP = NO;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_OPTIMIZATION_LEVEL = 0;
                                GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1";
                                INFOPLIST_FILE = Info.plist;
                                PRODUCT_NAME = Barcodes;
+                               "PROVISIONING_PROFILE[sdk=iphoneos*]" = "3B103E1C-067D-4368-B6A0-6FDCFE7B0D47";
                        };
                        name = Debug;
                };
                                GCC_PREFIX_HEADER = ZXing_Prefix.pch;
                                INFOPLIST_FILE = Info.plist;
                                PRODUCT_NAME = Barcodes;
-                               "PROVISIONING_PROFILE[sdk=iphoneos*]" = "6827259A-0073-4678-82F6-329E230F6801";
+                               "PROVISIONING_PROFILE[sdk=iphoneos*]" = "3B103E1C-067D-4368-B6A0-6FDCFE7B0D47";
                        };
                        name = Release;
                };
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ARCHS = "$(ARCHS_STANDARD_32_BIT)";
-                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: Christian Brunschen";
                                GCC_C_LANGUAGE_STANDARD = c99;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES;
                                GCC_WARN_UNUSED_VARIABLE = YES;
                                PREBINDING = NO;
-                               "PROVISIONING_PROFILE[sdk=iphoneos*]" = "3A1B16DE-FE88-44B7-B4AD-D409BB8F7DDD";
                                SDKROOT = iphoneos2.0;
                        };
                        name = "AdHoc Distribution";
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
-                               CODE_SIGN_ENTITLEMENTS = Entitlements.plist;
+                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: Christian Brunschen";
                                COPY_PHASE_STRIP = YES;
                                GCC_PRECOMPILE_PREFIX_HEADER = YES;
                                GCC_PREFIX_HEADER = ZXing_Prefix.pch;
                                INFOPLIST_FILE = Info.plist;
                                PRODUCT_NAME = Barcodes;
-                               "PROVISIONING_PROFILE[sdk=iphoneos*]" = "6CDE626B-71E0-4E2A-BED0-DDE5BE24A701";
+                               "PROVISIONING_PROFILE[sdk=iphoneos*]" = "3A1B16DE-FE88-44B7-B4AD-D409BB8F7DDD";
                        };
                        name = "AdHoc Distribution";
                };
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ARCHS = "$(ARCHS_STANDARD_32_BIT)";
-                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
                                GCC_C_LANGUAGE_STANDARD = c99;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES;
                                GCC_WARN_UNUSED_VARIABLE = YES;
                                ONLY_ACTIVE_ARCH = YES;
                                PREBINDING = NO;
-                               "PROVISIONING_PROFILE[sdk=iphoneos*]" = "F7E3CE9A-42BC-4860-A74F-B4D05A088442";
                                SDKROOT = macosx10.5;
                        };
                        name = Test;
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
+                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: Christian Brunschen";
                                COPY_PHASE_STRIP = NO;
                                GCC_DYNAMIC_NO_PIC = NO;
                                GCC_OPTIMIZATION_LEVEL = 0;
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ARCHS = "$(ARCHS_STANDARD_32_BIT)";
-                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
                                GCC_C_LANGUAGE_STANDARD = c99;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES;
                                GCC_WARN_UNUSED_VARIABLE = YES;
                                PREBINDING = NO;
-                               "PROVISIONING_PROFILE[sdk=iphoneos*]" = DefaultProfileUuid;
                                SDKROOT = iphoneos2.0;
                        };
                        name = Distribution;
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ALWAYS_SEARCH_USER_PATHS = NO;
-                               CODE_SIGN_ENTITLEMENTS = "";
                                "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: Christian Brunschen";
                                COPY_PHASE_STRIP = YES;
                                GCC_PRECOMPILE_PREFIX_HEADER = YES;
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ARCHS = "$(ARCHS_STANDARD_32_BIT)";
-                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
                                GCC_C_LANGUAGE_STANDARD = c99;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES;
                                GCC_WARN_UNUSED_VARIABLE = YES;
                                ONLY_ACTIVE_ARCH = YES;
                                PREBINDING = NO;
-                               "PROVISIONING_PROFILE[sdk=iphoneos*]" = "F7E3CE9A-42BC-4860-A74F-B4D05A088442";
                                SDKROOT = iphoneos2.0;
                        };
                        name = Debug;
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                ARCHS = "$(ARCHS_STANDARD_32_BIT)";
-                               "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
                                GCC_C_LANGUAGE_STANDARD = c99;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES;
                                GCC_WARN_UNUSED_VARIABLE = YES;
                                PREBINDING = NO;
-                               "PROVISIONING_PROFILE[sdk=iphoneos*]" = DefaultProfileUuid;
                                SDKROOT = iphoneos2.0;
                        };
                        name = Release;