You should use neither UIImageJPEGRepresentation
nor UIImagePNGRepresentation
. Those will lose the image's meta-data, make the file larger (or if you choose a JPEG compression factor to make the NSData
smaller, it will degrade the image), etc.
I'd suggest that you save the UIImagePickerControllerReferenceURL
and, then, when the user chooses to save the image, that you go back to the Photos framework and retrieve the underlying NSData
of the image.
So, make sure to import the Photos framework:
@import Photos;
Also, define a property to capture the URL:
@property (nonatomic, strong) NSURL *imageReferenceURL;
And then capture this URL when you get the image:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *chosenImage = info[UIImagePickerControllerEditedImage];
self.imageView.image = chosenImage;
self.imageReferenceURL = info[UIImagePickerControllerReferenceURL];
[picker dismissViewControllerAnimated:YES completion:nil];
}
And when you go to upload the picture, retrieve the original asset's NSData
from the Photos framework:
- (IBAction)uploadPic:(UIButton *)sender {
PHFetchResult *result = [PHAsset fetchAssetsWithALAssetURLs:@[self.imageReferenceURL] options:nil];
PHAsset *asset = [result firstObject];
if (asset) {
PHImageManager *manager = [PHImageManager defaultManager];
[manager requestImageDataForAsset:asset options:nil resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
// insert your code for uploading here, referencing the `imageData` here rather than `dataImage`.
// Or, I might recommend AFNetworking:
//
// For example, if your web service was expecting a `multipart/form-data` POST and was
// going to return a JSON response, you could do something like:
NSString *urlString = @"http://192.168.0.10/udazz/2.0/2.2/ios/1.0/actions.php?targ=user&subTarg=post&txtComment=123456&txtType=ff";
NSDictionary *parameters = @{@"targ" : @"user",
@"subTarg" : @"post",
@"txtComment" : @"123456",
@"txtType" : @"ff"};
NSURL *fileURL = info[@"PHImageFileURLKey"];
NSString *filename = [fileURL lastPathComponent];
NSString *mimeType = [self mimeTypeForPath:filename];
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
// manager.responseSerializer = [AFHTTPResponseSerializer serializer]; // if response is string rather than JSON, uncomment this line
[manager POST:urlString parameters:parameters constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:imageData name:@"userfile" fileName:filename mimeType:mimeType];
} success:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(@"responseObject = %@", responseObject);
} failure:^(NSURLSessionDataTask *task, NSError *error) {
NSLog(@"error = %@", error);
}];
}];
}
}
Or, if you want to use your own upload code, just adjust it to use NSURLSession
(because NSURLConnection
is now deprecated and you should never do synchronous network requests, anyway):
- (IBAction)uploadPic:(UIButton *)sender {
PHFetchResult *result = [PHAsset fetchAssetsWithALAssetURLs:@[self.imageReferenceURL] options:nil];
PHAsset *asset = [result firstObject];
if (asset) {
PHImageManager *manager = [PHImageManager defaultManager];
[manager requestImageDataForAsset:asset options:nil resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
// upload the `imageData`
NSURL *fileURL = info[@"PHImageFileURLKey"];
NSString *filename = [fileURL lastPathComponent];
NSString *mimeType = [self mimeTypeForPath:filename];
NSString *urlString = @"http://192.168.0.10/udazz/2.0/2.2/ios/1.0/actions.php?targ=user&subTarg=post&txtComment=123456&txtType=ff";
NSMutableURLRequest* request= [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]];
[request setHTTPMethod:@"POST"];
NSString *boundary = @"---------------------------14737809831466499882746641449";
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundary];
[request addValue:contentType forHTTPHeaderField: @"Content-Type"];
NSMutableData *postbody = [NSMutableData data];
[postbody appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[postbody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"userfile\"; filename=\"%@\"\r\n", filename] dataUsingEncoding:NSUTF8StringEncoding]];
[postbody appendData:[[NSString stringWithFormat:@"Content-Type: %@\r\n\r\n", mimeType] dataUsingEncoding:NSUTF8StringEncoding]];
[postbody appendData:imageData];
[postbody appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
NSURLSessionTask *task = [[NSURLSession sharedSession] uploadTaskWithRequest:request fromData:postbody completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"Response %@",responseString);
}];
[task resume];
}];
}
}
By the way, my routine for programmatically determining the mime-type (because you really can't just assume the image is a JPEG; it could be a PNG, amongst other types, too) is as follows:
- (NSString *)mimeTypeForPath:(NSString *)path {
// get a mime type for an extension using MobileCoreServices.framework
CFStringRef extension = (__bridge CFStringRef)[path pathExtension];
CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, extension, NULL);
assert(UTI != NULL);
NSString *mimetype = CFBridgingRelease(UTTypeCopyPreferredTagWithClass(UTI, kUTTagClassMIMEType));
assert(mimetype != NULL);
CFRelease(UTI);
return mimetype;
}
If you need to support iOS versions that predate the Photos framework, then use the ALAssetsLibrary
to get the NSData
. If you need example of how to do that (only if you need to support iOS versions before 8.0), let me know.