1

I'm new to objective-c. I need the image picked in the first function to be uploaded in the second one:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {

    UIImage *chosenImage = info[UIImagePickerControllerEditedImage];
    self.imageView.image = chosenImage;

    [picker dismissViewControllerAnimated:YES completion:NULL];

}

- (IBAction)uploadPic:(UIButton *)sender {
    // COnvert Image to NSData
    NSData *dataImage = UIImageJPEGRepresentation([UIImage imageNamed:@"yourImage"], 1.0f);

//added after editing

    // set your URL Where to Upload Image
    NSString *urlString = @"http://url";

    // set your Image Name
    NSString *filename = @"uploaded_file";

    // Create 'POST' MutableRequest with Data and Other Image Attachment.
    NSMutableURLRequest* request= [[NSMutableURLRequest alloc] init];
    [request setURL:[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=\"%@.jpg\"\r\n", filename] dataUsingEncoding:NSUTF8StringEncoding]];
    [postbody appendData:[[NSString stringWithString:@"Content-Type: application/octet-stream\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
    [postbody appendData:[NSData dataWithData:dataImage]];
    [postbody appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [request setHTTPBody:postbody];

    // Get Response of Your Request
    NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
    NSString *responseString = [[NSString alloc] initWithData:returnData encoding:NSUTF8StringEncoding];
    NSLog(@"Response  %@",responseString);
//end editing
    }

The added code, in btween editing comments, is the one that I use to upload the image

3 Answers3

2

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.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • I'm new to objective-c and, to be honest, I don't know where to put that code. –  Sep 29 '15 at 17:04
  • @MarianoPelizzari - No worries. I expanded my code snippet to make it more clear. – Rob Sep 29 '15 at 17:38
  • Thanks. Now, what part of my code goes in `//upload the imageData here`? –  Sep 29 '15 at 17:55
  • @MarianoPelizzari - Sorry, I assumed you already had code to upload the image. Unfortunately, the answer depends entirely upon how your web service needs the image upload request to be formed. Many web services would expect a `POST` request with a `Content-Type` of `multipart/form-data` (and a tool like [AFNetworking](https://github.com/AFNetworking/AFNetworking) greatly simplifies the process of creating this complicated type of request), but you need to confirm that because there are a plethora of alternatives. You also need details like the URL, the field name, etc. – Rob Sep 29 '15 at 18:01
  • I added code to my question, it is between `//added after editing` and `//end editing`. As the code shows I need to upload and image. Could you tell me if I can use part of that code (or all of it) in your code, where you say `//upload the imageData here` –  Sep 29 '15 at 18:29
  • @MarianoPelizzari - Yes, just put your upload code there. Having said that, if you're going to do this yourself, you really should use `NSURLSession` method `uploadTaskWithRequest:fromData:completion:` rather than `NSURLConnection` method `sendSynchronousRequest` because (a) you should never do synchronous network requests; and (b) `NSURLConnection` is now deprecated as of iOS 9, anyway. In my example code, I used AFNetworking (though you can get away with your code to manually build the request and using `NSURLSession` if you prefer). – Rob Sep 29 '15 at 18:40
  • FWIW, this `"PHImageFileURLKey"` technique to get the file name doesn't work in iOS 13 anymore. See https://stackoverflow.com/q/57202965/1271826. – Rob Jun 17 '20 at 18:12
0

You are assigning the picked image to your imageView. So you can access it using the image property of that UIImageView.

You can access like:

- (IBAction)uploadPic:(UIButton *)sender
{
    NSData *dataImage = UIImageJPEGRepresentation(self.imageView.image, 1.0f);
    // Do your stuff here
}
Midhun MP
  • 103,496
  • 31
  • 153
  • 200
0

I have done your requirement in my demo project. I have picked image using UIIMagePicker delegate function

@interface ViewController ()
{
    UIImage *chooseImage;
}


- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    NSDate *time = [NSDate date];
    NSDateFormatter* df = [NSDateFormatter new];
    [df setDateFormat:@"ddMMyyyy-hhmmss"];
    NSString *timeString = [df stringFromDate:time];
   NSString *fileName = [NSString stringWithFormat:@"%@", timeString];
    
    chooseImage = info[UIImagePickerControllerEditedImage];
    

    
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    documentsDirectoryPath = [paths objectAtIndex:0];
    
    NSLog(@"View Controller Path:%@",documentsDirectoryPath);
    
    
    savedImagePath = [documentsDirectoryPath
                      stringByAppendingPathComponent:[NSString stringWithFormat: @"%@-%d.png", fileName, num]];
    
    num += 1;
    
    NSData *imageData = UIImagePNGRepresentation(chooseImage);
    [imageData writeToFile:savedImagePath atomically:NO];
    
    
    [picker dismissViewControllerAnimated:YES completion:NULL];
    [self displayImage];
    
   }

-(void)displayImage
{
    self.imageView.image = chooseImage;
}

and from that method i have called another function->displayImage, which i am using for displaying image in UIImageView. Here below is code.

Karishma
  • 11
  • 1
  • 3