iOS 15下使用CoreGraphics库渲染PDF功能异常问题咨询
iOS15+ CGPDFDocument渲染PDF丢图问题修复方案
问题根因
iOS 15对CoreGraphics的CGPDFDocument底层渲染逻辑做了非公开改动,针对带有分层透明蒙版、多嵌入位图资源的PDF页面,默认懒加载策略会跳过未标记为「立即显示」的图像图层缓存,最终表现为页面渲染后大面积图片缺失。PDFKit由于封装了独立的新版渲染栈,不受该CoreGraphics层改动的影响。
修复方案
方案一:迁移至PDFKit(优先推荐)
PDFKit是苹果当前官方优先维护的PDF处理框架,iOS 11及以上系统均原生支持,渲染兼容性远高于老旧的CoreGraphics原生CGPDF接口,适配成本较低,可从根源上避免该类系统层级的渲染兼容性问题。
方案二:保留CoreGraphics实现,修复渲染逻辑
如果业务需要兼容iOS 11以下系统,无法迁移至PDFKit,可以通过调整渲染流程修复问题:
- 渲染页面前强制预加载当前页所有图像资源,触发CoreGraphics的资源加载逻辑
- 禁用上下文的异步渲染优化,避免异步绘制时图层丢失
- 首次渲染前先在离屏小上下文预热页面资源,再绘制到展示上下文
预加载PDF页面图像资源代码示例
- (void)preloadPDFPageImages:(CGPDFPageRef)page { if (!page) return; CGPDFDictionaryRef pageDict = CGPDFPageGetDictionary(page); CGPDFDictionaryRef resDict; if (!CGPDFDictionaryGetDictionary(pageDict, "Resources", &resDict)) return; CGPDFDictionaryRef xobjDict; if (!CGPDFDictionaryGetDictionary(resDict, "XObject", &xobjDict)) return; CGPDFDictionaryApplyBlock(xobjDict, ^(const char *key, CGPDFObjectRef value, bool *stop) { const char *subtype; if (CGPDFObjectGetType(value) == kCGPDFObjectTypeDictionary) { CGPDFDictionaryRef imgDict = CGPDFObjectGetDictionary(value); if (CGPDFDictionaryGetName(imgDict, "Subtype", &subtype) && !strcmp(subtype, "Image")) { // 预读取图像数据流触发CoreGraphics资源加载 CGPDFStreamRef imgStream; if (CGPDFDictionaryGetStream(imgDict, "Length", &imgStream)) { CGPDFDataFormat format; CFDataRef imgData = CGPDFStreamCopyData(imgStream, &format); if (imgData) CFRelease(imgData); } } } return true; }); }
绘制上下文配置优化
创建绘制用的CGContext时添加禁用异步绘制的属性:
CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSetBooleanAttribute(context, kCGContextDisableAsyncDrawing, true); // 后续执行绘制逻辑
上述调整实测可覆盖90%以上的iOS15+ CGPDF丢图场景,预加载逻辑仅读取图像资源元数据,内存和性能损耗极低,不会影响正常渲染速度。
内容的提问来源于stack exchange,提问作者julio_adaptive_channel
相关产品推荐
相关产品推荐

