2

I have a user pick a picture to crop from their Camera Roll. I display all of these pictures as thumbnails for the user to press.

I use UIImage(CGImage: asset.fullScreenImage!.CGImage!, scale: scale, orientation: UIImageOrientation.Up) to ensure that my image remains the same way it faces in the thumbnail. With asset.fullResolutionImage! this doesn't work.

Now comes the weird part. When I take a picture with the iPhone camera, then head to my cropping ViewController, the image is rotated 90 degrees! I have no idea why.

If I leave my app, take a picture with the camera normally, save it to my camera roll, and then choose it from the list of thumbnails like I do other pictures, it works perfectly fine.

What is the cause of this? How does one fix it?

Edit: There are two solutions posted below. One in Objective-C, and the other being a translated copy of that into Swift.

David
  • 7,028
  • 10
  • 48
  • 95

3 Answers3

1

You can try to use this category:

UIImage+FixOrientation.h

UIImage+FixOrientation.m

It is built in Objective-C, then you can use bridging header to use ObjC in combination with Swift, or you can just have a look to understand how to fix that.

Usage example:

UIImage *image = <image from camera image>
image = [image fixOrientation];
gontovnik
  • 690
  • 5
  • 9
  • Well, that fixed it, but why does this happen? Is it an iOS 8 bug? Will this solution work for iOS 4-7, etc.? Also, maybe it is just my eyes, but it looks as though the image I get at the end, while having the correct orientation, has a very slight lower quality. – David Aug 29 '15 at 08:28
  • 1
    No, it is not really an issue. When you take a picture it takes device orientation (that's how I think, not 100% sure that it is correct), so it was solution to fix that which I use since iOS 6. Hm, quality should not be lower, as they do not scale, only rotate. – gontovnik Aug 29 '15 at 08:30
  • Yeah, I've taken some more pics and am pretty certain my eyes are deceiving me :P. Alright. Thanks a ton! So this has been happening since iOS 6? – David Aug 29 '15 at 08:32
  • Maybe was happening even before iOS 6. As I see in stackoverflow, people are facing that since 2011. I think it is very rare issue. It is not even an issue, it is just how camera works. :) – gontovnik Aug 29 '15 at 08:33
  • Btw, I posted another answer which is basically your code but in Swift. Feel free to take a look. – David Aug 29 '15 at 08:41
0

This answer is to complement gontovnik's answer.

I have taken his Objective-C solution and written it in Swift. Put this function wherever needed. Just pass in the UIImage in question.

That said, you could probably just make this a UIImage class function. Would actually be nice to just call UIImage.fixOrientation(image: imageInQuestion).

func fixOrientation(image: UIImage) -> UIImage {
    // No-op if the orientation is already correct
    if (image.imageOrientation == UIImageOrientation.Up) { return image; }

    println(image.imageOrientation)

    // 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.
    var transform = CGAffineTransformIdentity

    switch (image.imageOrientation) {
        case .Down, .DownMirrored:
            transform = CGAffineTransformTranslate(transform, image.size.width, image.size.height)
            transform = CGAffineTransformRotate(transform, CGFloat(M_PI))
            break
        case .Left, .LeftMirrored:
            transform = CGAffineTransformTranslate(transform, image.size.width, 0)
            transform = CGAffineTransformRotate(transform, CGFloat(M_PI_2))
            break        
        case .Right, .RightMirrored:
            transform = CGAffineTransformTranslate(transform, 0, image.size.height)
            transform = CGAffineTransformRotate(transform, CGFloat(-M_PI_2))
            break            
        case .Up, .UpMirrored:
                break
    }

    switch (image.imageOrientation) {
        case .UpMirrored, .DownMirrored:
            transform = CGAffineTransformTranslate(transform, image.size.width, 0)
            transform = CGAffineTransformScale(transform, -1, 1)
            break       
        case .LeftMirrored, .RightMirrored:
            transform = CGAffineTransformTranslate(transform, image.size.height, 0)
            transform = CGAffineTransformScale(transform, -1, 1)
            break
        case .Up, .Down, .Left, .Right:
            break
    }

    // Now we draw the underlying CGImage into a new context, applying the transform
    // calculated above.

    var ctx = CGBitmapContextCreate(nil, Int(image.size.width), Int(image.size.height), CGImageGetBitsPerComponent(image.CGImage), 0, CGImageGetColorSpace(image.CGImage), CGImageGetBitmapInfo(image.CGImage))

    CGContextConcatCTM(ctx, transform);

    switch (image.imageOrientation) {
        case .Left, .LeftMirrored, .Right, .RightMirrored:
            // Grr...
            CGContextDrawImage(ctx, CGRectMake(0, 0, image.size.height, image.size.width), image.CGImage)
            break

        default:
            CGContextDrawImage(ctx, CGRectMake(0, 0, image.size.width, image.size.height), image.CGImage)
            break
    }

    // And now we just create a new UIImage from the drawing context
        var cgimg = CGBitmapContextCreateImage(ctx)
        var img = UIImage(CGImage: cgimg)

        return img!
}
David
  • 7,028
  • 10
  • 48
  • 95
0

Swift 3 version

func fixOrientation(image: UIImage) -> UIImage {
    // No-op if the orientation is already correct
    if (image.imageOrientation == UIImageOrientation.up) { return image; }

    print(image.imageOrientation)

    // 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.
    var transform = CGAffineTransform.identity

    switch (image.imageOrientation) {
    case .down, .downMirrored:
      transform = transform.translatedBy(x: image.size.width, y: image.size.height)
      transform = transform.rotated(by: CGFloat(M_PI))
      break
    case .left, .leftMirrored:
      transform = transform.translatedBy(x: image.size.width, y: 0)
      transform = transform.rotated(by: CGFloat(M_PI_2))
      break
    case .right, .rightMirrored:
      transform = transform.translatedBy(x: 0, y: image.size.height)
      transform = transform.rotated(by: CGFloat(-M_PI_2))
      break
    case .up, .upMirrored:
      break
    }

    switch (image.imageOrientation) {
    case .upMirrored, .downMirrored:
      transform = transform.translatedBy(x: image.size.width, y: 0)
      transform = transform.scaledBy(x: -1, y: 1)
      break
    case .leftMirrored, .rightMirrored:
      transform = transform.translatedBy(x: image.size.height, y: 0)
      transform = transform.scaledBy(x: -1, y: 1)
      break
    case .up, .down, .left, .right:
      break
    }

    // Now we draw the underlying CGImage into a new context, applying the transform
    // calculated above.

    let ctx = CGContext(data: nil, width: Int(image.size.width), height: Int(image.size.height), bitsPerComponent: image.cgImage!.bitsPerComponent, bytesPerRow: 0, space: image.cgImage!.colorSpace!, bitmapInfo: image.cgImage!.bitmapInfo.rawValue)

    ctx!.concatenate(transform);

    switch (image.imageOrientation) {
    case .left, .leftMirrored, .right, .rightMirrored:
      // Grr...
      ctx?.draw(image.cgImage!, in: CGRect(origin: .zero, size: CGSize(width: image.size.height, height: image.size.width)))

      break

    default:
      ctx?.draw(image.cgImage!, in: CGRect(origin: .zero, size: CGSize(width: image.size.width, height: image.size.height)))
      break
    }

    // And now we just create a new UIImage from the drawing context
    let cgimg = ctx!.makeImage()
    let img = UIImage(cgImage: cgimg!)

    return img
  }
asmad
  • 387
  • 4
  • 13