2010-11-05 6 views
10

Wir zeigen zur Zeit PDF-Inhalte mit UIWebViews an. Idealerweise würde ich gerne in der Lage sein, Thumbnails im UITableView anzuzeigen, ohne viele verschiedene UIWebViews gleichzeitig zu laden ... sie sind langsam genug, ein Dokument zu laden - egal 10+!Wie kann ich programmatisch ein Miniaturbild einer PDF mit dem iPhone SDK generieren?

Hat jemand irgendwelche Tipps, wie ich das mache?

Ich habe über den Bildschirm Erfassung eines Dokuments unter Verwendung UIDocumentInteractionController oder UIWebView gedacht, aber das bedeutet, dass sie alle thumbnailed werden müssen, bevor die Tabelle angezeigt wird.

Antwort

11

Apple liefert eine ganze Reihe von Methoden auf der Ebene CoreGraphics zum Zeichnen von PDF-Inhalten direkt. Soweit mir bekannt ist, ist nichts davon ordentlich verpackt auf der Ebene UIKit, so dass es zu diesem Zeitpunkt möglicherweise nicht gut zu Ihrem Projekt passt, besonders wenn Sie auf der C-Ebene nicht so komfortabel sind. Die relevante Funktion ist jedoch CGContextDrawPDFPage; für die normale CoreGraphics Art der Dinge gibt es andere Methoden, um eine PDF-Referenz aus einer Datenquelle zu erstellen und dann eine Seitenreferenz aus einer PDF zu erhalten. Sie müssen sich dann mit der Skalierung und der Übersetzung in die gewünschte Ansicht befassen und darauf hingewiesen werden, dass Sie eine horizontale Spiegelung durchführen müssen, da PDFs (und OS X) die untere linke Ecke als Ursprung und iOS die obere linke Ecke verwenden . Beispielcode, weg von der Oberseite meines Kopfes:

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; 

Bei einer Vermutung, werden Sie wahrscheinlich wollen CGPDFPageGetBoxRect(pageRef, kCGPDFCropBox) verwenden, um die Zuschneiderahmen Seite und dann herausfinden, wie die Skalierung/bewegen Sie die Bildgröße zu passen .

Wahrscheinlich einfacher für Ihre Zwecke sind die -renderInContext: Methode auf CALayer (siehe QA 1703) - die alten Mittel ein Screenshot UIGetScreenImage war immer, aber das war nie wirklich offizielle API und scheinbar vorübergehend nur wegen der versehentlichen Genehmigung von RedLaser durfte . Mit dem Code in der QA können Sie sich einrichten, um ein UIImage von jeder anderen Ansicht zu erhalten, ohne dass diese Ansicht auf dem Bildschirm angezeigt werden muss. Welche löst möglicherweise etwas von Ihrem Problem mit der Bildschirmaufnahme? Obwohl das bedeutet, dass Sie nur OS 4.x unterstützen können.

In beiden Fällen zeichnen PDFs nicht so schnell. Wahrscheinlich müssen Sie die Tabelle auffüllen und dann die Miniaturbilder auf einen Hintergrundfaden zeichnen und nach oben schieben, wenn sie verfügbar sind. Sie können UIKit-Objekte nicht wirklich sicher auf Hintergrund-Threads verwenden, aber alle CoreGraphics-Dateien sind sicher.

12

Hier ist ein Beispielcode, der die Umwandlung berücksichtigt. :)

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

Hallo alones verwende ich Code PDF-Miniaturen zu bekommen. Es scheint, als ob die CGContextConcatCTM (context, pdfTransform) Zeile einen Speicherengpass erzeugt. Ich habe herausgefunden, dass es OK ist, wenn ich diese Zeile verlasse. Aber ich kann es nicht auslassen, weil ich das für ein richtiges Thumbnail brauche. Hast du eine Idee, wie wir das verbessern können? Thx btw ... – aslisabanci

+0

dieser funktioniert für mich ... der eine über ich weiß nicht warum, aber es erzeugt einen Dummy oder Müll thumbnail ... danke ... – Underdog

+0

docs sagen UIGraphicsGetImageFromCurrentImageContext() ist nicht thread sicher –

1

Hier ist ein schnelles 3 Verfahren zur Herstellung eines UIImage Miniaturbild für eine PDF-Seite zu erzeugen

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

Hey Emil, du bist etwa 7 Jahre zu spät zur Party - aber trotzdem danke, dass du diese Frage für alle, die das gleiche Problem haben, am Leben hältst ;-) –

Verwandte Themen