You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中将带图片的HTML转换为PDF的实现方案求助

解决方案:SwiftUI中HTML转PDF的两种可行方案

一、修复WKWebView.createPDF的报错问题

你的代码报错核心原因是网页还未加载完成就调用了createPDF,WKWebView需要等待页面完全渲染后才能生成有效PDF。通过WKNavigationDelegate监听页面加载完成事件,再执行PDF生成逻辑即可解决:

修改后的WebView实现:

struct ContentView: View {
    var body: some View {
        if let url = Bundle.main.url(forResource: "file", withExtension: "html") {
            WebView(request: URLRequest(url: url))
        }
    }
}

struct WebView: UIViewRepresentable {
    let request: URLRequest
    
    // 用Coordinator处理导航代理逻辑
    class Coordinator: NSObject, WKNavigationDelegate {
        var parent: WebView
        
        init(parent: WebView) {
            self.parent = parent
        }
        
        // 页面加载完成后触发PDF生成
        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            parent.generatePDF(from: webView)
        }
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(parent: self)
    }
    
    func makeUIView(context: Context) -> WKWebView {
        let webView = WKWebView()
        webView.navigationDelegate = context.coordinator
        return webView
    }
    
    func updateUIView(_ uiView: WKWebView, context: Context) {
        uiView.load(request)
    }
    
    // 独立封装PDF生成逻辑
    func generatePDF(from webView: WKWebView) {
        let pdfConfiguration = WKPDFConfiguration()
        pdfConfiguration.rect = CGRect(x: 0, y: 0, width: 810.0, height: 810.0 * 297.0 / 210.0)
                
        webView.createPDF(configuration: pdfConfiguration) { result in
            switch result {
            case .success(let data):
                do {
                    let docFolders = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
                    guard let docFolder = docFolders.first else { return }
                    
                    let pdfURL = docFolder.appendingPathComponent("Output.pdf")
                    try data.write(to: pdfURL)
                    print("PDF已生成:\(pdfURL)")
                } catch {
                    print("写入PDF失败:\(error)")
                }
            case .failure(let error):
                print("生成PDF失败:\(error)")
            }
        }
    }
}

关键改动:

  • 新增Coordinator类实现WKNavigationDelegate,监听页面加载完成事件
  • 在didFinish navigation回调中执行PDF生成,确保页面已完全渲染
  • 将PDF生成逻辑独立为方法,代码结构更清晰

二、修复UIMarkupTextPrintFormatter不显示图片的问题

使用UIMarkupTextPrintFormatter时,图片不显示通常是资源嵌入不规范或渲染配置缺失导致,按以下要点调整:

  1. Base64格式必须完整:需包含data:image/[格式];base64,前缀,例如data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...
  2. 配合UIPrintPageRenderer控制渲染:单独使用UIMarkupTextPrintFormatter无法处理复杂排版,用UIPrintPageRenderer可精准控制页面尺寸和渲染范围
  3. 确保HTML结构规范:完整的DOCTYPE、html标签,避免CSS样式隐藏图片

示例代码:

func generatePDFWithMarkup(htmlString: String) {
    let printFormatter = UIMarkupTextPrintFormatter(markupText: htmlString)
    
    // 配置A4打印尺寸(72dpi为UIKit默认打印分辨率)
    let pageRenderer = UIPrintPageRenderer()
    pageRenderer.addPrintFormatter(printFormatter, startingAtPageAt: 0)
    
    let pageSize = CGSize(width: 8.5 * 72, height: 11 * 72)
    let printableRect = CGRect(x: 20, y: 20, width: pageSize.width - 40, height: pageSize.height - 40)
    let paperRect = CGRect(origin: .zero, size: pageSize)
    
    pageRenderer.setValue(NSValue(cgRect: paperRect), forKey: "paperRect")
    pageRenderer.setValue(NSValue(cgRect: printableRect), forKey: "printableRect")
    
    // 生成PDF数据并写入文件
    let pdfData = pageRenderer.generatePDFData()
    if let docFolder = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
        let pdfURL = docFolder.appendingPathComponent("MarkupOutput.pdf")
        do {
            try pdfData.write(to: pdfURL)
            print("Markup PDF已生成:\(pdfURL)")
        } catch {
            print("写入失败:\(error)")
        }
    }
}

若Base64图片仍不显示,排查方向:

  • 用在线工具验证Base64字符串是否可正常解码
  • 检查HTML中是否有CSS样式(如display:none、width:0)隐藏图片
  • 确保HTML的DOCTYPE和根标签完整,避免渲染异常

额外建议

  • 若HTML包含外部CSS、字体资源,建议全部转为Base64内嵌,避免加载失败
  • 测试时可先打印PDF数据大小,若数据过小,说明渲染流程存在异常,需排查页面加载或HTML结构问题

内容的提问来源于stack exchange,提问作者Dave Thompson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 17:24:54