Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS Image Orientation has Strange Behavior

For the past few weeks I've been working with images in objective-c and noticing a lot of strange behavior. First, like many other people, I've been having this problem where images taken with the camera (or taken with somebody else's camera and MMS'd to me) are rotated 90 degrees. I wasn't sure why in the world this was happening (hence my question) but I was able to come up with a cheap work around.

My question this time is why is this happening? Why is Apple rotating images? When I take a photo with my camera right-side up, unless I perform my code mentioned above, when I save the photo it gets saved rotated. Now, my workaround was okay up until a few days ago.

My application modifies individual pixels of an image, specifically the alpha channel of a PNG (so any JPEG conversion gets thrown out of the window for my scenario). A few days ago I noticed that even though the image is displayed properly in my app thanks to my workaround code, when my algorithm modifies the individual pixels of the image, it thinks the image is rotated. So instead of modifying the pixels at the top of the image, it modifies the pixels on the side of the image (because it thinks it should be rotated)! I can't figure out how to rotate the image in memory - ideally I would prefer to just wipe away that imageOrientation flag all together.

Here's something else that has been baffling me as well... When I take the photo, the imageOrientation is set to 3. My workaround code is smart enough to realize this and flip it so the user never notices. Additionally, my code to save the image to the library realizes this, flips it, then saves it so it appears in the camera roll properly.

That code looks like so:

NSData* pngdata = UIImagePNGRepresentation (self.workingImage); //PNG wrap  UIImage* img = [self rotateImageAppropriately:[UIImage imageWithData:pngdata]];    UIImageWriteToSavedPhotosAlbum(img, nil, nil, nil); 

When I load this newly saved image into my app, the imageOrientation is 0 - exactly what I want to see, and my rotation workaround doesn't even need to run (note: when loading images from the internet as opposed to images taken with a camera, the imageOrientation is always 0, resulting in perfect behavior). For some reason, my save code seems to wipe away this imageOrientation flag. I was hoping to just steal that code and use it to wipe away my imageOrientation as soon as the user takes a photo and has it added to the app, but it doesn't seem to work. Does UIImageWriteToSavedPhotosAlbum do something special with imageOrientation?

Would the best fix for this problem be to just blow away imageOrientation as soon as the user is done taking an image. I assume Apple has the rotation behavior done for a reason, right? A few people suggested that this is an Apple defect.

(... if you're not lost yet... Note2: When I take a horizontal photo, everything seems to work perfectly, just like photos taken from the internet)

EDIT:

Here are what some of the images and scenarios actually look like. Based off the comments so far, it looks like this strange behavior is more than just an iPhone behavior, which I think is good.

This is a picture of the photo I took with my phone (note the proper orientation), it appears exactly as it did on my phone when I snapped the photo:

Actual Photo taken on iPhone

Here is what the image looks like in Gmail after I emailed it to myself (looks like Gmail handles it properly):

Photo as it appears in Gmail

Here is what the image looks like as a thumbnail in windows (doesn't look like it is handled properly):

Windows Thumbnail

And here is what the actual image looks like when opened with Windows Photo Viewer (still not handled properly):

Windows Photo Viewer Version

After all of the comments on this question, here's what I'm thinking... The iPhone takes an image, and says "to display this properly, it needs to be rotated 90 degrees". This information would be in the EXIF data. (Why it needs to be rotated 90 degrees, rather than defaulting to straight vertical, I don't know). From here, Gmail is smart enough to read and analyze that EXIF data, and properly display it. Windows however, is not smart enough to read the EXIF data, and therefore displays the image improperly. Are my assumptions correct?

like image 367
Boeckm Avatar asked May 15 '12 12:05

Boeckm


People also ask

Why does my iPhone keep rotating my pictures?

To lock the screen in portrait orientation, swipe up from the bottom edge of the screen to open Control Center, then tap (lock with circle arrow icon). The Portrait orientation lock icon (lock with circle arrow icon) appears in the status bar when the screen orientation is locked. Regards, Jeff D.

Why are my photos the wrong way round?

Photos are displayed according to the orientation information from the camera that took the photo. This can cause some photos to appear sideways or upside down. For example, If you used a camera and held it vertically to take a photo in portrait mode, that photo can be saved sideways, in landscape mode.

Why are my pictures turning sideways?

The reason your photo would appear this way is because the photo was taken that way (either with the phone sideways or upside down) and the image file itself is in this orientation. For example, if you hold your phone upright and take a photo, the photo is saved in portrait mode or "sideways".


1 Answers

I had the same problem when I get the image from Camera, I put the following code to fix it.. Added the method scaleAndRotateImage from here

- (void) imagePickerController:(UIImagePickerController *)thePicker didFinishPickingMediaWithInfo:(NSDictionary *)imageInfo {             // Images from the camera are always in landscape, so rotate                     UIImage *image = [self scaleAndRotateImage: [imageInfo objectForKey:UIImagePickerControllerOriginalImage]];     //then save the image to photo gallery or wherever           }   - (UIImage *)scaleAndRotateImage:(UIImage *) image {     int kMaxResolution = 320;      CGImageRef imgRef = image.CGImage;      CGFloat width = CGImageGetWidth(imgRef);     CGFloat height = CGImageGetHeight(imgRef);       CGAffineTransform transform = CGAffineTransformIdentity;     CGRect bounds = CGRectMake(0, 0, width, height);     if (width > kMaxResolution || height > kMaxResolution) {         CGFloat ratio = width/height;         if (ratio > 1) {             bounds.size.width = kMaxResolution;             bounds.size.height = bounds.size.width / ratio;         }         else {             bounds.size.height = kMaxResolution;             bounds.size.width = bounds.size.height * ratio;         }     }      CGFloat scaleRatio = bounds.size.width / width;     CGSize imageSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef));     CGFloat boundHeight;     UIImageOrientation orient = image.imageOrientation;     switch(orient) {          case UIImageOrientationUp: //EXIF = 1             transform = CGAffineTransformIdentity;             break;          case UIImageOrientationUpMirrored: //EXIF = 2             transform = CGAffineTransformMakeTranslation(imageSize.width, 0.0);             transform = CGAffineTransformScale(transform, -1.0, 1.0);             break;          case UIImageOrientationDown: //EXIF = 3             transform = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height);             transform = CGAffineTransformRotate(transform, M_PI);             break;          case UIImageOrientationDownMirrored: //EXIF = 4             transform = CGAffineTransformMakeTranslation(0.0, imageSize.height);             transform = CGAffineTransformScale(transform, 1.0, -1.0);             break;          case UIImageOrientationLeftMirrored: //EXIF = 5             boundHeight = bounds.size.height;             bounds.size.height = bounds.size.width;             bounds.size.width = boundHeight;             transform = CGAffineTransformMakeTranslation(imageSize.height, imageSize.width);             transform = CGAffineTransformScale(transform, -1.0, 1.0);             transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);             break;          case UIImageOrientationLeft: //EXIF = 6             boundHeight = bounds.size.height;             bounds.size.height = bounds.size.width;             bounds.size.width = boundHeight;             transform = CGAffineTransformMakeTranslation(0.0, imageSize.width);             transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);             break;          case UIImageOrientationRightMirrored: //EXIF = 7             boundHeight = bounds.size.height;             bounds.size.height = bounds.size.width;             bounds.size.width = boundHeight;             transform = CGAffineTransformMakeScale(-1.0, 1.0);             transform = CGAffineTransformRotate(transform, M_PI / 2.0);             break;          case UIImageOrientationRight: //EXIF = 8             boundHeight = bounds.size.height;             bounds.size.height = bounds.size.width;             bounds.size.width = boundHeight;             transform = CGAffineTransformMakeTranslation(imageSize.height, 0.0);             transform = CGAffineTransformRotate(transform, M_PI / 2.0);             break;          default:             [NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"];      }      UIGraphicsBeginImageContext(bounds.size);      CGContextRef context = UIGraphicsGetCurrentContext();      if (orient == UIImageOrientationRight || orient == UIImageOrientationLeft) {         CGContextScaleCTM(context, -scaleRatio, scaleRatio);         CGContextTranslateCTM(context, -height, 0);     }     else {         CGContextScaleCTM(context, scaleRatio, -scaleRatio);         CGContextTranslateCTM(context, 0, -height);     }      CGContextConcatCTM(context, transform);      CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, width, height), imgRef);     UIImage *imageCopy = UIGraphicsGetImageFromCurrentImageContext();     UIGraphicsEndImageContext();      return imageCopy; } 
like image 149
Dilip Rajkumar Avatar answered Sep 21 '22 04:09

Dilip Rajkumar