最近有很多关于绘制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对象做了一些内部缓存,我没有找到如何摆脱。


对于一个简单有效的PDF查看器,当你只需要有限的功能时,你现在可以(iOS 4.0+)使用QuickLook框架:

首先,你需要链接QuickLook.framework和#import <快速直观/ QuickLook.h >;

然后,在viewDidLoad或任何惰性初始化方法中:

QLPreviewController *previewController = [[QLPreviewController alloc] init];
previewController.dataSource = self;
previewController.delegate = self;
previewController.currentPreviewItemIndex = indexPath.row;
[self presentModalViewController:previewController animated:YES];
[previewController release];

自iOS 11以来,您可以使用称为PDFKit的原生框架来显示和操作pdf。

导入PDFKit后,您应该使用本地或远程URL初始化PDFView并在视图中显示它。

if let url = Bundle.main.url(forResource: "example", withExtension: "pdf") {
    let pdfView = PDFView(frame: view.frame)
    pdfView.document = PDFDocument(url: url)
    view.addSubview(pdfView)
}

在苹果开发者文档中阅读更多关于PDFKit的信息。