Save UIImage array to disk - swift

I have a UIImage array that I'm trying to save to disk (documents directory). I've converted it to Data so it can be saved but I can't figure out the correct/best way to save that [Data] to disk.
(arrayData as NSArray).write(to: filename, atomically: false) doesn't seem right or there seems like there is some better way.
Code so far:
// Get the new UIImage
let image4 = chartView.snapShot()
// Make UIImage into Data to save
let data = UIImagePNGRepresentation(image4!)
// Add Data image to Data Array
arrayData.append(data!)
// Get Disk/Folder
let filename = getDocumentsDirectory().appendingPathComponent("images")
// This is how I'd Write Data image to Disk
// try? data?.write(to: filename)
// TODO: Write array Data images to Disk
(arrayData as NSArray).write(to: filename, atomically: false)

To save your images to the document directory, you could start by creating a function to save your image as follows. The function handles creating the image name for you and returns it.
func saveImage(image: UIImage) -> String {
let imageData = NSData(data: UIImagePNGRepresentation(image)!)
let paths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
let docs = paths[0] as NSString
let uuid = NSUUID().uuidString + ".png"
let fullPath = docs.appendingPathComponent(uuid)
_ = imageData.write(toFile: fullPath, atomically: true)
return uuid
}
Now since you want to save an array of images, you can simply loop and call the saveImage function:
for image in images {
saveImage(image: image)
}
If you prefer to name those images yourself, you can amend the first function to the following:
func saveImage(image: UIImage, withName name: String) {
let imageData = NSData(data: UIImagePNGRepresentation(image)!)
let paths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
let docs = paths[0] as NSString
let name = name
let fullPath = docs.appendingPathComponent(name)
_ = imageData.write(toFile: fullPath, atomically: true)
}
When you save an image as a UIImagePNGRepresentation as you are trying to do, please note that is does not save orientation for you. This means that when you attempt to retrieve the image, it might be titled to the left. You will need to redraw your image to make sure it has the right orientation as this post will explain how to save png correctly. However, if you save your image with UIImageJPEGRepresentation you will not have to worry about all that and you can simply save your image without any extra effort.
EDITED TO GIVE ARRAY OF IMAGES
To retrieve the images you have saved, you can use the following function where you pass an array of the image names and you get an array back:
func getImage(imageNames: [String]) -> [UIImage] {
var savedImages: [UIImage] = [UIImage]()
for imageName in imageNames {
if let imagePath = getFilePath(fileName: imageName) {
savedImage.append(UIImage(contentsOfFile: imagePath))
}
}
return savedImages
}
Which relies on this function to work:
func getFilePath(fileName: String) -> String? {
let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
var filePath: String?
let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
if paths.count > 0 {
let dirPath = paths[0] as NSString
filePath = dirPath.appendingPathComponent(fileName)
}
else {
filePath = nil
}
return filePath
}

You can below code to stored image into local.
let fileManager = NSFileManager.defaultManager()
let paths = (NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString).stringByAppendingPathComponent("ImageName.png")
let image = YOUR_IMAGE_TO_STORE.
let imageData = UIImageJPEGRepresentation(image!, 0.5)
fileManager.createFileAtPath(paths as String, contents: imageData, attributes: nil)

Related

loadImageFromDisk - function modyfication swift

im using the below code to load a downloaded image from disk, when the file exists I can load it as image. If it doesn't image returns as nil.
How could I modify the code to replace return nil with loading a placeholder image from my asset folder called default.png. So instead of returning nil, there is always an image return, either downloaded one that's trying to load or if it doesn't exist, my own asset image.
func loadImageFromDiskWith(fileName: String) -> UIImage? {
let documentDirectory = FileManager.SearchPathDirectory.documentDirectory
let userDomainMask = FileManager.SearchPathDomainMask.userDomainMask
let paths = NSSearchPathForDirectoriesInDomains(documentDirectory, userDomainMask, true)
if let dirPath = paths.first {
let imageUrl = URL(fileURLWithPath: dirPath).appendingPathComponent(fileName)
let image = UIImage(contentsOfFile: imageUrl.path)
return image
}
return nil
}
You can do as below -
func loadImageFromDiskWith(fileName: String) -> UIImage {
let documentDirectory = FileManager.SearchPathDirectory.documentDirectory
let userDomainMask = FileManager.SearchPathDomainMask.userDomainMask
let paths = NSSearchPathForDirectoriesInDomains(documentDirectory, userDomainMask, true)
var image = UIImage(named: "default") // Make sure there must be "default.png" in your main bundle.
if let dirPath = paths.first {
let imageUrl = URL(fileURLWithPath: dirPath).appendingPathComponent(fileName)
if FileManager.default.fileExists(atPath: imageUrl.path) { //Check here for file existence. It won't crash.
image = UIImage(contentsOfFile: imageUrl.path)
}
}
return image
}

Getting EXC_BAD_ACCESS when using UIImage(contentsOfFile: )

I am currently using UIImage(contentsOfFile: path) if a function to return image of a file path but it is getting me EXC_BAD_ACCESS.
I have searched a lot and found some things about auto releasing and solutions in Objective-C but I couldn't find anything for Swift. What should I do in Swift?
Check for nil:
let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
if let dirPath = paths.first {
let imageURL = URL(fileURLWithPath: dirPath).appendingPathComponent("Image2.png")
let image = UIImage(contentsOfFile: imageURL.path)
// Do whatever you want with the image
}

How To Add A Image In CoreData And How to Save The Image In CoreData [duplicate]

This question already has answers here:
Saving Picked Image to CoreData
(2 answers)
Closed 4 years ago.
How to add an image in core data? The image type what that I have selected. And how to save the core data image. How can I add a image?
Step 1:- Save the image in Document Directory
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
let path = try! FileManager.default.url(for: FileManager.SearchPathDirectory.documentDirectory, in: FileManager.SearchPathDomainMask.userDomainMask, appropriateFor: nil, create: false)
let newPath = path.appendingPathComponent("image.jpg") //Possibly you Can pass the dynamic name here
// Save this name in core Data using you code as a String.
let jpgImageData = UIImageJPEGRepresentation(image, 1.0)
do {
try jpgImageData!.write(to: newPath)
} catch {
print(error)
}
}}
Step:-2: Fetch the Image back from the Document Directory and display index path row wise in table view cell.
let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
if let dirPath = paths.first
{
let imageURL = URL(fileURLWithPath: dirPath).appendingPathComponent("image.png") //Pass the image name fetched from core data here
let image = UIImage(contentsOfFile: imageURL.path)
cell.imageView.image = image
}
This is simple and More convenient Method

Issue setting UIImageView from local image in documents directory

I am trying to load images that I have downloaded using Alamofire to the documents directory. I store the filenames in a Realm database. Once it is time to display the image I take the path to the documents directory and append the filename. This path doesn't seem to work for building a UIImage though.
if let name = playlist.RLMsongs[indexPath.row].name, let imageURL = playlist.RLMsongs[indexPath.row].album?.image?.getImageURL(.SmallImage), let fileName = playlist.RLMsongs[indexPath.row].album?.image?.smallLocalFileName {
cell.songName.text = name
let range = imageURL.rangeOfString("http")
if let theRange = range where theRange.startIndex == imageURL.startIndex { // imageURL starts with "http" (remote url)
cell.albumImage.sd_setImageWithURL(NSURL(string: imageURL), placeholderImage: UIColor.imageFromColor(UIColor.grayColor())) {
_ in
cell.albumImage.fadeIn(completion: nil)
}
} else {
cell.albumImage.image = UIImage(named: fileName) // images still do not load
// tried this first -> cell.albumImage.sd_setImageWithURL(NSURL(fileURLWithPath: imageURL), placeholderImage: UIColor.imageFromColor(UIColor.grayColor()))
}
}
Here is the bit that builds the path (imageURL above):
let documentsDir = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
let path = documentsDir.URLByAppendingPathComponent(localFile).path
return path
As per TiM's recommendation I checked the value of imageURL on a breakpoint and it looks just fine:
imageURL: "/Users/danielnall/Library/Developer/CoreSimulator/Devices/0B8D64B5-9593-4F86-BBD3-E408682C5C0F/data/Containers/Data/Application/011E4805-40EB-4221-9D7D-1C1D64660186/Documents/75.9226ecd6893cb01a306c974d9d8ffd62803109c1.png"
This is the full path on the simulator and is only missing the file schema (file://) which for the use of NSURL fileURLWithPath should be just fine I think.
If you already have the PNG file in Documents then all you need to do is this.
(Assuming that cell.albumImage is UIImageView)
let imageFileName = "75.9226ecd6893cb01a306c974d9d8ffd62803109c1.png"
cell.albumImage.image = UIImage(named: imageFileName)
Check if file exists:
func fileExists(filePath: String) -> Bool {
let filemanager = NSFileManager.defaultManager()
if filemanager.fileExistsAtPath(filePath) {
return true
}
return false
}
I ended up finding the solution to the problem which was unrelated to the direction of this question. Turned out that the issue was in my override of the prepareForReuse method in my UITableViewCell class. Thank you for everyone's suggestions though.

How do I save and read an image to my temp folder when quitting and loading my app

I want to save and read a UIImage to my temp folder when my app closes and then load and delete it when the app loads. How do I accomplish this. Please help.
These methods allow you to save and retrieve an image from the documents directory on the iphone
+ (void)saveImage:(UIImage *)image withName:(NSString *)name {
NSData *data = UIImageJPEGRepresentation(image, 1.0);
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:name];
[fileManager createFileAtPath:fullPath contents:data attributes:nil];
}
+ (UIImage *)loadImage:(NSString *)name {
NSString *fullPath = [documentsDirectory stringByAppendingPathComponent:name];
UIImage *img = [UIImage imageWithContentsOfFile:fullPath];
return img;
}
Swift 3 xCode 8.2
Documents directory obtaining:
func getDocumentDirectoryPath() -> NSString {
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let documentsDirectory = paths[0]
return documentsDirectory as NSString
}
Saving:
func saveImageToDocumentsDirectory(image: UIImage, withName: String) -> String? {
if let data = UIImagePNGRepresentation(image) {
let dirPath = getDocumentDirectoryPath()
let imageFileUrl = URL(fileURLWithPath: dirPath.appendingPathComponent(withName) as String)
do {
try data.write(to: imageFileUrl)
print("Successfully saved image at path: \(imageFileUrl)")
return imageFileUrl.absoluteString
} catch {
print("Error saving image: \(error)")
}
}
return nil
}
Loading:
func loadImageFromDocumentsDirectory(imageName: String) -> UIImage? {
let tempDirPath = getDocumentDirectoryPath()
let imageFilePath = tempDirPath.appendingPathComponent(imageName)
return UIImage(contentsOfFile:imageFilePath)
}
Example:
//TODO: pass your image to the actual method call here:
let pathToSavedImage = saveImageToDocumentsDirectory(image: imageToSave, withName: "imageName.png")
if (pathToSavedImage == nil) {
print("Failed to save image")
}
let image = loadImageFromDocumentsDirectory(imageName: "imageName.png")
if image == nil {
print ("Failed to load image")
}
Swift 4 implementation:
// saves an image, if save is successful, returns its URL on local storage, otherwise returns nil
func saveImage(_ image: UIImage, name: String) -> URL? {
guard let imageData = image.jpegData(compressionQuality: 1) else {
return nil
}
do {
let imageURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent(name)
try imageData.write(to: imageURL)
return imageURL
} catch {
return nil
}
}
// returns an image if there is one with the given name, otherwise returns nil
func loadImage(withName name: String) -> UIImage? {
let imageURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent(name)
return UIImage(contentsOfFile: imageURL.path)
}
Usage example (assuming we have an image):
let image = UIImage(named: "milan")
let url = saveImage(image, name: "savedMilan.jpg")
print(">>> URL of saved image: \(url)")
let reloadedImage = loadImage(withName: "savedMilan.jpg")
print(">>> Reloaded image: \(reloadedImage)")
In addition, you don't ever want to save anything into the actual tmp directory that you want around after the app shuts down. The tmp directory can be purged by the system. By definition, it exist solely to hold minor files needed only when the app is running.
Files you want to preserve should always go into the documents directory.
Tested Code for swift
//to get document directory path
func getDocumentDirectoryPath() -> NSString {
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
let documentsDirectory = paths[0]
return documentsDirectory
}
Call using
if let data = UIImagePNGRepresentation(img) {
let filename = self.getDocumentDirectoryPath().stringByAppendingPathComponent("resizeImage.png")
data.writeToFile(filename, atomically: true)
}
The Untested Swift tweak for selected answer:
class func saveImage(image: UIImage, withName name: String) {
let documentsDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as! String
var data: NSData = UIImageJPEGRepresentation(image, 1.0)!
var fileManager: NSFileManager = NSFileManager.defaultManager()
let fullPath = NSURL(fileURLWithPath: NSTemporaryDirectory()).URLByAppendingPathComponent(name)
fileManager.createFileAtPath(fullPath.absoluteString, contents: data, attributes: nil)
}
class func loadImage(name: String) -> UIImage {
var fullPath: String = NSURL(fileURLWithPath: NSTemporaryDirectory()).URLByAppendingPathComponent(name).absoluteString
var img:UIImage = UIImage(contentsOfFile: fullPath)!
return img
}