适用于 iPhone / iPad / iOS 的快速、精益 PDF 查看器 - 提示和提示?
最近有很多关于绘制 PDF 的问题。
是的,您可以使用 UIWebView
非常轻松地呈现 PDF,但这无法提供您所期望的优秀 PDF 查看器的性能和功能。
您可以将 PDF 页面绘制到 CALayer或到UIImage。 Apple 甚至有示例代码来展示如何绘制大型 PDF 在可缩放的 UIScrollview
但同样的问题不断出现。
UIImage 方法:
UIImage
中的 PDF 不具有光学效果 规模以及层方法。- CPU 和内存在生成时命中 来自
PDFcontext
的UIImages
限制/阻止使用它来创建 新缩放级别的实时渲染。
CATiledLayer 方法:
- 开销很大(时间) 将完整的 PDF 页面绘制到
CALayer
:可以看到各个图块的渲染(即使调整了tileSize) CALayers
无法提前准备 时间(在屏幕外渲染)。
一般来说,PDF 查看器对内存的占用也很大。甚至可以监控苹果可缩放 PDF 示例的内存使用情况。
在我当前的项目中,我正在开发一个 PDF 查看器,并在单独的线程中渲染页面的 UIImage
(这里也有问题!),并在比例为 x1 时呈现它。一旦比例>1,CATiledLayer
渲染就会开始。 iBooks 采用类似的双看方法,就好像您滚动页面一样,您可以在清晰版本出现之前看到页面的较低分辨率版本,时间不到一秒钟。
我在焦点页面的每一侧渲染 2 个页面,以便 PDF 图像在开始绘制之前准备好遮盖图层。当页面距焦点页面 +2 页时,页面将再次被销毁。
是否有人对改善绘图 PDF 的性能/内存处理有任何见解,无论多么小或多么明显?或此处讨论的任何其他问题?
编辑:一些提示(来源 - Luke Mcneice、VdesmedT、Matt Gallagher、Johann):
将任何媒体保存到尽可能将
如果在 TiledLayers 上渲染,请使用更大的tileSizes
使用占位符对象初始化经常使用的数组,或者另一种设计方法是这个
请注意,图像渲染速度比
CGPDFPageRef
使用
NSOperations
或 GCD & 块用于准备前面的页面调用
CGContextSetInterpolationQuality(ctx, kCGInterpolationHigh); CGContextSetRenderingIntent(ctx, kCGRenderingIntentDefault);
在CGContextDrawPDFPage
之前,减少绘图时的内存使用- docRef 绘制
初始化
NSOperations
时的内存使用量是一个坏主意(内存),将 docRef 包装成单例。 取消不必要的
NSOperations
当你可以的时候,特别是当它们将使用内存时,请注意不要让上下文保持打开状态!回收页面对象并销毁未使用的视图
在不需要时立即关闭所有打开的上下文
收到内存警告时释放并重新加载 DocRef 和任何页面缓存
其他 PDF 功能:
获取 PDF 中的链接(以及 此处和此处)
获取链接的目标(从
/Dest
数组中获取页码)
搜索(和此处)(不适用于所有 PDF(有些只是显示奇怪的字符,我猜这是一个编码问题,但我不确定)-Credit BrainFeeder)
CALayer 和离屏渲染 - 渲染下一页以实现快速/平滑显示
文档
- Quartz PDFObjects(用于元信息、注释、缩略图)
- Abobe PDF 规范
示例项目
- Apple/ ZoomingPDF - 缩放,< code>UIScrollView,
CATiledLayer
- vfr/ reader - 缩放、分页,
UIScrollView
,CATiledView
- brow/leaves - 分页具有良好的过渡
- /skim - 看起来的一切(OSX 的 PDF 阅读器/编辑器)
There has been many Questions recently about drawing PDF's.
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.
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 Method:
- PDF's in a
UIImage
don't optically
scale as well as a Layer approach. - The CPU and memory hit on generating
theUIImages
from aPDFcontext
limits/prevents using it to create a
real-time render of new zoom-levels.
CATiledLayer Method:
- Theres a significant Overhead (time)
drawing a full PDF page to aCALayer
: individual tiles can be seen rendering (even with a tileSize tweak) CALayers
cant be prepared ahead of
time (rendered off-screen).
Generally PDF viewers are pretty heavy on memory too. Even monitor the memory usage of apple's zoomable PDF example.
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 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.
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: Some Tips (Credit- Luke Mcneice,VdesmedT,Matt Gallagher,Johann):
Save any media to disk when you can.
Use larger tileSizes if rendering on TiledLayers
init frequently used arrays with placeholder objects, alternitively another design approach is this one
Note that images will render faster than a
CGPDFPageRef
Use
NSOperations
or GCD & Blocks to prepare pages ahead
of time.call
CGContextSetInterpolationQuality(ctx, kCGInterpolationHigh); CGContextSetRenderingIntent(ctx, kCGRenderingIntentDefault);
beforeCGContextDrawPDFPage
to reduce memory usage while drawinginit'ing your
NSOperations
with a docRef is a bad idea (memory), wrap the docRef into a singleton.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
on receiving memory warnings release and reload the DocRef and any page Caches
Other PDF Features:
Getting Links inside a PDF (and here and here)
Getting the target of the link (Getting the page number from the
/Dest
array)
Getting Raw Text (and here and Here and here (positioning focused))
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 and Off-Screen Rendering - render the next page for fast/smooth display
Documentation
- Quartz PDFObjects (Used for meta info, annotations, thumbs)
- Abobe PDF Spec
Example projects
- 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)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我已经使用大致相同的方法构建了此类应用程序,除了:
UIImage
进行覆盖,而是在缩放为 1 时在图层中绘制图像。当发出内存警告时,这些图块将自动释放。每当用户开始缩放时,我都会获取 CGPDFPage 并使用适当的 CTM 渲染它。
- (void)drawLayer: (CALayer*)layer inContext: (CGContextRef) context
中的代码如下:问题是包含
CGPDFDocumentRef
的对象。我同步了访问 pdfDoc 属性的部分,因为我在收到内存警告时释放了它并重新创建了它。 CGPDFDocumentRef 对象似乎做了一些内部缓存,我没有找到如何摆脱它。I have build such kind of application using approximatively the same approach except :
UIImage
but instead draw the image in the layer when zooming is 1. Those tiles will be released automatically when memory warnings are issued.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 :issue is the object containg the
CGPDFDocumentRef
. I synchronize the part where I access thepdfDoc
property because I release it and recreate it when receiving memoryWarnings. It seems that theCGPDFDocumentRef
object do some internal caching that I did not find how to get rid of.对于简单有效的 PDF 查看器,当您只需要有限的功能时,您现在可以 (iOS 4.0+) 使用 QuickLook 框架:
首先,您需要链接
QuickLook.framework
和#进口
;
然后,在
viewDidLoad
或任何延迟初始化方法中:For a simple and effective PDF viewer, when you require only limited functionality, you can now (iOS 4.0+) use the QuickLook framework:
First, you need to link against
QuickLook.framework
and#import
<QuickLook/QuickLook.h>;
Afterwards, in either
viewDidLoad
or any of the lazy initialization methods:自 iOS 11 起,您可以使用名为 PDFKit 的本机框架来显示和操作 PDF。
导入 PDFKit 后,您应该使用本地或远程 URL 初始化
PDFView
并将其显示在您的视图中。在 Apple 开发者文档中了解有关 PDFKit 的更多信息。
Since iOS 11, you can use the native framework called PDFKit for displaying and manipulating PDFs.
After importing PDFKit, you should initialize a
PDFView
with a local or a remote URL and display it in your view.Read more about PDFKit in the Apple Developer documentation.