A couple of thoughts:
The
UIImageJPEGRepresentation
function does not return the "original" image. For example, if you employ acompressionQuality
of1.0
, it does not, technically, return the "original" image, but rather it returns a JPEG rendition of the image withcompressionQuality
at its maximum value. This can actually yield an object that is larger than the original asset (at least if the original image is a JPEG). You're also discarding all of the metadata (information about where the image was taken, the camera settings, etc.) in the process.If you want the original asset, you should use
PHImageManager
:NSURL *url = [info objectForKey:UIImagePickerControllerReferenceURL]; PHFetchResult *result = [PHAsset fetchAssetsWithALAssetURLs:@[url] options:nil]; PHAsset *asset = [result firstObject]; PHImageManager *manager = [PHImageManager defaultManager]; [manager requestImageDataForAsset:asset options:nil resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) { NSString *filename = [(NSURL *)info[@"PHImageFileURLKey"] lastPathComponent]; // do what you want with the `imageData` }];
In iOS versions prior to 8, you'd have to use
assetForURL
of theALAssetsLibrary
class:NSURL *url = [info objectForKey:UIImagePickerControllerReferenceURL]; ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init]; [library assetForURL:url resultBlock:^(ALAsset *asset) { ALAssetRepresentation *representation = [asset defaultRepresentation]; NSLog(@"size of original asset %llu", [representation size]); // I generally would write directly to a `NSOutputStream`, but if you want it in a // NSData, it would be something like: NSMutableData *data = [NSMutableData data]; // now loop, reading data into buffer and writing that to our data strea NSError *error; long long bufferOffset = 0ll; NSInteger bufferSize = 10000; long long bytesRemaining = [representation size]; uint8_t buffer[bufferSize]; NSUInteger bytesRead; while (bytesRemaining > 0) { bytesRead = [representation getBytes:buffer fromOffset:bufferOffset length:bufferSize error:&error]; if (bytesRead == 0) { NSLog(@"error reading asset representation: %@", error); return; } bytesRemaining -= bytesRead; bufferOffset += bytesRead; [data appendBytes:buffer length:bytesRead]; } // ok, successfully read original asset; // do whatever you want with it here } failureBlock:^(NSError *error) { NSLog(@"error=%@", error); }];
Please note that this
assetForURL
runs asynchronously.If you want a
NSData
with compression, you can useUIImageJPEGRepresentation
with acompressionQuality
less than1.0
. Your code actually does this with acompressionQuality
of0.0
, which should offer maximum compression. But you don't save thatNSData
, but rather use it to create aUIImage
and you then get a newUIImageJPEGRepresentation
with acompressionQuality
of1.0
, thus losing much of the compression you originally achieved.Consider the following code:
// a UIImage of the original asset (discarding meta data) UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage]; // this may well be larger than the original asset NSData *jpgDataHighestCompressionQuality = UIImageJPEGRepresentation(image, 1.0); [jpgDataHighestCompressionQuality writeToFile:[docsPath stringByAppendingPathComponent:@"imageDataFromJpeg.jpg"] atomically:YES]; NSLog(@"compressionQuality = 1.0; length = %u", [jpgDataHighestCompressionQuality length]); // this will be smaller, but with some loss of data NSData *jpgDataLowestCompressionQuality = UIImageJPEGRepresentation(image, 0.0); NSLog(@"compressionQuality = 0.0; length = %u", [jpgDataLowestCompressionQuality length]); UIImage *image2 = [UIImage imageWithData:jpgDataLowestCompressionQuality]; // ironically, this will be larger than jpgDataLowestCompressionQuality NSData *newImageSize = UIImageJPEGRepresentation(image2, 1.0); NSLog(@"new size %u", [newImageSize length]);
In addition to the JPEG compression quality outlined the prior point, you could also just resize the image. You can also marry this with the JPEG
compressionQuality
, too.