379 Stimmen

Schneller und schlanker PDF-Viewer für iPhone / iPad / iOS - Tipps und Hinweise?

In letzter Zeit gab es viele Fragen zum Zeichnen von PDFs.

Ja, Sie können PDFs sehr einfach mit einem UIWebView aber das kann nicht die Leistung und Funktionalität bieten, die Sie von einem guten PDF-Viewer erwarten würden.

Sie können eine PDF-Seite zeichnen zu einer CAL-Schicht o zu einem UIImage . Apple hat sogar Beispielcode, der zeigt, wie man eine große PDF-Datei zeichnet. in einer zoombaren UIScrollview

Aber die gleichen Probleme tauchen immer wieder auf.

UIImage-Methode:

  1. PDF's in einem UIImage optisch nicht so gut skalieren wie ein Layer-Ansatz.
  2. Die CPU- und Speicherbelastung bei der Erzeugung von der UIImages de un PDFcontext begrenzt/verhindert die Verwendung zur Erstellung eines Echtzeit-Rendering von neuen Zoomstufen.

CATiledLayer-Methode:

  1. Es gibt einen erheblichen Overhead (Zeit) das Zeichnen einer ganzen PDF-Seite in ein CALayer Einzelne Kacheln können gerendert werden (sogar mit einer tileSize-Änderung)
  2. CALayers c vorbereitet werden (wird außerhalb des Bildschirms gerendert).

Auch PDF-Viewer sind in der Regel recht speicherintensiv. Überprüfen Sie sogar den Speicherverbrauch von Apples zoombarem PDF-Beispiel.

In meinem aktuellen Projekt entwickle ich einen PDF-Viewer und rendere eine UIImage einer Seite in einem separaten Thema (auch hier!) und deren Darstellung bei einem Maßstab von x1. CATiledLayer Das Rendering setzt ein, sobald die Skalierung >1 ist. iBooks verfolgt einen ähnlichen Ansatz, denn wenn Sie durch die Seiten blättern, sehen Sie eine Version mit geringerer Auflösung für weniger als eine Sekunde, bevor eine scharfe Version erscheint.

Im Rendering 2 Seiten jede Seite der Seite im Fokus, so dass das PDF-Bild bereit ist, die Ebene zu maskieren, bevor es beginnt drawing.Pages sind wieder zerstört, wenn sie +2 Seiten von der fokussierten Seite entfernt sind.

Hat irgendjemand irgendwelche Erkenntnisse, egal wie klein oder offensichtlich, um die Leistung/Speicherhandhabung von Drawing PDF's zu verbessern? oder irgendwelche anderen hier diskutierten Probleme?

EDITAR: Einige Tipps (Credit- Luke Mcneice,VdesmedT,Matt Gallagher,Johann):

  • Speichern Sie alle Medien auf der Festplatte, wenn Sie können.

  • Verwenden Sie größere tileSizes, wenn Sie auf TiledLayers rendern

  • init häufig verwendete Arrays mit Platzhalterobjekten, alternativ dazu ist ein anderer Gestaltungsansatz diese

  • Beachten Sie, dass Bilder schneller gerendert werden als eine CGPDFPageRef

  • 使用方法 NSOperations oder GCD & Blöcke zur Vorbereitung von Seiten im Voraus der Zeit vorzubereiten.

  • aufrufen CGContextSetInterpolationQuality(ctx, kCGInterpolationHigh); CGContextSetRenderingIntent(ctx, kCGRenderingIntentDefault); vor CGContextDrawPDFPage um die Speichernutzung beim Zeichnen zu reduzieren

  • Ihre Initiation NSOperations mit einer docRef ist eine schlechte Idee (Speicher), wrap die docRef in ein Singleton.

  • Unnötiges stornieren NSOperations Wenn es möglich ist, vor allem wenn sie Speicherplatz benötigen, sollten Sie sich davor hüten, Kontexte offen zu lassen!

  • Recyceln von Seitenobjekten und Zerstören unbenutzter Ansichten

  • Schließen Sie alle offenen Kontexte, sobald Sie sie nicht mehr benötigen

  • beim Erhalt von Speicherwarnungen das DocRef und alle Seiten-Caches freigeben und neu laden

Andere PDF-Funktionen:

Dokumentation

Beispielhafte Projekte

104voto

VdesmedT Punkte 8927

Ich habe eine solche Anwendung mit ungefähr dem gleichen Ansatz erstellt, außer :

  • Ich speichere das generierte Bild auf der Festplatte und generiere immer zwei bis drei Bilder im Voraus in einem separaten Thread.
  • Ich überlagere nicht mit einer UIImage sondern zeichnen stattdessen das Bild in der Ebene, wenn der Zoomfaktor 1 ist. Diese Kacheln werden automatisch freigegeben, wenn Speicherwarnungen ausgegeben werden.

Immer wenn der Benutzer zu zoomen beginnt, erhalte ich die CGPDFPage und rendert sie mit der entsprechenden Gemeinschaftsmarke. Der Code in - (void)drawLayer: (CALayer*)layer inContext: (CGContextRef) context ist wie :

CGAffineTransform currentCTM = CGContextGetCTM(context);    
if (currentCTM.a == 1.0 && baseImage) {
    //Calculate ideal scale
    CGFloat scaleForWidth = baseImage.size.width/self.bounds.size.width;
    CGFloat scaleForHeight = baseImage.size.height/self.bounds.size.height; 
    CGFloat imageScaleFactor = MAX(scaleForWidth, scaleForHeight);

    CGSize imageSize = CGSizeMake(baseImage.size.width/imageScaleFactor, baseImage.size.height/imageScaleFactor);
    CGRect imageRect = CGRectMake((self.bounds.size.width-imageSize.width)/2, (self.bounds.size.height-imageSize.height)/2, imageSize.width, imageSize.height);
    CGContextDrawImage(context, imageRect, [baseImage CGImage]);
} else {
    @synchronized(issue) { 
        CGPDFPageRef pdfPage = CGPDFDocumentGetPage(issue.pdfDoc, pageIndex+1);
        pdfToPageTransform = CGPDFPageGetDrawingTransform(pdfPage, kCGPDFMediaBox, layer.bounds, 0, true);
        CGContextConcatCTM(context, pdfToPageTransform);    
        CGContextDrawPDFPage(context, pdfPage);
    }
}

Problem ist das Objekt, das die CGPDFDocumentRef . Ich synchronisiere den Teil, in dem ich auf die pdfDoc Eigenschaft, denn ich gebe sie frei und stelle sie wieder her, wenn ich memoryWarnings erhalte. Es scheint, dass die CGPDFDocumentRef Objekt einige interne Zwischenspeicher, die ich nicht gefunden habe, wie man sie loswird.

67voto

Joshua J. McKinnon Punkte 1686

Für einen einfachen und effektiven PDF-Viewer, für den Sie nur eine begrenzte Funktionalität benötigen, können Sie jetzt (ab iOS 4.0) das QuickLook-Framework verwenden:

Zunächst müssen Sie einen Link gegen QuickLook.framework y #import <QuickLook/QuickLook.h>;

Danach, entweder in viewDidLoad oder eine der Methoden der trägen Initialisierung:

QLPreviewController *previewController = [[QLPreviewController alloc] init];
previewController.dataSource = self;
previewController.delegate = self;
previewController.currentPreviewItemIndex = indexPath.row;
[self presentModalViewController:previewController animated:YES];
[previewController release];

9voto

Tamás Sengel Punkte 51405

Seit iOS 11 können Sie das native Framework namens PDFKit für die Anzeige und Bearbeitung von PDF-Dateien.

Nachdem Sie PDFKit importiert haben, sollten Sie eine PDFView mit einer lokalen oder einer entfernten URL und zeigen Sie sie in Ihrer Ansicht an.

if let url = Bundle.main.url(forResource: "example", withExtension: "pdf") {
    let pdfView = PDFView(frame: view.frame)
    pdfView.document = PDFDocument(url: url)
    view.addSubview(pdfView)
}

Lesen Sie mehr über PDFKit in der Apple Developer Dokumentation.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X