9

Do you know how to save into a UIImageView the first page of a pdf file? I have to create the preview for the pdf. Do you have any idea?

Thanks for help Nicco

iconso
  • 275
  • 1
  • 3
  • 11

4 Answers4

9

The following method will build a thumbnail from a PDF file. It is RetinaDisplay-aware, so the thumbnails should be especially crisp on such devices.

- (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;
}

You will need to supply a CGPDFDocumentRef corresponding to your PDF file, something like the following. (This one assumes that the file test.pdf exists in your app's main bundle.)

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;
}

Finally, you can display the thumbnail image in an UIImageView, like so:

  UIImageView *thumbnailImageView = [[UIImageView alloc] initWithImage:[self buildThumbnailImage]];

  [self.view addSubview:thumbnailImageView];
inwit
  • 935
  • 6
  • 11
  • Thanks everybody! I will try as soon as possible! First time I use stackoverflow, it's simple amazing! – iconso Jun 07 '12 at 17:07
7

As part of a project I was working on, I modified inwit's code to be used with variables in their calls. I figured I would post them here to help anyone who was looking for a similar solution:

To call them:

//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)];

The method and C function:

- (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;
}
jonschneider
  • 424
  • 1
  • 6
  • 11
  • Can we get first file Snapshot for doc, Xls, CSV etc.. can we get those – kiri May 12 '16 at 06:20
  • The PDF preview in the above code is rendered using Core Graphics to render the first page of the PDF (https://developer.apple.com/library/mac/documentation/GraphicsImaging/Reference/CGPDFPage/). Core Graphics does not offer a similar feature for rendering office document types, so to implement document previews you will need to implement your own rendering code to create previews. This method cannot be easily modified for your purpose. – jonschneider May 14 '16 at 15:58
0

There are ways of taking screenshots of UIViews:

Look Here http://www.icodeblog.com/2009/07/27/1188/

Also look here: How Do I Take a Screen Shot of a UIView?

this might be hacky, but you could open the PDF in a UIWebview take the screenshot of the first page using code in one of the above links to a UIImageView. Then close the PDF.

Community
  • 1
  • 1
trumpetlicks
  • 7,033
  • 2
  • 19
  • 33
0

Is this what you're looking for? - http://ipdfdev.com/2011/03/28/convert-a-pdf-page-to-image-on-the-iphone-and-ipad/. The output is a UIImage, so you should be able to display that in your UIImageView.

gtmtg
  • 3,010
  • 2
  • 22
  • 35