最近有很多关于绘制PDF的问题.

是的,你可以用UIWebView很容易地呈现PDF,但这不能提供一个好的PDF查看器所期望的性能和功能.

您可以绘制PDF页面to a CALayer to a UIImage.Apple甚至有示例代码来展示如何绘制大型PDF in a Zoomable UIScrollview

但同样的问题不断出现.

UIImage Method:

  1. PDF格式的UIImage不要光学 可伸缩性以及层次化方法.
  2. 生成时CPU和内存命中 从PDFcontext开始的UIImages 限制/阻止使用它创建 实时渲染新的zoom 级别.

CATiledLayer Method:

  1. 有相当大的开销(时间) 将整个PDF页面绘制到CALayer:可以看到单个平铺的渲染(即使调整了tileSize)
  2. CALayers不能提前做好准备 时间(在屏幕外渲染).

一般来说,PDF阅读器的内存也相当大.甚至可以监控苹果可zoom PDF示例的内存使用情况.

In my current project, I'm developing a PDF viewer and am rendering a UIImage of a page in a separate thread (issues here too!) and presenting it while the scale is x1. CATiledLayer rendering kicks in once the scale is >1. iBooks takes a similar double take approach as if you scroll the pages you can see a lower res version of the page for just less than a second before a crisp version appears.

Im呈现聚焦页面的每一面2页,以便PDF图像在开始绘制之前准备好遮罩该层.当页面距离焦点页面+2页时,页面再次被销毁.

Does anyone have any insights, no matter how small or obvious to improve the performance/ memory handling of Drawing PDF's? or any other issues discussed here?

EDIT:个小贴士(Credit-Luke Mcneice,VdesmedT,Matt Gallagher,Johann):

  • 尽可能将任何介质保存到磁盘.

  • 如果在切片图层上渲染,请使用较大的切片大小

  • 使用占位符对象初始化常用数组,或者另一种设计方法是this one

  • 请注意,图像渲染速度将超过CGPDFPageRef

  • 使用NSOperations或GCD&Blocks页提前准备

  • CGContextDrawPDFPage之前调用CGContextSetInterpolationQuality(ctx, kCGInterpolationHigh); CGContextSetRenderingIntent(ctx, kCGRenderingIntentDefault);以减少绘制时的内存使用量

  • 用docRef初始化你的NSOperations是个坏主意(内存),把docRef打包成一个单件.

  • 如果可以,取消不必要的NSOperations,尤其是如果他们将使用内存,请注意不要让上下文处于打开状态!

  • 回收页面对象并销毁未使用的视图

  • 在不需要任何打开的上下文时立即将其关闭

  • 收到内存警告时,释放并重新加载DocRef和所有页面缓存

Other PDF Features:

Documentation

Example projects

推荐答案

我已经使用大致相同的方法构建了此类应用程序,除了:

  • 我将生成的图像缓存在磁盘上,并始终在单独的线程中提前生成两到三个图像.
  • 我没有使用UIImage覆盖,而是在zoom 为1时在图层中绘制图像.当发出内存警告时,这些平铺将自动释放.

每当用户开始zoom 时,我都会获取CGPDFPage,并使用适当的CTM进行渲染.- (void)drawLayer: (CALayer*)layer inContext: (CGContextRef) context中的代码如下所示:

CGAffineTransform currentCTM = CGContextGetCTM(context);    
if (currentCTM.a == 1.0 && baseImage) {
    //Calculate ideal scale
    CGFloat scaleForWidth = baseImage.size.width/self.bounds.size.width;
    CGFloat scaleForHeight = baseImage.size.height/self.bounds.size.height; 
    CGFloat imageScaleFactor = MAX(scaleForWidth, scaleForHeight);

    CGSize imageSize = CGSizeMake(baseImage.size.width/imageScaleFactor, baseImage.size.height/imageScaleFactor);
    CGRect imageRect = CGRectMake((self.bounds.size.width-imageSize.width)/2, (self.bounds.size.height-imageSize.height)/2, imageSize.width, imageSize.height);
    CGContextDrawImage(context, imageRect, [baseImage CGImage]);
} else {
    @synchronized(issue) { 
        CGPDFPageRef pdfPage = CGPDFDocumentGetPage(issue.pdfDoc, pageIndex+1);
        pdfToPageTransform = CGPDFPageGetDrawingTransform(pdfPage, kCGPDFMediaBox, layer.bounds, 0, true);
        CGContextConcatCTM(context, pdfToPageTransform);    
        CGContextDrawPDFPage(context, pdfPage);
    }
}

问题是包含CGPDFDocumentRef的对象.我用同步来访问第pdfDoc个属性的部分,因为我会在收到Memory Warning时释放它并重新创建它.似乎CGPDFDocumentRef对象做了一些我不知道如何go 除的内部缓存.

Ios相关问答推荐

如何让AVAudio.installTap()每秒回调125次

在SwiftUI中使用系统图像和色调创建圆形按钮

如果条件不满足,S从@ViewBuilder返回什么?

自定义油漆圆角三角形

IOS:在UI线程中执行代码的闭包样式的替代

如何在SwiftUI中将图像整合到文本标签中间?

安装新版本 XCode 15.0 后无法运行应用程序 XCode

在 iOS 上以后台模式安排任务(屏幕时间 API)

iOS设备网页自动化中,在向字段发送文本后未启用按钮

小部件链接有效,但不执行任何操作

SwiftUI - ScrollView 不显示底部文本

包装在 AnyView 中时 UIViewControllerRepresentable 无法正常工作

从视图模型中更新 EnvironmentObject

setNeedsLayout 和 setNeedsDisplay

Xcode 4.1 致命错误:自构建预编译头文件后修改了 stdlib

Xcode 项目格式:3.1、3.2、6.3 和 8.0 有什么区别?

在 Xcode 4 中将静态库链接到 iOS 项目

应用程序不包含正确的测试版权利

NSURLSession:如何增加 URL 请求的超时时间?

如何关闭 iOS 键盘?