How to flip UIImage horizontally with Swift?
Asked Answered
M

9

47

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!

Mario answered 25/7, 2014 at 22:51 Comment(0)
D
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)
Deppy answered 25/7, 2014 at 23:8 Comment(4)
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) } }Glyceric
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?Unreel
@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.Classy
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 itemSow
H
53

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

Hawn answered 9/2, 2018 at 9:24 Comment(4)
Brilliant, but does not respect the vertical orientations for images captured from AVFoundation- flips the image upside downIdioplasm
Perhaps there is a way to adjust this after the withHorizontallyFlippedOrientation()?Hawn
#available(iOS 10.0, *)Scutter
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.Tedder
D
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)
Deppy answered 25/7, 2014 at 23:8 Comment(4)
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) } }Glyceric
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?Unreel
@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.Classy
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 itemSow
H
34

In Swift.... (6.3.1)

YourUIImage.transform = CGAffineTransformMakeScale(-1, 1)

This also works with a UIView

Hoax answered 28/4, 2015 at 14:50 Comment(3)
This is not for flipping a UIImage, but for flipping UIImageView.Harwin
It's not flipping UIImage. But it solves my UI issues.Jaxartes
not all UI elements are derived from UIView so they haven't transform property (like UIBarButtonItem)Sow
L
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
}
Lepley answered 21/4, 2017 at 7:7 Comment(1)
1)why do you scale by x and y simultaneously? 2)when I assign the image result from your function it disappears in UIBarButtonItemSow
D
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()
Denham answered 9/12, 2019 at 22:33 Comment(3)
This create black background image instead of transparent . Please take noteLulita
@RajuyourPepe I have updated the answer to allow for transparency. Thank you!Denham
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).Highflown
R
10

Swift 4

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

This might also be handy:

YOURIMAGE.imageFlippedForRightToLeftLayoutDirection()
Renettarenew answered 21/12, 2017 at 11:54 Comment(2)
The question is about UIImage, not UIImageViewPortemonnaie
This is not correct answer but in other condition it works for me thanksFirelock
M
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
    }

}


}
Mountain answered 3/3, 2020 at 10:55 Comment(0)
G
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)
    }
  }
}
Gyration answered 9/12, 2020 at 16:51 Comment(1)
Used it: imgClone.image = pickedImage.flipped(.vertical)Nicolas
D
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)
    }
}
Dulosis answered 15/11, 2019 at 13:31 Comment(1)
Cannot convert value of type 'UIImage.Orientation' to expected argument type 'UInt32'Sow

© 2022 - 2024 — McMap. All rights reserved.