【问题标题】:Saving image and then loading it in Swift (iOS)保存图像然后在 Swift (iOS) 中加载它
【发布时间】:2016-09-17 14:36:40
【问题描述】:

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

新信息:

保存文件不能正常工作(打印“[-] 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")
        }

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

旧信息:

调试信息说:

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

然后我使用检索此位置

fileInDocumentsDirectory("tempImage")

结果是正确的。

然后我使用这个路径加载文件

    let image = UIImage(contentsOfFile: path)

    if image == nil {

        print("missing image at: \(path)")
    }else{
        print("!!!IMAGE FOUND at: \(path)")
    }

路径是正确的,但消息是“缺少图像...”。该文件是否以某种方式无法访问或未存储?这种行为的原因可能是什么?

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

编辑: 1.fileInDocumentsDirectory函数

func fileInDocumentsDirectory(filename: String) -> String {

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

【问题讨论】:

  • 在finder中查看图片,是否可用。并为图像 *.png 或 *.jpeg 添加一些扩展名。
  • 不保存图像的完整路径只保存图像名称并在名称后附加实时文档目录路径。就是这样,因为文档目录路径在每次运行时都不会返回相同的值。
  • @NitinGohel 我只是保存文件,然后尝试像这样加载它 loadImageFromPath(fileInDocumentsDirectory("abc.png"))
  • fineInDocumentDirectory 是实时路径还是从数据库加载?
  • @NitinGohel 我添加了这个函数的代码。只有三行。

标签: ios swift caching file-manager image-caching


【解决方案1】:

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

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

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

【讨论】:

【解决方案2】:

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

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

第二件事替换下面的行,

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

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

atomically的参数需要设置为false。

原子地:

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

希望这会有所帮助:)

【讨论】:

  • 嗨,我这样做了,但它仍然不起作用 -- !!!save: file:///var/mobile/Applications/E78F2521-929E-4E4D-834F-57C07A62DB84/Documents/ tempImage.png !!!miss: file:///var/mobile/Applications/E78F2521-929E-4E4D-834F-57C07A62DB84/Documents/tempImage.png !!!miss: file:///var/mobile/Applications/ E78F2521-929E-4E4D-834F-57C07A62DB84/Documents/tempImage.png
  • 确保你的图片不为零!!并且您在let image = UIImage(contentsOfFile: path) 中传递的路径与您编写的路径完全相同,并且该路径应该带有扩展名。一旦尝试从该路径检索NSData 而不是UIImage。如果您有数据,则意味着将其转换为图像存在问题。
  • 顺便说一句。我正在使用此代码stackoverflow.com/questions/30953070/…——来自@dharmesh-khini 的回答。
  • 尝试从那个答案中保存像saveImage(tempImage, path: fileInDocumentsDirectory("tempImage.png")) 这样的图像。
  • 我现在正在这样做,但仍然无法正常工作。
【解决方案3】:

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

【讨论】:

  • 这不是真的。您当然可以在沙盒文档目录中创建一个目录并将您的图像保存在那里,但您不必这样做。将图像直接保存到 Documents 目录中效果很好。
  • @DuncanC 谢谢。很高兴知道这一点,但它目前对我有用。没有这个我有问题。
【解决方案4】:

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

 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()

【讨论】:

  • 他的意思是从本地加载和检索
【解决方案5】:

此功能将在文档文件夹中保存图像:

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
    }
}

使用方法:

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

此函数将获取该图像:

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
}

使用方法:

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

【讨论】:

  • 也适用于 **Swift 4.2 **! :)
  • 如何处理let success ?我如何存储或插入,或者你会举一个例子来保存按钮点击并按下其他按钮应该显示在图像视图中
【解决方案6】:

iOS 13+ Swift 5.1

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
}

【讨论】:

    【解决方案7】:

    详情

    • Xcode 版本 10.2 (10E125),Swift 5

    解决方案

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

    用法

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

    检查结果

    open the iOS simulator directory

    【讨论】:

      【解决方案8】:

      斯威夫特 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
      

      【讨论】:

      • 您应该在答案中添加 cmets 或对正在发生的事情的描述
      【解决方案9】:

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

      假设 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)
      

      还有这个功能

      @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)
      }
      

      }

      【讨论】:

        【解决方案10】:

        您实际上可以使用 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)
                    })
        
            }
        }
        

        【讨论】:

          【解决方案11】:

          将图像保存在本地 Xcode 文档目录中

          传入你的图片和你想给它起的名字(你选择你想要的文件名)。

          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")
                  }
              }
          }
          

          阅读

          使用与保存时相同的文件名

          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)")
              }
          }
          

          【讨论】:

            猜你喜欢
            • 2023-03-20
            • 1970-01-01
            • 2011-07-19
            • 2017-09-18
            • 1970-01-01
            • 2020-08-22
            • 1970-01-01
            • 1970-01-01
            • 2011-07-16
            相关资源
            最近更新 更多