iOS中使用WKWebView生成PDF时如何避免图片被分页截断?
问题:WKWebView生成PDF时动态图片被分页截断
在iOS应用中使用WKWebView渲染HTML内容,生成PDF时遇到问题:动态加载到DOM中的图片会被分页截断。常规浏览器打印时图片可避免跨页截断,但iOS中通过WKWebView生成PDF时,图片会根据页面尺寸和位置被随机截断高度。
生成PDF的Swift代码
func createPdf(completion: @escaping (PDFDocument?) -> Void) { let formatter: UIViewPrintFormatter = self.viewPrintFormatter() let render = UIPrintPageRenderer() render.addPrintFormatter(formatter, startingAtPageAt: 0) let page = CGRect(x: 0, y: 0, width: 595.2, height: 841.8) let printableWidth = page.width - 2 * 32 let printableHeight = page.height - 2 * 64 let printable = CGRect(x: 32, y: 32, width: printableWidth, height: printableHeight) render.setValue(NSValue(cgRect: page), forKey: "paperRect") render.setValue(NSValue(cgRect: printable), forKey: "printableRect") let pdfData = NSMutableData() UIGraphicsBeginPDFContextToData(pdfData, CGRect.zero, nil) for i in 0..<render.numberOfPages { UIGraphicsBeginPDFPage(); let bounds = UIGraphicsGetPDFContextBounds() render.drawPage(at: i, in: bounds) if i > 0 { let pageNumber = i let footerText = "Page \(pageNumber)" let attributes: [NSAttributedString.Key: Any] = [ .font: UIFont.systemFont(ofSize: 12), .foregroundColor: UIColor.black ] let textSize = footerText.size(withAttributes: attributes) let textRect = CGRect( x: bounds.width - textSize.width - 32, y: bounds.height - textSize.height - 20, width: textSize.width, height: textSize.height ) footerText.draw(in: textRect, withAttributes: attributes) } } UIGraphicsEndPDFContext() completion(PDFDocument(data: pdfData as Data)) }
解决方案
1. 给图片添加CSS分页控制
在HTML样式中,给动态图片或其容器添加分页避免属性,强制WebKit不在图片内部分页:
.image-wrap { page-break-inside: avoid; break-inside: avoid; /* 兼容现代渲染逻辑 */ display: block; margin: 0 0 1em 0; /* 添加底部间距,避免图片紧贴分页边界 */ } .image-wrap img { max-width: 100%; height: auto; }
注意:动态加载的图片需确保样式在加载完成后正确应用,可通过JS在图片加载完成后给元素添加类名。
2. 等待所有图片加载完成再生成PDF
动态图片未加载完成就触发PDF生成,会导致尺寸计算错误引发截断。可通过JS监听页面加载状态:
// 生成PDF前确认所有图片加载完成 webView.evaluateJavaScript("Array.from(document.images).every(img => img.complete) && document.readyState === 'complete'") { (result, error) in guard let isReady = result as? Bool, isReady else { // 延迟重试,确保图片加载完成 DispatchQueue.main.asyncAfter(deadline: .now() + 0.8) { // 重新检查加载状态 } return } // 图片全部加载完成,执行PDF生成 self.createPdf { pdfDoc in // 处理结果 } }
3. 改用WebKit原生PDF生成API(iOS14+)
iOS14及以上提供的WKWebView.createPDFAPI更贴近浏览器打印逻辑,对CSS分页支持更完善:
func createPdfWithWebKit(completion: @escaping (PDFDocument?) -> Void) { let pdfConfig = WKPDFConfiguration() pdfConfig.pageWidth = 595.2 pdfConfig.pageHeight = 841.8 pdfConfig.margins = UIEdgeInsets(top: 32, left: 32, bottom: 64, right: 32) webView.createPDF(configuration: pdfConfig) { result in switch result { case .success(let data): completion(PDFDocument(data: data)) case .failure(let error): print("PDF生成失败:\(error.localizedDescription)") completion(nil) } } }
该API会自动处理图片分页避免,无需手动调整打印渲染器逻辑。
4. 避免Swift代码中手动绘制页码干扰分页
原代码中在PDF生成后手动绘制页码,可能干扰WebKit的原始分页计算。建议通过HTML的@page规则添加页脚页码,保持渲染逻辑统一:
@page { @bottom-right { content: "Page " counter(page); font-size: 12px; } }
内容的提问来源于stack exchange,提问作者Ariful Jannat Arif
相关产品推荐
相关产品推荐

