如何在Swift中将UIImage转换为HEIF / HEIC数据?

10

NSKeyedArchiver适合将UIImage转换为Data吗?

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

还是使用pngData()更为合适,否则是否有些过头了?

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

我该如何将UIImage转换为HEIF/HEIC Data

目的是将图像保存到设备的文件系统中。

1个回答

23

不要使用NSKeyedArchiver将您的图像转换为数据。选择图像格式(HEIC,PNG,JPEG等)并获取其数据表示形式。仅在保存用于UI的图像时才应使用PNG。大多数情况下,jpeg是首选。如果设备支持HEIC,则可以考虑其图像质量和减小的数据大小。

如果您需要检查用户设备是否支持HEIC类型,则可以按以下步骤操作:

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

如果您需要将图像转换为HEIC格式,则需要从UIImage获取CGImage并将UIImageimageOrientation转换为CGImagePropertyOrientation以在创建其数据表示时保留方向:

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) }
}

无损压缩的用法:

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

或者给您的图像添加压缩:

if isHeicSupported, let heicData = image.heic(compressionQuality: 0.75) {
    // write your compressed heic image data to disk
}

如果我想在将每个图像写入磁盘时包含一些元数据,例如时间戳,并且我使用这些元属性子类化UIImage或使用具有属性的结构体包装图像,那么推荐的数据序列化是什么? - lurning too koad
你为什么需要时间戳?你可以使用URL资源的创建日期。 - Leo Dabus
如果您需要为图像命名,可以像苹果IMG_0000.heic一样或类似的方式进行。 - Leo Dabus
为什么要将数据转换为属性列表?如果您需要将任何内容存储在磁盘上或发送到服务器,则建议使用JSON文件(Codable协议)。 - Leo Dabus
1
扩展 URL { var contentAccessDate: Date? { (try? resourceValues(forKeys: [.contentAccessDateKey]))?.contentAccessDate } } https://developer.apple.com/documentation/foundation/urlresourcekey/1408314-contentaccessdatekey - Leo Dabus
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接