我们都知道,在iPhone/iPad显示pdf的基本方法有两个,一个是使用UIWebView直接加载pdf文件,另一个是使用Core Graphics进行渲染(姑且称之为CGPDF方法)。UIWebView的方法是简单,只需加载pdf,其他诸如放大翻页等问题通通交给UIWebView去头痛吧。但其缺点是性能较慢,功能有限,比如要实现搜索,添加笔记等功能就比较难。而使用CGPDF方法,功能就没有限制(虽然pdf解析方面,苹果提供的文档实在有限),使用Core Graphics进行渲染,性能上也比UIWebView要提高许多,只不过翻页,放大缩小等功能都需要自己实现。
有关pdf放大缩小,翻页等功能可以使用UIScrollView实现,不在本文讨论的范围之内。笔者在项目中使用了CGPDF的过程中,曾遇到两个小问题,因此,在这里总结一下:
1. 页面放大后变得不清晰
先看看我程序中的渲染代码,可以放在- (void)drawRect:(CGRect)rect 或者 -(void)drawLayer:(CALayer*)layer inContext:(CGContextRef)context 中:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
-
(
void
)drawRect
:
(CGRect
)rect
{ CGContextRef context = UIGraphicsGetCurrentContext ( ); // fill in the white background for pdf page CGContextSetRGBFillColor ( context, 1.0, 1.0, 1.0, 1.0 ); CGContextFillRect ( context, CGContextGetClipBoundingBox ( context ) ); CGContextSaveGState (context ); // Flip the context so that the PDF page is rendered // right side up. CGContextTranslateCTM ( context, 0.0, self.bounds.size.height ); CGContextScaleCTM ( context, 1.0, -1.0 ); // Scale the context so that the PDF page is rendered // at the correct size for the zoom level. CGAffineTransform pdfXfm = CGPDFPageGetDrawingTransform ( _page.page, kCGPDFMediaBox, self.bounds, 0, true ); CGContextConcatCTM ( context, pdfXfm ); CGContextSetInterpolationQuality (context, kCGInterpolationHigh ); CGContextSetRenderingIntent (context, kCGRenderingIntentDefault ); CGContextDrawPDFPage ( context, _page.page ); CGContextRestoreGState (context ); } |
简单地说,这段代码就是使用Core Graphics进行pdf的渲染,可是我的pdf放大后为什么不清晰呢?先看看放大pdf后可以使其清晰的部分代码吧:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
-
(
id
)initWithPdfPage
:
(PDFPage
*
)page
{ if ( (self = [super initWithFrame :CGRectMake (0, 0, page.size.width, page.size.height ) ] ) ) { CATiledLayer * layer = (CATiledLayer * ) [self layer ]; layer.levelsOfDetail = 4; layer.levelsOfDetailBias = 4; layer.tileSize = CGSizeMake (1024.0, 1024.0 ); } return self; } + ( Class )layerClass { return [CATiledLayer class ]; } |
其秘诀就在CATiledLayer,简单地说就是CATiledLayer将不同等级的tiles(拼贴)缓存起来,而CGContextDrawPDFPage则根据最合适的放大等级将pdf渲染出来。
根据文档CATiledLayer可以更高效,高质量地渲染pdf文档,但我则遇到了第二个问题。
2. 页面渲染速度慢,而且呈块状渲染
简而言之就是pdf页面一块一块地慢慢渲染出来,效果非常不好。这是怎么回事?经过一番研究发现是CATiledLayer的动画效果在作怪。每个Tile的渲染据说都有0.25s的动画时间,其结果就是pdf文档一块一块地出现了。要怎样解决这个问题呢?最为直接的方法就是把0.25s的动画时间直接设置为0。下面是代码(采用继承CATiledLayer的方法):
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
@interface FastCATiledLayer
: CATiledLayer
@end @implementation FastCATiledLayer + (CFTimeInterval )fadeDuration { return 0.0; } + ( Class )layerClass { return [FastCATiledLayer class ]; } - ( id )initWithPdfPage : (PDFPage * )page { if ( (self = [super initWithFrame :CGRectMake (0, 0, page.size.width, page.size.height ) ] ) ) { FastCATiledLayer * layer = (FastCATiledLayer * ) [self layer ]; layer.levelsOfDetail = 4; layer.levelsOfDetailBias = 4; layer.tileSize = CGSizeMake (1024.0, 1024.0 ); } return self; } @end |