49

The solution to do UIImage flipping is with the Objective-C code:

[UIImage imageWithCGImage:img.CGImage scale:1.0 orientation: UIImageOrientationDownMirrored]

However, imageWithCGImage is not available in Swift! Is there a solution for flipping image horizontally with Swift? Thanks!

9 Answers 9

54

For me the simplest way was to use the .withHorizontallyFlippedOrientation() instance method of UIImage as follows:

let flippedImage = straightImage.withHorizontallyFlippedOrientation()

Simple one-liners always make me happy :)

Sign up to request clarification or add additional context in comments.

4 Comments

Brilliant, but does not respect the vertical orientations for images captured from AVFoundation- flips the image upside down
Perhaps there is a way to adjust this after the withHorizontallyFlippedOrientation()?
#available(iOS 10.0, *)
this seems to have a significant performance hit for me on MacOS. Fine if my image is small and/or I'm doing it occasionally, but if it needs to be responsive maybe not.
36

Most factory methods are converted to initializers in swift. Whenever available, even if the class method is still available, they are preferred. You can use:

    init(CGImage cgImage: CGImage!, scale: CGFloat, orientation: UIImageOrientation)

The usage would look like this:

var image = UIImage(CGImage: img.CGImage, scale: 1.0, orientation: .DownMirrored)

Swift 5

var image = UIImage(cgImage: img.cgImage!, scale: 1.0, orientation: .downMirrored)

4 Comments

Tried this and it doesn't seem to flip the image. Is there a way to respect the orientation when rendering? public extension UIImage { var flippedHorizontally: UIImage { return UIImage(CGImage: self.CGImage!, scale: self.scale, orientation: .UpMirrored) } }
Oh... I was using the .LeftMirrored option for selfie photos. It works well to display the photo after the flipping. However, the photo is upside down after saving to photo album. Any ideas?
@Gujamin, that extension worked perfectly. I converted it into Swift 3 syntax and was able to swap the image of a UIButton with no problem. Thanks.
The answer is wrong. When I create UIBarButtonItem with the original image its scale is normal. But when I use your method image becomes huge! Note: I don't apply any transformations to an image other than your one - just assign it to bar button item
34

In Swift.... (6.3.1)

YourUIImage.transform = CGAffineTransformMakeScale(-1, 1)

This also works with a UIView

3 Comments

This is not for flipping a UIImage, but for flipping UIImageView.
It's not flipping UIImage. But it solves my UI issues.
not all UI elements are derived from UIView so they haven't transform property (like UIBarButtonItem)
19

Changing image orientation parameter is not actually flipping the image in all cases. Image must be redrawn somehow... For example like this:

Swift 3

func flipImageLeftRight(_ image: UIImage) -> UIImage? {

    UIGraphicsBeginImageContextWithOptions(image.size, false, image.scale)
    let context = UIGraphicsGetCurrentContext()!
    context.translateBy(x: image.size.width, y: image.size.height)
    context.scaleBy(x: -image.scale, y: -image.scale)

    context.draw(image.cgImage!, in: CGRect(origin:CGPoint.zero, size: image.size))

    let newImage = UIGraphicsGetImageFromCurrentImageContext()

    UIGraphicsEndImageContext()

    return newImage
}

1 Comment

1)why do you scale by x and y simultaneously? 2)when I assign the image result from your function it disappears in UIBarButtonItem
15

Swift 5 Solution

Here is the simplest solution for actually flipping the image

extension UIImage {
    func flipHorizontally() -> UIImage? {
        UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale)
        let context = UIGraphicsGetCurrentContext()!
        
        context.translateBy(x: self.size.width/2, y: self.size.height/2)
        context.scaleBy(x: -1.0, y: 1.0)
        context.translateBy(x: -self.size.width/2, y: -self.size.height/2)
        
        self.draw(in: CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height))
        
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        return newImage
    }
}

and to use this solution you can do the following

let image = UIImage(named: "image.png")!
let newImage = image.flipHorizontally()

3 Comments

This create black background image instead of transparent . Please take note
@RajuyourPepe I have updated the answer to allow for transparency. Thank you!
Great Answer! For anyone wondering, if you want to flip the image vertically just change context.scaleBy(x: -1.0, y: 1.0) to context.scaleBy(x: 1.0, y: -1.0).
10

Swift 4

YOURIMAGEVIEW.transform = CGAffineTransform(scaleX: -1, y: 1)

This might also be handy:

YOURIMAGE.imageFlippedForRightToLeftLayoutDirection()

2 Comments

The question is about UIImage, not UIImageView
This is not correct answer but in other condition it works for me thanks
2

To flip image in swift 4

class ViewController: UIViewController {
var first = 1
var second = 1

@IBOutlet weak var img: UIImageView!
override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
}

@IBAction func flip1(_ sender: Any) {

    if first == 1 {
        img.transform = CGAffineTransform(scaleX: -1, y: 1)
        first = 2
    }
    else if first == 2
    {
        img.transform = CGAffineTransform(scaleX: +1, y: 1)
        first = 1
    }

}


}

Comments

2

Swift 5

If your use case requires saving the UIImage after transforming, it will need to be drawn into a new CGContext.

extension UIImage {
  
  enum Axis {
    case horizontal, vertical
  }
  
  func flipped(_ axis: Axis) -> UIImage {
    let renderer = UIGraphicsImageRenderer(size: size)
    
    return renderer.image {
      let context = $0.cgContext
      context.translateBy(x: size.width / 2, y: size.height / 2)
      
      switch axis {
      case .horizontal:
        context.scaleBy(x: -1, y: 1)
      case .vertical:
        context.scaleBy(x: 1, y: -1)
      }
      
      context.translateBy(x: -size.width / 2, y: -size.height / 2)
      
      draw(at: .zero)
    }
  }
}

1 Comment

Used it: imgClone.image = pickedImage.flipped(.vertical)
0

There is couple of similar questions on SO. And I believe it's worth to post solution using CoreImage here too.

Please note: when getting final UIImage, it's necessary to convert to CGImage first to respect extent of CIImage

extension UIImage {
    func imageRotated(by degrees: CGFloat) -> UIImage {

        let orientation = CGImagePropertyOrientation(imageOrientation)
        // Create CIImage respecting image's orientation 
        guard let inputImage = CIImage(image: self)?.oriented(orientation) 
            else { return self }

        // Flip the image itself
        let flip = CGAffineTransform(scaleX: 1, y: -1)
        let outputImage = inputImage.transformed(by: flip)

        // Create CGImage first
        guard let cgImage = CIContext().createCGImage(outputImage, from: outputImage.extent) 
            else { return self }

        // Create output UIImage from CGImage
        return UIImage(cgImage: cgImage)
    }
}

1 Comment

Cannot convert value of type 'UIImage.Orientation' to expected argument type 'UInt32'

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.