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:

Add purpose string

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:

Privacy - Photo Library Usage Description

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.

Advertisements