Skip to content

Instantly share code, notes, and snippets.

@muukii
Created March 30, 2021 15:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save muukii/1d5b59b83303a4fc4cbef7270e953516 to your computer and use it in GitHub Desktop.
Save muukii/1d5b59b83303a4fc4cbef7270e953516 to your computer and use it in GitHub Desktop.
extension CGImage {
enum Flipping {
case vertically
case horizontally
}
func rotated(angle: CGFloat, flipping: Flipping? = nil) throws -> CGImage
{
guard angle != 0 else {
return self
}
var rotatedSize: CGSize =
size
.applying(.init(rotationAngle: angle))
rotatedSize.width = abs(rotatedSize.width)
rotatedSize.height = abs(rotatedSize.height)
let cgImage = try autoreleasepool { () -> CGImage? in
let rotatingContext = try CGContext.makeContext(for: self, size: rotatedSize)
.perform { c in
if let flipping = flipping {
switch flipping {
case .vertically:
c.translateBy(x: 0, y: rotatedSize.height)
c.scaleBy(x: 1, y: -1)
case .horizontally:
c.translateBy(x: rotatedSize.width, y: 0)
c.scaleBy(x: -1, y: 1)
}
}
c.translateBy(x: rotatedSize.width / 2, y: rotatedSize.height / 2)
c.rotate(by: angle)
c.translateBy(
x: -size.width / 2,
y: -size.height / 2
)
c.draw(self, in: .init(origin: .zero, size: self.size))
}
return rotatingContext.makeImage()
}
return try cgImage.unwrap()
}
func oriented(_ orientation: CGImagePropertyOrientation) throws -> CGImage {
let angle: CGFloat
switch orientation {
case .down, .downMirrored:
angle = CGFloat.pi
case .left, .leftMirrored:
angle = CGFloat.pi / 2.0
case .right, .rightMirrored:
angle = CGFloat.pi / -2.0
case .up, .upMirrored:
angle = 0
}
let flipping: Flipping?
switch orientation {
case .upMirrored, .downMirrored:
flipping = .horizontally
case .leftMirrored, .rightMirrored:
flipping = .vertically
case .up, .down, .left, .right:
flipping = nil
}
let result = try rotated(angle: angle, flipping: flipping)
return result
}
}
extension CGContext {
@discardableResult
func perform(_ drawing: (CGContext) -> Void) -> CGContext {
UIGraphicsPushContext(self)
defer {
UIGraphicsPopContext()
}
drawing(self)
return self
}
static func makeContext(for image: CGImage, size: CGSize? = nil) throws -> CGContext {
let context = CGContext.init(
data: nil,
width: size.map { Int($0.width) } ?? image.width,
height: size.map { Int($0.height) } ?? image.height,
bitsPerComponent: image.bitsPerComponent,
bytesPerRow: 0,
space: try image.colorSpace.unwrap(),
bitmapInfo: image.bitmapInfo.rawValue
)
return try context.unwrap()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment