SwiftUI Image Exporter only saving the first image

65 Views Asked by At

I made this app which lets the user pick photos from their library and then export them as a pdf however only the first photo gets exported and then an alert pops up saying:

"Exported PNG image.png" couldn't be moved to "images" because either the former doesn't exist, or the folder containing the latter doesn't exist. The file doesn't exist.

I tried everything but couldn't get it to work. It's not even a file based app.

This is my code:

    import SwiftUI
    import UniformTypeIdentifiers
    import PhotosUI
    
    struct ImageDocument: FileDocument {
        static var readableContentTypes: [UTType] {
            [.image,.png,.jpeg]
        }
        
        var image = UIImage()
        
        init(image: UIImage) {
            self.image = image
        }
        
        init(configuration: ReadConfiguration) throws {
            if let data = configuration.file.regularFileContents {
                image = UIImage(data: data) ?? UIImage()
            } else {
                image = UIImage()
            }
        }
        
        @MainActor func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
            return FileWrapper(regularFileWithContents: Data(image.pngData()!))
        }
    }
    
    
    struct ContentView: View {
        @State private var selectedItems = [PhotosPickerItem]()
        @State private var documents = [ImageDocument]()
        @State private var showExporter = false
        
        var body: some View {
            NavigationStack {
                ScrollView {
                    LazyVStack {
                        ForEach(0..<documents.count, id: \.self) { i in
                            Image(uiImage: documents[i].image)
                                .resizable()
                                .scaledToFit()
                                .frame(width: 300, height: 300)
                        }
                    }
                }
                .toolbar {
                    ToolbarItem {
                        PhotosPicker("Select images", selection: $selectedItems, matching: .images)
                    }
                    ToolbarItem {
                        Button("Export") {
                            showExporter.toggle()
                        }
                    }
                }
                .fileExporter(isPresented: $showExporter, documents: documents, contentType: .png, onCompletion: { result in 
                    print(result)
                })
                .onChange(of: selectedItems) {
                    Task {
                        documents.removeAll()
                        
                        for item in selectedItems {
                            if let image = try? await item.loadTransferable(type: Image.self) {
                                documents.append(ImageDocument(image: image.render() ?? UIImage()))
                            }
                        }
                    }
                }
            }
        }
    }
    
    extension View {
        /// Usually you would pass  `@Environment(\.displayScale) var displayScale`
        @MainActor func render(scale displayScale: CGFloat = 1.0) -> UIImage? {
            let renderer = ImageRenderer(content: self)
            
            renderer.scale = displayScale
            
            return renderer.uiImage
        }
        
    }
}
0

There are 0 best solutions below