How can I programmatically generate a thumbnail of a PDF with iOS?

Here is sample code considering transformation. :)

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

Here is a swift 3 method for generating a UIImage thumbnail for a pdf page

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
}

Apple supply a whole bunch of methods down at the CoreGraphics level for drawing PDF content directly. As far as I'm aware, none of it is neatly packaged up at the UIKit level, so it may not be a good fit for your project at this point, especially if you're not as comfortable down at the C level. However, the relevant function is CGContextDrawPDFPage; per the normal CoreGraphics way of things there are other methods to create a PDF reference from a data source and then to get a page reference from a PDF. You'll then need to deal with scaling and translating to the view you want, and be warned that you'll need to perform a horizontal flip because PDFs (and OS X) use the lower left as the origin whereas iOS uses the top left. Example code, off the top of my head:

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;

At a guess, you'll probably want to use CGPDFPageGetBoxRect(pageRef, kCGPDFCropBox) to get the page's crop box and then work out how to scale/move that to fit your image size.

Probably easier for your purposes is the -renderInContext: method on CALayer (see QA 1703) — the old means of getting a screenshot was UIGetScreenImage, but that was never really official API and was seemingly temporarily allowed only because of the accidental approval of RedLaser. With the code in the QA you can rig yourself up to get a UIImage from any other view without that view having to be on screen. Which possibly resolves some of your issue with screen capturing? Though it means you can support OS 4.x only.

In either case, PDFs just don't draw that quickly. You probably need to populate the table then draw the thumbnails on a background thread, pushing them upwards when available. You can't actually use UIKit objects safely on background threads but all the CoreGraphics stuff is safe.