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

185,867

Solution 1

UIImage(data:imageData,scale:1.0) presuming the image's scale is 1.

In swift 4.2, use below code for get Data().

image.pngData()

Solution 2

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

To save: let data = UIImagePNGRepresentation(image)

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

Solution 3

Use imageWithData: method, which gets translated to Swift as UIImage(data:)

let image : UIImage = UIImage(data: imageData)

Solution 4

Now in Swift 4.2 you can use pngData() new instance method of UIImage to get the data from the image

let profileImage = UIImage(named:"profile")!
let imageData = profileImage.pngData()

Solution 5

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

Share:
185,867

Related videos on Youtube

pete
Author by

pete

Updated on January 31, 2022

Comments

  • pete
    pete over 2 years

    I'm trying to save a UIImage to NSData and then read the NSData back to a new UIImage in Swift. To convert the UIImage to NSData I'm using the following code:

    let imageData: NSData = UIImagePNGRepresentation(myImage)
    

    How do I convert imageData (i.e., NSData) back to a new UIImage?

  • superarts.org
    superarts.org over 6 years
    Isn't let imagePt = UIImage(data: caminhodaImagem) enough?
  • Dani
    Dani almost 6 years
    Is Swift 4.2 in Beta? I don't see this function available
  • Archy Will He 何魏奇
    Archy Will He 何魏奇 over 5 years
    looks like it has been renamed
  • j2abro
    j2abro about 5 years
    'pngData()' has been renamed to 'UIImagePNGRepresentation(_:)'
  • Gallaugher
    Gallaugher almost 5 years
    Vasily, this was hugely helpful. I'm able to convert UIImages to bmps using your code. I also need to remove alpha from bmp. I've tried to set options to remove the alpha & can't seem to get it to get rid of the layer. I'm calling like this: let options: NSDictionary = [kCGImagePropertyHasAlpha: false] let convertToBmp = image.toData(options: options, type: .bmp)
  • Vasily  Bodnarchuk
    Vasily Bodnarchuk almost 5 years
    @Gallaugher are you sure that it is not working? Try to create png image with out alpha and check it. May be it is impossible to use kCGImagePropertyHasAlpha property with bmp.
  • Gallaugher
    Gallaugher almost 5 years
    @vasily-bodnarchuk Thanks for the lead (and earlier code). I got rid of the alpha - I couldn't do it through png, but I used resizedImage.toJpegData with alpha as false, then converted this data back into a UIImage, then did an toData of type .bmp. Options didn't have an impact, but this removed alpha layer in Photoshop & created a smaller file. Still can't produce the exact 16-bit raster graphic bmp format I need for a PyPortal. For some reason conveted data isn't showing by does when I convert via tool like online-convert. Thx.
  • Gallaugher
    Gallaugher almost 5 years
    @vasily-bodnarchuk, the bmp I've saved using your helpful code opens in Photoshop w/the bmp option "Flip row order". If I resave & uncheck this option on the "BMP Options" screen appearing after "Save as...", then load bmp on the PyPortal, updated bmp shows. I don't see any Apple docs that looks like a "Flip row order" option, I'm unsure why this shows up as the default save & I'm unsure how to "undo" this in Swift. BTW: I've posted my Q & related files at: stackoverflow.com/questions/57241391/… Thanks!
  • Dharman
    Dharman over 4 years
    Please take a moment to read through the editing help in the help center. Formatting on Stack Overflow is different than other sites.
  • Michael Szabo
    Michael Szabo over 2 years
    this returns a nil value when I try? and suggestions?
  • Michael Szabo
    Michael Szabo over 2 years
    to clarify, I have saved an excel file as a pdf, I know my functions work because I am able to attach said PDF to an email and view it in my phones "pdf viewer" out side of the app. The PDF is stored as NSData. If I print(my data.thePDF) I get a value but after converting it with the above script it returns nil. I have also attempted NSData to data, which will print a value but the when I cover the Data to a UIImage it returns nil. :(
  • BadmintonCat
    BadmintonCat about 2 years
    Problem with this is that the data is converted to PNG, aka format change. This is a problem if you want to retrieve the file size of the original image.