I am new to Swift and I am trying to save an image from the gallery of the phone (or the Internet) to my app. I found many tutorials showing how to view the image but not how to save it to my app (I guess to my assets folder) and use it later on. Can someone please pint me to the right direction?
func saveImage (image: UIImage, path: String ) -> Bool{
let pngImageData = UIImagePNGRepresentation(image)
//let jpgImageData = UIImageJPEGRepresentation(image, 1.0) // if you want to save as JPEG
let result = pngImageData!.writeToFile(path, atomically: true)
return result
}
Here is how to use the function later in your code:
saveImage(image, path: imagePath)
However before you can Save or Load anything you have to know the ‘path’ you are going to use.
We’ll need 3 things:
a function to pinpoint the documents directory
a file in the documents directory a function to pinpoint
a variable to store the location ( path ) of the image we want to save
Here is how we are going to do that:
func getDocumentsURL() -> NSURL {
let documentsURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
return documentsURL
}
func fileInDocumentsDirectory(filename: String) -> String {
let fileURL = getDocumentsURL().URLByAppendingPathComponent(filename)
return fileURL.path!
}
// Define the specific path, image name
let imagePath = fileInDocumentsDirectory(myImageName)
Visit for more: http://helpmecodeswift.com/image-manipulation/saving-loading-images
Related
I'm trying to store images inside the app's document folder, so the user can retrieve them at any later time that they want to. This is my code to store them:
func store(_ image: UIImage) -> String {
let imageName = "\(Date().timeIntervalSince1970)"
let imagePath = "\(documentasPath)/\(imageName).png"
let imageData = UIImagePNGRepresentation(image)
fileManager.createFile(atPath: imagePath, contents: imageData, attributes: nil)
return imagePath
}
And this is my code to retrieve the image from the storage:
func retrieveImage(from path: String) -> UIImage? {
guard fileManager.fileExists(atPath: path) else {
return nil
}
return UIImage(contentsOfFile: path)
}
It seems to work fine, except when I rebuild the app from xcode. Then all of my stored images disappear (although all of the paths I stored that pointed to them are still present and correct).
Is this some behavior of the default file manager? And is there a way to avoid this from happening? I want the images to only be deleted either manually or when I uninstall the app.
Thanks
The problem is that you are storing an absolute path. You can't do that, because your app is sandboxed, which means (in part) that the URL of the Documents folder can change. Store just the document name, and each time you want to save to it or write from it, calculate the path to the Documents folder again and append the document name and use that result as your path.
Change to this
func store(_ image: UIImage) -> String {
let imageName = "\(Date().timeIntervalSince1970)"
let documentsUrl = NSURL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0])
var imagePath = documentsUrl.appendingPathComponent("\(imageName).png")
let imageData = UIImagePNGRepresentation(image)
fileManager.createFile(atPath: imagePath, contents: imageData, attributes: nil)
return imagePath
}
func retrieveImage(from path: String) -> UIImage? {
guard fileManager.fileExists(atPath: path) else {
return nil
}
return UIImage(contentsOfFile: path)
}
Here are my functions to save an image.
static func getDirectoryPath() -> String {
let path = (NSSearchPathForDirectoriesInDomains(.picturesDirectory, .userDomainMask, true))[0]
return path
}
static func savePhoto(with path: String, image: UIImage) {
let fM = FileManager.default
let path = getDirectoryPath() + path
let data = UIImageJPEGRepresentation(image, 0.5)
let success = fM.createFile(atPath: path, contents: data, attributes: nil)
print("File creation was \(success)")
}
and then I'm calling it like this
let path = "/SpotCheck_\(spot.name)_Photo\(indx).jpg"
PhotoManager.savePhoto(with: path, image: photo)
When I call create file is returns false every time and the photo is not saved.
EDIT: The problem was the second line needed to be documentDirectory instead of picturesDirectory. As shown below:
let path = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true))[0]
iOS apps run in a sandbox. You can't write to the Pictures folder.
If you want to add a picture to the user's photo library then use PHPhotoLibrary or just UIImageWriteToSavedPhotosAlbum.
If you simply want to save the image within your own app then store the file in the Documents folder.
FYI - when using NSSearchPathForDirectoriesInDomains in iOS, the only useful directories are:
libraryDirectory
documentDirectory
cachesDirectory
applicationSupportDirectory
All the others are only useful in macOS.
In my app I am storing an image in local storage and I am saving the path of that image in my Realm database. And now i have problems with load this image from that path?
Thats how I save path to database:
let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory,nsUserDomainMask, true)
let dirPath = paths.first
let imageURL1 = URL(fileURLWithPath: dirPath!).appendingPathComponent("refuge1.jpg")
let med1 = Meditation()
med1.name = "Refuge"
med1.count = 0
med1.targetAmount = 111111
med1.malasStep = 108
med1.imagePath = imageURL1.path
med1.id = 1
It's straightforward that am trying to get an image from this meditation.imagePath path. I double-checked the path, image is there still am not able to set the image using this path, is there is something that am missing?
In debug mode I see this:
Meditation {
name = Refuge;
count = 0;
targetAmount = 111111;
malasStep = 108;
imagePath = /Users/macbook/Library/Developer/CoreSimulator/Devices/2E25309F-D6A9-41C3-9EF4-67203142172C/data/Containers/Data/Application/F198640B-3C72-4F9C-8173-FB00D3ABEC15/Documents/refuge1.jpg;
id = 1;}
but my variable image still nil in debug mode
// Configure the cell...
cell.nameOfMeditation.text = meditation.name
cell.countOfMeditation.text = String(meditation.count)
let image = UIImage(contentsOfFile: meditation.imagePath)
cell.imageForMeditation.image = image
return cell
I see name of meditation and sound, bot no omg.
It's not advised to save the absolute file path of a file in an iOS app (ie, everything including /Users/macbook/Library/Developer/...), in Realm or anywhere else.
For security reasons, iOS devices rename the UUID folder name between launches. This means that while the folder path was valid at the time it was saved, it won't be at a later date.
Instead, it's recommended to save just the relative path of the file (eg, its location in relation to just the Documents folder. In this case, it would be just /refuge1.jpg) and to then dynamically build the absolute path by requesting the Documents directory path as you need it.
Try this:
// Use these convenience methods if you do a lot of saving and loading
func getDocumentsURL() -> URL {
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
return documentsURL
}
func fileInDocumentsDirectory(_ filename: String) -> String {
let fileURL = getDocumentsURL().appendingPathComponent(filename)
return fileURL.path
}
func saveRefugeOne(image: UIImage) {
// Create a file name, and then save the path in your documents with that name
let imageFileName:String = "refuge1.jpg"
let imagePath = fileInDocumentsDirectory(imageFileName!)
saveImage(image, path: imagePath)
}
func loadRefugeOne() -> UIImage? {
// Get the image back
let imageName:String = "refuge1.jpg" // Or whatever name you saved
let imagePath = fileInDocumentsDirectory(imageName)
if let loadedImage = self.loadImageFromPath(imagePath) {
return loadedImage
} else {
print("Couldn't Load: \(imageName)")
return nil
}
}
// This will be your method to save image
func saveImage(_ image: UIImage, path: String ) {
//If you want PNG use this let pngImageData = UIImagePNGRepresentation(image)
// But since you mentioned JPEG:
if let jpgData = UIImageJPEGRepresentation(image, 1.0) {
try? jpgData.write(to: URL(fileURLWithPath: path), options: [.atomic])
}
}
// This will load image from saved path. Make sure to store the path
// somewhere. This makes it easier to save images locally. You can
// save the image in the documents directory, and then just save the
// path in CoreData or something similar.
func loadImageFromPath(_ path: String) -> UIImage? {
let image = UIImage(contentsOfFile: path)
if image == nil {
print("couldn't find image at path: \(path)")
}
return image
}
Hopefully this will help. It's the method I always use, and it works like a charm when I follow my own steps right ;-)
I am writing an iOS app(in Swift) that includes and options to save pictures to a safe location. Once a picture is chosen(from Camera or Saved Images), it is written to the File and the file location is saved in NSUserDefaults. I am able to re-access the image, when I relaunch the app after killing it. But when I run the app from Xcode again(after recompiling), the image is lost from the Image path.
Attaching the saving and loading functions below
func getDocumentsURL() -> NSURL {
let documentsURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
return documentsURL
}
func fileInDocumentsDirectory(filename: String) -> String {
let fileURL = getDocumentsURL().URLByAppendingPathComponent(filename)
return fileURL.path!
}
func saveImage (image: UIImage, path: String ) -> Bool{
// let pngImageData = UIImagePNGRepresentation(image)
let jpgImageData = UIImageJPEGRepresentation(image, 1.0) // if you want to save as JPEG
let result = jpgImageData!.writeToFile(path, atomically: true)
return result
}
func loadImageFromPath(path: String) -> UIImage? {
let image = UIImage(contentsOfFile: path)
if image == nil {
print("missing image at: \(path)")
}
print("Loading image from path: \(path)") // this is just for you to see the path in case you want to go to the directory, using Finder.
return image
}
What could be causing this?
The Document Directory path is different after each run.
Save to NSUserDefaults only the relative path from the Documents Directory (what you append to the getDocumentsURL() NSURL).
So in your case, you don't specify a subdirectory in your apps Document Directory, so the only thing you need on the next run, is the file name that you saved.
After that, you can retrieve the saved image with:
func loadImageNamed(name: String) -> UIImage? {
let imagePath = fileInDocumentsDirectory(name)
let image = UIImage(contentsOfFile: imagePath)
if image == nil {
print("missing image at: \(path)")
}
print("Loading image from path: \(path)") // this is just for you to see the path in case you want to go to the directory, using Finder.
return image
}
When reinstalling the app, the documents directory will change. You shouldn't save the full path, but a relative path from the documents directory.
I am having the user take a photo with UIImagePickerController and I need it to be saved to the app so that it can be displayed when they need to see it later. How can I accomplish this?
I have heard NSUserDefaults would be a mistake. All I need to save is a single image, never more.
Here is the function to save your image to document folder
func saveImage (image: UIImage, path: String ) -> Bool{
let pngImageData = UIImagePNGRepresentation(image)
//let jpgImageData = UIImageJPEGRepresentation(image, 1.0) // if you want to save as JPEG
let result = pngImageData.writeToFile(path, atomically: true)
return result
}
Here is the function to get your document directory path with image name
func fileInDocumentsDirectory(filename: String) -> String {
let documentsFolderPath = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0] as! String
return documentsFolderPath.stringByAppendingPathComponent(filename)
}
Here is an example of how to use your image path
let imagePath = fileInDocumentsDirectory(myImageName)
And here is how you save your image to that folder
saveImage(image, path: imagePath)
Now the last part is to get your image, so use this function to get your image
func loadImageFromPath(path: String) -> UIImage? {
let image = UIImage(contentsOfFile: path)
if image == nil {
println("Image not available at: (path)")
}
return image
}
And here is how you use the above function
image = loadImageFromPath(imagePath)
imageView.image = image
Hope this helps you