From fd5090164773cdab90916875f8591fd6244a5fda Mon Sep 17 00:00:00 2001 From: "christian.brunschen" Date: Mon, 13 Oct 2008 16:09:09 +0000 Subject: [PATCH 1/1] improved image cropping, also work around iPhone OS 2.1 bug when picking from photo roll git-svn-id: http://zxing.googlecode.com/svn/trunk@614 59b500cc-1b3d-0410-9834-0bbf25fbcc57 --- iphone/Classes/Decoder.h | 4 ++- iphone/Classes/Decoder.m | 42 ++++++++++++++++++-------- iphone/Classes/DecoderDelegate.h | 2 +- iphone/Classes/DecoderViewController.h | 2 +- iphone/Classes/DecoderViewController.m | 37 +++++++++++++++-------- iphone/ZXing.xcodeproj/project.pbxproj | 20 ++++-------- 6 files changed, 64 insertions(+), 43 deletions(-) diff --git a/iphone/Classes/Decoder.h b/iphone/Classes/Decoder.h index 8d2c161a..4b28141f 100644 --- a/iphone/Classes/Decoder.h +++ b/iphone/Classes/Decoder.h @@ -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 delegate; - (void) decodeImage:(UIImage *)image; -- (void) decodeImage:(UIImage *)image cropRectangle:(CGRect)cropRect; +- (void) decodeImage:(UIImage *)image cropRect:(CGRect)cropRect; @end diff --git a/iphone/Classes/Decoder.m b/iphone/Classes/Decoder.m index 74bb6ed9..0cac0026 100644 --- a/iphone/Classes/Decoder.m +++ b/iphone/Classes/Decoder.m @@ -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 ...") diff --git a/iphone/Classes/DecoderDelegate.h b/iphone/Classes/DecoderDelegate.h index a2db6088..35d454e8 100644 --- a/iphone/Classes/DecoderDelegate.h +++ b/iphone/Classes/DecoderDelegate.h @@ -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; diff --git a/iphone/Classes/DecoderViewController.h b/iphone/Classes/DecoderViewController.h index 12745362..a941eb30 100644 --- a/iphone/Classes/DecoderViewController.h +++ b/iphone/Classes/DecoderViewController.h @@ -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; diff --git a/iphone/Classes/DecoderViewController.m b/iphone/Classes/DecoderViewController.m index 0e92b750..02dc7318 100644 --- a/iphone/Classes/DecoderViewController.m +++ b/iphone/Classes/DecoderViewController.m @@ -196,7 +196,7 @@ - (void)pickAndDecodeFromSource:(UIImagePickerControllerSourceType) sourceType { [self reset]; - \ + // Create the Image Picker if ([UIImagePickerController isSourceTypeAvailable:sourceType]) { UIImagePickerController* picker = [[UIImagePickerController alloc] init]; @@ -301,9 +301,9 @@ // 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]; } @@ -399,9 +399,14 @@ 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) { @@ -410,17 +415,23 @@ #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; } } } @@ -428,7 +439,7 @@ [[picker parentViewController] dismissModalViewControllerAnimated:YES]; [imageToDecode retain]; [picker release]; - [self.decoder decodeImage:imageToDecode]; + [self.decoder decodeImage:imageToDecode cropRect:cropRect]; [imageToDecode release]; [self updateToolbar]; } diff --git a/iphone/ZXing.xcodeproj/project.pbxproj b/iphone/ZXing.xcodeproj/project.pbxproj index ac26f7a1..3fda9cfa 100755 --- a/iphone/ZXing.xcodeproj/project.pbxproj +++ b/iphone/ZXing.xcodeproj/project.pbxproj @@ -1846,6 +1846,7 @@ 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; @@ -1854,6 +1855,7 @@ GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1"; INFOPLIST_FILE = Info.plist; PRODUCT_NAME = Barcodes; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = "3B103E1C-067D-4368-B6A0-6FDCFE7B0D47"; }; name = Debug; }; @@ -1867,7 +1869,7 @@ 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; }; @@ -1901,12 +1903,10 @@ 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"; @@ -1915,13 +1915,13 @@ 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"; }; @@ -2107,13 +2107,11 @@ 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; @@ -2122,6 +2120,7 @@ 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; @@ -2205,12 +2204,10 @@ 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; @@ -2219,7 +2216,6 @@ 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; @@ -2302,13 +2298,11 @@ 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; @@ -2317,12 +2311,10 @@ 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; -- 2.20.1