41

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!

Shruti Thombre
  • 989
  • 4
  • 11
  • 27
Lim Thye Chean
  • 7,600
  • 9
  • 42
  • 83

9 Answers9

43

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 :)

Francesco D.M.
  • 1,911
  • 17
  • 26
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)
Khaled Annajar
  • 14,364
  • 5
  • 33
  • 44
drewag
  • 91,251
  • 28
  • 136
  • 127
  • 11
    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) } }` – Gujamin Feb 09 '16 at 04:17
  • 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? – RainCast Jul 15 '16 at 03:16
  • 1
    @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. – liquidki Aug 02 '16 at 21:52
35

In Swift.... (6.3.1)

YourUIImage.transform = CGAffineTransformMakeScale(-1, 1)

This also works with a UIView

duyn9uyen
  • 8,627
  • 12
  • 37
  • 51
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
}
Alex Shubin
  • 3,481
  • 1
  • 26
  • 32
11

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()
Josh Bernfeld
  • 3,806
  • 2
  • 30
  • 35
8

Swift 4

YOURIMAGEVIEW.transform = CGAffineTransform(scaleX: -1, y: 1)
Ahmadreza
  • 6,284
  • 2
  • 41
  • 62
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
    }

}


}
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)
    }
}
Martin Pilch
  • 3,145
  • 2
  • 34
  • 60
0

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)
    }
  }
}
jimj
  • 956
  • 2
  • 10
  • 21