Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Extension to fix orientation of an UIImage (Sets orientation to portrait)
extension UIImage {
func fixedOrientation() -> UIImage {
if imageOrientation == UIImageOrientation.Up {
return self
}
var transform: CGAffineTransform = CGAffineTransformIdentity
switch imageOrientation {
case UIImageOrientation.Down, UIImageOrientation.DownMirrored:
transform = CGAffineTransformTranslate(transform, size.width, size.height)
transform = CGAffineTransformRotate(transform, CGFloat(M_PI))
break
case UIImageOrientation.Left, UIImageOrientation.LeftMirrored:
transform = CGAffineTransformTranslate(transform, size.width, 0)
transform = CGAffineTransformRotate(transform, CGFloat(M_PI_2))
break
case UIImageOrientation.Right, UIImageOrientation.RightMirrored:
transform = CGAffineTransformTranslate(transform, 0, size.height)
transform = CGAffineTransformRotate(transform, CGFloat(-M_PI_2))
break
case UIImageOrientation.Up, UIImageOrientation.UpMirrored:
break
}
switch imageOrientation {
case UIImageOrientation.UpMirrored, UIImageOrientation.DownMirrored:
CGAffineTransformTranslate(transform, size.width, 0)
CGAffineTransformScale(transform, -1, 1)
break
case UIImageOrientation.LeftMirrored, UIImageOrientation.RightMirrored:
CGAffineTransformTranslate(transform, size.height, 0)
CGAffineTransformScale(transform, -1, 1)
case UIImageOrientation.Up, UIImageOrientation.Down, UIImageOrientation.Left, UIImageOrientation.Right:
break
}
let ctx: CGContextRef = CGBitmapContextCreate(nil, Int(size.width), Int(size.height), CGImageGetBitsPerComponent(CGImage), 0, CGImageGetColorSpace(CGImage), CGImageAlphaInfo.PremultipliedLast.rawValue)!
CGContextConcatCTM(ctx, transform)
switch imageOrientation {
case UIImageOrientation.Left, UIImageOrientation.LeftMirrored, UIImageOrientation.Right, UIImageOrientation.RightMirrored:
CGContextDrawImage(ctx, CGRectMake(0, 0, size.height, size.width), CGImage)
break
default:
CGContextDrawImage(ctx, CGRectMake(0, 0, size.width, size.height), CGImage)
break
}
let cgImage: CGImageRef = CGBitmapContextCreateImage(ctx)!
return UIImage(CGImage: cgImage)
}
}
@gavin-tang

This comment has been minimized.

Copy link

@gavin-tang gavin-tang commented Oct 16, 2016

Swift 3

func fixedOrientation() -> UIImage {

    if imageOrientation == UIImageOrientation.up {
        return self
    }

    var transform: CGAffineTransform = CGAffineTransform.identity

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

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

    ctx.concatenate(transform)

    switch imageOrientation {
    case UIImageOrientation.left, UIImageOrientation.leftMirrored, UIImageOrientation.right, UIImageOrientation.rightMirrored:
        ctx.draw(self.cgImage!, in: CGRect(origin: CGPoint.zero, size: size))
    default:
        ctx.draw(self.cgImage!, in: CGRect(origin: CGPoint.zero, size: size))
        break
    }

    let cgImage: CGImage = ctx.makeImage()!

    return UIImage(cgImage: cgImage)
}
@hendrawd

This comment has been minimized.

Copy link

@hendrawd hendrawd commented Jan 17, 2017

@darktm func fixedOrientation() -> UIImage { is not wrapped to the code view, maybe you can edit it again

@matthiasnagel

This comment has been minimized.

Copy link

@matthiasnagel matthiasnagel commented Jan 19, 2017

@darktm you did a mistake in setting the size. Occurs if you have a non square image. The correct Swift 3 code looks like: https://gist.github.com/matthiasnagel/fe7ed96dc66310c67b45fb759cf6de8c

@kunj369

This comment has been minimized.

Copy link

@kunj369 kunj369 commented Jun 2, 2017

Great!

@Nightsd01

This comment has been minimized.

Copy link

@Nightsd01 Nightsd01 commented Jun 15, 2017

I have discovered a bug that occurs occasionally with your Swift 3 version @darktim.

In your code at the bottom of the function where it draws the CGContext into the specific CGRect, your CGRext sizing isn't correct so in some orientations it will leave a blank space at the bottom of the fixed image.

Here is an adjusted function, also clipped some unnecessary stuff for brevity and stopped using the deprecated M_PI stuff:

func fixedOrientation() -> UIImage
    {
        if imageOrientation == .up {
            return self
        }
        
        var transform: CGAffineTransform = CGAffineTransform.identity
        
        switch imageOrientation {
        case .down, .downMirrored:
            transform = transform.translatedBy(x: size.width, y: size.height)
            transform = transform.rotated(by: CGFloat.pi)
            break
        case .left, .leftMirrored:
            transform = transform.translatedBy(x: size.width, y: 0)
            transform = transform.rotated(by: CGFloat.pi / 2.0)
            break
        case .right, .rightMirrored:
            transform = transform.translatedBy(x: 0, y: size.height)
            transform = transform.rotated(by: CGFloat.pi / -2.0)
            break
        case .up, .upMirrored:
            break
        }
        switch imageOrientation {
        case .upMirrored, .downMirrored:
            transform.translatedBy(x: size.width, y: 0)
            transform.scaledBy(x: -1, y: 1)
            break
        case .leftMirrored, .rightMirrored:
            transform.translatedBy(x: size.height, y: 0)
            transform.scaledBy(x: -1, y: 1)
        case .up, .down, .left, .right:
            break
        }
        
        let ctx: CGContext = CGContext(data: nil, width: Int(size.width), height: Int(size.height), bitsPerComponent: self.cgImage!.bitsPerComponent, bytesPerRow: 0, space: self.cgImage!.colorSpace!, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)!
        
        ctx.concatenate(transform)
        
        switch imageOrientation {
        case .left, .leftMirrored, .right, .rightMirrored:
            ctx.draw(self.cgImage!, in: CGRect(x: 0, y: 0, width: size.height, height: size.width))
        default:
            ctx.draw(self.cgImage!, in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
            break
        }
        
        return UIImage(cgImage: ctx.makeImage()!)
    }
@vinamelody

This comment has been minimized.

Copy link

@vinamelody vinamelody commented Aug 21, 2017

@Nightsd01 the part where you switch imageOrientation is not working. It should be

      switch imageOrientation {
        case .upMirrored, .downMirrored:
            transform = transform.translatedBy(x: size.width, y: 0)
            transform = transform.scaledBy(x: -1, y: 1)
        case .leftMirrored, .rightMirrored:
            transform = transform.translatedBy(x: size.height, y: 0)
            transform = transform.scaledBy(x: -1, y: 1)
        default:
            break
        }
@marcelmendesfilho

This comment has been minimized.

Copy link

@marcelmendesfilho marcelmendesfilho commented Feb 24, 2018

This extension saved may day! Thank you.

@JangSungChul

This comment has been minimized.

Copy link

@JangSungChul JangSungChul commented Mar 27, 2018

It's a great help! Thanks a lot!


I used under code.

Swift3

extension UIImage {
    
    func fixedOrientation() -> UIImage {
        
        if imageOrientation == UIImageOrientation.up {
            return self
        }
        
        var transform: CGAffineTransform = CGAffineTransform.identity
        
        switch imageOrientation {
        case .down, .downMirrored:
            transform = transform.translatedBy(x: size.width, y: size.height)
            transform = transform.rotated(by: CGFloat.pi)
            break
        case .left, .leftMirrored:
            transform = transform.translatedBy(x: size.width, y: 0)
            transform = transform.rotated(by: CGFloat.pi / 2.0)
            break
        case .right, .rightMirrored:
            transform = transform.translatedBy(x: 0, y: size.height)
            transform = transform.rotated(by: CGFloat.pi / -2.0)
            break
        case .up, .upMirrored:
            break
        }
        switch imageOrientation {
        case .upMirrored, .downMirrored:
            transform.translatedBy(x: size.width, y: 0)
            transform.scaledBy(x: -1, y: 1)
            break
        case .leftMirrored, .rightMirrored:
            transform.translatedBy(x: size.height, y: 0)
            transform.scaledBy(x: -1, y: 1)
        case .up, .down, .left, .right:
            break
        }
        
        let ctx: CGContext = CGContext(data: nil, width: Int(size.width), height: Int(size.height), bitsPerComponent: self.cgImage!.bitsPerComponent, bytesPerRow: 0, space: self.cgImage!.colorSpace!, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)!
        
        ctx.concatenate(transform)
        
        switch imageOrientation {
        case .left, .leftMirrored, .right, .rightMirrored:
            ctx.draw(self.cgImage!, in: CGRect(x: 0, y: 0, width: size.height, height: size.width))
        default:
            ctx.draw(self.cgImage!, in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
            break
        }
        
        return UIImage(cgImage: ctx.makeImage()!)
    }
@haikieu

This comment has been minimized.

Copy link

@haikieu haikieu commented Mar 27, 2018

Swift 4 tested ( + handled some cases)

extension UIImage {

    func fixedOrientation() -> UIImage? {
        
        guard imageOrientation != UIImageOrientation.up else {
            //This is default orientation, don't need to do anything
            return self.copy() as? UIImage
        }
        
        guard let cgImage = self.cgImage else {
            //CGImage is not available
            return nil
        }

        guard let colorSpace = cgImage.colorSpace, let ctx = CGContext(data: nil, width: Int(size.width), height: Int(size.height), bitsPerComponent: cgImage.bitsPerComponent, bytesPerRow: 0, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) else {
            return nil //Not able to create CGContext
        }
        
        var transform: CGAffineTransform = CGAffineTransform.identity
        
        switch imageOrientation {
        case .down, .downMirrored:
            transform = transform.translatedBy(x: size.width, y: size.height)
            transform = transform.rotated(by: CGFloat.pi)
            break
        case .left, .leftMirrored:
            transform = transform.translatedBy(x: size.width, y: 0)
            transform = transform.rotated(by: CGFloat.pi / 2.0)
            break
        case .right, .rightMirrored:
            transform = transform.translatedBy(x: 0, y: size.height)
            transform = transform.rotated(by: CGFloat.pi / -2.0)
            break
        case .up, .upMirrored:
            break
        }
        
        //Flip image one more time if needed to, this is to prevent flipped image
        switch imageOrientation {
        case .upMirrored, .downMirrored:
            transform.translatedBy(x: size.width, y: 0)
            transform.scaledBy(x: -1, y: 1)
            break
        case .leftMirrored, .rightMirrored:
            transform.translatedBy(x: size.height, y: 0)
            transform.scaledBy(x: -1, y: 1)
        case .up, .down, .left, .right:
            break
        }
        
        ctx.concatenate(transform)
        
        switch imageOrientation {
        case .left, .leftMirrored, .right, .rightMirrored:
            ctx.draw(self.cgImage!, in: CGRect(x: 0, y: 0, width: size.height, height: size.width))
        default:
            ctx.draw(self.cgImage!, in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
            break
        }
        
        guard let newCGImage = ctx.makeImage() else { return nil }
        return UIImage.init(cgImage: newCGImage, scale: 1, orientation: .up)
    }
}
@gokeji

This comment has been minimized.

Copy link

@gokeji gokeji commented Mar 30, 2018

Thanks @haikieu it works perfectly on Swift 4

@chmziaurrehman

This comment has been minimized.

Copy link

@chmziaurrehman chmziaurrehman commented Apr 16, 2018

Good job.

@akaashdev-sc

This comment has been minimized.

Copy link

@akaashdev-sc akaashdev-sc commented Apr 16, 2018

Objective C version

-(UIImage *) fixedOrientation:(UIImage *) image {
    
    if (image.imageOrientation == UIImageOrientationUp) {
        return image;
    }
    
    CGAffineTransform transform = CGAffineTransformIdentity;
    
    switch (image.imageOrientation) {
        case UIImageOrientationDown:
        case UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate(transform, image.size.width, image.size.height);
            transform = CGAffineTransformRotate(transform, M_PI);
            break;
            
        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
            transform = CGAffineTransformTranslate(transform, image.size.width, 0);
            transform = CGAffineTransformRotate(transform, M_PI_2);
            break;
            
        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate(transform, 0, image.size.height);
            transform = CGAffineTransformRotate(transform, -M_PI_2);
            break;
            
        default: break;
    }
    
    switch (image.imageOrientation) {
        case UIImageOrientationUpMirrored:
        case UIImageOrientationDownMirrored:
            CGAffineTransformTranslate(transform, image.size.width, 0);
            CGAffineTransformScale(transform, -1, 1);
            break;
            
        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRightMirrored:
            CGAffineTransformTranslate(transform, image.size.height, 0);
            CGAffineTransformScale(transform, -1, 1);
            break;
            
        default: break;
    }
    
    CGContextRef ctx = CGBitmapContextCreate(nil, image.size.width, image.size.height, CGImageGetBitsPerComponent(image.CGImage), 0, CGImageGetColorSpace(image.CGImage), kCGImageAlphaPremultipliedLast);
    
    CGContextConcatCTM(ctx, transform);
    
    switch (image.imageOrientation) {
        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            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;
    }

    CGImageRef cgImage = CGBitmapContextCreateImage(ctx);
    
    return [UIImage imageWithCGImage:cgImage];
}
@schneipp

This comment has been minimized.

Copy link

@schneipp schneipp commented Apr 18, 2018

thanks, the swift4 version works perfect :) 👍

@liamnichols

This comment has been minimized.

Copy link

@liamnichols liamnichols commented Apr 30, 2018

You can simplify this work instead by using UIImage.draw(in:) instead of CGContext.draw(...). For example:

UIGraphicsBeginImageContextWithOptions(size, false, scale)
draw(in: CGRect(origin: .zero, size: size))
let processedImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return processedImage
@juliand665

This comment has been minimized.

Copy link

@juliand665 juliand665 commented May 2, 2018

@liamnichols that's what i was looking for! Clever, concise, and eliminates the need to handle any special cases.

@estebanefi

This comment has been minimized.

Copy link

@estebanefi estebanefi commented May 25, 2018

The Swift 4 example didn't really work for me, I'm not sure why though. All I would notice is that the image was reduced in quality. I was breaking my head trying to understand why, but had no luck. Eventually I tried just returning an image from its own cgimage, and that actually fixed the orientation for me and kept the quality. Working from the work @haikieu did, I reduced to this. Does anyone understand why this would rotate?

extension UIImage {
    func fixedOrientation() -> UIImage? {
        guard imageOrientation != UIImageOrientation.up else {
            //This is default orientation, don't need to do anything
            return self.copy() as? UIImage
        }
        guard let cgImage = self.cgImage else {
            //CGImage is not available
            return nil
        }
        
        return UIImage(cgImage: cgImage)
    }
}
@chika-kasymov

This comment has been minimized.

Copy link

@chika-kasymov chika-kasymov commented May 28, 2018

@estebanefi you should use a different scale in the end:

return UIImage.init(cgImage: newCGImage, scale: scale, orientation: .up) // here use original images scale instead of 1
@iosdev-republicofapps

This comment has been minimized.

Copy link

@iosdev-republicofapps iosdev-republicofapps commented Jun 23, 2018

Hey @akaashdev-sc thanks for the Objective-C version. I think you have a couple of small bugs in your version - you're forgetting to assign to the transform in the second switch since the ObjC version doesn't mutate the original.

Here's the corrected version for anybody that comes along later (and still gloriously uses Objective-C like me :p):

-(UIImage *) fixedOrientation:(UIImage *) image {
    
    if (image.imageOrientation == UIImageOrientationUp) {
        return image;
    }
    
    CGAffineTransform transform = CGAffineTransformIdentity;
    
    switch (image.imageOrientation) {
        case UIImageOrientationDown:
        case UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate(transform, image.size.width, image.size.height);
            transform = CGAffineTransformRotate(transform, M_PI);
            break;
            
        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
            transform = CGAffineTransformTranslate(transform, image.size.width, 0);
            transform = CGAffineTransformRotate(transform, M_PI_2);
            break;
            
        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate(transform, 0, image.size.height);
            transform = CGAffineTransformRotate(transform, -M_PI_2);
            break;
            
        default: break;
    }
    
    switch (image.imageOrientation) {
        case UIImageOrientationUpMirrored:
        case UIImageOrientationDownMirrored:
            // CORRECTION: Need to assign to transform here
            transform = CGAffineTransformTranslate(transform, image.size.width, 0);
            transform = CGAffineTransformScale(transform, -1, 1);
            break;
            
        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRightMirrored:
            // CORRECTION: Need to assign to transform here
            transform = CGAffineTransformTranslate(transform, image.size.height, 0);
            transform = CGAffineTransformScale(transform, -1, 1);
            break;
            
        default: break;
    }
    
    CGContextRef ctx = CGBitmapContextCreate(nil, image.size.width, image.size.height, CGImageGetBitsPerComponent(image.CGImage), 0, CGImageGetColorSpace(image.CGImage), kCGImageAlphaPremultipliedLast);
    
    CGContextConcatCTM(ctx, transform);
    
    switch (image.imageOrientation) {
        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            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;
    }

    CGImageRef cgImage = CGBitmapContextCreateImage(ctx);
    
    return [UIImage imageWithCGImage:cgImage];
}
@totoro0103

This comment has been minimized.

Copy link

@totoro0103 totoro0103 commented Aug 14, 2018

Thank @haikieu . You save my life

@LightMan

This comment has been minimized.

Copy link

@LightMan LightMan commented Dec 11, 2018

For all the people that say @haikieu code or any other variant is not working, it is not flipped horizontally correctly. Take into account @vinamelody comment:
The second part of fixing the horizontal flip, the transform is not applied because the var is not reassigned to itself. The code should be like @vinamelody says:

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

@jeffmcfadden

This comment has been minimized.

Copy link

@jeffmcfadden jeffmcfadden commented Jan 31, 2019

Swift 4.2, with Mirroring case fix:

extension UIImage {
    
    func fixedOrientation() -> UIImage? {
        
        guard imageOrientation != UIImage.Orientation.up else {
            //This is default orientation, don't need to do anything
            return self.copy() as? UIImage
        }
        
        guard let cgImage = self.cgImage else {
            //CGImage is not available
            return nil
        }
        
        guard let colorSpace = cgImage.colorSpace, let ctx = CGContext(data: nil, width: Int(size.width), height: Int(size.height), bitsPerComponent: cgImage.bitsPerComponent, bytesPerRow: 0, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) else {
            return nil //Not able to create CGContext
        }
        
        var transform: CGAffineTransform = CGAffineTransform.identity
        
        switch imageOrientation {
        case .down, .downMirrored:
            transform = transform.translatedBy(x: size.width, y: size.height)
            transform = transform.rotated(by: CGFloat.pi)
            break
        case .left, .leftMirrored:
            transform = transform.translatedBy(x: size.width, y: 0)
            transform = transform.rotated(by: CGFloat.pi / 2.0)
            break
        case .right, .rightMirrored:
            transform = transform.translatedBy(x: 0, y: size.height)
            transform = transform.rotated(by: CGFloat.pi / -2.0)
            break
        case .up, .upMirrored:
            break
        }
        
        //Flip image one more time if needed to, this is to prevent flipped image
        switch imageOrientation {
        case .upMirrored, .downMirrored:
            transform = transform.translatedBy(x: size.width, y: 0)
            transform = transform.scaledBy(x: -1, y: 1)
            break
        case .leftMirrored, .rightMirrored:
            transform = transform.translatedBy(x: size.height, y: 0)
            transform = transform.scaledBy(x: -1, y: 1)
        case .up, .down, .left, .right:
            break
        }
        
        ctx.concatenate(transform)
        
        switch imageOrientation {
        case .left, .leftMirrored, .right, .rightMirrored:
            ctx.draw(self.cgImage!, in: CGRect(x: 0, y: 0, width: size.height, height: size.width))
        default:
            ctx.draw(self.cgImage!, in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
            break
        }
        
        guard let newCGImage = ctx.makeImage() else { return nil }
        return UIImage.init(cgImage: newCGImage, scale: 1, orientation: .up)
    }
}
@kirkbyo

This comment has been minimized.

Copy link

@kirkbyo kirkbyo commented Feb 3, 2019

@jeffmcfadden Thank you!

@fractaldragonflies

This comment has been minimized.

Copy link

@fractaldragonflies fractaldragonflies commented Apr 7, 2019

I really liked @jeffmcfadden code but I'm working in macOS. I converted the code to a CGImage extension, but I still had problems with rectangular (non-square) images. After several interesting changes and some personal learnings along the way I got something that works for my case. Here is my take on the problem as playground code with CGImage extension.

Observations:

  • Created graphics context with newSize of the oriented image.
  • .left, .leftMirrored uses x:size.height
  • .right, .rightMirrored uses y: size.width
  • .mirrored cases use x=size.width (since scale is always x: -1, y:1)
  • ctx.draw uses original width: size.width, height: size:height.

This last of draw using the original size surprised me. So it seems draw uses the size it wants to draw into as though from the original image. It works in my tests in playground using rectangular images.

`// Test with square, wider then tall, taller than wide images.
enum CGImageOrientation {
case up
case down
case left
case right
case upMirrored
case downMirrored
case leftMirrored
case rightMirrored
}

extension CGImage {
func orientImage(_ imageOrientation: CGImageOrientation) -> CGImage? {
return orientImageWithTransform(imageOrientation).0
}

// Method to get image and transform in tuple.
func orientImageWithTransform(_ imageOrientation: CGImageOrientation) -> (CGImage?, CGAffineTransform) {
    
    var transform = CGAffineTransform.identity
    if imageOrientation == .up { return (self.copy(), transform)}
    
    let size = NSSize(width: width, height: height)
    let newSize = [.left,.leftMirrored, .right, .rightMirrored].contains(imageOrientation)
        ? NSSize(width: size.height, height: size.width) : size
    
    // Guard that we have color space and core graphics context.
    guard let colorSpace = self.colorSpace,
        // New graphic context uses transformed width and height.
        let ctx = CGContext(data: nil, width: Int(newSize.width), height: Int(newSize.height),
                            bitsPerComponent: self.bitsPerComponent, bytesPerRow: 0,
                            space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)
        else { return (nil, transform)}

    // OK, now the actual work of constructing transform and creating new image.
    switch imageOrientation {
    case .down, .downMirrored:
        transform = transform.translatedBy(x: size.width, y: size.height)
        transform = transform.rotated(by: CGFloat.pi)
        break
    case .left,.leftMirrored:
        transform = transform.translatedBy(x: size.height, y: 0)
        transform = transform.rotated(by: CGFloat.pi/2)
        break
    case .right, .rightMirrored:
         transform = transform.translatedBy(x: 0, y: size.width)
         transform = transform.rotated(by: -CGFloat.pi/2)
         break
    case .up, .upMirrored:
        break
    }
    
    if [.upMirrored, .downMirrored,.leftMirrored, .rightMirrored].contains(imageOrientation) {
        transform = transform.translatedBy(x: size.width, y: 0)
        transform = transform.scaledBy(x: -1, y: 1)
    }
    
    ctx.concatenate(transform)
    // Interestingly, drawing with the original width and height?!
    // So width and height here are pre-transform.
    ctx.draw(self, in: NSRect(x: 0, y: 0, width: size.width, height: size.height))

    return (ctx.makeImage(), transform)
}

}

guard var image = NSImage(contentsOf: imageurl) else { exit(1) }
guard let cgImage = image.cgImage(forProposedRect: nil, context: nil, hints: nil) else { exit(2)}

if let orientedImage = cgImage.orientImage(.upMirrored) {
image = NSImage(cgImage: orientedImage, size: NSZeroSize)
}

`

@Sam-Spencer

This comment has been minimized.

Copy link

@Sam-Spencer Sam-Spencer commented Apr 20, 2019

Swift 5.0

Includes previous fixes for mirroring issues.

extension UIImage {
    
    /// Fix image orientaton to protrait up
    func fixedOrientation() -> UIImage? {
        guard imageOrientation != UIImage.Orientation.up else {
            // This is default orientation, don't need to do anything
            return self.copy() as? UIImage
        }
        
        guard let cgImage = self.cgImage else {
            // CGImage is not available
            return nil
        }
        
        guard let colorSpace = cgImage.colorSpace, let ctx = CGContext(data: nil, width: Int(size.width), height: Int(size.height), bitsPerComponent: cgImage.bitsPerComponent, bytesPerRow: 0, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) else {
            return nil // Not able to create CGContext
        }
        
        var transform: CGAffineTransform = CGAffineTransform.identity
        
        switch imageOrientation {
        case .down, .downMirrored:
            transform = transform.translatedBy(x: size.width, y: size.height)
            transform = transform.rotated(by: CGFloat.pi)
        case .left, .leftMirrored:
            transform = transform.translatedBy(x: size.width, y: 0)
            transform = transform.rotated(by: CGFloat.pi / 2.0)
        case .right, .rightMirrored:
            transform = transform.translatedBy(x: 0, y: size.height)
            transform = transform.rotated(by: CGFloat.pi / -2.0)
        case .up, .upMirrored:
            break
        @unknown default:
            break
        }
        
        // Flip image one more time if needed to, this is to prevent flipped image
        switch imageOrientation {
        case .upMirrored, .downMirrored:
            transform = transform.translatedBy(x: size.width, y: 0)
            transform = transform.scaledBy(x: -1, y: 1)
        case .leftMirrored, .rightMirrored:
            transform = transform.translatedBy(x: size.height, y: 0)
            transform = transform.scaledBy(x: -1, y: 1)
        case .up, .down, .left, .right:
            break
        @unknown default:
            break
        }
        
        ctx.concatenate(transform)
        
        switch imageOrientation {
        case .left, .leftMirrored, .right, .rightMirrored:
            ctx.draw(cgImage, in: CGRect(x: 0, y: 0, width: size.height, height: size.width))
        default:
            ctx.draw(cgImage, in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
            break
        }
        
        guard let newCGImage = ctx.makeImage() else { return nil }
        return UIImage.init(cgImage: newCGImage, scale: 1, orientation: .up)
    }
}
@w-i-n-s

This comment has been minimized.

Copy link

@w-i-n-s w-i-n-s commented Apr 28, 2019

@Sam-Spencer Thanks a lot for extension. Could you please fix unneeded_break_in_switch and force_unwrapping. Thanks

@Sam-Spencer

This comment has been minimized.

Copy link

@Sam-Spencer Sam-Spencer commented Apr 29, 2019

@w-i-n-s Should be all good to go now!

@w-i-n-s

This comment has been minimized.

Copy link

@w-i-n-s w-i-n-s commented Apr 30, 2019

@TaoufikBouabid

This comment has been minimized.

Copy link

@TaoufikBouabid TaoufikBouabid commented Jun 24, 2019

To Flip UIImage, the simplest way is :

let flippedImage = originalImage.withHorizontallyFlippedOrientation()

tested and worked fine!

@chrisvoronin

This comment has been minimized.

Copy link

@chrisvoronin chrisvoronin commented Aug 21, 2019

works well, but uses a lot of memory creating a spike.

@jlorfeo

This comment has been minimized.

Copy link

@jlorfeo jlorfeo commented Jan 28, 2020

Awesome! Thanks alot! This helps quite a bit :)

@peterdk

This comment has been minimized.

Copy link

@peterdk peterdk commented Feb 13, 2020

Seems to create massive memoryleak. I run it in a loop based on a CMSampleBuffer, and when I add the .fixedOrientation() mem usage keeps growing with 8MB per call. When removing that call, mem usage stays stable.
Update
Turns out my mem leak was caused by running this code on a background thread. It turns out the CGContext doesnt release it's buffer memory when not on Main thread. It can be fixed easily by adding return autoreleasepool { at the start and }at the end. Now the buffer gets released also when in a background thread.

@dhoerl

This comment has been minimized.

Copy link

@dhoerl dhoerl commented Apr 18, 2020

I had a similar issue, but wanted to load an image from the file system (Data) and not have to go through an intermediate UIImage, as doing this translation to .up often causes a memory spike. I based this on Sam Spencer's code, and it works fine in Xcode 11.4 / Swift 5.2:

func image(data: Data, orientation: UIImage.Orientation = .up) -> UIImage? {
    let context: CGContext
    let width: CGFloat
    let height: CGFloat

    func defaultImage() -> UIImage? {
        return UIImage(data: data)
    }

    do {
        guard
            let imageSource = CGImageSourceCreateWithData(data as CFData, nil),
            let properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as NSDictionary?,
            let orientation = CGImagePropertyOrientation(rawValue: properties[kCGImagePropertyOrientation] as? UInt32 ?? 1),
            let image = CGImageSourceCreateImageAtIndex(imageSource, 0, nil)
        else { return defaultImage() }

        guard orientation != .up else { return UIImage(cgImage: image) }
        let imageOrientation = UIImage.Orientation(orientation)

        let bytesPerRow: Int
        switch imageOrientation {
        case .left, .leftMirrored, .right, .rightMirrored:
            width = CGFloat(image.height)
            height = CGFloat(image.width)
            bytesPerRow = ((Int(width)+15)/16) * 16 * (image.bitsPerPixel/8)
        default:
            width = CGFloat(image.width)
            height = CGFloat(image.height)
            bytesPerRow = image.bytesPerRow
        }

        guard let _context = CGContext(data: nil,
                                       width: Int(width),
                                       height: Int(height),
                                       bitsPerComponent: image.bitsPerComponent,
                                       bytesPerRow: bytesPerRow,
                                       space: image.colorSpace ?? CGColorSpace(name: CGColorSpace.sRGB)!,
                                       bitmapInfo: image.bitmapInfo.rawValue)
        else { return defaultImage() }
        context = _context

        let drawRect: CGRect
        var transform: CGAffineTransform = CGAffineTransform.identity

        switch imageOrientation {
        case .down, .downMirrored:
            transform = transform.translatedBy(x: width, y: height)
            transform = transform.rotated(by: CGFloat.pi)
        case .left, .leftMirrored:
            transform = transform.translatedBy(x: width, y: 0)
            transform = transform.rotated(by: CGFloat.pi / 2.0)
        case .right, .rightMirrored:
            transform = transform.translatedBy(x: 0, y: height)
            transform = transform.rotated(by: CGFloat.pi / -2.0)
        case .up, .upMirrored:
            break
        @unknown default:
            break
        }

        // Flip image one more time if needed to, this is to prevent flipped image
        switch imageOrientation {
        case .upMirrored, .downMirrored:
            transform = transform.translatedBy(x: width, y: 0)
            transform = transform.scaledBy(x: -1, y: 1)
        case .leftMirrored, .rightMirrored:
            transform = transform.translatedBy(x: height, y: 0)
            transform = transform.scaledBy(x: -1, y: 1)
        case .up, .down, .left, .right:
            break
        @unknown default:
            break
        }

        context.concatenate(transform)

        switch imageOrientation {
        case .left, .leftMirrored, .right, .rightMirrored:
            drawRect = CGRect(x: 0, y: 0, width: height, height: width)
        default:
            drawRect = CGRect(x: 0, y: 0, width: width, height: height)
        }

        context.draw(image, in: drawRect)
        // image released
    }

    guard let newImage = context.makeImage() else { return defaultImage() }

    let uiImage = UIImage(cgImage: newImage, scale: 1, orientation: .up)
    return uiImage
}

@rubencodes

This comment has been minimized.

Copy link

@rubencodes rubencodes commented Apr 26, 2020

Gosh, this works amazingly, but seems to cause a memory crash for me half the time. Just calling it once. Even after adding return autoreleasepool {} around it as suggested by @peterdk.

@dhoerl

This comment has been minimized.

Copy link

@dhoerl dhoerl commented Apr 26, 2020

@rubencodes
I also saw memory spikes. I first tried just keeping around a large enough memory blog to use with CGContext so it wouldn't have to keep creating one. That helped the smiles but the floor of memory usage rose (of course). Then I tripped on this CIImage filter (new in iOS11):

//image is a UIImage
let newImage = origImage.oriented(CGImagePropertyOrientation(image.imageOrientation))
guard let cgImage = context.createCGImage(newImage, from: newImage.extent) else { fatalError() }
let showImage = UIImage(cgImage: cgImage)

It creates much smaller memory spikes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.