最近有很多关于绘制PDF的问题。
是的,你可以用UIWebView很容易地渲染PDF,但这不能给你从一个好的PDF浏览器所期望的性能和功能。
你可以绘制一个PDF页面到一个CALayer或一个UIImage。苹果甚至有样例代码来展示如何在可缩放的ui视图中绘制一个大的PDF
但同样的问题不断出现。
用户界面图像方法:
PDF在UIImage中不是光学的
缩放以及分层方法。
CPU和内存在生成
UIImages来自一个PDFcontext
限制/阻止使用它来创建
实时渲染新的缩放级别。
CATiledLayer方法:
有很大的开销(时间)
绘制一个完整的PDF页面到CALayer:单个的瓷砖可以看到渲染(即使有一个tileSize调整)
calayer不能提前准备
时间(显示在屏幕外)。
一般来说,PDF查看器也占用大量内存。甚至监控苹果可缩放PDF示例的内存使用情况。
在我目前的项目中,我正在开发一个PDF查看器,并在一个单独的线程中渲染一个页面的UIImage(这里也有问题!),并在缩放为x1时呈现它。CATiledLayer渲染开始时,比例是>1。iBooks采用了类似的重复查看方法,如果你滚动页面,你可以在不到一秒钟的时间内看到页面的低分辨率版本,然后就会出现清晰的版本。
我渲染2页页的每一面在焦点上,这样PDF图像就可以在开始绘制之前遮罩图层了。当页面距离焦点页面+2页时,页面再次被销毁。
有谁有任何见解,无论多么小或明显的提高性能/内存处理的绘图PDF ?或者这里讨论的其他问题?
编辑:一些建议(来源: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); before CGContextDrawPDFPage to reduce memory usage while drawing
init'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
其他PDF功能:
Getting Links inside a PDF (and here and here)
Understanding the PDF Rect for link positioning
Converting PDF annot datestrings
Getting the target of the link (Getting the page number from the /Dest array)
Getting a table of contents
Document title and Keywords
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
文档
石英PDFObjects(用于元信息,注释,拇指)
Abobe PDF规格
示例项目
Apple/ ZoomingPDF -缩放,UIScrollView, CATiledLayer
vfr/ reader -缩放,分页,UIScrollView, CATiledView
眉/叶-分页与良好的过渡
/略读-一切似乎(OSX PDF阅读器/编辑器)
我已经使用近似相同的方法构建了这样的应用程序,除了:
我将生成的图像缓存到磁盘上,并且总是在一个单独的线程中预先生成两到三张图像。
我没有使用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);
}
}
issue是包含CGPDFDocumentRef的对象。我同步访问pdfDoc属性的部分,因为我在接收memoryWarnings时释放它并重新创建它。似乎CGPDFDocumentRef对象做了一些内部缓存,我没有找到如何摆脱。
我已经使用近似相同的方法构建了这样的应用程序,除了:
我将生成的图像缓存到磁盘上,并且总是在一个单独的线程中预先生成两到三张图像。
我没有使用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);
}
}
issue是包含CGPDFDocumentRef的对象。我同步访问pdfDoc属性的部分,因为我在接收memoryWarnings时释放它并重新创建它。似乎CGPDFDocumentRef对象做了一些内部缓存,我没有找到如何摆脱。