swift-video-generator icon indicating copy to clipboard operation
swift-video-generator copied to clipboard

UIImage.imageOrientation not honored

Open actow opened this issue 3 years ago • 1 comments

Images loaded by UIImagePickerController don't always have .imageOrientation set to UIImage.Orientation.up.

Transformations need to be applied accordingly before encoding them into the video.

actow avatar Nov 06 '21 03:11 actow

Very rough, not well tested code that applies the orientation.

extension UIImage {
  func fixedOrientation() -> UIImage {
    guard imageOrientation != .up else {
      return self
    }

    guard let cgImage = cgImage else {
      return self
    }

    let w = size.width
    let h = size.height

    let colorSpace = CGColorSpaceCreateDeviceRGB()
    let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)

    guard let ctx = CGContext(data: nil, width: Int(w), height: Int(h), bitsPerComponent: 8, bytesPerRow: Int(w) * 4, space: colorSpace, bitmapInfo: bitmapInfo.rawValue) else {
      return self
    }

    switch imageOrientation {
    case .down, .downMirrored:
      ctx.translateBy(x: w, y: h)
      ctx.rotate(by: .pi)
    case .left, .leftMirrored:
      ctx.translateBy(x: w, y: 0)
      ctx.rotate(by: .pi / 2.0)
    case .right, .rightMirrored:
      ctx.translateBy(x: 0, y: h)
      ctx.rotate(by: -.pi / 2.0)
    case .up, .upMirrored:
      break
    @unknown default:
      return self
    }

    switch imageOrientation {
    case .upMirrored, .downMirrored:
      ctx.translateBy(x: size.width, y: 0)
      ctx.scaleBy(x: -1, y: 1)
    case .leftMirrored, .rightMirrored:
      ctx.translateBy(x: size.height, y: 0)
      ctx.scaleBy(x: -1, y: 1)
    case .up, .down, .left, .right:
      break
    @unknown default:
      return self
    }

    switch imageOrientation {
    case .left, .leftMirrored, .right, .rightMirrored:
      ctx.draw(cgImage, in: CGRect(x: 0, y: 0, width: h, height: w))
    default:
      ctx.draw(cgImage, in: CGRect(x: 0, y: 0, width: w, height: h))
    }

    guard let resultCgImage: CGImage = ctx.makeImage() else {
      return self
    }

    return UIImage(cgImage: resultCgImage)
  }
}

actow avatar Nov 06 '21 04:11 actow