UIImage+Orientation.swift 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. //
  2. // UIImage+Orientation.swift
  3. // WeScan
  4. //
  5. // Created by Boris Emorine on 2/16/18.
  6. // Copyright © 2018 WeTransfer. All rights reserved.
  7. //
  8. import Foundation
  9. @available(iOS 10, *)
  10. extension UIImage {
  11. /// Returns the same image with a portrait orientation.
  12. func applyingPortraitOrientation() -> UIImage {
  13. switch imageOrientation {
  14. case .up:
  15. return rotated(by: Measurement(value: Double.pi, unit: .radians), options: []) ?? self
  16. case .down:
  17. return rotated(by: Measurement(value: Double.pi, unit: .radians), options: [.flipOnVerticalAxis, .flipOnHorizontalAxis]) ?? self
  18. case .left:
  19. return self
  20. case .right:
  21. return rotated(by: Measurement(value: Double.pi / 2.0, unit: .radians), options: []) ?? self
  22. default:
  23. return self
  24. }
  25. }
  26. /// Data structure to easily express rotation options.
  27. struct RotationOptions: OptionSet {
  28. let rawValue: Int
  29. static let flipOnVerticalAxis = RotationOptions(rawValue: 1)
  30. static let flipOnHorizontalAxis = RotationOptions(rawValue: 2)
  31. }
  32. /// Rotate the image by the given angle, and perform other transformations based on the passed in options.
  33. ///
  34. /// - Parameters:
  35. /// - rotationAngle: The angle to rotate the image by.
  36. /// - options: Options to apply to the image.
  37. /// - Returns: The new image rotated and optentially flipped (@see options).
  38. func rotated(by rotationAngle: Measurement<UnitAngle>, options: RotationOptions = []) -> UIImage? {
  39. guard let cgImage = self.cgImage else { return nil }
  40. let rotationInRadians = CGFloat(rotationAngle.converted(to: .radians).value)
  41. let transform = CGAffineTransform(rotationAngle: rotationInRadians)
  42. let cgImageSize = CGSize(width: cgImage.width, height: cgImage.height)
  43. var rect = CGRect(origin: .zero, size: cgImageSize).applying(transform)
  44. rect.origin = .zero
  45. let format = UIGraphicsImageRendererFormat()
  46. format.scale = 1
  47. let renderer = UIGraphicsImageRenderer(size: rect.size, format: format)
  48. let image = renderer.image { renderContext in
  49. renderContext.cgContext.translateBy(x: rect.midX, y: rect.midY)
  50. renderContext.cgContext.rotate(by: rotationInRadians)
  51. let x = options.contains(.flipOnVerticalAxis) ? -1.0 : 1.0
  52. let y = options.contains(.flipOnHorizontalAxis) ? 1.0 : -1.0
  53. renderContext.cgContext.scaleBy(x: CGFloat(x), y: CGFloat(y))
  54. let drawRect = CGRect(origin: CGPoint(x: -cgImageSize.width / 2.0, y: -cgImageSize.height / 2.0), size: cgImageSize)
  55. renderContext.cgContext.draw(cgImage, in: drawRect)
  56. }
  57. return image
  58. }
  59. }