7

I am new to iOS and I have been bashing head against the wall for this for the past week looking around online for tutorials such as: Dealing with Exif Images, Resizing images, and many more random questions here on StackOverflow. From these, I figured that >=iOS 4.0, all images taken from the camera contain EXIF-based rotation information.

What's not working: After trying different image cropping techniques, all I end up with is cropping of the image at some random corners and also, the resulting image appears to be zoomed in :( When I use a png image from the internet (which don't contain EXIF data), the cropping is working. By random corners, I mean - the image ends up being cropped at the top-right/top-left and zoomed-in.

What I am trying to accomplish:
I am trying to crop an image 100 px from top and 100 px from bottom. Essentially, I am using two overlay strips - 1 at the top, and 1 at the bottom with the CGRect(0.0, 0.0, SCREEN_WIDTH, 100.0) [a 100.0 px tall strip at the top] and another CGRect(0.0, SCREEN_HEIGHT - 100, SCREEN_WIDTH, 100.0) [another 100 px tall strip at the bottom]. I need to get the image between these two strips: I assume the height of the image is: SCREEN_HEIGHT - 200.0.

Displaying UIImagePickerController for camera with overlay:


    //SCREEN_HEIGHT = 480 and SCREEN_WIDTH = 320
    UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];

    if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera] == NO) 
    {
        NSLog(@"Camera not available");
        return;
    }

    imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
    imagePicker.delegate = self;
    imagePicker.allowsEditing = NO;


    // Hide the controls
    imagePicker.showsCameraControls = NO;
    imagePicker.navigationBarHidden = YES;

    // Make camera view full screen
    imagePicker.wantsFullScreenLayout = YES;
    //imagePicker.cameraViewTransform = CGAffineTransformScale(imagePicker.cameraViewTransform, CAMERA_TRANSFORM_X, CAMERA_TRANSFORM_Y);


    //Overlay
    //OverlayView is a plain UIView with the CGRects mentioned in the question.
    OverlayView *overlay = [[OverlayView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)]; 
    [overlay initOverlay:self];
    imagePicker.cameraOverlayView = overlay;
    [self presentModalViewController:imagePicker animated:YES];

Code to rotate image based on EXIF imageOrientation property and cropping it


- (UIImage *) cropImage: (UIImage *) originalImage 
{

    CGRect cropRect = CGRectMake(0, 100.0, SCREEN_WIDTH, SCREEN_HEIGHT - 100);

    CGRect transformedRect = [self TransformCGRectForUIImageOrientation:cropRect :originalImage.imageOrientation :originalImage.size];

    CGImageRef resultImageRef = CGImageCreateWithImageInRect(originalImage.CGImage, transformedRect);

    UIImage *newImage = [[[UIImage alloc] initWithCGImage:resultImageRef scale:1.0 orientation:originalImage.imageOrientation] autorelease];

    return newImage;
}

- (CGRect) TransformCGRectForUIImageOrientation: (CGRect) source: (UIImageOrientation) orientation: (CGSize) imageSize {

    switch (orientation) {
        case UIImageOrientationLeft: { // EXIF #8
            CGAffineTransform txTranslate = CGAffineTransformMakeTranslation(
                                                                             imageSize.height, 0.0);
            CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate,
                                                                   M_PI_2);
            return CGRectApplyAffineTransform(source, txCompound);
        }
        case UIImageOrientationDown: { // EXIF #3
            CGAffineTransform txTranslate = CGAffineTransformMakeTranslation(
                                                                             imageSize.width, imageSize.height);
            CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate,
                                                                   M_PI);
            return CGRectApplyAffineTransform(source, txCompound);
        }
        case UIImageOrientationRight: { // EXIF #6
            CGAffineTransform txTranslate = CGAffineTransformMakeTranslation(
                                                                             0.0, imageSize.width);
            CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate,
                                                                   M_PI + M_PI_2);
            return CGRectApplyAffineTransform(source, txCompound);
        }
        case UIImageOrientationUp: // EXIF #1 - do nothing
        default: // EXIF 2,4,5,7 - ignore
            return source;
    }


The cropImage method seems to work for images downloaded from the internet (which don't contain any orientation info). I am running out of options. Could someone PLEASE help me out?

Thanks for reading!

Community
  • 1
  • 1
Sagar Hatekar
  • 8,700
  • 14
  • 56
  • 72

1 Answers1

17

When you can, it is easier to skip drawing images with Core Graphics:

- (UIImage *)cropImage:(UIImage *)oldImage {
    CGSize imageSize = oldImage.size
    UIGraphicsBeginImageContextWithOptions( CGSizeMake( imageSize.width,
                                                        imageSize.height - 200),
                                            NO,
                                            0.);
    [oldImage drawAtPoint:CGPointMake( 0, -100)
                blendMode:kCGBlendModeCopy
                    alpha:1.];
    UIImage *croppedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return croppedImage;
}
Mats
  • 8,528
  • 1
  • 29
  • 35
  • +1 Thanks, Matt. Trying to understand the code: Line #2 "selects" the image with the bottom 200 px clipped and then places the new images 100 px upwards of the original image, thereby clipping the top 100px, and the bottom 100 px right? It worked for me! Thanks a lot for your efforts!! Although the clipped image isn't exactly similar to the one seen with the camera overlay but I will probably have to tweak the nos. a bit. BTW, this code isn't thread-safe right? And I guess the CG lib provides a thread-safe way of doing this - so would be great to use it in a thread-safe manner. – Sagar Hatekar Dec 13 '11 at 23:05
  • 1
    It is thread safe on iOS 4.0 and later, [QA 1637](http://developer.apple.com/library/ios/#qa/qa1637/_index.html). – Mats Dec 14 '11 at 07:18
  • perfect! I have tried several methods, none worked as expected considering the image orientation. I always ended with the image rotated. thanks. – Duck Jan 15 '12 at 07:54
  • @Mats, is there a way to do a similar cropping, but also include x offset points? I mean something like crop a rect, not only top and bottom parts? – Eugene Jan 28 '12 at 09:04
  • OMG I'd give you +1000 if I could. This finally works!! thanks! – Evan Layman Dec 10 '12 at 19:13
  • @Mats I am trying the function, but it increases the allocation size significantly. Any reason? – Dejell Feb 07 '13 at 12:37
  • @Odelya UIImages take a lot of memory – quantumpotato Jun 26 '13 at 16:21