适用于 iPhone/iPad/iOS 的快速精益 PDF 查看器 - 提示和提示? [英] Fast and Lean PDF Viewer for iPhone / iPad / iOS - tips and hints?

查看:20
本文介绍了适用于 iPhone/iPad/iOS 的快速精益 PDF 查看器 - 提示和提示?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

There has been many Questions recently about drawing PDF's.

是的,您可以使用 UIWebView 非常轻松地呈现 PDF,但这无法提供您对优秀 PDF 查看器所期望的性能和功能.

Yes, you can render PDF's very easily with a UIWebView but this cant give the performance and functionality that you would expect from a good PDF viewer.

你可以绘制一个PDF页面到一个CALayer 到 UIImage.Apple 甚至有示例代码来展示如何绘制大型 PDF 在可缩放的 UIScrollview 中

You can draw a PDF page to a CALayer or to a UIImage. Apple even have sample code to show how draw a large PDF in a Zoomable UIScrollview

但同样的问题不断出现.

But the same issues keep cropping up.

UIImage 方法:

  1. UIImage 中的 PDF 在视觉上不是缩放以及层方法.
  2. CPU 和内存在生成时命中来自 PDFcontextUIImages限制/阻止使用它来创建实时渲染新的缩放级别.
  1. PDF's in a UIImage don't optically scale as well as a Layer approach.
  2. The CPU and memory hit on generating the UIImages from a PDFcontext limits/prevents using it to create a real-time render of new zoom-levels.

CATiledLayer 方法:

  1. 存在显着的开销(时间)将完整的 PDF 页面绘制到 CALayer:可以看到单个图块的渲染(即使使用 tileSize 调整)
  2. CALayers 不能提前准备时间(在屏幕外渲染).
  1. Theres a significant Overhead (time) drawing a full PDF page to a CALayer: individual tiles can be seen rendering (even with a tileSize tweak)
  2. CALayers cant be prepared ahead of time (rendered off-screen).

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

Generally PDF viewers are pretty heavy on memory too. Even monitor the memory usage of apple's zoomable PDF example.

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

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.

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

Im rendering 2 pages each side of the page in focus so that the PDF image is ready to mask the layer before it starts drawing.Pages are destroyed again when they are +2 pages away from the focused page.

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

一些提示(图片来源:Luke Mcneice、VdesmedT、Matt Gallagher、Johann):

Some Tips (Credit- Luke Mcneice,VdesmedT,Matt Gallagher,Johann):

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

  • Save any media to disk when you can.

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

Use larger tileSizes if rendering on TiledLayers

init 经常使用占位符对象的数组,或者另一种设计方法是 这个

init frequently used arrays with placeholder objects, alternitively another design approach is this one

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

Note that images will render faster than a CGPDFPageRef

使用 NSOperations 或 GCD &阻止提前准备页面时间.

Use NSOperations or GCD & Blocks to prepare pages ahead of time.

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

call CGContextSetInterpolationQuality(ctx, kCGInterpolationHigh); CGContextSetRenderingIntent(ctx, kCGRenderingIntentDefault); before CGContextDrawPDFPage to reduce memory usage while drawing

用 docRef 初始化你的 NSOperations 是个坏主意(内存),将 docRef 包装成一个单例.

init'ing your NSOperations with a docRef is a bad idea (memory), wrap the docRef into a singleton.

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

Cancel needless NSOperations When you can, especially if they will be using memory, beware of leaving contexts open though!

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

Recycle page objects and destroy unused views

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

Close any open Contexts as soon as you don't need them

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

on receiving memory warnings release and reload the DocRef and any page Caches

其他 PDF 功能:

转换 PDF 注释日期字符串

获取链接的目标(从/Dest数组中获取页码)

获取目录

文档标题关键字

获取原始文本(和此处此处here(定位重点)

Getting Raw Text (and here and Here and here (positioning focused))

搜索(和此处)(不适用于所有 PDF(有些只显示奇怪的字符,我想这是一个编码问题,但我不确定)-Credit BrainFeeder)

Searching(and here) (doesn't work with all PDFs (some just show weird characters, I guess it's an encoding issue but I'm not sure) -Credit BrainFeeder)

CALayer 和离屏渲染 - 渲染下一页快速/流畅的显示

CALayer and Off-Screen Rendering - render the next page for fast/smooth display

文档

  • Quartz PDFObjects (Used for meta info, annotations, thumbs)
  • Abobe PDF Spec

示例项目

  • Apple/ ZoomingPDF - zooming, UIScrollView, CATiledLayer
  • vfr/ reader - zooming, paging, UIScrollView, CATiledView
  • brow/ leaves - paging with nice transitions
  • / skim - everything it seems (PDF reader/editor for OSX)

推荐答案

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

I have build such kind of application using approximatively the same approach except :

  • 我将生成的图像缓存在磁盘上,并且总是在单独的线程中预先生成两到三个图像.
  • 我没有用 UIImage 覆盖,而是在缩放为 1 时在图层中绘制图像.当发出内存警告时,这些图块将自动释放.
  • I cache the generated image on the disk and always generate two to three images in advance in a separate thread.
  • I don't overlay with a UIImage but instead draw the image in the layer when zooming is 1. Those tiles will be released automatically when memory warnings are issued.

每当用户开始缩放时,我都会获取 CGPDFPage 并使用适当的 CTM 渲染它.- (void)drawLayer: (CALayer*)layer inContext: (CGContextRef) context 中的代码就像:

Whenever the user start zooming, I acquire the CGPDFPage and render it using the appropriate CTM. The code in - (void)drawLayer: (CALayer*)layer inContext: (CGContextRef) context is like :

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 对象做了一些我没有找到如何摆脱的内部缓存.

issue is the object containg the CGPDFDocumentRef. I synchronize the part where I access the pdfDoc property because I release it and recreate it when receiving memoryWarnings. It seems that the CGPDFDocumentRef object do some internal caching that I did not find how to get rid of.

这篇关于适用于 iPhone/iPad/iOS 的快速精益 PDF 查看器 - 提示和提示?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆