保存图像,然后在 Swift (iOS) 中加载它

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/37344822/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 09:08:09  来源:igfitidea点击:

Saving image and then loading it in Swift (iOS)

iosswift

提问by tesgoe

I am saving an image using saveImage.

我正在使用 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)--

保存文件无法正常工作(打印“[-] ERROR SAVING FILE”)--

            // 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?

为什么 saveImage 函数不保存图像?访问权限?

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.

我正在使用 ios 7 的 iphone 4 和使用 ios 7 模拟器的 iphone 5 上测试此代码。

Edit: 1. The fileInDocumentsDirectory function

编辑: 1. fileInDocumentsDirectory 函数

func fileInDocumentsDirectory(filename: String) -> String {

    let documentsURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
    let fileURL = documentsURL.URLByAppendingPathComponent(filename).absoluteString
    return fileURL        
}

回答by Bobby

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
}

回答by Sam Bing

iOS 13+ Swift 5.1

iOS 13+ Swift 5.1

iOS 12 introduced some API Changes.

iOS 12 引入了一些 API 更改。

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
}

回答by Vasily Bodnarchuk

Details

细节

  • Xcode Version 10.2 (10E125), Swift 5
  • Xcode 版本 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

打开iOS模拟器目录

回答by Ketan Parmar

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

您应该使用扩展名保存图像名称,以便您的路径应该像,

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

///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.

您需要将 false 设置为 的参数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.

原子地:

如果为 true,则将数据写入备份文件,然后(假设没有发生错误)将备份文件重命名为 path 指定的名称;否则,数据直接写入路径。

Hope this will help :)

希望这会有所帮助:)

回答by guru

If you want to load image from server you can do like below

如果你想从服务器加载图像,你可以像下面这样

 let url = URL(string: "http://live-wallpaper.net/iphone/img/app/i/p/iphone-4s-wallpapers-mobile-backgrounds-dark_2466f886de3472ef1fa968033f1da3e1_raw_1087fae1932cec8837695934b7eb1250_raw.jpg")
        URLSession.shared.dataTask(with: url!) { (data, response, error) in
            guard
                let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
                let mimeType = response?.mimeType, mimeType.hasPrefix("image"),
                let data = data, error == nil
                else { return }
                DispatchQueue.main.async() { () -> Void in
                let fileManager = FileManager.default
                let paths = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent("apple.jpg")
                print(paths)
                fileManager.createFile(atPath: paths as String, contents: data, attributes: nil)

            }}.resume()

回答by Duncan C

Ashish's comment has a clue to the answer. If you read the docs on UIImage(contentsOfFile:)they say

Ashish 的评论提供了答案的线索。如果你阅读了UIImage(contentsOfFile:)他们说的文档

path The path to the file. This path should include the filename extensionthat identifies the type of the image data.

path 文件的路径。此路径应包括标识图像数据类型的文件扩展名

The imageNamedcall is smart enough to try the .png and .jpg extensions, but the contentsOfFilecall expects a full path including extension.

imageNamed调用足够智能,可以尝试 .png 和 .jpg 扩展名,但该contentsOfFile调用需要包含扩展名的完整路径。

回答by tesgoe

You have to create a directory in the Documents directory to be able to store a file.

您必须在 Documents 目录中创建一个目录才能存储文件。

回答by John Ro

Swift 5

斯威夫特 5

func saveImage(image: UIImage) -> Bool{
    guard let data = image.jpegData(compressionQuality: 1) ?? image.pngData() 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("\(txtNom.text!).png")!)
        print(directory)
        print(data)
        print("si se pudo")
        return true
    } catch {
        print(error.localizedDescription)
        return false
    }
} // saveImage

回答by ninahadi

I found the solution on StackOverFlow some time ago. I didn't remember the author

前段时间我在 StackOverFlow 上找到了解决方案。不记得作者了

Assuming yourImage is UIImage()

假设 yourImage 是 UIImage()

let ciImage = yourImage!.ciImage
let context = CIContext()
let cgImage = context.createCGImage(ciImage!, from: ciImage!.extent)
let uiImage = UIImage(cgImage: cgImage!)

UIImageWriteToSavedPhotosAlbum(uiImage, self, 
#selector(self.image(_:didFinishSavingWithError:contextInfo:)), nil)

and this function

和这个功能

@objc func image(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
if let error = error {
    // we got back an error!
    let ac = UIAlertController(title: "Save error", message: error.localizedDescription, preferredStyle: .alert)
    ac.addAction(UIAlertAction(title: "OK", style: .default))
    present(ac, animated: true)
} else {
    let ac = UIAlertController(title: "Saved!", message: "Your altered image has been saved to your photos.", preferredStyle: .alert)
    ac.addAction(UIAlertAction(title: "OK", style: .default))
    present(ac, animated: true)
}

}

}

回答by Gurkan Soykan

You can actually use PHPhotoLibrary to do that. Here is the code for saving the image and fetching the image url.

您实际上可以使用 PHPhotoLibrary 来做到这一点。这是用于保存图像和获取图像 url 的代码。

extension UIImage {
func saveToPhotoLibrary(completion: @escaping (URL?) -> Void) {
    var localeId: String?
    PHPhotoLibrary.shared().performChanges({
        let request = PHAssetChangeRequest.creationRequestForAsset(from: self)
        localeId = request.placeholderForCreatedAsset?.localIdentifier
    }) { (isSaved, error) in
        guard isSaved else {
            debugPrint(error?.localizedDescription)
            completion(nil)
            return
        }
        guard let localeId = localeId else {
            completion(nil)
            return
        }
        let fetchOptions = PHFetchOptions()
        fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
        let result = PHAsset.fetchAssets(withLocalIdentifiers: [localeId], options: fetchOptions)
        guard let asset = result.firstObject else {
            completion(nil)
            return
        }
        getPHAssetURL(of: asset) { (phAssetUrl) in
            completion(phAssetUrl)
        }
    }
}

static func getPHAssetURL(of asset: PHAsset, completionHandler : @escaping ((_ responseURL : URL?) -> Void))
    {
            let options: PHContentEditingInputRequestOptions = PHContentEditingInputRequestOptions()
            options.canHandleAdjustmentData = {(adjustmeta: PHAdjustmentData) -> Bool in
                return true
            }
            asset.requestContentEditingInput(with: options, completionHandler: { (contentEditingInput, info) in
                completionHandler(contentEditingInput!.fullSizeImageURL)
            })

    }
}