iosswiftxcodeuiimagepickercontroller

Selecting images with UIImagePickerController() auto-rotates them


In my app, I am importing selected photos from a user's photo library and using them as thumbnails/displaying them in UIImageViews. They are imported and saved to the user's documents folder.

The code used is below, however the images are being automatically rotated before being saved, and I'm not sure why.

For example, this image is rotated 180°: https://imgur.com/a/r2xm0if, as are some others that are wider than they are high. I'm not sure why, but not all images are rotated like this. Some are rotated 90°, and some not at all.

They are rotated on the disk - not just in the UIImageView, so I know it's not an issue with how that is set up.

importPicture() is called when the user taps a "+" button.

@objc func importPicture() {
    let picker                  = UIImagePickerController()
    picker.mediaTypes           = [kUTTypeMovie as String, kUTTypeImage as String]
    picker.allowsEditing        = true
    picker.delegate             = self

    present(picker, animated: true)
}


@objc func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {


    let documentsDirectoryURL = try! FileManager().url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
    // create a name for your image
    let addedURL = UUID().uuidString
    let fileURL = documentsDirectoryURL.appendingPathComponent("\(addedURL).png")

    let videoURL2 = documentsDirectoryURL.appendingPathComponent("\(addedURL).mov")



    let mediaType = info[UIImagePickerController.InfoKey.mediaType] as AnyObject

    // Movie
    if mediaType as! String == kUTTypeMovie as String {
        let videoURL = info[UIImagePickerController.InfoKey.mediaURL] as? URL
        print("VIDEO URL: \(videoURL!)")

        let myVideoVarData = try! Data(contentsOf: videoURL! as URL)
        if !FileManager.default.fileExists(atPath: videoURL2.path) {
            do {
                try myVideoVarData.write(to: videoURL2)
                print("Video Added Successfully")
                print(videoURL2)
            } catch {
                print(error)
            }
        } else {
            print("Video not added")
        }

        photosNew.append("\(addedURL).mov")

        collectionView.reloadData()



    }


    // Image
    if mediaType as! String == kUTTypeImage as String {

        guard let image = info[.originalImage] as? UIImage else {
            return
        }
        if let imageData = image.pngData() {
            if !FileManager.default.fileExists(atPath: fileURL.path) {
                do {
                    try imageData.write(to: fileURL)
                    print("Image Added Successfully")
                    print(fileURL)
                } catch {
                    print(error)
                }
            } else {
                print("Image Not Added")
            }
        }

        photosNew.append("\(addedURL).png")

        collectionView.reloadData()

    }

Solution

  • Created an UIImage extension to keep the image in the original position,

    extension UIImage {
        func fixedOrientation() -> UIImage {
            
            if imageOrientation == .up {
                return self
            }
            
            var transform: CGAffineTransform = CGAffineTransform.identity
            
            switch imageOrientation {
            case .down, .downMirrored:
                transform = transform.translatedBy(x: size.width, y: size.height)
                transform = transform.rotated(by: CGFloat.pi)
            case .left, .leftMirrored:
                transform = transform.translatedBy(x: size.width, y: 0)
                transform = transform.rotated(by: CGFloat.pi / 2)
            case .right, .rightMirrored:
                transform = transform.translatedBy(x: 0, y: size.height)
                transform = transform.rotated(by: CGFloat.pi / -2)
            case .up, .upMirrored:
                break
            }
            
            switch imageOrientation {
            case .upMirrored, .downMirrored:
                transform = transform.translatedBy(x: size.width, y: 0)
                transform = transform.scaledBy(x: -1, y: 1)
            case .leftMirrored, .rightMirrored:
                transform = transform.translatedBy(x: size.height, y: 0)
                transform = transform.scaledBy(x: -1, y: 1)
            case .up, .down, .left, .right:
                break
            }
            
            if let cgImage = self.cgImage, let colorSpace = cgImage.colorSpace,
                let ctx: CGContext = CGContext(data: nil, width: Int(size.width), height: Int(size.height), bitsPerComponent: cgImage.bitsPerComponent, bytesPerRow: 0, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue) {
                ctx.concatenate(transform)
                
                switch imageOrientation {
                case .left, .leftMirrored, .right, .rightMirrored:
                    ctx.draw(cgImage, in: CGRect(x: 0, y: 0, width: size.height, height: size.width))
                default:
                    ctx.draw(cgImage, in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
                }
                if let ctxImage: CGImage = ctx.makeImage() {
                    return UIImage(cgImage: ctxImage)
                } else {
                    return self
                }
            } else {
                return self
            }
        }
    }
    

    To use the extension's method, please should do the following with your image,

    let orientedImage = image?.fixedOrientation()
    

    In your case, inside func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) method,

    ...
    guard let image = info[.originalImage] as? UIImage else {
            return
        }
    let orientedImage = image.fixedOrientation()
    if let imageData = orientedImage.pngData() {
    ...