25

I think I found a bug in latest iOS 7 by running an app with Base SDK set to iOS 6.1 (possibly even lower versions too, haven't tested that out yet)

I have this image in my photo library: https://i.stack.imgur.com/x2g1T.jpg

I present a UIImagePickerController via:

UIImagePickerController *vc = [[UIImagePickerController alloc] init];
vc.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
vc.delegate = self;
vc.allowsEditing = YES;
[self presentViewController:vc animated:YES completion:nil];

I save the chosen image to my desktop (I am running this on simulator, but this works on device too)

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {

    UIImage* outputImage = [info objectForKey:UIImagePickerControllerEditedImage];
    if (outputImage == nil) {
        outputImage = [info objectForKey:UIImagePickerControllerOriginalImage];
    }
    NSData *d = UIImagePNGRepresentation(outputImage);
    [d writeToFile:@"/Users/Admin/Desktop/test.png" atomically:YES];
    [self dismissViewControllerAnimated:YES completion:nil];
}

This is the resulting image: enter image description here

Notice the big black bar to the right. What's causing this?

To reproduce this, you need:

  • iOS 7
  • App with Base SDK set to 6.1 (maybe even lower SDKs too, i haven't tried yet)
  • iPhone 5/5c/5s
  • Only happens to pictures that were taken with iPhone 5/5c/5s camera (you can use the original image I linked above for testing)

NOTE: Just to be clear, the black bar is part of the actual image. The image you see there is not a screenshot of a UIImageView, but the actual image saved to disk and uploaded here...

Segev
  • 19,035
  • 12
  • 80
  • 152
0xSina
  • 20,973
  • 34
  • 136
  • 253
  • Well your source is set to `UIImagePickerControllerSourceTypePhotoLibrary`, so it does seem you are not using the actual camera, but picking up images from the library. Right ? – Lefteris Oct 18 '13 at 12:55
  • I've seen issues like this with edited images and/or rotated images. Does this occur for images taken in other orientations? Does it happen if you don't allow editing? – Jesse Rusak Oct 18 '13 at 13:53
  • Does this happen if you change the editing rect? One of these issues we saw only happened if the user accepted the default crop rect. – Jesse Rusak Oct 18 '13 at 13:58
  • @Lefteris yes, it only happens when images are chosen from Library. If they are taken from camera within the app, it works fine. – 0xSina Oct 18 '13 at 22:59
  • Can you clarify? What is the issue here, is the black bar meant to be there? – Joshua Oct 18 '13 at 23:41
  • I suspect this has something to do with metadata handling, specifically with orientation and size. Some portion of internal code may consider orientation while other may not when handling image size.I can't verify it now but UIImage.size used (iOS 5) to return value which reflected the orientation of the image while CGImageGetWidth/Height would not. Since output image w and h are equal and the extra bar is black, destination image might have been produced from original image drawn into calloc'd cgbitmapcontext with wrong (ratio) size.What happens if you save to UIImageJPEGRepresentation? – TheBlack Oct 19 '13 at 14:01
  • @TheBlack Not really metadata related.. The CropRect values are wrong. Check out the answer I just added. Nice find 0xSina! – Segev Oct 20 '13 at 18:10
  • Well done 0xSina -- this is a clear and obvious Apple bug. It's really surprising I think this is THE ONLY question on the topic. – Fattie Mar 01 '14 at 10:08
  • PS related http://stackoverflow.com/questions/4094533/incorrect-values-for-uiimagepickercontrollercroprect-rectangle – Fattie Mar 01 '14 at 15:42

4 Answers4

22

Your question is "What's causing this?" So I'll focus on that instead of giving a workaround. This is definitely a bug in iOS 7 dealing with edited images in lower base SDKs. We can also rule out that XCode 5 & Base SDK 6.1 causing this because I'm getting the same issue with XCode 4.6.3 & 6.1 SDK running on iOS 7 Simulator.

The source of the problem is that the CropRect values that are calculated by the SDK are wrong. If you'll print out the info NSDictionary from imagePickerController:didFinishPickingMediaWithInfo you'll see that:

iOS 7 running any SDK lower than 7 we'll get:

UIImagePickerControllerCropRect = "NSRect: {{154, 495}, {1705, 1705}}";

While running iOS 6 or 5 with their SDK will give us:

UIImagePickerControllerCropRect = "NSRect: {{0, 149}, {1704, 1705}}";

You're probably saying, hmm, those y values are changing between SDKs too. Well, yea, if you'll slide your pic all the way down and select it you'll also get a black bar at the bottom of the picture.

enter image description here

Suggested Solutions:

  1. File a bug report to Apple here ...Did that!

  2. Don't use UIImagePickerControllerEditedImage and take the original picture instead.

  3. Calculate and do the cropping your self.

  4. Use a 3rd party cropping library such as PEPhotoCropEditor or SSPhotoCropperViewController


Edit - very simple solution added by fan of the answer!

Amazingly, it can be this simple and elegant to crop it yourself:

{
// There is a bug in iOS. When using ALBUM, you must crop it yourself:

fromAlbum = [info objectForKey:UIImagePickerControllerOriginalImage];
fromAlbum = [fromAlbum fixOrientation];

CGRect crop = [[info valueForKey:@"UIImagePickerControllerCropRect"] CGRectValue];
fromAlbum = [self ordinaryCrop:fromAlbum toRect:crop];
}

Here's the whole routine ordinaryCrop:toRect:

-(UIImage *)ordinaryCrop:(UIImage *)imageToCrop toRect:(CGRect)cropRect
 {
 CGImageRef imageRef = CGImageCreateWithImageInRect([imageToCrop CGImage], cropRect);
 UIImage *cropped = [UIImage imageWithCGImage:imageRef];
 CGImageRelease(imageRef);
 return cropped;
 }

Now as Jesse points out, it is critical to rotate the image properly. This absolutely incredible piece of code by Anomie does the job:

iOS UIImagePickerController result image orientation after upload

Fixing UIImage orientation .. UIImage+fixOrientation.h

It's that simple, hope it helps someone. Thanks again for the priceless answers here.

Community
  • 1
  • 1
Segev
  • 19,035
  • 12
  • 80
  • 152
  • 1
    Just a note ... March 2014 ... this bug is still totally there, even in iOS7, and apps that are only for iOS7. Segev's solution at (3) seems to be the solution, thanks Segev. – Fattie Mar 01 '14 at 08:32
  • @JoeBlow Great edit. Thanks Joe! I wonder if that's fixed in 7.1 beta – Segev Mar 01 '14 at 17:29
  • iOS 9 still there (iPad mini 4) – Jakub Truhlář May 31 '16 at 17:32
  • @BobdeGraaf the iOS 11 bug is actually a little different. See https://stackoverflow.com/q/48056398/368085. And it cannot be worked around like this one. – mluisbrown Mar 10 '18 at 17:01
  • @mluisbrown Hm perhaps, although that one is about top/bottom cropping while I actually still have an issue with a black bar on the right.. And I was able to fix it using code in this answer :) – Bob de Graaf Mar 12 '18 at 08:39
  • @BobdeGraaf well, on iOS 10 I have no cropping issues at all. `UIImagePickerControllerEditedImage` returns the correct image, although you do have to correct its orientation if it comes from the camera. On iOS 11, the bug is the crop square is positioned wrongly, leading to a cropped image that is offset down from where the user thought they were cropping. – mluisbrown Mar 12 '18 at 11:48
  • @mluisbrown yeah and that's what the difference is. I don't have the offset down, I have a black bar on the right... – Bob de Graaf Mar 13 '18 at 13:02
  • Bug still persists on iOS 12 (iPhone 6) – yohannes Oct 03 '18 at 07:34
4

I believe we ended up working around similar issues by never asking for the edited image directly; ask for the original image and the crop information (UIImagePickerControllerCropRect) and do the cropping yourself. Note that you need to worry about rotations in the source image if you do the cropping yourself.

You might find the answer in this question helpful for implementing this work-around.

Community
  • 1
  • 1
Jesse Rusak
  • 56,530
  • 12
  • 101
  • 102
-1

Try find and change mode (Aspect Fit, Aspect Fill, Scale to Fill) programmatically.

Alex
  • 2,100
  • 19
  • 26
  • The black bar is part of the actual image. The image you see there is not a screenshot of a UIImageView, but the actual image saved to disk and uploaded here... – 0xSina Oct 16 '13 at 12:15
-2

I'm trying to reproduce this bug. And have no luck on simulator, simulator 64-bit and iPad mini. All running iOS 7.0.

I put your code in my app:

UIImage *image = [info valueForKey:UIImagePickerControllerEditedImage];
if (!image)
    image = [info valueForKey:UIImagePickerControllerOriginalImage];

// Save photo to custom album only if taken by camera
if (picker.sourceType == UIImagePickerControllerSourceTypeCamera)
    [ALAssetsLibrary saveImageToCustomAlbum:image
                                   assetURL:[info valueForKey:UIImagePickerControllerReferenceURL]];


NSData *d = UIImagePNGRepresentation(image);
[d writeToFile:@"/Volumes/Alko/Temp/test.png" atomically:YES];

UIImageWriteToSavedPhotosAlbum(image, nil, NULL, nil);

[self setImage:image];
[self dismissPicker:picker];
[self photoPickerDidFinish];

And it works correct using image downloaded from https://i.stack.imgur.com/4Mlze.jpg. I think you have issue in your app, not in UIImagePickerController.

AlKozin
  • 904
  • 8
  • 25