Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I convert from UIImage to HEIF / HEIC Data in Swift?

Is NSKeyedArchiver appropriate to convert UIImage to Data?

do {
    let data = try NSKeyedArchiver.archivedData(withRootObject: UIImage(named: somePath), requiringSecureCoding: true)
    ...
} catch {
    print(error)
}

Or is it overkill and using pngData() is more appropriate?

let image = UIImage(named: somePath)
let data = image?.pngData()

and how can I convert from UIImage to HEIF / HEIC Data ?

The goal is to save the image to the device's file system.

like image 210
kidcoder SAVE UKRAINE Avatar asked May 16 '20 00:05

kidcoder SAVE UKRAINE


1 Answers

No. Never use NSKeyedArchiver to convert your image to Data. Choose an image format (HEIC, PNG, JPEG, etc) and get its data representation. You should only use PNG when saving images to use in your UI. Most of the time jpeg is the preferred choice. If the device supports HEIC it is an option considering the image quality and reduced data size.

If you need to check if the user device supports HEIC type you can do it as follow:

var isHeicSupported: Bool {
    (CGImageDestinationCopyTypeIdentifiers() as! [String]).contains("public.heic")
}

If you need to convert your image to HEIC you need to get a CGImage from your UIImage and convert your UIImage's imageOrientation to CGImagePropertyOrientation to preserve the orientation when creating its data representation:

extension UIImage {
    var heic: Data? { heic() }
    func heic(compressionQuality: CGFloat = 1) -> Data? {
        guard
            let mutableData = CFDataCreateMutable(nil, 0),
            let destination = CGImageDestinationCreateWithData(mutableData, "public.heic" as CFString, 1, nil),
            let cgImage = cgImage 
        else { return nil }
        CGImageDestinationAddImage(destination, cgImage, [kCGImageDestinationLossyCompressionQuality: compressionQuality, kCGImagePropertyOrientation: cgImageOrientation.rawValue] as CFDictionary)
        guard CGImageDestinationFinalize(destination) else { return nil }
        return mutableData as Data
    }
}

extension CGImagePropertyOrientation {
    init(_ uiOrientation: UIImage.Orientation) {
        switch uiOrientation {
            case .up: self = .up
            case .upMirrored: self = .upMirrored
            case .down: self = .down
            case .downMirrored: self = .downMirrored
            case .left: self = .left
            case .leftMirrored: self = .leftMirrored
            case .right: self = .right
            case .rightMirrored: self = .rightMirrored
        @unknown default:
            fatalError()
        }
    }
}

extension UIImage {
    var cgImageOrientation: CGImagePropertyOrientation { .init(imageOrientation) }
}

Usage for lossless compression:

if isHeicSupported, let heicData = image.heic {
    // write your heic image data to disk
}

or adding compression to your image:

if isHeicSupported, let heicData = image.heic(compressionQuality: 0.75) {
    // write your compressed heic image data to disk
}
like image 104
Leo Dabus Avatar answered Oct 17 '22 03:10

Leo Dabus