Converting an Image from Heic to Jpeg/Jpg
Asked Answered
J

5

13

I have an application where user can upload multiple images and all the images will be stored in a server and will be displayed on a web view in my iOS application.

Now everything used to work just about fine till iOS 10 but suddenly we started seeing some pictures/ images not being displayed , after a little debugging we found out that this is the problem caused because of the new image format of apple (HEIC),

I tried changing back to the Native UIImagePicker (picks only one image) and the images are being displayed as Apple I guess is converting the Image from HEIC to JPG when a user picks them, but this is not the case when I use 3rd party libraries as I need to implement multiple image picker.

Though we are hard at work to make the conversion process on the server side to avoid users who have not updated the app to face troubles, I also want to see if there is any way in which I can convert the image format locally in my application.

Joli answered 22/11, 2017 at 7:56 Comment(0)
H
15

There's a workaround to convert HEIC photos to JPEG before uploading them to the server :

NSData *jpgImageData = UIImageJPEGRepresentation(image, 0.7);

If you use PHAsset, the, in order to have the image object, you'll need to call this method from PHImageManager:

- (PHImageRequestID)requestImageForAsset:(PHAsset *)asset targetSize:(CGSize)targetSize contentMode:(PHImageContentMode)contentMode options:(nullable PHImageRequestOptions *)options resultHandler:(void (^)(UIImage *__nullable result, NSDictionary *__nullable info))resultHandler;

On server side you also have the ability to use this API or this website directly

Herrin answered 22/11, 2017 at 9:5 Comment(4)
I am actually using an array of assets to store, any solution for that, please ?Joli
By assets you mean PHAsset ?Herrin
I updated my answer, all you have to do is to loop over your array and call this requestImageForAsset method.Herrin
I am trying to do something similar, and this looks like a nice, easy solution! However, I am uncertain of what exactly is going on here. What is the following line, and where do you put it? "NSData *jpgImageData = UIImageJPEGRepresentation(image, 0.7);" line? And/or, what are all the dependencies?Nelson
E
6

I've done it this way,

     let newImageSize = Utility.getJpegData(imageData: imageData!, referenceUrl: referenceUrl!)

     /**
         - Convert heic image to jpeg format
     */
     public static func getJpegData(imageData: Data, referenceUrl: NSURL) -> Data {
         var newImageSize: Data?
         if (try? Data(contentsOf: referenceUrl as URL)) != nil
         {
                let image: UIImage = UIImage(data: imageData)!
                newImageSize = image.jpegData(compressionQuality: 1.0)
         }
            return newImageSize!
     }
Emrick answered 11/10, 2019 at 10:8 Comment(0)
B
2

In Swift 3, given an input path of an existing HEIF pic and an output path where to save the future JPG file:

func fromHeicToJpg(heicPath: String, jpgPath: String) -> UIImage? {
        let heicImage = UIImage(named:heicPath)
        let jpgImageData = UIImageJPEGRepresentation(heicImage!, 1.0)
        FileManager.default.createFile(atPath: jpgPath, contents: jpgImageData, attributes: nil)
        let jpgImage = UIImage(named: jpgPath)
        return jpgImage
    }

It returns the UIImage of the jpgPath or null if something went wrong.

Biggers answered 21/2, 2020 at 19:4 Comment(0)
A
1

I have done this way, its working for me.

step 1: pick image from folder then checking their extension

Step 2: If that is heic then that data convert into image after that image converting into jpegdata.

func getJpegData(imageData: Data) -> Data? {
         var newImageSize: Data?
     guard imageData.count != 0 else {
         return nil
     }
    let image: UIImage = UIImage(data: imageData)!
      newImageSize = image.jpegData(compressionQuality:0.6)
     return newImageSize!

     }

step 3: then change that file extension with jpeg before sending file name with extension to server.

let fName = filename.replacingOccurrences(of: "heic", with: "jpeg")

Final code to call :

func attachmentPickerMenu(_ menu: HSAttachmentPicker, upload data: Data, filename: String, image: UIImage?) {
      
        let fm = FileManager.default
        let docsurl = try! fm.url(for:.documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
        let myurl = docsurl.appendingPathComponent(filename)
        let mtype = myurl.mimeType()
        let imgExtensons = myurl.pathExtension
        print("mtype:",mtype,"myurl:",myurl, "docsurl:",docsurl,"imgExtensins:",imgExtensons, "filenamess:",filename)
        
        if imgExtensons.lowercased() == "heic" {
           
            let imgData = CEnumClass.share.getJpegData(imageData: data)
            guard  imgData != nil  else{
                return self.view.makeToast(ConstantStr.somethingWorng.val, duration: 2, position: .center)
            }
            let fName = filename.replacingOccurrences(of: "heic", with: "jpeg")
            DispatchQueue.main.async {
                self.pendingDocViewModel.uploadAddReimburseData(serviceFormData: imgData!, mimeTpes: "image/jpeg", fileName: fName)
            }
        }}
Ashlar answered 17/11, 2023 at 10:54 Comment(0)
S
0

I have found the existing answers to be helpful but I have decided to post my take on the solution to this problem as well. Hopefully it's a bit clearer and "complete".

This solution saves the image to a file.

private let fileManager: FileManager

func save(asset: PHAsset, to destination: URL) {
    let options = PHContentEditingInputRequestOptions()
    options.isNetworkAccessAllowed = true

    asset.requestContentEditingInput(with: options) { input, info in
        guard let input = input, let url = input.fullSizeImageURL else {
            return // you might want to handle this case
        }

        do {
            try self.save(input, at: url, to: destination)
            // success!
        } catch {
            // failure, handle the error!
        }
    }
}

private func copy(
    _ input: PHContentEditingInput, at url: URL, to destination: URL
) throws {
    let uniformType = input.uniformTypeIdentifier ?? ""
    switch uniformType {
    case UTType.jpeg.identifier:
        // Copy JPEG files directly
        try fileManager.copyItem(at: url, to: destination)
    default:
        // Convert HEIC/PNG and other formats to JPEG and save to file
        let image = UIImage(data: try Data(contentsOf: url))
        guard let data = image?.jpegData(compressionQuality: 1) else {
            return // you might want to handle this case
        }
        try data.write(to: destination)
    }
}
Scoreboard answered 31/5, 2022 at 16:24 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.