Select an image from the gallery using the Image Picker
The first thing we need to do is access the Image Gallery from inside our app so that we can select an image.
In order to do that we will use the UIImagePickerController class. This component will allow us to navigate through the Image Gallery and select and image. We will use a delegate to detect when the user has finished the selection process, and obtain the selected image.
1. Open the UIImagePickerController
We can, for example, create a button that when clicked will open the UIImagePickerController like this:
@IBAction func openImageGallery(_ sender: UIBarButtonItem) { let myPickerController = UIImagePickerController() myPickerController.delegate = self; myPickerController.sourceType = UIImagePickerControllerSourceType.photoLibrary self.present(myPickerController, animated: true, completion: nil) }
Notice the line myPickerController.delegate = self; where we have established our class as the delegate for our myPickerController UIImagePickerController; this brings us up to the next point: adopting, and implementing the protocols.
2. Adopt the delegates methods
First we need to adopt the following delegates: UIImagePickerControllerDelegate, and UINavigationControllerDelegate, and implement the function didFinishPickingMediaWithInfo
Extension MyViewController: UIImagePickerControllerDelegate,UINavigationControllerDelegate { func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) { let image_data = info[UIImagePickerControllerOriginalImage] as? UIImage let imageData:Data = UIImagePNGRepresentation(image_data)! let imageStr = imageData.base64EncodedString() self.dismiss(animated: true, completion: nil) } }
The function above will be called when the user has selected and image. We will use it to recover the image selected by the user:
let image_data = info[UIImagePickerControllerOriginalImage] as? UIImage
We process the image (more on that later), and dismiss the picker.
3. Add a purpose string to Info.plist
If we try to run the code above as it is, the application will crash. If we examine the console we will see the following error message:
This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app’s Info.plist must contain an NSPhotoLibraryUsageDescription key with a string value explaining
To get rid of that error we must do as the message says and add a descriptive string to our app’s Info.plist:
Since we are accessing the device image gallery we must use the Privacy- photo Library Usage Description key, and as a description I added the text “Used to access the Image Gallery”.
Notice that the above description will be displayed to the user the first time he access the functionality:
The user can accept or deny the access to the Photo Gallery: if it denies it the picker will not pop up and the user will not be able to select an image, but at least the application will not crash 🙂
If you want to read more about purpose strings you can check this wonderful post at useyourloaf.com that describes in detail how purpose strings work (in short is an Apple privacy feature that forces you to ask user consent before accessing his private data)
Uploading the image to the server: using multipart data
We got our image in the variable image_data
let image_data = info[UIImagePickerControllerOriginalImage] as? UIImage
So we can send it to the server via REST, as we would do with any other kind of data. We might do it using a plain URLRequest ( or using a networking library like Alamofire), and as content-type we are going to use multipart data.
The content type multipart is used when we want to send mixed type of data; a typical example would be an email where we can send text, and images or files as attachments.
Here is an example of how our JSON could look like:
"Body": { "content": [ { "contentType":"multipart\/mixed; Boundary=\"0__=0A44F337DFD4CB448f9e8a93df938690918c0ABBF337DFD4CB36\"" }, { "contentType":"text\/plain; charset=US-ASCII", "contentTransferEncoding":"quoted-printable", "boundary":"--2__=0A44F337DFD4CB448f9e8a93df938690918c0ABBF337DFD4CB36", "data":"\r\nA text here.\r\nAttachment: (See attached file: image.png)\r\n" }, { "contentType":"image\/png; name=\"SomeImage.png\"", "contentID":"<2__=0AFAF335GFD4CB368f9e8a54df93869091@local>", "contentTransferEncoding":"base64", "boundary":"--1__=0A44F337DFD4CB448f9e8a93df938690918c0ABBF337DFD4CB36", "data":"R0lGODlhDAAOALMAAAAAAP\/\/\/7q6w7m5wrW1vf7+\/u\/v7+Hh4dLS0dasdasdKysqKiooCAgP\/\/\r\n\/wAAACH5BAEAAA4ALAAAAAcAAARCdsvsOuEqudasdOuEquzjsBJNuraOuEqu\/Z4zPV6\r\nBLzcOALMAAAABRCFJyfPEKIiwWqsXAiAVFqKiofPEKjFb1CcCADs=\r\n\r\n", "contentDisposition":"inline; filename=\"SomeImage.png\"" } ], "type":"multipart" }
We see that the image is send encoded as base64 so we need to take the UIImage that we have in image_data variable, and encode it accordingly. And that is what we do in the following lines:
let imageData:Data = UIImagePNGRepresentation(image_data)! let imageStr = imageData.base64EncodedString()
Now that we have recovered the image selected by the user, and we have encoded as a base64 string we can send it to the server in a JSON following the structure described above (remember to configure ATP if you are sending your data over http, instead of using https)
Hope it helps! If you found this post of use, you can subscribe to my blog (click at the follow button at the bottom) so you can be notified of new posts.
December 6, 2017 at 3:00 pm
It is a good solution to have a little more control in the transfer of files, the problem is in the increase of bytes, for example:
An image whose normal weight is 391KB using the function .base64EncodedString () can then have a weight of 521KB.
LikeLike
December 6, 2017 at 6:45 pm
Hello Angel,
Thanks for your input. As you correctly pointed out whenever we use a base 64 encoding we are going to face a increase in the size of the file.
In a real life usage we could mitigate the problem by scaling or/and compressing the image to reduce its original size before we send it to the server. What do you think?
LikeLike
April 1, 2018 at 12:40 am
Thank you man.. I had been thinking the best and easiest way to post images to my DB… and you really helped.. Thank you
LikeLiked by 1 person
April 1, 2018 at 6:04 pm
Thank you, I am glad it was of help 🙂
LikeLike
January 7, 2019 at 7:34 pm
Reblogged this on Tech Reblogs.
LikeLike
January 7, 2019 at 7:49 pm
Thank you for reblogging 🙂
LikeLike