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:
- PDF jest w
UIImage
nie optycznie skalowanie oraz podejście warstwowe. - procesor i pamięć hit przy generowaniu
UIImages
zPDFcontext
ogranicza / uniemożliwia użycie go do stworzenia renderowanie w czasie rzeczywistym nowych poziomów powiększenia.
Metoda CATiledLayer:
- istnieje znaczna nadmiarowość (czas)
rysowanie pełnej strony PDF do
CALayer
: można zobaczyć renderowanie poszczególnych płytek (nawet z tileSize tweak) -
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);
przedCGContextDrawPDFPage
, 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:
-
Pobieranie linków wewnątrz pliku PDF (i tutaj i tutaj)
-
Uzyskanie celu linku (uzyskanie numeru strony z tablicy
/Dest
)
Getting Raw Text (and here and Here and here (pozycjonowanie focused))
-
Wyszukiwanie (i tutaj) (nie działa ze wszystkimi plikami PDF (niektóre po prostu pokazują dziwne znaki, myślę, że to problem z kodowaniem, ale nie jestem pewien) -Credit BrainFeeder)
-
Renderowanie CALayer i off-Screen - renderowanie następnej strony dla szybkiego / płynnego wyświetlania
Dokumentacja
- Quartz PDFObjects (używany do meta info, adnotacje, kciuki)
- Abobe PDF Spec
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)
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ć.
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];
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)
}
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);
} }
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