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

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

问题描述

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



是的,您可以使用 UIWebView 轻松渲染PDF,但这无法提供您所需的性能和功能期待一个好的PDF查看器。



你可以画一个PDF页面到CALayer 到UIImage 。 Apple甚至有示例代码来展示如何绘制大型PDF



但同样的问题不断出现。



UIImage方法:


  1. PDF在 UIImage中没有光学
    比例以及Layer方法。

  2. 产生
    的CPU和内存 UIImages 来自 PDFcontext
    限制/阻止使用它来创建
    实时渲染新的缩放级别。

CATiledLayer方法:


  1. 有一个重要的开销(时间)
    将完整的PDF页面绘制到 CALayer :可以看到单个图块呈现(即使是一个tileSize调整)

  2. CALayers 无法在
    之前做好准备时间(在屏幕外呈现)。

一般来说PDF查看器的内存也相当沉重。甚至监视apple的可缩放PDF示例的内存使用情况。



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



我在页面每侧渲染2页焦点,以便PDF图像准备好在图层开始绘制之前屏蔽图层。当页面离焦点页面+2页时会再次销毁。



是否有人有任何见解,无论多么小或明显改善Drawing PDF的性能/内存处理?或者此处讨论的任何其他问题?



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





其他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:

  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 Method:

  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).

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); 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

Other PDF Features:

Documentation

Example projects

解决方案

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屋!

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