【问题标题】:Creating pdf Thumbnail in iphone在iphone中创建pdf缩略图
【发布时间】:2011-08-05 06:21:12
【问题描述】:

我是 Objective-c iPhone 编程的新手。我有一个应用程序可以在 UIWebView 中成功显示 PDF,但现在我想创建 PDF 的缩略图。我的 PDF 存储在我的资源文件夹中。

所以请给我代码,告诉我如何显示 PDF 的缩略图。我的代码用于显示 PDF 是在按钮功能中采用的:

-(void)show:(id)sender {

    pdfView.autoresizesSubviews = NO;
    pdfView.scalesPageToFit=YES;
    pdfView.autoresizingMask=(UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth);
    [pdfView setDelegate:self];

    NSString *path = [[NSBundle mainBundle] pathForResource:@"com" ofType:@"pdf"];
    NSLog(@"Path of res is%@",path);
    NSURL *url = [NSURL fileURLWithPath:path];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    [pdfView loadRequest:request];
}

【问题讨论】:

    标签: iphone objective-c pdf


    【解决方案1】:

    试试下面的方法:

    - (UIImage *)imageFromPDFWithDocumentRef:(CGPDFDocumentRef)documentRef {
        CGPDFPageRef pageRef = CGPDFDocumentGetPage(documentRef, 1);
        CGRect pageRect = CGPDFPageGetBoxRect(pageRef, kCGPDFCropBox);
    
        UIGraphicsBeginImageContext(pageRect.size);
        CGContextRef context = UIGraphicsGetCurrentContext();
        CGContextTranslateCTM(context, CGRectGetMinX(pageRect),CGRectGetMaxY(pageRect));
        CGContextScaleCTM(context, 1, -1);  
        CGContextTranslateCTM(context, -(pageRect.origin.x), -(pageRect.origin.y));
        CGContextDrawPDFPage(context, pageRef);
    
        UIImage *finalImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        return finalImage;
    } 
    

    【讨论】:

    • 感谢它运行并给了我 pdf 的单个图像,但是如果我的 pdf 有 7 页,我想显示我的 pdf 的缩略图,那么它给了我 pdf 的 7 个缩略图,这就是我编写以下代码的原因跨度>
    • 把上面的函数改成这样: - (UIImage *)imageFromPDFWithDocumentRef:(CGPDFDocumentRef)documentRef and PageNumber:(int)pageNumber { CGPDFPageRef pageRef = CGPDFDocumentGetPage(documentRef, pageNumber); 然后循环调用它。
    • 您知道这为我节省了多少时间吗?我要打印你的照片并用它制作出来。
    • 这段代码在iOS8中出现问题..谁能帮忙?
    【解决方案2】:

    您可能已经知道 2 种渲染 PDF 的方法:

    • UIWebView
    • 石英渲染

    在撰写本文时,其他答案都集中在 Quartz 上。这主要与性能相关有很多很好的理由,但我认为使用 Quartz 是值得的。我建议阅读 this thread 以更好地了解优缺点。

    显然有一个出色的基于 Quartz 的 pdf 渲染的新 API here

    您可以通过 UIWebView 呈现 pdf 并使用石英渲染拇指。

    还有一些关于拇指的困惑,对于人们新的石英 pdf 魔法,经过一番搜索后似乎有支持拇指的 API,您应该检查是否支持 嵌入式仅限拇指,许多 PDF 没有这些。

    另一种选择是自己创建拇指(使用石英),网上有很多这样的例子,包括上面的两个答案。但是,如果您的目标是 iOS 4 或更高版本,我强烈建议您使用块。 (从 4 开始,图形上下文也是线程安全的)。

    我发现使用块生成拇指时性能显着提高。

    我过去做过的是:

    • 为你的 ViewController 大拇指,它有一个滚动视图 适合所有人的内容大小 你的页面。插入占位符 如果您愿意,可以将 ImageViews 放入。

    • 在加载文档时,启动拇指 后台生成器(见代码 下面)

    • 下面的代码调用了一个方法drawImageView,它获取页面的索引,从磁盘中抓取图像并将其放入滚动视图中

    • 如果你真的有动力,你可以在拇指滚动视图上实现一个渲染范围(只渲染你需要的拇指 - 无论如何你应该为 pdf 做一些事情)

    • 完成后不要忘记删除拇指,除非你想缓存..

    #define THUMB_SIZE 100,144

    -(void)generateThumbsWithGCD
    {
    
        thumbQueue = dispatch_queue_create("thumbQueue", 0);//thumbQueue = dispatch_queue_t
        NSFileManager *fm = [NSFileManager defaultManager];
        //good idea to check for previous thumb cache with NSFileManager here   
    
        CGSize thumbSize = CGSizeMake(THUMB_SIZE);
        __block CGPDFPageRef myPageRef;     
    
        NSString *reqSysVer = @"4.0";   
        NSString *currSysVer = [[UIDevice currentDevice] systemVersion];    
    
        //need to handle ios versions < 4
        if ([currSysVer compare:reqSysVer options:NSNumericSearch] == NSOrderedAscending) {NSLog(@"UIKIT MULTITHREADING NOT SUPPORTED!");return;}//thread/api saftey
    
    dispatch_async(thumbQueue, ^{
    
        for (i=1; i<=_maxPages; i++) {      
    
            //check if worker is valid (class member bool) for cancelations
    
            myPageRef=[[PDFDocument sharedPDFDocument]getPageData:i];//pdfdocument is a singleton class     
    
            if(!myPageRef)return;
    
    
    
    
                NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    
                NSString* imageName = [NSString stringWithFormat:@"%@thumb%i.png",documentName,i];  
                NSString* fullPathToFile =  [thumbDocPath stringByAppendingPathComponent:imageName];
    
                if(![fm fileExistsAtPath:fullPathToFile]){
                    //NSLog(@"Not there");
                    UIGraphicsBeginImageContext(thumbSize);//thread Safe in iOs4
                    CGContextRef context = UIGraphicsGetCurrentContext();//thread Safe in iOs4          
                    CGContextTranslateCTM(context, 0, 144);
                    CGContextScaleCTM(context, 0.15, -0.15);
                    CGContextDrawPDFPage (context, myPageRef);
                    UIImage * render = UIGraphicsGetImageFromCurrentImageContext();                     
                    UIGraphicsEndImageContext();        
                    NSData* imageData= UIImagePNGRepresentation(render);
    
                    if(imageData){
                        NSLog(@"WROTE TO:%@",fullPathToFile);
                        if(![imageData writeToFile:fullPathToFile atomically:NO])NSLog(@"ERROR: Thumb Didnt Save"); //COMMENT OUT TO DISABLE WRITE                  
                    }               
                }
                else NSLog(@"Allready There! %@",fullPathToFile);
                        //update progress on thumb viewController if you wish here
                [pool release];
                dispatch_sync(dispatch_get_main_queue(), ^{
                [self drawImageView:i];
            });
    
        }   
        });
        dispatch_release(thumbQueue);
    
    }
    

    【讨论】:

    • 很好的答案,我看到了您的 PDFDocument 单例,您如何处理需要释放 CGPDFDocument 以刷新它在访问页面时创建的缓存的内存警告?
    • 如果我需要删除文档,那么在 2 级警告上我会这样做,但也会设置一个标志,以便我的后台任务定期检查。您的缩略图生成器需要在其中包含逻辑(即在循环开始时或至少在它访问文档之前),如果它看到此标志,可以提前结束它的生成。如果在开始拇指之前,您还检查它是否已经存在(或先进行全面检查),那么它将不必重做已缓存的拇指(这对于重新打开文档和通过拇指更改文档参考中途也有效操作)
    • 显然 UIGraphicsGetCurrentContext 在 5.0 中不是线程安全的
    【解决方案3】:

    我刚刚将 Objective-C 代码重写为 Swift。也许其他人可以使用它:

    func getThumbnail(url:NSURL, pageNumber:Int) -> UIImage {
    
        var pdf:CGPDFDocumentRef = CGPDFDocumentCreateWithURL(url as CFURLRef);
    
        var firstPage = CGPDFDocumentGetPage(pdf, pageNumber)
    
        var width:CGFloat = 240.0;
    
        var pageRect:CGRect = CGPDFPageGetBoxRect(firstPage, kCGPDFMediaBox);
        var pdfScale:CGFloat = width/pageRect.size.width;
        pageRect.size = CGSizeMake(pageRect.size.width*pdfScale, pageRect.size.height*pdfScale);
        pageRect.origin = CGPointZero;
    
        UIGraphicsBeginImageContext(pageRect.size);
    
        var context:CGContextRef = UIGraphicsGetCurrentContext();
    
        // White BG
        CGContextSetRGBFillColor(context, 1.0,1.0,1.0,1.0);
        CGContextFillRect(context,pageRect);
    
        CGContextSaveGState(context);
    
        // ***********
        // Next 3 lines makes the rotations so that the page look in the right direction
        // ***********
        CGContextTranslateCTM(context, 0.0, pageRect.size.height);
        CGContextScaleCTM(context, 1.0, -1.0);
        CGContextConcatCTM(context, CGPDFPageGetDrawingTransform(firstPage, kCGPDFMediaBox, pageRect, 0, true));
    
        CGContextDrawPDFPage(context, firstPage);
        CGContextRestoreGState(context);
    
        var thm:UIImage = UIGraphicsGetImageFromCurrentImageContext();
    
        UIGraphicsEndImageContext();
        return thm;
    }
    

    【讨论】:

      【解决方案4】:

      斯威夫特 3

      (感谢 Prine 的 Swift 2!)

      func getPdfThumb(url:NSURL, pageBase1:Int) -> UIImage? {
          guard let document = CGPDFDocument(url as CFURL) else { return nil }
          guard let firstPage = document.page(at: pageBase1) else { return nil }
      
          let width:CGFloat = 240.0;
      
          var pageRect:CGRect = firstPage.getBoxRect(.mediaBox)
          let pdfScale:CGFloat = width/pageRect.size.width
          pageRect.size = CGSize(width: pageRect.size.width*pdfScale, height: pageRect.size.height*pdfScale)
          pageRect.origin = CGPoint.zero
      
          UIGraphicsBeginImageContext(pageRect.size)
      
          let context:CGContext = UIGraphicsGetCurrentContext()!
      
          // White background
          context.setFillColor(red: 1.0,green: 1.0,blue: 1.0,alpha: 1.0)
          context.fill(pageRect)
      
          context.saveGState()
      
          // Handle rotation
          context.translateBy(x: 0.0, y: pageRect.size.height)
          context.scaleBy(x: 1.0, y: -1.0)
          context.concatenate(firstPage.getDrawingTransform(.mediaBox, rect: pageRect, rotate: 0, preserveAspectRatio: true))
      
          context.drawPDFPage(firstPage)
          context.restoreGState()
      
          let image:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
      
          UIGraphicsEndImageContext()
          return image
      }
      

      【讨论】:

        【解决方案5】:

        我想出了一个使用 CoreGraphics 和 Swift 3.0 的解决方案。它受到亚历山大提出的那一个的高度启发。在我看来,我的方法会产生更多“Swifty”代码。此外,我的解决方案还解决了结果图像的缩放和方向问题。

        请注意,我的代码使用 AVMakeRect(aspectRatio:, insideRect:) 并且需要导入 AVFoundation

        //pages numbering starts from 1.
        func generate(size: CGSize, page: Int) -> UIImage? {
            guard let document = CGPDFDocument(url as CFURL), let page = document.page(at: page) else { return nil }
        
            let originalPageRect: CGRect = page.getBoxRect(.mediaBox)
            var targetPageRect = AVMakeRect(aspectRatio: originalPageRect.size, insideRect: CGRect(origin: CGPoint.zero, size: size))
            targetPageRect.origin = CGPoint.zero
        
            UIGraphicsBeginImageContextWithOptions(targetPageRect.size, true, 0)
            defer { UIGraphicsEndImageContext() }
            guard let context = UIGraphicsGetCurrentContext() else { return nil }
        
            context.setFillColor(gray: 1.0, alpha: 1.0)
            context.fill(targetPageRect)
        
            context.saveGState()
            context.translateBy(x: 0.0, y: targetPageRect.height)
            context.scaleBy(x: 1.0, y: -1.0)
            context.concatenate(page.getDrawingTransform(.mediaBox, rect: targetPageRect, rotate: 0, preserveAspectRatio: true))
            context.drawPDFPage(page)
            context.restoreGState()
        
            return context.makeImage().flatMap() { UIImage(cgImage: $0, scale: UIScreen.main.scale, orientation: .up) }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-02-20
          • 2017-06-04
          • 2014-11-24
          • 1970-01-01
          • 2011-03-03
          • 1970-01-01
          • 2012-11-19
          • 1970-01-01
          相关资源
          最近更新 更多