Take, save and retrieve a photo — iOS #13

Another useful tutorial today — how to take a photo using the camera, save it and then retrieve it later.

(*** UPDATE! Check out my latest blogs — each with a different view of the future! https://medium.com/@LeMarquisOfAndy/what-your-day-will-be-like-in-2039-mostly-optimistic-version-553b1b6f8202

and

https://medium.com/@LeMarquisOfAndy/what-your-day-will-be-like-in-2039-mostly-pessimistic-version-41a6c31ee506 ****)

Let’s dive straight in — open a new project in Xcode and in the Storyboard drag out an ImageView onto the View Controller — this will display the photo after we take it — and resize / reposition it like this:

Now add a few Buttons like so:

Yes, I know that those colours are awful! No time today to make it look amazing! Now, we’ll add Outlet variables and Actions to these — open the Assistant Editor (via the little button with the two circles) to see the code beside the Storyboard:

Now Control-drag from the ImageView and call it something like … “imageView”:

and then do the same for each Button, remembering to select Action and not Outlet for those:

When all four are done they should look like:

Let’s add another View Controller, for the “Gallery” — where we’ll show the saved photo. I add a Label and set it to “Gallery” aswell, just because we can!

Add a new code file for this new View Controller — right-click on the main project folder and select New file:

pick Cocoa Touch Class

give it a Class name like GalleryViewController, making sure the Subclass is UIViewController:

which will add a new file:

Now in the Storyboard, click on the little yellow button on the top of our new View Controller and in the Identity Inspector on the right, enter GalleryViewController (or whatever name you called the file) into the Class field:

Ok, the View Controller and the code file are now linked. Add another ImageView to this one, and Control-drag to the GalleryViewController file to create an Outlet, again called “imageView”. It’s cool to call variables the same name if they’re in different Classes:

Now, add a Segue between the View Controllers, by Control-dragging from one (from the yellow button) to the other, choosing Present Modally:

and give the resultant Segue and Identifier of “gallerySegue” in the Attributes Inspector:

Ok, that should be all the Storyboard work for now.

Open the ViewController.swift file and we’ll add code to take photos! The way is works is using a new Class / Object called ImagePickerController. This is a special type of View Controller that appears on screen with the camera open, allowing you to take a photo.

To use it, first add the code below in bold at the top of the file:

class ViewController: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate {

This is saying that we’re going to implement the UIImagePickerController delegate and also the UINavigationController delegate. Remember delegates have handy pre-defined functions that we can use / change to do some cool things?

Now, add a new variable of Class UIImagePickerController:

var imagePickerController : UIImagePickerController!

and in onPhotoButton add this:

@IBAction func onPhotoButton(_ sender: Any) {   imagePickerController = UIImagePickerController()   imagePickerController.delegate = self   imagePickerController.sourceType = .camera   present(imagePickerController, animated: true, completion: nil)}

This line creates an instance of UIImagePickerController:

imagePickerController = UIImagePickerController()

This line assigns the delegate:

imagePickerController.delegate = self

This line specifies to use the camera:

imagePickerController.sourceType = .camera

and this line actually starts up the UIImagePickerController:

present(imagePickerController, animated: true, completion: nil)

Now add this delegate function:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {}

Note that the function is empty — we’ll be adding code to it. It is called after you take a photo — so lets add this code:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {   imagePickerController.dismiss(animated: true, completion: nil)   imageView.image = info[UIImagePickerControllerOriginalImage] as? UIImage}

The first line “dismisses” the UIImagePickerViewController i.e. removes the camera screen and the second line stores in our imageView variable the image that was taken by the camera.

Getting User Permission

Ok, before we run the app and see how this code works, we need to add something to the app that tells it to ask for the user’s permission to use the camera.

Click on the info.plist on the left-hand panel:

This file contains a lot of different app settings and their values. We’re going to add another one. Click on the last line:

and then on the little plus symbol:

and you’ll see this:

Scroll down to Privacy — Camera Usage Description:

and then double-click on the Value column and enter a reason for why you’re requesting access to the camera; the user will see this:

Ok, run this now on your phone (it won’t work in the Simulator as that doesn’t have a camera!).

You’ll see this:

Hit the Take photo button and you should see this:

It’s asking for permission, using the message you just put into the Info.plist! Hit OK and see the camera open … looking at one of my classic Sega Megadrive games!

Take the photo and you’ll have the choice to Retake or Use Photo:

Hit Use Photo and you should see:

Amazing — the image is now showing in our imageView object on screen!

Saving an image

Now let’s save it to the app, so we can use it again later. We save it to the Documents Directory, which is part of your app where you can save .. things like images!

Add this function to the ViewController.swift file:

func saveImage(imageName: String){
//create an instance of the FileManager
let fileManager = FileManager.default
//get the image path
let imagePath = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent(imageName)
//get the image we took with camera
let image = imageView.image!
//get the PNG data for this image
let data = UIImagePNGRepresentation(image)
//store it in the document directory fileManager.createFile(atPath: imagePath as String, contents: data, attributes: nil)}

This function takes in the name of an image as a parameter:

func saveImage(imageName: String){

so when we retrieve the image later, we’ll use the same image name.

let fileManager = FileManager.default

creates an instance of the FileManager — how we access the Documents Directory.

let imagePath = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent(imageName)

basically get the “path” that we’ll save the image to. Think of this like the file-paths you may use in Windows or on a Mac — the “address” of the file.

Chuck in a:

print(imagePath)

if you want to see what it looks like:

let image = imageView.image!

gets the actual image that we took with the camera and stored in the imageView variable.

let data = UIImagePNGRepresentation(image)

gets the PNG data version of the file, which is how its stored.

fileManager.createFile(atPath: imagePath as String, contents: data, attributes: nil)

then actually stores it in the Document Directory.

We then call this function in our onSaveButton function:

Note I’ve given it a name of “test.png”, I could have chosen anything.

Retrieve image

Now we want to retrieve the image on our other Gallery View Controller — so first add this to the onGalleryButton function:

performSegue(withIdentifier: “gallerySegue”, sender: self)

i.e.

so when the user hits that Button, the Gallery View Controller will open.

Now open the GalleryViewController.swift file and include this function:

func getImage(imageName: String){   let fileManager = FileManager.default   let imagePath = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent(imageName)   if fileManager.fileExists(atPath: imagePath){
imageView.image = UIImage(contentsOfFile: imagePath)
}else{
print("Panic! No Image!")
}
}

This creates an instance of the FileManager again:

let fileManager = FileManager.default

This gets the path again:

let imagePath = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent(imageName)

This then checks the path for the image, if it exists it sets the imageView on the Gallery View Controller to that image:

if fileManager.fileExists(atPath: imagePath){
imageView.image = UIImage(contentsOfFile: imagePath)
}else{
print("Panic! No Image!")
}

We call this function in the viewDidLoad function:

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.getImage(imageName: "test.png")}

Ok, let’s run all that — run the app and take a photo, this time of another 80s classic game! It’s Golden Axe 2!!

Now hit Use Photo:

Hit Save photo, then hit Go to gallery:

It’s pulled that image from the Document Directory. If you shut the app down, then open it and go straight to the Gallery, you’ll see it gets pulled back and displayed also.

OK! So we now know how to take an image, save it and retrieve it! There’s way more things we can do to images — write on them, apply filters etc and also do things like changing their orientation but we’ll look at all that another day!

If this was useful, please hit the little heart button below! or go nuts and share! Andy

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Andy O'Sullivan

Andy O'Sullivan

Creator of Boxapopa, the iOS game for young kids with zero ads, just fun! https://apps.apple.com/ie/app/boxapopa/id1550536188