From 17e7ce77a1dc64e1f11924114024f3d7328807a4 Mon Sep 17 00:00:00 2001 From: Tom Taylor Date: Thu, 23 Jun 2016 12:03:07 +0100 Subject: [PATCH] Fix the rotation of the camera image in demo. The image coming out of the image picker was being fed into Tesseract upside down, resulting in gibberish. This uses the EXIF header to rotate the pixels to be 'up', returning sane results from Tesseract. --- .../project.pbxproj | 6 ++ .../G8ViewController.m | 5 +- .../UIImage+FixRotation.h | 15 +++ .../UIImage+FixRotation.m | 93 +++++++++++++++++++ 4 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 Template Framework Project/Template Framework Project/UIImage+FixRotation.h create mode 100644 Template Framework Project/Template Framework Project/UIImage+FixRotation.m diff --git a/Template Framework Project/Template Framework Project.xcodeproj/project.pbxproj b/Template Framework Project/Template Framework Project.xcodeproj/project.pbxproj index edd7cbe7..107d987c 100644 --- a/Template Framework Project/Template Framework Project.xcodeproj/project.pbxproj +++ b/Template Framework Project/Template Framework Project.xcodeproj/project.pbxproj @@ -21,6 +21,7 @@ 64DDA75B188FD9140025590D /* tessdata in Resources */ = {isa = PBXBuildFile; fileRef = 64DDA75A188FD9140025590D /* tessdata */; }; 64E40AB1180C6D4D00C36DDE /* libstdc++.6.0.9.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 64E40AB0180C6D4D00C36DDE /* libstdc++.6.0.9.dylib */; }; 73BE4C421A5D83AB002C15F1 /* TesseractOCR.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73BE4C411A5D83AB002C15F1 /* TesseractOCR.framework */; }; + E2345E101D1BF8C200D789AF /* UIImage+FixRotation.m in Sources */ = {isa = PBXBuildFile; fileRef = E2345E0F1D1BF8C200D789AF /* UIImage+FixRotation.m */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -44,6 +45,8 @@ 64E40AB0180C6D4D00C36DDE /* libstdc++.6.0.9.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libstdc++.6.0.9.dylib"; path = "usr/lib/libstdc++.6.0.9.dylib"; sourceTree = SDKROOT; }; 73BE4C411A5D83AB002C15F1 /* TesseractOCR.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TesseractOCR.framework; path = "../build/Debug-iphoneos/TesseractOCR.framework"; sourceTree = ""; }; 73C0A7BE1A59565100D823D4 /* TesseractOCR.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = TesseractOCR.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + E2345E0E1D1BF8C200D789AF /* UIImage+FixRotation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+FixRotation.h"; sourceTree = ""; }; + E2345E0F1D1BF8C200D789AF /* UIImage+FixRotation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+FixRotation.m"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -105,6 +108,8 @@ 6400DDEE180C5DE000443362 /* G8ViewController.m */, 6400DDF0180C5DE000443362 /* Images.xcassets */, 6400DDDF180C5DE000443362 /* Supporting Files */, + E2345E0E1D1BF8C200D789AF /* UIImage+FixRotation.h */, + E2345E0F1D1BF8C200D789AF /* UIImage+FixRotation.m */, ); path = "Template Framework Project"; sourceTree = ""; @@ -192,6 +197,7 @@ 6400DDE5180C5DE000443362 /* main.m in Sources */, 6400DDE9180C5DE000443362 /* G8AppDelegate.m in Sources */, 6400DDEF180C5DE000443362 /* G8ViewController.m in Sources */, + E2345E101D1BF8C200D789AF /* UIImage+FixRotation.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Template Framework Project/Template Framework Project/G8ViewController.m b/Template Framework Project/Template Framework Project/G8ViewController.m index a38208e5..7edd99a6 100644 --- a/Template Framework Project/Template Framework Project/G8ViewController.m +++ b/Template Framework Project/Template Framework Project/G8ViewController.m @@ -8,6 +8,7 @@ // #import "G8ViewController.h" +#import "UIImage+FixRotation.h" @interface G8ViewController () @@ -149,7 +150,9 @@ - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { UIImage *image = info[UIImagePickerControllerOriginalImage]; + UIImage *rotatedImage = [image fixOrientation]; [picker dismissViewControllerAnimated:YES completion:nil]; - [self recognizeImageWithTesseract:image]; + + [self recognizeImageWithTesseract:rotatedImage]; } @end diff --git a/Template Framework Project/Template Framework Project/UIImage+FixRotation.h b/Template Framework Project/Template Framework Project/UIImage+FixRotation.h new file mode 100644 index 00000000..028ea0d9 --- /dev/null +++ b/Template Framework Project/Template Framework Project/UIImage+FixRotation.h @@ -0,0 +1,15 @@ +// +// UIImage+FixRotation.h +// Template Framework Project +// +// Created by Tom Taylor on 23/06/2016. +// Copyright © 2016 Daniele Galiotto - www.g8production.com. All rights reserved. +// + +#import + +@interface UIImage (fixOrientation) + +- (UIImage *)fixOrientation; + +@end \ No newline at end of file diff --git a/Template Framework Project/Template Framework Project/UIImage+FixRotation.m b/Template Framework Project/Template Framework Project/UIImage+FixRotation.m new file mode 100644 index 00000000..422dc7e9 --- /dev/null +++ b/Template Framework Project/Template Framework Project/UIImage+FixRotation.m @@ -0,0 +1,93 @@ +// +// UIImage+FixRotation.m +// Template Framework Project +// +// Created by Tom Taylor on 23/06/2016. +// Copyright © 2016 Daniele Galiotto - www.g8production.com. All rights reserved. +// + +#import "UIImage+FixRotation.h" + +@implementation UIImage (FixOrientation) + +- (UIImage *)fixOrientation { + + // No-op if the orientation is already correct + if (self.imageOrientation == UIImageOrientationUp) return self; + + // We need to calculate the proper transformation to make the image upright. + // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored. + CGAffineTransform transform = CGAffineTransformIdentity; + + switch (self.imageOrientation) { + case UIImageOrientationDown: + case UIImageOrientationDownMirrored: + transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height); + transform = CGAffineTransformRotate(transform, M_PI); + break; + + case UIImageOrientationLeft: + case UIImageOrientationLeftMirrored: + transform = CGAffineTransformTranslate(transform, self.size.width, 0); + transform = CGAffineTransformRotate(transform, M_PI_2); + break; + + case UIImageOrientationRight: + case UIImageOrientationRightMirrored: + transform = CGAffineTransformTranslate(transform, 0, self.size.height); + transform = CGAffineTransformRotate(transform, -M_PI_2); + break; + case UIImageOrientationUp: + case UIImageOrientationUpMirrored: + break; + } + + switch (self.imageOrientation) { + case UIImageOrientationUpMirrored: + case UIImageOrientationDownMirrored: + transform = CGAffineTransformTranslate(transform, self.size.width, 0); + transform = CGAffineTransformScale(transform, -1, 1); + break; + + case UIImageOrientationLeftMirrored: + case UIImageOrientationRightMirrored: + transform = CGAffineTransformTranslate(transform, self.size.height, 0); + transform = CGAffineTransformScale(transform, -1, 1); + break; + case UIImageOrientationUp: + case UIImageOrientationDown: + case UIImageOrientationLeft: + case UIImageOrientationRight: + break; + } + + // Now we draw the underlying CGImage into a new context, applying the transform + // calculated above. + CGContextRef ctx = CGBitmapContextCreate(NULL, self.size.width, self.size.height, + CGImageGetBitsPerComponent(self.CGImage), 0, + CGImageGetColorSpace(self.CGImage), + CGImageGetBitmapInfo(self.CGImage)); + CGContextConcatCTM(ctx, transform); + switch (self.imageOrientation) { + case UIImageOrientationLeft: + case UIImageOrientationLeftMirrored: + case UIImageOrientationRight: + case UIImageOrientationRightMirrored: + // Grr... + CGContextDrawImage(ctx, CGRectMake(0,0,self.size.height,self.size.width), self.CGImage); + break; + + default: + CGContextDrawImage(ctx, CGRectMake(0,0,self.size.width,self.size.height), self.CGImage); + break; + } + + // And now we just create a new UIImage from the drawing context + CGImageRef cgimg = CGBitmapContextCreateImage(ctx); + UIImage *img = [UIImage imageWithCGImage:cgimg]; + CGContextRelease(ctx); + CGImageRelease(cgimg); + return img; +} + +@end