Szybka i szczupła przeglądarka PDF dla iPhone / iPad / iOs-porady i wskazówki?

Ostatnio pojawiło się wiele pytań na temat rysowania plików PDF.]}

Tak, możesz renderować pliki PDF bardzo łatwo za pomocą UIWebView, ale to nie daje wydajności i funkcjonalności, których można oczekiwać od dobrej przeglądarki PDF.

Możesz narysować stronę PDF do Calayera lub do UIImage . Apple ma nawet przykładowy kod, aby pokazać, jak narysować duży plik PDF w Zoomable UIScrollview

Ale wciąż te same problemy przycinają w górę.

Metoda UIImage:

  1. PDF jest w UIImage nie optycznie skalowanie oraz podejście warstwowe.
  2. procesor i pamięć hit przy generowaniu UIImages z PDFcontext ogranicza / uniemożliwia użycie go do stworzenia renderowanie w czasie rzeczywistym nowych poziomów powiększenia.

Metoda CATiledLayer:

  1. istnieje znaczna nadmiarowość (czas) rysowanie pełnej strony PDF do CALayer: można zobaczyć renderowanie poszczególnych płytek (nawet z tileSize tweak)
  2. CALayers nie można być przygotowanym przed czas (renderowany poza ekranem).

Ogólnie przeglądarki plików PDF są również dość obciążone pamięcią. Monitoruj nawet wykorzystanie pamięci w przykładzie zoomable PDF firmy apple.

W moim obecnym projekcie rozwijam przeglądarkę PDF i renderuję UIImage strony w osobnym wątku (problemy również tutaj!) i prezentując go, gdy skala jest x1. CATiledLayer renderowanie rozpoczyna się, gdy skala jest >1. iBooks ma podobne podejście podwójne, jak gdyby przewijanie stron możesz zobaczyć niższą wersję res strony przez mniej niż sekundę, zanim pojawi się wyraźna wersja.

Im renderuje 2 strony z każdej strony strony w ostrości tak, że obraz PDF jest gotowy do zamaskowania warstwy przed rozpoczęciem rysowania.Strony są ponownie niszczone, gdy są oddalone o +2 strony od strony skupionej.

Czy ktoś ma jakieś spostrzeżenia, bez względu na to, jak małe lub oczywiste, aby poprawić wydajność / obsługę pamięci rysowania PDF? lub inne omówione tutaj zagadnienia?

edytuj: niektóre wskazówki (kredyt-Luke Mcneice, VdesmedT, Matt Gallagher, Johann):

  • Zapisz dowolny nośnik na dysku, Kiedy możesz.

  • Użyj większych tileSizes jeśli renderowanie na TiledLayers

  • Init często używane tablice z obiektami zastępczymi, naprzemiennie innym podejściem projektowym jest ten

  • Zauważ, że obrazy będą renderowane szybciej niż CGPDFPageRef

  • Użyj NSOperations lub bloków GCD & , aby przygotować strony do przodu czasu.

  • Wywołanie CGContextSetInterpolationQuality(ctx, kCGInterpolationHigh); CGContextSetRenderingIntent(ctx, kCGRenderingIntentDefault); przed CGContextDrawPDFPage, aby zmniejszyć zużycie pamięci podczas rysowania

  • Init ' in your NSOperations with a docRef is a bad idea( memory), wrap the docRef into a singleton.

  • Anuluj niepotrzebne NSOperations kiedy możesz, zwłaszcza jeśli będą używać pamięci, uważaj jednak na pozostawienie kontekstów otwartych!

  • Recykling obiektów strony i zniszcz nieużywane widoki

  • Zamknij wszelkie otwarte konteksty, gdy tylko ich nie potrzebujesz

  • Po otrzymaniu ostrzeżeń o pamięci zwalnia i przeładowuje DocRef i wszelkie buforowane strony

Inne funkcje PDF:

Dokumentacja

Przykładowe projekty

  • Apple / ZoomingPDF - zooming, UIScrollView, CATiledLayer
  • vfr / reader - powiększanie, przywoływanie, UIScrollView, CATiledView
  • brwi / liście - stronicowanie z ładnymi przejściami
  • [227]} / skim - everything it seems (PDF reader/editor for OSX)
Author: Luke Mcneice, 2010-10-08

4 answers

Zbudowałem tego typu aplikację używając mniej więcej tego samego podejścia z wyjątkiem :

  • buforuję wygenerowany obraz na dysku i zawsze generuję dwa do trzech obrazów z wyprzedzeniem w osobnym wątku.
  • nie nakładam się na UIImage, ale zamiast tego rysuję obraz w warstwie, gdy powiększenie wynosi 1. Płytki te zostaną zwolnione automatycznie, gdy zostaną wydane ostrzeżenia dotyczące pamięci.

Gdy użytkownik zacznie powiększać, nabywam CGPDFPage i renderuję go za pomocą odpowiednie CTM. Kod w - (void)drawLayer: (CALayer*)layer inContext: (CGContextRef) context jest następujący:

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 jest obiektem składającym się z CGPDFDocumentRef. Synchronizuję część, w której uzyskuję dostęp do właściwości pdfDoc, ponieważ zwalniam ją i odtwarzam podczas odbierania memoryWarnings. Wygląda na to, że obiekt CGPDFDocumentRef wykonuje wewnętrzne buforowanie, którego nie znalazłem, jak się go pozbyć.

 103
Author: VdesmedT,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-11 10:03:59

Dla prostej i skutecznej przeglądarki PDF, gdy potrzebujesz tylko ograniczonej funkcjonalności, możesz teraz (iOS 4.0+) użyć frameworka QuickLook:

Najpierw musisz połączyć się z QuickLook.framework i #import <QuickLook/QuickLook.h>;

Potem albo viewDidLoad albo którąkolwiek z leniwych metod inicjalizacji:

QLPreviewController *previewController = [[QLPreviewController alloc] init];
previewController.dataSource = self;
previewController.delegate = self;
previewController.currentPreviewItemIndex = indexPath.row;
[self presentModalViewController:previewController animated:YES];
[previewController release];
 65
Author: Joshua J. McKinnon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-17 21:27:32

Od wersji iOS 11 możesz używać natywnego frameworka o nazwie PDFKit do wyświetlania i manipulowania plikami PDF.

Po zaimportowaniu PDFKit powinieneś zainicjować PDFView lokalnym lub zdalnym adresem URL i wyświetlić go w widoku.

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

Przeczytaj więcej o PDFKit w dokumentacji Apple Developer.

 4
Author: the4kman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-08 14:07:29
 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);
     } }
 -2
Author: Kuldeep singh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-21 11:45:05