保存图像然后加载到Swift(iOS)

时间:2016-05-20 10:52:45

标签: ios swift

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

新信息:

保存文件无效(" [ - ]错误保存文件"已打印) -

            // 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和带有ios 7模拟器的iphone 5在iphone 4上测试此代码。

编辑: 1. fileInDocumentsDirectory函数

func fileInDocumentsDirectory(filename: String) -> String {

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

10 个答案:

答案 0 :(得分:29)

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

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
}

答案 1 :(得分:8)

iOS 12 Swift 4.2

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
}

答案 2 :(得分:3)

您应该使用扩展程序保存图片名称,这样您的路径应该是,

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

第二件事取代以下行,

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

atomically

您需要将false设置为#include <iostream> #include <functional> struct Int { Int() { std::cout << "Int(): " << v << std::endl; } Int(const Int& o) { v = o.v; std::cout << "Int(const Int&): " << v << std::endl; } Int(int o) { v = o; std::cout << "Int(int): " << v << std::endl; } ~Int() { std::cout << "~Int(): " << v << std::endl; } Int& operator=(const Int& o) { v = o.v; std::cout << "operator= " << v << std::endl; return *this; } int v; }; namespace std { template<> Int&& forward<Int>(Int& a) noexcept { std::cout << "Int&: " << a.v << std::endl; return static_cast<Int&&>(a); } template<> Int&& forward<Int>(Int&& a) noexcept { std::cout << "Int&&: " << a.v << std::endl; return static_cast<Int&&>(a); } } std::function<void(Int)> myLambda(Int& n) { std::cout << "++n: " << n.v << std::endl; ++n.v; return [&](Int m) { std::cout << "n: " << m.v << std::endl; }; } int main() { Int n(0); myLambda(n)(n); return 0; } 的参数。

  

原子

     

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

希望这会有所帮助:)

答案 3 :(得分:2)

如果您想从服务器加载图片,可以执行以下操作

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

答案 4 :(得分:1)

Ashish的评论有一个答案的线索。如果您阅读UIImage(contentsOfFile:)上的文档,则说明

  

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

imageNamed电话非常智能,可以尝试.png和.jpg扩展程序,但contentsOfFile调用需要包含扩展名的完整路径。

答案 5 :(得分:0)

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

答案 6 :(得分:0)

详细信息

  • 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

答案 7 :(得分:0)

快速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

答案 8 :(得分:0)

前一段时间,我在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)
}

}

答案 9 :(得分:0)

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

    }
}