113

I can create UIImage from NSData using [UIImage imageWithData:] or [UIImage initWithData:] methods.

I wonder if I can get the NSData back from an existing UIImage? Something on the line of NSData *myData = [myImage getData];

8 Answers 8

196

Objective-C

NSData *imageData = UIImageJPEGRepresentation(image, 0.7); // 0.7 is JPG quality 

or

NSData *imageData = UIImagePNGRepresentation(image); 

Depending if you want your data in PNG format or JPG format.

Swift

In modern versions of Swift, the methods above have been replaced with

let data = image.jpegData(compressionQuality: 0.7) 

and

let data = image.pngData() 

respectively.

Note that both return an optional value (Data?).

Sign up to request clarification or add additional context in comments.

8 Comments

I don't know why this answer is up-voted so many times nor that it is accepted. The OP asked to retrieve the data that was given initially. Using UIImageJPEGRepresentation or UIImagePNGRepresentation will alter the data and do a reconversion. Is there any way to really achieve what was asked for?
This answer is no good, because it will lower the quality of the image if it is already in a lossy format.
@CipherCom I see what you're saying about wanting the exact data back. However, I think for the majority of people that come across question, this answer will be perfect for their needs... hence the upvotes. If you come across an answer for getting the original data back, please share ;)
@1dayitwillmake Even the PNG rep? Not my area of expertise, but I thought PNGs don't suffer loss?
@Bob Spryn This won't help. The property CIImage is only set if it was initialized with imageWithCIImage:. Also this isn't directly the used data but rather another image representation object.
|
31

When initialising a UIImage object with init(data: originalData), that originalData will be converted into raw data in some kind of internal format. These data can be retrieved later with

let rawData = myImage.cgImage?.dataProvider?.data as Data? 

However because the rawData is raw, it is going to be even larger than when using UIImagePNGRepresentation.

3 Comments

how do I do this in Objective-C
NSData *rawData = (__bridge NSData *) CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage));
@ZardozSpeaks the obj-c variant perfectly viable to be included as an edit in this answer.
12

Swift 4.2

let dataPng = image.pngData() // return image as PNG. May return nil if image has no CGImageRef or invalid bitmap format let dataJpg = image.jpegData(compressionQuality: 1) // return image as JPEG. May return nil if image has no CGImageRef or invalid bitmap format. compression is 0(most)..1(least) 

Comments

8

Just because I stumbled upon this and i like swift :)

Here is the swift translation of Caroiline's post.

var imageData = UIImagePNGRepresentation(image) 

Or

var imageData = UIImageJPEGRepresentation(image, 0.7) 

1 Comment

I'm gonna upvote nsij's answer, Cross, cuz it was really helpful!!!
6

You can expect that a UIImage is an object formatted for display and so won't be using the original data (which is probably in PNG or JPEG format) but more likely a pixel array or some other internal format. In other words, UIImage(data: foo) will not retain foo.

  1. If you just want to use it elsewhere in your program, the original UIImage will do fine (I presume that's not actually the case here)

  2. If you want to serialise, UIImagePNGRepresentation(...) will work but will be oversized if the original was a JPEG; UIImageJPEGRepresentation(...) will often result in slightly oversize data and is slightly lossy if your original was PNG. It should be okay to pick one based on the way the image will be displayed and the format you expect to be provided. If you happen to be using PNG in and want PNG out, you should get a good file size and almost identical data, special PNG chunks aside.

  3. If you want to get an exact copy of the original data (perhaps to save a file after thumbnailing, or to SHA1 it), then you need to retain it separately. You might do something like:

    var image:UIImage var imageData:NSData { didSet { image = UIImage(data: imageData) } } 

Comments

1

This will get you the underlying data of a UIImage, no png/jpeg conversion required.

extension UIImage { var rawData: Data? { guard let cgImage else { return nil } let colorSpace = CGColorSpaceCreateDeviceRGB() let context = CGContext( data: nil, width: cgImage.width, height: cgImage.height, bitsPerComponent: cgImage.bitsPerComponent, bytesPerRow: cgImage.bytesPerRow, space: colorSpace, bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue ) context?.draw( cgImage, in: .init( origin: .zero, size: .init( width: CGFloat(cgImage.width), height: CGFloat(cgImage.height) ) ) ) guard let data = context?.data else { print("Failed to get image data") return nil } return .init(bytes: data, count: cgImage.bytesPerRow * cgImage.height) } } 

1 Comment

Though I think actually this much simpler answer works fine. Was getting a compiler error when I tried initially but was able to resolve it.
0

The only solution I found to serialize/unserialize a UIImage (via Data) is by using this solution.

You can then serialize/unserialize regardless of how the UIImage was created by using the extension method on UIImage:

let originalImage: UIImage = ... let cgData = image.cgImage!.png! let image = UIImage(data: cgData)! 

Comments

-2

Things have changed since the above answer was given, for those still looking because they share CipherCom's concern: iOS 5 has added the CIImage property.

2 Comments

I'm not seeing a way to use CIImage to get the underlying NSData... am I missing something?
This won't help. The property CIImage is only set if it was initialized with imageWithCIImage:. Also this isn't directly the used data but rather another image representation object.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.