SwiftUI - 使用 .fileExporter() 导出图像列表时出现问题

问题描述 投票:0回答:1

我正在尝试从 SwiftUI 视图生成一些图像,然后将它们导出到文件系统。我在网上查了一下,似乎无法让事情发挥作用。点击文件导出按钮不会执行任何操作。

我应该将图像转换为其他格式吗?我觉得我错过了一些明显的东西,这比应该的更难。

struct Temp: View {
    let screenshots: [ScreenshotModel]
    let size: CGSize

    @State private var isShowingExport = false

    @State private var exportImages = [UIImage]()

    var body: some View {
        ScrollView {
            VStack {
                ForEach(exportImages, id: \.self) {
                    Image(uiImage: $0)
                }

                Button("Export to Files", systemImage: "folder") {
                    isShowingExport.toggle()
                }
            }
        }
        .task {
            await generateImages()
        }
        .fileExporter(
            isPresented: $isShowingExport,
            items: exportImages.map { $0.pngData()! }
        ) { result in
            switch result {
            case .success:
                print("Success")
            case .failure(let error):
                print(error)
            }
        } onCancellation: { }
    }

    func generateImages() async {
        exportImages = await withTaskGroup(of: UIImage.self) { group in
            for screenshot in screenshots {
                group.addTask {
                    await generateImage(screenshot: screenshot)
                }
            }

            var allImages = [UIImage]()
            for await image in group {
                allImages.append(image)
            }

            return allImages
        }
    }

    @MainActor
    func generateImage(screenshot: ScreenshotModel) -> UIImage {
        let content = ScreenshotPreviewView(
            screenshotModel: screenshot,
            size: size
        ).frame(size: size)

        let renderer = ImageRenderer(content: content)

        return renderer.uiImage!
    }
}
swift xcode swiftui uiimage
1个回答
0
投票

您可以使用

.fileExporter(isPresented: ..., documents: ...)
ImageDocument: FileDocument
来使用此方法,如图所示。

示例代码:

struct ContentView: View {
    var body: some View {
        // for testing
        Temp(screenshots: [ScreenshotModel(name: "house"),ScreenshotModel(name: "globe")], size: .zero)
    }
}

// for testing
struct ScreenshotModel: Identifiable {
    let id = UUID()
    var name: String
}

struct Temp: View {
    let screenshots: [ScreenshotModel]
    let size: CGSize

    @State private var isShowingExport = false

    @State private var exportImages = [UIImage]()

    var body: some View {
        ScrollView {
            VStack {
                ForEach(exportImages, id: \.self) {
                    Image(uiImage: $0)
                }

                Button("Export to Files", systemImage: "folder") {
                    isShowingExport.toggle()
                }
            }
        }
        .task {
            await generateImages()
        }
        .fileExporter(
            isPresented: $isShowingExport,
            documents: exportImages.map{ImageDocument(image: $0)} // <-- here
        ) { result in
            switch result {
            case .success:
                print("-----> Success")
            case .failure(let error):
                print(error)
            }
        } onCancellation: { }
    }

    func generateImages() async {
        exportImages = await withTaskGroup(of: UIImage.self) { group in
            for screenshot in screenshots {
                group.addTask {
                    await generateImage(screenshot: screenshot)
                }
            }

            var allImages = [UIImage]()
            for await image in group {
                allImages.append(image)
            }

            return allImages
        }
    }

    @MainActor
    func generateImage(screenshot: ScreenshotModel) async -> UIImage { // <-- here
//        let content = ScreenshotPreviewView(
//            screenshotModel: screenshot,
//            size: size
//        ).frame(size: size)
//
//        let renderer = ImageRenderer(content: content)
//
//        return renderer.uiImage!
        
        // for testing
        return UIImage(systemName: screenshot.name)!
    }
}

struct ImageDocument: FileDocument {
  static var readableContentTypes: [UTType] { [.png] }

  var image: UIImage

  init(image: UIImage?) {
    self.image = image ?? UIImage()
  }

  init(configuration: ReadConfiguration) throws {
    guard let data = configuration.file.regularFileContents,
          let image = UIImage(data: data)
    else {
      throw CocoaError(.fileReadCorruptFile)
    }
    self.image = image
  }

  func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
      let fw = FileWrapper(regularFileWithContents: image.pngData()!)
      fw.filename = String(UUID().uuidString.prefix(6))  // <--- for testing
      return fw
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.