I'm trying to upload an image by picking it via UIImagePickerController and uploading it to the server. For this I need the actual local path (url) of the image. As I'm targeting iOS 9.0 and above, I'm using the Photos Framework.
I'm able to fetch the filename as well as the url from PHAsset
. I'm also checking if the file is present at this url, but when I'm trying to upload the image I'm not sure if this is the proper url to supply to a php script on the server. The php script requires file name, the actual location on the device as well the file data.
Here is my code:
#import "ViewController.h"
#import <Photos/Photos.h>
#import <MobileCoreServices/MobileCoreServices.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
switch (status) {
case PHAuthorizationStatusAuthorized:
NSLog(@"PHAuthorizationStatusAuthorized");
break;
case PHAuthorizationStatusDenied:
NSLog(@"PHAuthorizationStatusDenied");
break;
case PHAuthorizationStatusNotDetermined:
NSLog(@"PHAuthorizationStatusNotDetermined");
break;
case PHAuthorizationStatusRestricted:
NSLog(@"PHAuthorizationStatusRestricted");
break;
}
}];
NSLog(@"%@",NSHomeDirectory());
}
- (IBAction)fileSelect:(id)sender {
UIAlertController * actionSheet = [UIAlertController alertControllerWithTitle:nil message:@"File oprions:" preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction * camera = [UIAlertAction actionWithTitle:@"Take photo with camera" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
NSLog(@"Camera");
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
// Set source to the camera
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
// Delegate is self
imagePicker.delegate = self;
// Allow editing of image ?
// Show image picker
//[[UINavigationBar appearance] setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
[self presentViewController:imagePicker animated:YES completion:nil];
}];
UIAlertAction * gallery = [UIAlertAction actionWithTitle:@"Choose an existing photo" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
NSLog(@"Gallery");
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
// Set source to the camera
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
// Delegate is self
imagePicker.delegate = self;
// Allow editing of image ?
// Show image picker
//[[UINavigationBar appearance] setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
[self presentViewController:imagePicker animated:YES completion:nil];
}];
UIAlertAction * document = [UIAlertAction actionWithTitle:@"Choose a document" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
NSLog(@"Document");
NSArray *types = @[(NSString*)kUTTypeImage,
(NSString*)kUTTypeSpreadsheet,
(NSString*)kUTTypePresentation,
(NSString*)kUTTypeDatabase,
(NSString*)kUTTypeFolder,
(NSString*)kUTTypeZipArchive,
(NSString*)kUTTypeVideo,
(NSString*)kUTTypePDF,
(NSString*)kUTTypeMovie,
(NSString*)kUTTypeAudio,
(NSString*)kUTTypeMPEG,
(NSString*)kUTTypeMPEG2Video,
(NSString*)kUTTypeMP3,
(NSString*)kUTTypeMPEG4,
(NSString*)kUTTypeMPEG4Audio,
(NSString*)kUTTypeJPEG,
(NSString*)kUTTypePNG,
(NSString*)kUTTypeGIF,
(NSString*)kUTTypeRTFD,
(NSString*)kUTTypeWebArchive,
(NSString*)kUTTypeText,
(NSString*)kUTTypePlainText,
(NSString*)kUTTypeRTF];
//Create a object of document picker view and set the mode to Import
UIDocumentPickerViewController *docPicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:types inMode:UIDocumentPickerModeImport];
//Set the delegate
docPicker.delegate = self;
//present the document picker
[self presentViewController:docPicker animated:YES completion:nil];
}];
UIAlertAction * cancel = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
NSLog(@"Cancelled");
}];
[actionSheet addAction:camera];
[actionSheet addAction:gallery];
[actionSheet addAction:document];
[actionSheet addAction:cancel];
//For iPad a PopOverViewController is needed
UIPopoverPresentationController * popoverController = actionSheet.popoverPresentationController;
actionSheet.modalPresentationStyle = UIModalPresentationPopover;
popoverController.sourceView = self.view;
popoverController.sourceRect = CGRectMake(self.view.bounds.size.width/2, self.view.bounds.size.height/2, 0, 0);
popoverController.permittedArrowDirections = 0;
popoverController.delegate = self;
[self presentViewController:actionSheet animated:true completion:nil];
}
#pragma mark - Image Picker Delegate
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info
{
NSLog(@"Image picked");
NSLog(@"%@",info);
if (picker.sourceType == UIImagePickerControllerSourceTypePhotoLibrary)
{
// NSData * data = UIImageJPEGRepresentation([info valueForKey:@"UIImagePickerControllerOriginalImage"], 0.5);
//
// NSString * path = [NSHomeDirectory() stringByAppendingPathComponent:@"Documents/image.JPEG"];
// [data writeToFile:path atomically:true];
}
else
{
UIImageWriteToSavedPhotosAlbum([info valueForKey:@"UIImagePickerControllerOriginalImage"], nil, nil, nil);
}
UIImageView * imgView = [[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 50, 50)];
imgView.contentMode = UIViewContentModeScaleAspectFit;
imgView.image = [info valueForKey:@"UIImagePickerControllerOriginalImage"];
/* //Works in simulator, iOS 10+, iPhone
NSURL * fileurl = [info valueForKey:@"UIImagePickerControllerImageURL"];
NSMutableString * filepath = [NSMutableString stringWithFormat:@"%@",fileurl];
[filepath replaceOccurrencesOfString:@"file://" withString:@"" options:0 range:NSMakeRange(0, filepath.length)];
*/
NSURL *refURL = [info valueForKey:UIImagePickerControllerReferenceURL];
PHFetchResult *result = [PHAsset fetchAssetsWithALAssetURLs:@[refURL] options:nil];
PHAsset *asset = [result firstObject];
[[PHImageManager defaultManager] requestImageDataForAsset:asset options:nil resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
UIImage* newImage = [UIImage imageWithData:imageData];
imgView.image = newImage;
}];
NSMutableString * __block filepath = nil;
NSString __block *filename = [[result firstObject] filename];
[result enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
PHAsset *asset = (PHAsset *)obj;
[asset requestContentEditingInputWithOptions:nil completionHandler:^(PHContentEditingInput * _Nullable contentEditingInput, NSDictionary * _Nonnull info) {
NSLog(@"URL:%@", contentEditingInput.fullSizeImageURL.absoluteString);
//file:///var/mobile/Media/PhotoData/CPLAssets/group125/0888AEED-48C6-4E6E-93AB-CE99A6E706AF.JPG
NSString* path = [contentEditingInput.fullSizeImageURL.absoluteString substringFromIndex:7];//screw all the crap of file://
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL isExist = [fileManager fileExistsAtPath:path];
if (isExist)
filepath = [path mutableCopy];
else {
NSLog(@"damn");
}
}];
}];
UIAlertController *alertController = [UIAlertController
alertControllerWithTitle:@"UIImagePicker"
message:@"Image picked"
preferredStyle:UIAlertControllerStyleAlert];
[alertController.view addSubview:imgView];
[alertController addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[self uploadImage:imgView.image withPath:filepath andName:filename];// works perfectly if provided with proper filepath
}]];
[self dismissViewControllerAnimated:true completion:nil];
[self presentViewController:alertController animated:YES completion:nil];
}
@end
I only wish to know where am I going wrong. Is file:///var/mobile/Media/PhotoData/CPLAssets/group125/0888AEED-48C6-4E6E-93AB-CE99A6E706AF.JPG the proper filepath?
The PHP script only needs an image in the data form and file name and that you want to give the file. It's just to name a file and you can keep anything that makes sense to your system.
There is no need to give a file path as you already giving the image in the binary form. So you should reimplement your uploadImage: method to only receive data and file name.