Saving image and then loading it in Swift (iOS)

70,404

Solution 1

This function will save an image in the documents folder:

func saveImage(image: UIImage) -> Bool {
    guard let data = UIImageJPEGRepresentation(image, 1) ?? UIImagePNGRepresentation(image) else {
        return false
    }
    guard let directory = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) as NSURL else {
        return false
    }
    do {
        try data.write(to: directory.appendingPathComponent("fileName.png")!)
        return true
    } catch {   
        print(error.localizedDescription)
        return false
    }
}

To use:

let success = saveImage(image: UIImage(named: "image.png")!)

This function will get that image:

func getSavedImage(named: String) -> UIImage? {
    if let dir = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) {
        return UIImage(contentsOfFile: URL(fileURLWithPath: dir.absoluteString).appendingPathComponent(named).path)
    }
    return nil
}

To use:

if let image = getSavedImage(named: "fileName") {
    // do something with image
}

Solution 2

iOS 13+ Swift 5.1

iOS 12 introduced some API Changes.

func saveImage(imageName: String, image: UIImage) {


 guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }

    let fileName = imageName
    let fileURL = documentsDirectory.appendingPathComponent(fileName)
    guard let data = image.jpegData(compressionQuality: 1) else { return }

    //Checks if file exists, removes it if so.
    if FileManager.default.fileExists(atPath: fileURL.path) {
        do {
            try FileManager.default.removeItem(atPath: fileURL.path)
            print("Removed old image") 
        } catch let removeError {
            print("couldn't remove file at path", removeError)
        }

    }

    do {
        try data.write(to: fileURL)
    } catch let error {
        print("error saving file with error", error) 
    }

}



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
}

Solution 3

Details

  • Xcode Version 10.2 (10E125), Swift 5

Solution

// save
extension UIImage {

    func save(at directory: FileManager.SearchPathDirectory,
              pathAndImageName: String,
              createSubdirectoriesIfNeed: Bool = true,
              compressionQuality: CGFloat = 1.0)  -> URL? {
        do {
        let documentsDirectory = try FileManager.default.url(for: directory, in: .userDomainMask,
                                                             appropriateFor: nil,
                                                             create: false)
        return save(at: documentsDirectory.appendingPathComponent(pathAndImageName),
                    createSubdirectoriesIfNeed: createSubdirectoriesIfNeed,
                    compressionQuality: compressionQuality)
        } catch {
            print("-- Error: \(error)")
            return nil
        }
    }

    func save(at url: URL,
              createSubdirectoriesIfNeed: Bool = true,
              compressionQuality: CGFloat = 1.0)  -> URL? {
        do {
            if createSubdirectoriesIfNeed {
                try FileManager.default.createDirectory(at: url.deletingLastPathComponent(),
                                                        withIntermediateDirectories: true,
                                                        attributes: nil)
            }
            guard let data = jpegData(compressionQuality: compressionQuality) else { return nil }
            try data.write(to: url)
            return url
        } catch {
            print("-- Error: \(error)")
            return nil
        }
    }
}

// load from path

extension UIImage {
    convenience init?(fileURLWithPath url: URL, scale: CGFloat = 1.0) {
        do {
            let data = try Data(contentsOf: url)
            self.init(data: data, scale: scale)
        } catch {
            print("-- Error: \(error)")
            return nil
        }
    }
}

Usage

// save image (way 1)
let path = "photo/temp/album1/img.jpg"
guard   let img = UIImage(named: "img"),
        let url = img.save(at: .documentDirectory,
                           pathAndImageName: path) else { return }
print(url)

// get image from directory
guard let img2 = UIImage(fileURLWithPath: url) else { return }

// save image (way 2)
let tempDirectoryUrl = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(path)
guard let url2 = img2.save(at: tempDirectoryUrl) else { return }
print(url2)

Check results

open the iOS simulator directory

Solution 4

You should save image name with extension so your path should be like,

///var/mobile/Applications/BDB992FB-E378-4719-B7B7-E9A364EEE54B/Documents/tempImage.png

And second thing replace below line,

   let result = pngImageData!.writeToFile(path, atomically: true)

with

    let result = pngImageData!.writeToFile(path, atomically: false)

You need to set false as parameter of atomically.

atomically:

If true, the data is written to a backup file, and then—assuming no errors occur—the backup file is renamed to the name specified by path; otherwise, the data is written directly to path.

Hope this will help :)

Solution 5

Save image in local Xcode Documents directory

Pass in your image and the name you want to call it (you choose what you want fileName to be).

func saveImageLocally(image: UIImage, fileName: String) {
    
 // Obtaining the Location of the Documents Directory
    let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
    
    // Creating a URL to the name of your file
    let url = documentsDirectory.appendingPathComponent(fileName)
    
    if let data = image.pngData() {
        do {
            try data.write(to: url) // Writing an Image in the Documents Directory
        } catch {
            print("Unable to Write \(fileName) Image Data to Disk")
        }
    }
}

Read

Use the same fileName as when you saved it

func getImageFromName(fileName: String) {
    let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
    let url = documentsDirectory.appendingPathComponent(fileName)
    
    if let imageData = try? Data(contentsOf: url) {
        let image = UIImage(data: imageData) // HERE IS YOUR IMAGE! Do what you want with it!
        
    } else {
        print("Couldn't get image for \(fileName)")
    }
}
Share:
70,404
tesgoe
Author by

tesgoe

Updated on July 09, 2022

Comments

  • tesgoe
    tesgoe almost 2 years

    I am saving an image using saveImage.

    func saveImage (image: UIImage, path: String ) -> Bool{
    
        let pngImageData = UIImagePNGRepresentation(image)
        //let jpgImageData = UIImageJPEGRepresentation(image, 1.0)   // if you want to save as JPEG
    
        print("!!!saving image at:  \(path)")
    
        let result = pngImageData!.writeToFile(path, atomically: true)
    
        return result
    }
    

    New info:

    Saving file does not work properly ("[-] ERROR SAVING FILE" is printed)--

                // save your image here into Document Directory
            let res = saveImage(tempImage, path: fileInDocumentsDirectory("abc.png"))
            if(res == true){
                print ("[+] FILE SAVED")
            }else{
                print ("[-] ERROR SAVING FILE")
            }
    

    Why doesn't the saveImage function save the image? Access rights?

    Older info:

    The debug info says:

    !!!saving image at:  file:///var/mobile/Applications/BDB992FB-E378-4719-B7B7-E9A364EEE54B/Documents/tempImage
    

    Then I retrieve this location using

    fileInDocumentsDirectory("tempImage")
    

    The result is correct.

    Then I am loading the file using this path

        let image = UIImage(contentsOfFile: path)
    
        if image == nil {
    
            print("missing image at: \(path)")
        }else{
            print("!!!IMAGE FOUND at: \(path)")
        }
    

    The path is correct, but the message is "missing image at..". Is the file somehow inaccessible or not stored? What can be a reason for this behavior?

    I am testing this code on iphone 4 with ios 7 and iphone 5 with ios 7 simulator.

    Edit: 1. The fileInDocumentsDirectory function

    func fileInDocumentsDirectory(filename: String) -> String {
    
        let documentsURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
        let fileURL = documentsURL.URLByAppendingPathComponent(filename).absoluteString
        return fileURL        
    }
    
  • tesgoe
    tesgoe about 8 years
    Hi, I did that, but it still does not work -- !!!save: file:///var/mobile/Applications/E78F2521-929E-4E4D-834F-57C0‌​7A62DB84/Documents/t‌​empImage.png !!!miss: file:///var/mobile/Applications/E78F2521-929E-4E4D-834F-57C0‌​7A62DB84/Documents/t‌​empImage.png !!!miss: file:///var/mobile/Applications/E78F2521-929E-4E4D-834F-57C0‌​7A62DB84/Documents/t‌​empImage.png
  • Ketan Parmar
    Ketan Parmar about 8 years
    Make sure your image is not nil!! and you are passing path in let image = UIImage(contentsOfFile: path) is exact same as you write it and this path should be with extension. And once try to retrieve in NSData instead of UIImage from this path. If you got data then that means there is a problem to convert it in image.
  • tesgoe
    tesgoe about 8 years
    I added the extension, but that hasn't helped so far. Btw. I am using this code stackoverflow.com/questions/30953070/… -- from the @dharmesh-kheni 's answer.
  • tesgoe
    tesgoe about 8 years
    Btw. I am using this code stackoverflow.com/questions/30953070/… -- from the @dharmesh-kheni 's answer.
  • Ketan Parmar
    Ketan Parmar about 8 years
    try to save image like this saveImage(tempImage, path: fileInDocumentsDirectory("tempImage.png")) from that answer.
  • tesgoe
    tesgoe about 8 years
    I'm doing exactly that now and it still does not work.
  • Ketan Parmar
    Ketan Parmar about 8 years
    It should work!! strange if not work!! once try to change different name like abc.png instead tempImage.png
  • tesgoe
    tesgoe about 8 years
    loadImageFromPath(fileInDocumentsDirectory("abc.png")) returns null when saveImage(tempImage, path: fileInDocumentsDirectory("abc.png")) used.
  • tesgoe
    tesgoe about 8 years
    This is how it looks like from my perspective !!!save: file:///var/mobile/Applications/AE7C3783-C25C-4C4A-8ABB-6504‌​00CB32A7/Documents/a‌​bc.png !!!miss: file:///var/mobile/Applications/AE7C3783-C25C-4C4A-8ABB-6504‌​00CB32A7/Documents/a‌​bc.png
  • Duncan C
    Duncan C about 8 years
    That's just not true. You can certainly create a directory inside the sandboxed Documents directory and save your images there, but you don't have to do so. It works just fine to save image directly into the Documents directory.
  • tesgoe
    tesgoe about 8 years
    @DuncanC Thank you. Good to know that, but it currently works for me. I had a problem without this.
  • uplearned.com
    uplearned.com over 5 years
    Works for **Swift 4.2 ** as well! :)
  • iOS Developer
    iOS Developer over 5 years
    what to do with let success ? how can i store or insert or would you give an example to save on a button click and press on other button should show in image view
  • Michael
    Michael almost 5 years
    You should add comments or a description of what is going on in your answer
  • ayan chakraborty
    ayan chakraborty almost 4 years
    he means to load & retrive from locally