Convert UIImage to NSData and convert back to UIImage in Swift?

前端 未结 9 1433
一向
一向 2020-12-02 07:33

I\'m trying to save a UIImage to NSData and then read the NSData back to a new UIImage in Swift. To convert the UII

相关标签:
9条回答
  • 2020-12-02 08:01

    Thanks. Helped me a lot. Converted to Swift 3 and worked

    To save: let data = UIImagePNGRepresentation(image)

    To load: let image = UIImage(data: data)

    0 讨论(0)
  • 2020-12-02 08:03

    For safe execution of code, use if-let block with Data to prevent app crash & , as function UIImagePNGRepresentation returns an optional value.

    if let img = UIImage(named: "TestImage.png") {
        if let data:Data = UIImagePNGRepresentation(img) {
           // Handle operations with data here...         
        }
    }
    

    Note: Data is Swift 3+ class. Use Data instead of NSData with Swift 3+

    Generic image operations (like png & jpg both):

    if let img = UIImage(named: "TestImage.png") {  //UIImage(named: "TestImage.jpg")
            if let data:Data = UIImagePNGRepresentation(img) {
                   handleOperationWithData(data: data)     
            } else if let data:Data = UIImageJPEGRepresentation(img, 1.0) {
                   handleOperationWithData(data: data)     
            }
    }
    
    *******
    func handleOperationWithData(data: Data) {
         // Handle operations with data here...
         if let image = UIImage(data: data) {
            // Use image...
         }
    }
    

    By using extension:

    extension UIImage {
    
        var pngRepresentationData: Data? {
            return UIImagePNGRepresentation(self)
        }
    
        var jpegRepresentationData: Data? {
            return UIImageJPEGRepresentation(self, 1.0)
        }
    }
    
    *******
    if let img = UIImage(named: "TestImage.png") {  //UIImage(named: "TestImage.jpg")
          if let data = img.pngRepresentationData {
                  handleOperationWithData(data: data)     
          } else if let data = img.jpegRepresentationData {
                  handleOperationWithData(data: data)     
         }
    }
    
    *******
    func handleOperationWithData(data: Data) {
         // Handle operations with data here...
         if let image = UIImage(data: data) {
            // Use image...
         }
    }
    
    0 讨论(0)
  • 2020-12-02 08:07

    Details

    • Xcode 10.2.1 (10E1001), Swift 5

    Solution 1

    guard let image = UIImage(named: "img") else { return }
    let jpegData = image.jpegData(compressionQuality: 1.0)
    let pngData = image.pngData()
    

    Solution 2.1

    extension UIImage {
        func toData (options: NSDictionary, type: CFString) -> Data? {
            guard let cgImage = cgImage else { return nil }
            return autoreleasepool { () -> Data? in
                let data = NSMutableData()
                guard let imageDestination = CGImageDestinationCreateWithData(data as CFMutableData, type, 1, nil) else { return nil }
                CGImageDestinationAddImage(imageDestination, cgImage, options)
                CGImageDestinationFinalize(imageDestination)
                return data as Data
            }
        }
    }
    

    Usage of solution 2.1

    // about properties: https://developer.apple.com/documentation/imageio/1464962-cgimagedestinationaddimage
    let options: NSDictionary =     [
        kCGImagePropertyOrientation: 6,
        kCGImagePropertyHasAlpha: true,
        kCGImageDestinationLossyCompressionQuality: 0.5
    ]
    
    // https://developer.apple.com/documentation/mobilecoreservices/uttype/uti_image_content_types
    guard let data = image.toData(options: options, type: kUTTypeJPEG) else { return }
    let size = CGFloat(data.count)/1000.0/1024.0
    print("\(size) mb")
    

    Solution 2.2

    extension UIImage {
    
        func toJpegData (compressionQuality: CGFloat, hasAlpha: Bool = true, orientation: Int = 6) -> Data? {
            guard cgImage != nil else { return nil }
            let options: NSDictionary =     [
                                                kCGImagePropertyOrientation: orientation,
                                                kCGImagePropertyHasAlpha: hasAlpha,
                                                kCGImageDestinationLossyCompressionQuality: compressionQuality
                                            ]
            return toData(options: options, type: .jpeg)
        }
    
        func toData (options: NSDictionary, type: ImageType) -> Data? {
            guard cgImage != nil else { return nil }
            return toData(options: options, type: type.value)
        }
        // about properties: https://developer.apple.com/documentation/imageio/1464962-cgimagedestinationaddimage
        func toData (options: NSDictionary, type: CFString) -> Data? {
            guard let cgImage = cgImage else { return nil }
            return autoreleasepool { () -> Data? in
                let data = NSMutableData()
                guard let imageDestination = CGImageDestinationCreateWithData(data as CFMutableData, type, 1, nil) else { return nil }
                CGImageDestinationAddImage(imageDestination, cgImage, options)
                CGImageDestinationFinalize(imageDestination)
                return data as Data
            }
        }
    
        // https://developer.apple.com/documentation/mobilecoreservices/uttype/uti_image_content_types
        enum ImageType {
            case image // abstract image data
            case jpeg                       // JPEG image
            case jpeg2000                   // JPEG-2000 image
            case tiff                       // TIFF image
            case pict                       // Quickdraw PICT format
            case gif                        // GIF image
            case png                        // PNG image
            case quickTimeImage             // QuickTime image format (OSType 'qtif')
            case appleICNS                  // Apple icon data
            case bmp                        // Windows bitmap
            case ico                        // Windows icon data
            case rawImage                   // base type for raw image data (.raw)
            case scalableVectorGraphics     // SVG image
            case livePhoto                  // Live Photo
    
            var value: CFString {
                switch self {
                case .image: return kUTTypeImage
                case .jpeg: return kUTTypeJPEG
                case .jpeg2000: return kUTTypeJPEG2000
                case .tiff: return kUTTypeTIFF
                case .pict: return kUTTypePICT
                case .gif: return kUTTypeGIF
                case .png: return kUTTypePNG
                case .quickTimeImage: return kUTTypeQuickTimeImage
                case .appleICNS: return kUTTypeAppleICNS
                case .bmp: return kUTTypeBMP
                case .ico: return kUTTypeICO
                case .rawImage: return kUTTypeRawImage
                case .scalableVectorGraphics: return kUTTypeScalableVectorGraphics
                case .livePhoto: return kUTTypeLivePhoto
                }
            }
        }
    }
    

    Usage of solution 2.2

    let compressionQuality: CGFloat = 0.4
    guard let data = image.toJpegData(compressionQuality: compressionQuality) else { return }
    printSize(of: data)
    
    let options: NSDictionary =     [
                                        kCGImagePropertyHasAlpha: true,
                                        kCGImageDestinationLossyCompressionQuality: compressionQuality
                                    ]
    guard let data2 = image.toData(options: options, type: .png) else { return }
    printSize(of: data2)
    

    Problems

    Image representing will take a lot of cpu and memory resources. So, in this case it is better to follow several rules:

    - do not run jpegData(compressionQuality:) on main queue

    - run only one jpegData(compressionQuality:) simultaneously

    Wrong:

    for i in 0...50 {
        DispatchQueue.global(qos: .utility).async {
            let quality = 0.02 * CGFloat(i)
            //let data = image.toJpegData(compressionQuality: quality)
            let data = image.jpegData(compressionQuality: quality)
            let size = CGFloat(data!.count)/1000.0/1024.0
            print("\(i), quality: \(quality), \(size.rounded()) mb")
        }
    }
    

    Right:

    let serialQueue = DispatchQueue(label: "queue", qos: .utility, attributes: [], autoreleaseFrequency: .workItem, target: nil)
    
    for i in 0...50 {
        serialQueue.async {
            let quality = 0.02 * CGFloat(i)
            //let data = image.toJpegData(compressionQuality: quality)
            let data = image.jpegData(compressionQuality: quality)
            let size = CGFloat(data!.count)/1000.0/1024.0
            print("\(i), quality: \(quality), \(size.rounded()) mb")
        }
    }
    

    Links

    • UTI Image Content Types
    • CGImageDestinationAddImage(::_:)
    • Thinking about Memory: Converting UIImage to Data in Swift
    • Different resize technics
    0 讨论(0)
提交回复
热议问题