适用于iPhone / iPad / iOs的快速精益PDF阅读器 - 提示和提示? [英] Fast and Lean PDF Viewer for iPhone / iPad / iOs - tips and hints?
问题描述
最近有很多关于绘制PDF的问题。
是的,您可以使用 UIWebView
轻松渲染PDF,但这无法提供您所需的性能和功能期待一个好的PDF查看器。
你可以画一个PDF页面到CALayer 或到UIImage 。 Apple甚至有示例代码来展示如何绘制大型PDF
但同样的问题不断出现。
UIImage方法:
- PDF在
UIImage中
没有光学
比例以及Layer方法。 - 产生
的CPU和内存UIImages
来自PDFcontext
限制/阻止使用它来创建
实时渲染新的缩放级别。
CATiledLayer方法:
- 有一个重要的开销(时间)
将完整的PDF页面绘制到CALayer
:可以看到单个图块呈现(即使是一个tileSize调整) -
CALayers
无法在
之前做好准备时间(在屏幕外呈现)。
一般来说PDF查看器的内存也相当沉重。甚至监视apple的可缩放PDF示例的内存使用情况。
在我当前的项目中,我正在开发一个PDF查看器并呈现 UIImage
一个单独的线程中的页面(这里也是问题!)并在比例为x1时显示它。 CATiledLayer
一旦比例> 1,渲染就会开始。 iBooks采用了类似的双重拍摄方式,就好像你滚动页面一样,你可以看到页面的低分辨率版本只有不到一秒钟,然后才出现一个清晰的版本。
我在页面每侧渲染2页焦点,以便PDF图像准备好在图层开始绘制之前屏蔽图层。当页面离焦点页面+2页时会再次销毁。
是否有人有任何见解,无论多么小或明显改善Drawing PDF的性能/内存处理?或者此处讨论的任何其他问题?
编辑: 一些提示(Credit-Luke Mcneice, VdesmedT,Matt Gallagher,Johann):
-
尽可能将所有媒体保存到磁盘。
-
在TiledLayers上渲染时使用更大的tileSizes
-
init常用数组和占位符对象,另外另一种设计方法是这一个
-
请注意,图片渲染速度快于
CGPDFPageRef
-
使用
NSOperations
或GCD& 阻止提前准备页面
的时间。 -
调用
CGContextSetInterpolationQuality(ctx,kCGInterpolationHigh); CGContextSetRenderingIntent(ctx,kCGRenderingIntentDefault);
在CGContextDrawPDFPage
之前减少绘制时的内存使用量 - 使用docRef初始化
NSOperations
是一个坏主意(内存),将docRef包装成单例。 -
取消不必要的
NSOperations
如果可以,特别是如果他们将使用内存,请注意保持上下文打开! -
回收页面对象并销毁未使用的视图
-
一旦不需要,关闭所有打开的上下文
p> -
收到内存警告时释放并重新加载DocRef和任何页面缓存
其他PDF功能:
-
-
获取链接的目标(从
/ Dest
数组中获取页码)
-
搜索(以及这里)(不适用于所有PDF(有些只显示奇怪的字符,我想这是一个编码问题,但我不确定)-Credit BrainFeeder)
-
< a href =https://stackoverflow.com/questions/3831304/calayer-and-off-screen-rendering> CALayer和离屏渲染 - 渲染下一页以便快速/流畅地显示
文档
- Quartz PDFObjects (用于元信息,注释,拇指)
- Abobe PDF Spec
示例项目
- Apple / ZoomingPDF - 缩放,
UIScrollView
,CATiledLayer
- vfr / reader - 缩放,分页,
UIScrollView
,CATiledView
- 眉毛/离开 - 带有漂亮过渡的分页
- / skim - 它看起来的一切(OSX的PDF阅读器/编辑器)
我使用近似相同的方法构建了这种类型的应用程序,除了:
- 我将生成的图像缓存在磁盘上,并且总是在一个单独的线程中预先生成两到三个图像。
- 我没有覆盖
UIImage
但是在缩放为1时在图层中绘制图像。当发出内存警告时,这些图块将自动释放。
每当用户开始缩放时,我获得 CGPDFPage
并使用适当的CTM渲染它。 - (void)drawLayer:(CALayer *)图层inContext:(CGContextRef)context
中的代码如下:
CGAffineTransform currentCTM = CGContextGetCTM(context);
if(currentCTM.a == 1.0&& baseImage){
//计算理想比例
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
对象做了一些内部缓存,我没有找到如何摆脱。
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
the
UIImages
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 a
CALayer
: 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)
I have build such kind of application using approximatively the same approach except :
- 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.
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);
}
}
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屋!