How to save a UIImage to documents directory?

KingTim picture KingTim · Mar 25, 2017 · Viewed 12.8k times · Source

I'm trying to save both a recorded video's file path, and a thumbnail from the video to the documents directory. Then, set those two values to an object using the file paths so I can use the object to populate a collection view. With the code I have currently (below), after I record a video, the video path gets saved to the documents directory, and the video path and thumbnail get set to my Post object, and the thumbnail appears properly in my collection view. All good so far.

However only the video path persists between app re-launches since it's in the directory, and the thumbnail isn't. I'd like to save the thumbnail there too but I don't know how to go about it since it appears you can only write URLs to the directory.

This is my first experience with utilizing the documents directory so any help will be appreciated! How can I write the thumbnail (UIImage) to my documents directory along with the video it's from?

Here's my code so far:

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

    let mediaType = info[UIImagePickerControllerMediaType] as! NSString
    dismiss(animated: true, completion: nil)

    if mediaType == kUTTypeMovie {
        // Componenets for a unique ID for the video
        var uniqueVideoID = ""
        var videoURL:NSURL? = NSURL()
        var uniqueID = ""
        uniqueID = NSUUID().uuidString

        // Get the path as URL
        videoURL = info[UIImagePickerControllerMediaURL] as? URL as NSURL?
        let myVideoVarData = try! Data(contentsOf: videoURL! as URL)

        // Write the video to the Document Directory at myVideoVarData (and set the video's unique ID)
        let docPaths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
        let documentsDirectory: AnyObject = docPaths[0] as AnyObject
        uniqueVideoID = uniqueID  + "VIDEO.MOV"
        let docDataPath = documentsDirectory.appendingPathComponent(uniqueVideoID) as String
        try? myVideoVarData.write(to: URL(fileURLWithPath: docDataPath), options: [])
        print("docDataPath under picker ", docDataPath)
        print("Video saved to documents directory")

        // Create a thumbnail image from the video (first frame)
        let asset = AVAsset(url: URL(fileURLWithPath: docDataPath))
        let assetImageGenerate = AVAssetImageGenerator(asset: asset)
        assetImageGenerate.appliesPreferredTrackTransform = true
        let time = CMTimeMake(asset.duration.value / 3, asset.duration.timescale)
        if let videoImage = try? assetImageGenerate.copyCGImage(at: time, actualTime: nil) {
            // Add thumbnail & video path to Post object
            let video = Post(pathToVideo: URL(fileURLWithPath: docDataPath), thumbnail: UIImage(cgImage: videoImage))
            posts.append(video)
            print("Video saved to Post object")
        }
    }
}

Answer

Ashwin Indianic picture Ashwin Indianic · Mar 25, 2017

One Suggestion: Save images to Library/Caches if that can be downloaded again as per apple's guide line.


As simple as this:

func saveImageToDocumentDirectory(_ chosenImage: UIImage) -> String {
        let directoryPath =  NSHomeDirectory().appending("/Documents/")
        if !FileManager.default.fileExists(atPath: directoryPath) {
            do {
                try FileManager.default.createDirectory(at: NSURL.fileURL(withPath: directoryPath), withIntermediateDirectories: true, attributes: nil)
            } catch {
                print(error)
            }
        }
        let filename = NSDate().string(withDateFormatter: yyyytoss).appending(".jpg")
        let filepath = directoryPath.appending(filename)
        let url = NSURL.fileURL(withPath: filepath)
        do {
            try UIImageJPEGRepresentation(chosenImage, 1.0)?.write(to: url, options: .atomic)
            return String.init("/Documents/\(filename)")

        } catch {
            print(error)
            print("file cant not be save at path \(filepath), with error : \(error)");
            return filepath
        }
    }

Swift4:

func saveImageToDocumentDirectory(_ chosenImage: UIImage) -> String {
        let directoryPath =  NSHomeDirectory().appending("/Documents/")
        if !FileManager.default.fileExists(atPath: directoryPath) {
            do {
                try FileManager.default.createDirectory(at: NSURL.fileURL(withPath: directoryPath), withIntermediateDirectories: true, attributes: nil)
            } catch {
                print(error)
            }
        }

        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyyMMddhhmmss"

        let filename = dateFormatter.string(from: Date()).appending(".jpg")
        let filepath = directoryPath.appending(filename)
        let url = NSURL.fileURL(withPath: filepath)
        do {
            try chosenImage.jpegData(compressionQuality: 1.0)?.write(to: url, options: .atomic)
            return String.init("/Documents/\(filename)")

        } catch {
            print(error)
            print("file cant not be save at path \(filepath), with error : \(error)");
            return filepath
        }
    }