【问题标题】:Fast and Lean PDF Viewer for iPhone / iPad / iOS - tips and hints?适用于 iPhone / iPad / iOS 的快速精益 PDF 查看器 - 提示和提示?
【发布时间】:2011-04-22 19:45:41
【问题描述】:

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

是的,您可以使用UIWebView 轻松呈现 PDF,但这无法提供您期望从一个好的 PDF 查看器中获得的性能和功能。

您可以在to a CALayer to a UIImage 绘制PDF 页面。苹果甚至有示例代码来展示如何绘制一个大的 PDF in a Zoomable UIScrollview

但同样的问题不断出现。

UIImage 方法:

  1. UIImage 中的 PDF 不是光学的 规模以及层方法。
  2. CPU 和内存命中生成 UIImages 来自 PDFcontext 限制/防止使用它来创建 新缩放级别的实时渲染。

CATiledLayer 方法:

  1. 存在大量开销(时间) 将完整的 PDF 页面绘制到 CALayer:可以看到各个图块呈现(即使调整了 tileSize)
  2. CALayers不能提前准备 时间(在屏幕外渲染)。

通常,PDF 查看器的内存也很重。甚至监控苹果的可缩放 PDF 示例的内存使用情况。

在我当前的项目中,我正在开发一个 PDF 查看器,并在单独的线程中呈现页面的UIImage(这里也有问题!)并在比例为 x1 时呈现它。 CATiledLayer 一旦比例大于 1,就会开始渲染。 iBooks 采用了类似的双重拍摄方法,就像您滚动页面时,您可以在不到一秒钟的时间内看到较低分辨率的页面,然后出现清晰的版本。

我在焦点页面的每一侧渲染 2 页,以便 PDF 图像在开始绘制之前准备好遮盖图层。当页面距离焦点页面 +2 页时,它们会再次被销毁。

有没有人有任何见解,无论多么小或多么明显,以提高绘图 PDF 的性能/内存处理?或此处讨论的任何其他问题?

编辑: 一些提示(Credit- Luke Mcneice、VdesmedT、Matt Gallagher、Johann):

  • 尽可能将任何媒体保存到磁盘。

  • 如果在 TiledLayers 上渲染,请使用更大的 tileSizes

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

  • 请注意,图像的渲染速度比 CGPDFPageRef 更快

  • 使用 NSOperations 或 GCD & Blocks 来准备页面 时间。

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

  • 使用 docRef 初始化您的 NSOperations 是个坏主意(内存),请将 docRef 包装到单例中。

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

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

  • 在不需要时立即关闭所有打开的上下文

  • 在收到内存警告时释放并重新加载 DocRef 和任何页面缓存

其他 PDF 功能:

文档

示例项目

【问题讨论】:

  • 发表评论以确保窥视者收到编辑通知
  • +1 感谢您添加所有这些信息,希望我在开发阅读器时拥有它;)也感谢您添加有关 PDF 注释的问题(它还包含示例代码的答案)。几天前我打开了这个:stackoverflow.com/questions/4097044/pdf-search-on-the-iphone你有什么建议吗?
  • 我自己还没有介绍过这个,所以除了将你指向随机想法博客之外,我无话可说:random-ideas.net/posts/42 不过感谢您的帖子,我正在尝试收集所有 PDF 问题在一个地方。
  • 在我的公司,我们使用了一个名为 PSPDFKit 的 3rd 方解决方案来进行 Pdf 渲染、符号等,它并不便宜,但值得:pspdfkit.com
  • +1 我为我的开源 pdf 查看器遵循了这些有用的提示 Swifty PDF github.com/prcela/SwiftyPDF

标签: ios swift pdf calayer apple-pdfkit


【解决方案1】:

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

  • 我将生成的图像缓存在磁盘上,并且总是在单独的线程中预先生成两到三个图像。
  • 我不覆盖UIImage,而是在缩放为 1 时在图层中绘制图像。当内存警告发出时,这些图块将自动释放。

每当用户开始缩放时,我都会获取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 属性的部分,因为我在收到memoryWarnings 时释放它并重新创建它。似乎CGPDFDocumentRef 对象做了一些我没有找到如何摆脱的内部缓存。

【讨论】:

  • 当用户开始缩放时你的方法是什么?
  • @Luke :我已经修改帖子来回答
  • 非常感谢,以及有关 CGPDFDocumentRef 缓存的提示。
  • 只是一个简单的问题:当比例为 1.0 时,为什么要获取 pdfPageRef 和转换?因为我看到您在创建转换之前绘制了一个 baseImage(来自 bg 工作人员的图像?)。
  • @Luke :请在此处发布您可以做出的任何性能改进。谢谢!
【解决方案2】:

对于一个简单有效的 PDF 查看器,当您只需要有限的功能时,您现在可以(iOS 4.0+)使用 QuickLook 框架:

首先,您需要链接到QuickLook.framework#import <QuickLook/QuickLook.h>;

之后,在 viewDidLoad 或任何惰性初始化方法中:

QLPreviewController *previewController = [[QLPreviewController alloc] init];
previewController.dataSource = self;
previewController.delegate = self;
previewController.currentPreviewItemIndex = indexPath.row;
[self presentModalViewController:previewController animated:YES];
[previewController release];

【讨论】:

  • 是的,这在概念上与使用 UIWebView 相同。如果这很容易,我们就不会花几个小时来弄清楚如何使用 CGPDF* 的东西。
  • 是的,当然。我当然不会把它作为一个完整的解决方案来呈现。但是这个问题的一些读者可能没有意识到,出于某些目的,这是一个合理的解决方案。更新了答案以明确这一点。
  • 为此 +1。我的主要兴趣是允许用户查看一些 PDF 格式的应用内文档。我不关心搜索、突出显示或任何其他的花里胡哨——只关心高性能的 PDF 渲染。
  • 我的 UIImage+PDF 类别是一个带有内置缓存层的快速简洁的 PDF 渲染器。 github.com/mindbrix/UIImage-PDF
【解决方案3】:

iOS 11 开始,您可以使用名为 PDFKit 的原生框架来显示和操作 PDF。

导入 PDFKit 后,您应该使用本地或远程 URL 初始化 PDFView 并将其显示在您的视图中。

if let url = Bundle.main.url(forResource: "example", withExtension: "pdf") {
    let pdfView = PDFView(frame: view.frame)
    pdfView.document = PDFDocument(url: url)
    view.addSubview(pdfView)
}

Read more about PDFKit in the Apple Developer documentation.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-30
    • 1970-01-01
    相关资源
    最近更新 更多