2010-11-05 8 views
10

Estamos mostrando contenido en PDF usando UIWebViews por el momento. Idealmente, me gustaría poder mostrar miniaturas en el UITableView sin cargar muchas UIWebViews al mismo tiempo ... son lo suficientemente lentas para cargar un documento, ¡no importa más de 10!¿Cómo puedo generar programáticamente una miniatura de un PDF con el SDK de iPhone?

¿Alguien tiene algún consejo sobre cómo hago esto?

He pensado en la captura de pantalla de un documento cargado usando UIDocumentInteractionController o UIWebView, pero esto significa que todos ellos tienen que ser miniaturas antes de mostrar la tabla.

Respuesta

11

Apple ofrece un montón de métodos en el nivel CoreGraphics para dibujar contenido PDF directamente. Hasta donde yo sé, nada de eso está bien empaquetado en el nivel UIKit, por lo que puede no ser una buena opción para su proyecto en este momento, especialmente si no está tan cómodo en el nivel C. Sin embargo, la función relevante es CGContextDrawPDFPage; por la forma normal de CoreGraphics Existen otros métodos para crear una referencia de PDF desde una fuente de datos y luego obtener una referencia de página de un PDF. Luego deberá ocuparse de escalar y traducir a la vista que desee, y tenga en cuenta que deberá realizar una inversión horizontal porque los archivos PDF (y OS X) usan la parte inferior izquierda como origen, mientras que iOS usa la parte superior izquierda . código de ejemplo, la parte superior de mi cabeza:

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; 

En una conjetura, es probable que quieren usar CGPDFPageGetBoxRect(pageRef, kCGPDFCropBox) conseguir cuadro de recorte de la página y luego encontrar la manera de escalar/mover de que para adaptarse a su tamaño de la imagen .

Probablemente más fácil para sus propósitos es el método -renderInContext: en CALayer (ver QA 1703) - los antiguos medios de conseguir una captura de pantalla fue UIGetScreenImage, pero que nunca fue realmente API oficial y fue aparentemente temporalmente autorizada sólo por la aprobación accidental de RedLaser . Con el código en el control de calidad, puede prepararse para obtener un UIImage desde cualquier otra vista sin que esa vista tenga que estar en la pantalla. ¿Cuál posiblemente resuelve algunos de tus problemas con la captura de pantalla? Aunque eso significa que solo puedes soportar OS 4.x.

En cualquier caso, los archivos PDF simplemente no dibujan tan rápido. Probablemente necesite llenar la tabla y luego dibujar las miniaturas en una cadena de fondo, empujándolas hacia arriba cuando esté disponible. En realidad, no puedes usar objetos UIKit de forma segura en los hilos de fondo, pero todas las cosas de CoreGraphics son seguras.

12

Aquí está el código de muestra que considera la transformación. :)

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

Hola alones, estoy usando el código para obtener miniaturas PDF. Parece que la línea CGContextConcatCTM (context, pdfTransform) produce un cuello de botella de memoria, descubrí que si dejo esta línea, entonces está bien. Pero no puedo dejarlo porque necesito esto para una miniatura adecuada. ¿Tienes alguna idea de cómo podemos mejorar esto? Thx por cierto ... – aslisabanci

+0

este funciona para mí ... el de arriba no sé por qué pero generó una miniatura ficticia o basura ... gracias ... – Underdog

+0

doc decir UIGraphicsGetImageFromCurrentImageContext() no es seguro –

1

Aquí es un método rápido 3 para generar una imagen en miniatura UIImage de una página PDF

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 
} 
+0

Hola Emil, llegas aproximadamente 7 años tarde a la fiesta, pero gracias de todas formas por mantener viva esta pregunta para cualquiera que tenga el mismo problema ;-) –

Cuestiones relacionadas