swiftswiftuisdwebimage

How can I save SDWebImageSwiftUI to Photos in Swift?


I've been searching for hours now on how to save to Photos a SwiftUI SDWebImage

ForEach(self.moodboardImages, id: \.self) { imageName in
                    WebImage(url: URL(string: imageName.fileLink))
                        .resizable()
                        .aspectRatio(contentMode: .fit)
                        .pinchToZoom()
                        .onTapGesture {
                            //Save to Library ?
                        }
                }

I have an array of object which has a photo URL, and I access that via imageName.fileLink In forEach Loop.

Now I'm trying to allow save to photos when the user taps on the image. Can't seem to find anything with SwiftUI, all the tutorials are using UIKit, and the also found SDWebImage for UIKit not SwiftUI.

Any possible help here ? or at least how can I approach this problem 🤔


Solution

  • Hopefully this will help others to achieve similar goal like mine, since I don't see a lot of answers on sdwebimage I had to take the time to write an answer my self. So finally after hours of searching and testing different approaches, in short you convert url image to UIImage and save that to the device.

    I was able to achieve my goal by the following code:

    First I created an image saver class:

    import Foundation
    import SwiftUI
    
    extension UIImage {
        var jpeg: Data? { jpegData(compressionQuality: 1) }  // QUALITY min = 0 / max = 1
        var png: Data? { pngData() }
    }
    
    extension Data {
        var uiImage: UIImage? { UIImage(data: self) }
    }
    
    class ImageSaver: NSObject {
        func writeToPhotoAlbum(image: UIImage) {
            UIImageWriteToSavedPhotosAlbum(image, self, #selector(saveError), nil)
        }
    
        @objc func saveError(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
            print("save finished")
        }
    }
    

    thats based on this repo: https://github.com/krish-21/Fiftygram

    Then added these two variables and function in my ContentView.swift

    @State var imageData: UIImage?
    @State private var imageSaved: Bool = false
    
        // save Image to Photo Album
        func saveImage() {
            let imageSaver = ImageSaver()
            if let uiImage = imageData {
                imageSaver.writeToPhotoAlbum(image: uiImage)
                imageSaved = true
            }
        }
    

    Then called this inside the save button or tap gesture:

    imageData = UIImage(data: try! Data(contentsOf: URL(string: imageName.fileLink)!))!
    
    saveImage()
    

    So my code looks like this, can't post the full code because of project privacy:

    import Foundation
    import SwiftUI
    import SDWebImageSwiftUI
    
    struct ContentView: View {
        @State var imageData: UIImage?
        @State private var imageSaved: Bool = false
    
        // save Image to Photo Album
        func saveImage() {
            let imageSaver = ImageSaver()
            if let uiImage = imageData {
                imageSaver.writeToPhotoAlbum(image: uiImage)
                imageSaved = true
            }
        }
    
        var body: some View {
            VStack {
                ForEach(self.moodboardImages, id: \.self) { imageName in
                    WebImage(url: URL(string: imageName.fileLink))
                        .resizable()
                        .aspectRatio(contentMode: .fit)
                        .pinchToZoom()
                        .onTapGesture {
                            //Save to Library ?
                            imageData = UIImage(data: try! Data(contentsOf: URL(string: moodboardImages[index].fileLink)!))!
                            saveImage()
                        }
                }
            }
            // alert the user after image is saved
            .alert(isPresented: $imageSaved) {
                Alert(title: Text("Saved"), message: Text("Moodboard image has been saved to Photos"), dismissButton: .default(Text("Done")))
            }
        }
    }
    

    Also after some digging on sdwebimage GitHub issues tab and version pull requests I was able to find this:

    You can get the raw image and data objects from WebImage by adding .onSuccess with the following param.

    WebImage(url: URL(string: imageName.fileLink))
                        .resizable()
                        .aspectRatio(contentMode: .fit)
                        .pinchToZoom()
                        .onSuccess {
                            (image, data, cacheType) in
                            // you can use image or data to save it, or do whatever you want with it, example:
                            // saveImage(data) or saveImage(image) , depending on your needs or code
                        }
    

    Note Works with SDWebImageSwiftUI 2.0+