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时,图片不显示通常是资源嵌入不规范或渲染配置缺失导致,按以下要点调整:
- Base64格式必须完整:需包含
data:image/[格式];base64,前缀,例如data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA... - 配合UIPrintPageRenderer控制渲染:单独使用
UIMarkupTextPrintFormatter无法处理复杂排版,用UIPrintPageRenderer可精准控制页面尺寸和渲染范围 - 确保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
相关产品推荐
相关产品推荐

