【问题标题】:How can I programmatically generate a thumbnail of a PDF with iOS?如何使用 iOS 以编程方式生成 PDF 的缩略图?
【发布时间】:2011-05-05 16:54:03
【问题描述】:

我们目前使用UIWebViews 显示PDF 内容。理想情况下,我希望能够在UITableView 中显示缩略图,而无需同时加载许多不同的UIWebViews...它们加载一个文档的速度足够慢-更不用说10+!

我该怎么做?

我曾考虑截屏使用UIDocumentInteractionControllerUIWebView 加载的文档,但这意味着在显示表格之前必须将它们全部缩略。

【问题讨论】:

    标签: ios objective-c pdf cocoa-touch


    【解决方案1】:

    如果你使用 PDFKit,有一个 PDFPage 的方法叫做 thumbnail。它适用于 iOS11 及更高版本,只需几行代码即可完成工作。这是在PDFDocument 中生成给定页面缩略图的简单方法。

    func makeThumbnail(pdfDocument: PDFDocument?, page: Int) -> UIImage? {
            return pdfDocument?.page(at: page)?.thumbnail(of: CGSize(width: 40, height: 40), for: .artBox)
        }
    

    很遗憾,它缺少官方文档(请参阅 https://developer.apple.com/documentation/pdfkit/pdfpage/2869834-thumbnail)。但是,PDFPage 的代码中有一些可访问的 cmets。

    【讨论】:

      【解决方案2】:

      这里是 swift 3 方法,用于为 pdf 页面生成 UIImage 缩略图

      static func getThumbnailForPDF(_ urlString:String, pageNumber:Int) -> UIImage? {
          let bundle = Bundle.main
          let path = bundle.path(forResource: urlString, ofType: "pdf")
          let pdfURL = URL(fileURLWithPath: path!)
      
          let pdf = CGPDFDocument(pdfURL as CFURL )!
          let page = pdf.page(at: pageNumber)!
          let rect = CGRect(x: 0, y: 0, width: 100.0, height: 70.0) //Image size here
      
          UIGraphicsBeginImageContext(rect.size)
          let context = UIGraphicsGetCurrentContext()!
      
          context.saveGState()
          context.translateBy(x: 0, y: rect.height)
          context.scaleBy(x: 1.0, y: -1.0)
          context.setFillColor(gray: 1.0, alpha: 1.0)
          context.fill(rect)
      
      
          let pdfTransform = page.getDrawingTransform(CGPDFBox.mediaBox, rect: rect, rotate: 0, preserveAspectRatio: true)
          context.concatenate(pdfTransform)
          context.drawPDFPage(page)
      
          let thumbImage = UIGraphicsGetImageFromCurrentImageContext()
          context.restoreGState()
      
          UIGraphicsEndImageContext()
      
          return thumbImage
      }
      

      【讨论】:

      • 嘿,埃米尔,你迟到了 7 年——但仍然感谢你为面临同样问题的任何人提出这个问题 ;-)
      【解决方案3】:

      Apple 在CoreGraphics 级别提供了一大堆方法,用于直接绘制 PDF 内容。据我所知,它们都没有被整齐地打包在UIKit 级别,所以目前它可能不适合您的项目,特别是如果您在 C 级别不那么舒服的话.但是,相关功能是CGContextDrawPDFPage;,按照正常的CoreGraphics 方式,还有其他方法可以从数据源创建PDF 引用,然后从PDF 获取页面引用。然后,您需要处理缩放和转换为您想要的视图,并被警告您需要执行水平翻转,因为 PDF(和 OS X)使用左下角作为原点,而 iOS 使用左上角.示例代码,在我脑海中浮现:

      UIGraphicsBeginImageContext(thumbnailSize);
      CGPDFDocumentRef pdfRef = CGPDFDocumentCreateWithProvider( (CGDataProviderRef)instanceOfNSDataWithPDFInside );
      CGPDFPageRef pageRef = CGPDFDocumentGetPage(pdfRef, 1); // get the first page
      
      CGContextRef contextRef = UIGraphicsGetCurrentContext();
      
      // ignore issues of transforming here; depends on exactly what you want and
      // involves a whole bunch of normal CoreGraphics stuff that is nothing to do
      // with PDFs
      CGContextDrawPDFPage(contextRef, pageRef);
      
      UIImage *imageToReturn = UIGraphicsGetImageFromCurrentImageContext();
      
      // clean up
      UIGraphicsEndImageContext();
      CGPDFDocumentRelease(pdfRef);
      
      return imageToReturn;
      

      您可能想使用CGPDFPageGetBoxRect(pageRef, kCGPDFCropBox) 来获取页面的裁剪框,然后确定如何缩放/移动它以适合您的图像大小。

      -renderInContext:CALayer 上的方法可能更容易为您服务(请参阅QA 1703) — 获取屏幕截图的旧方法是 UIGetScreenImage,但这从来都不是真正的官方 API,而且似乎只是暂时允许因为RedLaser的意外批准。使用 QA 中的代码,您可以自行安装以从任何其他视图获取 UIImage,而无需将该视图显示在屏幕上。这可能解决您的屏幕捕获问题?虽然这意味着您只能支持 OS 4.x。

      在任何一种情况下,PDF 的绘制速度都不会那么快。您可能需要填充表格,然后在后台线程上绘制缩略图,并在可用时将它们向上推。您实际上不能在后台线程上安全地使用 UIKit 对象,但所有 CoreGraphics 的东西都是安全的。

      【讨论】:

        【解决方案4】:

        这是考虑转换的示例代码。 :)

        NSURL* pdfFileUrl = [NSURL fileURLWithPath:finalPath];
        CGPDFDocumentRef pdf = CGPDFDocumentCreateWithURL((CFURLRef)pdfFileUrl);
        CGPDFPageRef page;
        
        CGRect aRect = CGRectMake(0, 0, 70, 100); // thumbnail size
        UIGraphicsBeginImageContext(aRect.size);
        CGContextRef context = UIGraphicsGetCurrentContext();
        UIImage* thumbnailImage;
        
        
        NSUInteger totalNum = CGPDFDocumentGetNumberOfPages(pdf);
        
        for(int i = 0; i < totalNum; i++ ) {
        
        
            CGContextSaveGState(context);
            CGContextTranslateCTM(context, 0.0, aRect.size.height);
            CGContextScaleCTM(context, 1.0, -1.0);
        
            CGContextSetGrayFillColor(context, 1.0, 1.0);
            CGContextFillRect(context, aRect);
        
        
            // Grab the first PDF page
            page = CGPDFDocumentGetPage(pdf, i + 1);
            CGAffineTransform pdfTransform = CGPDFPageGetDrawingTransform(page, kCGPDFMediaBox, aRect, 0, true);
            // And apply the transform.
            CGContextConcatCTM(context, pdfTransform);
        
            CGContextDrawPDFPage(context, page);
        
            // Create the new UIImage from the context
            thumbnailImage = UIGraphicsGetImageFromCurrentImageContext();
        
            //Use thumbnailImage (e.g. drawing, saving it to a file, etc)
        
            CGContextRestoreGState(context);
        
        }
        
        
        UIGraphicsEndImageContext();    
        CGPDFDocumentRelease(pdf);
        

        【讨论】:

        • 大家好,我正在使用您的代码获取 PDF 缩略图。似乎 CGContextConcatCTM(context, pdfTransform) 行会产生内存瓶颈,我发现如果我不考虑这一行,那就没问题了。但我不能忽略它,因为我需要它来获得正确的缩略图。您对我们如何改进这一点有任何想法吗?顺便说一句...
        • 这个对我有用......上面那个我不知道为什么,但它生成了一个虚拟或垃圾缩略图......谢谢......
        • 文档说 UIGraphicsGetImageFromCurrentImageContext() 不是线程安全的
        • 这个工作正常。接受的答案是生成一些空白图像
        猜你喜欢
        • 2018-08-18
        • 2012-01-26
        • 1970-01-01
        • 2011-06-15
        • 2011-05-20
        • 2015-06-05
        • 2017-11-16
        • 2016-07-29
        • 1970-01-01
        相关资源
        最近更新 更多