iOS SDK 第一页 PDF 的图像

9

你知道如何将pdf文件的第一页保存到UIImageView中吗? 我需要为pdf创建预览。 你有什么想法吗?

谢谢帮助 Nicco

4个回答

9
以下方法将从PDF文件中构建缩略图。它支持RetinaDisplay,因此这些缩略图在这种设备上应该特别清晰。
- (UIImage *)buildThumbnailImage
{
  BOOL hasRetinaDisplay = FALSE;  // by default
  CGFloat pixelsPerPoint = 1.0;  // by default (pixelsPerPoint is just the "scale" property of the screen)

  if ([UIScreen instancesRespondToSelector:@selector(scale)])  // the "scale" property is only present in iOS 4.0 and later
  {
    // we are running iOS 4.0 or later, so we may be on a Retina display;  we need to check further...
    if ((pixelsPerPoint = [[UIScreen mainScreen] scale]) == 1.0)
      hasRetinaDisplay = FALSE;
    else
      hasRetinaDisplay = TRUE;
  }
  else
  {
    // we are NOT running iOS 4.0 or later, so we can be sure that we are NOT on a Retina display
    pixelsPerPoint = 1.0;
    hasRetinaDisplay = FALSE;
  }

  size_t imageWidth = 320;  // width of thumbnail in points
  size_t imageHeight = 460;  // height of thumbnail in points

  if (hasRetinaDisplay)
  {
    imageWidth *= pixelsPerPoint;
    imageHeight *= pixelsPerPoint;
  }

  size_t bytesPerPixel = 4;  // RGBA
  size_t bitsPerComponent = 8;
  size_t bytesPerRow = bytesPerPixel * imageWidth;

  void *bitmapData = malloc(imageWidth * imageHeight * bytesPerPixel);

  // in the event that we were unable to mallocate the heap memory for the bitmap,
  // we just abort and preemptively return nil:
  if (bitmapData == NULL)
    return nil;

  // remember to zero the buffer before handing it off to the bitmap context:
  bzero(bitmapData, imageWidth * imageHeight * bytesPerPixel);

  CGContextRef theContext = CGBitmapContextCreate(bitmapData, imageWidth, imageHeight, bitsPerComponent, bytesPerRow,
                                                  CGColorSpaceCreateDeviceRGB(), kCGImageAlphaPremultipliedLast);

  CGPDFDocumentRef pdfDocument = MyGetPDFDocumentRef();  // NOTE: you will need to modify this line to supply the CGPDFDocumentRef for your file here...
  CGPDFPageRef pdfPage = CGPDFDocumentGetPage(pdfDocument, 1);  // get the first page for your thumbnail

  CGAffineTransform shrinkingTransform =
    CGPDFPageGetDrawingTransform(pdfPage, kCGPDFMediaBox, CGRectMake(0, 0, imageWidth, imageHeight), 0, YES);

  CGContextConcatCTM(theContext, shrinkingTransform);

  CGContextDrawPDFPage(theContext, pdfPage);  // draw the pdfPage into the bitmap context
  CGPDFDocumentRelease(pdfDocument);

  //
  // create the CGImageRef (and thence the UIImage) from the context (with its bitmap of the pdf page):
  //
  CGImageRef theCGImageRef = CGBitmapContextCreateImage(theContext);
  free(CGBitmapContextGetData(theContext));  // this frees the bitmapData we malloc'ed earlier
  CGContextRelease(theContext);

  UIImage *theUIImage;

  // CAUTION: the method imageWithCGImage:scale:orientation: only exists on iOS 4.0 or later!!!
  if ([UIImage respondsToSelector:@selector(imageWithCGImage:scale:orientation:)])
  {
    theUIImage = [UIImage imageWithCGImage:theCGImageRef scale:pixelsPerPoint orientation:UIImageOrientationUp];
  }
  else
  {
    theUIImage = [UIImage imageWithCGImage:theCGImageRef];
  }

  CFRelease(theCGImageRef);
  return theUIImage;
}

您需要提供一个对应于PDF文件的CGPDFDocumentRef,类似以下内容。(此处假设test.pdf文件存在于您的应用程序主包中。)
CGPDFDocumentRef MyGetPDFDocumentRef()
{
  NSString *inputPDFFile = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"test.pdf"];
  const char *inputPDFFileAsCString = [inputPDFFile cStringUsingEncoding:NSASCIIStringEncoding];
  //NSLog(@"expecting pdf file to exist at this pathname: \"%s\"", inputPDFFileAsCString);

  CFStringRef path = CFStringCreateWithCString(NULL, inputPDFFileAsCString, kCFStringEncodingUTF8);

  CFURLRef url = CFURLCreateWithFileSystemPath(NULL, path, kCFURLPOSIXPathStyle, 0);
  CFRelease (path);

  CGPDFDocumentRef document = CGPDFDocumentCreateWithURL(url);
  CFRelease(url);

  if (CGPDFDocumentGetNumberOfPages(document) == 0)
  {
    printf("Warning: No pages in pdf file \"%s\" or pdf file does not exist at this path\n", inputPDFFileAsCString);
    return NULL;
  }

  return document;
}

最后,你可以像这样在UIImageView中显示缩略图:
  UIImageView *thumbnailImageView = [[UIImageView alloc] initWithImage:[self buildThumbnailImage]];

  [self.view addSubview:thumbnailImageView];

谢谢大家!我会尽快尝试!这是我第一次使用stackoverflow,真是太棒了! - iconso

7

作为我正在处理的项目的一部分,我修改了inwit的代码以便在调用中使用变量。我想我会把它们发布在这里,以帮助任何寻找类似解决方案的人:

调用它们:

//Assume all your PDFs you want to create thumbnails for are in an array. This method saves the paths to all PDFs in your main bundle as NSStrings.
_pdfs = [[NSBundle mainBundle] pathsForResourcesOfType:@"pdf" inDirectory:nil];

//To be called in the cellForItemAtIndexPath method or a similar method where you want to create a thumbnail for the image:
NSString *loc = [_pdfs objectAtIndex:indexPath.row];    
UIImage *cellImage = [self buildThumbnailImage:MyGetPDFDocumentRef(loc)];

方法和C函数:
- (UIImage *)buildThumbnailImage:(CGPDFDocumentRef)pdfDocument
{
    BOOL hasRetinaDisplay = FALSE;  // by default
    CGFloat pixelsPerPoint = 1.0;  // by default (pixelsPerPoint is just the "scale" property of the screen)

    if ([UIScreen instancesRespondToSelector:@selector(scale)])  // the "scale" property is only present in iOS 4.0 and later
    {
        // we are running iOS 4.0 or later, so we may be on a Retina display;  we need to check further...
        if ((pixelsPerPoint = [[UIScreen mainScreen] scale]) == 1.0)
            hasRetinaDisplay = FALSE;
        else
            hasRetinaDisplay = TRUE;
    }
    else
    {
        // we are NOT running iOS 4.0 or later, so we can be sure that we are NOT on a Retina display
        pixelsPerPoint = 1.0;
        hasRetinaDisplay = FALSE;
    }

    size_t imageWidth = 320;  // width of thumbnail in points
    size_t imageHeight = 460;  // height of thumbnail in points

    if (hasRetinaDisplay)
    {
        imageWidth *= pixelsPerPoint;
        imageHeight *= pixelsPerPoint;
    }

    size_t bytesPerPixel = 4;  // RGBA
    size_t bitsPerComponent = 8;
    size_t bytesPerRow = bytesPerPixel * imageWidth;

    void *bitmapData = malloc(imageWidth * imageHeight * bytesPerPixel);

    // in the event that we were unable to mallocate the heap memory for the bitmap,
    // we just abort and preemptively return nil:
    if (bitmapData == NULL)
        return nil;

    // remember to zero the buffer before handing it off to the bitmap context:
    bzero(bitmapData, imageWidth * imageHeight * bytesPerPixel);

    CGContextRef theContext = CGBitmapContextCreate(bitmapData, imageWidth, imageHeight, bitsPerComponent, bytesPerRow,
                                                    CGColorSpaceCreateDeviceRGB(), kCGImageAlphaPremultipliedLast);

    //CGPDFDocumentRef pdfDocument = MyGetPDFDocumentRef();  // NOTE: you will need to modify this line to supply the CGPDFDocumentRef for your file here...
    CGPDFPageRef pdfPage = CGPDFDocumentGetPage(pdfDocument, 1);  // get the first page for your thumbnail

    CGAffineTransform shrinkingTransform =
    CGPDFPageGetDrawingTransform(pdfPage, kCGPDFMediaBox, CGRectMake(0, 0, imageWidth, imageHeight), 0, YES);

    CGContextConcatCTM(theContext, shrinkingTransform);

    CGContextDrawPDFPage(theContext, pdfPage);  // draw the pdfPage into the bitmap context
    CGPDFDocumentRelease(pdfDocument);

    //
    // create the CGImageRef (and thence the UIImage) from the context (with its bitmap of the pdf page):
    //
    CGImageRef theCGImageRef = CGBitmapContextCreateImage(theContext);
    free(CGBitmapContextGetData(theContext));  // this frees the bitmapData we malloc'ed earlier
    CGContextRelease(theContext);

    UIImage *theUIImage;

    // CAUTION: the method imageWithCGImage:scale:orientation: only exists on iOS 4.0 or later!!!
    if ([UIImage respondsToSelector:@selector(imageWithCGImage:scale:orientation:)])
    {
        theUIImage = [UIImage imageWithCGImage:theCGImageRef scale:pixelsPerPoint orientation:UIImageOrientationUp];
    }
    else
    {
        theUIImage = [UIImage imageWithCGImage:theCGImageRef];
    }

    CFRelease(theCGImageRef);
    return theUIImage;
}


CGPDFDocumentRef MyGetPDFDocumentRef(NSString *inputPDFFile)
{
    //NSString *inputPDFFile = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"test.pdf"];

    const char *inputPDFFileAsCString = [inputPDFFile cStringUsingEncoding:NSASCIIStringEncoding];
    //NSLog(@"expecting pdf file to exist at this pathname: \"%s\"", inputPDFFileAsCString);

    CFStringRef path = CFStringCreateWithCString(NULL, inputPDFFileAsCString, kCFStringEncodingUTF8);

    CFURLRef url = CFURLCreateWithFileSystemPath(NULL, path, kCFURLPOSIXPathStyle, 0);
    CFRelease (path);

    CGPDFDocumentRef document = CGPDFDocumentCreateWithURL(url);
    CFRelease(url);

    if (CGPDFDocumentGetNumberOfPages(document) == 0)
    {
        printf("Warning: No pages in pdf file \"%s\" or pdf file does not exist at this path\n", inputPDFFileAsCString);
        return NULL;
    }

    return document;
}

我们能否获取文档、Xls、CSV等文件的第一个文件快照,我们能够获取这些文件吗? - kiri
以上代码中的PDF预览是使用核心图形(Core Graphics)来渲染PDF的第一页(https://developer.apple.com/library/mac/documentation/GraphicsImaging/Reference/CGPDFPage/)。核心图形并不提供类似的功能以渲染办公文档类型,因此要实现文档预览,您需要实现自己的渲染代码来创建预览。这种方法不容易为您的目的进行修改。 - jonschneider

0

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接