İPhone / iPad / iO'lar için Hızlı ve Yalın PDF Görüntüleyici - ipuçları ve püf noktaları?


368

PDF'lerin çizimi hakkında son zamanlarda birçok soru oldu.

Evet, PDF'leri çok kolay bir şekilde oluşturabilirsiniz, UIWebViewancak bu iyi bir PDF görüntüleyiciden beklediğiniz performans ve işlevselliği veremez.

Bir PDF sayfasını çizebilirsiniz bir CALayer için ya bir UIImage için . Apple , Zumlanabilir UIScrollview'da büyük bir PDF'in nasıl çizileceğini gösteren örnek kodlara bile sahip

Ancak aynı sorunlar sürekli artmaktadır.

UIImage Yöntemi:

  1. PDF'ın bir de UIImageoptik bir Katman yaklaşımı yanı sıra ölçekli değil.
  2. CPU ve bellek üreten çarptı UIImagesbir gelen PDFcontext gerçek zamanlı yeni zum-seviyelerinin işlemek oluşturmak için kullanarak limitleri / önler.

CATiledLayer Yöntemi:

  1. Tam bir PDF sayfası CALayera'ya önemli bir Tepegöz (zaman) çekiyor : tek bir döşemenin oluşturulduğu görülebilir (bir tileSize ayarıyla bile)
  2. CALayers önceden hazırlanamaz (ekran dışında işlenir).

Genellikle PDF görüntüleyiciler de bellekte oldukça ağırdır. Apple'ın yakınlaştırılabilir PDF örneğinin bellek kullanımını bile izleyin.

Şu anki projemde bir PDF görüntüleyici geliştiriyorum ve UIImagebir sayfayı ayrı bir iş parçacığında (burada da sorunlar var!) Oluşturuyorum ve ölçek x1 iken sunuyorum. CATiledLayerölçek> 1 olduğunda tekme oluşturma. iBooks, sayfaları kaydırdığınızda benzer bir çift alma yaklaşımı izler ve net bir sürüm görünmeden önce sayfanın daha düşük bir res sürümünü bir saniyeden daha kısa bir süre görebilirsiniz.

PDF görüntüsünün çizilmeye başlamadan önce katmanı maskelemeye hazır olması için odaklanılan sayfanın her iki tarafını 2 sayfa oluşturuyorum.

Çizim PDF'lerinin performansını / bellek kullanımını iyileştirmek için ne kadar küçük veya açık olursa olsun, herhangi bir öngörü var mı? veya burada tartışılan başka sorunlar var mı?

EDIT: Bazı İpuçları (Kredi- Luke Mcneice, VdesmedT, Matt Gallagher, Johann):

  • Mümkün olduğunda tüm ortamları diske kaydedin.

  • TiledLayers'da görüntü oluşturuyorsanız daha büyük tileSizes kullanın

  • init sıkça yer tutucu nesnelerle diziler kullanılır, alternitively başka tasarım yaklaşımıdır bu bir

  • Görüntülerin bir CGPDFPageRef

  • Kullanın NSOperationsveya OBEB & Bloklar vaktinden sayfalarını hazırlamak.

  • çizim sırasında bellek kullanımını azaltmak için CGContextSetInterpolationQuality(ctx, kCGInterpolationHigh); CGContextSetRenderingIntent(ctx, kCGRenderingIntentDefault);önce arayınCGContextDrawPDFPage

  • Şu Verilerinizi init'ing NSOperationsbir docRef ile kötü bir fikir (bellek), bir tekil içine docRef sarın olduğunu.

  • Gereksiz olarak iptal edin Yapabildiğiniz NSOperationszaman, özellikle bellek kullanıyorlarsa, bağlamları açık bırakmaya dikkat edin!

  • Sayfa nesnelerini geri dönüştürün ve kullanılmayan görünümleri yok edin

  • Açık Bağlamları ihtiyacınız olmadığında kapatın

  • bellek uyarılarını alma hakkında DocRef ve tüm sayfa Önbelleklerini serbest bırakın ve yeniden yükleyin

Diğer PDF Özellikleri:

belgeleme

Örnek projeler


peeps düzenleme bildirimi almak sağlamak için yorum
Luke Mcneice

+1 ve tüm bu bilgileri eklediğiniz için teşekkürler, okuyucumu geliştirirken sahip olsaydım;) ayrıca PDF ek açıklamaları hakkındaki sorumu eklediğiniz için teşekkürler (ayrıca örnek kodlu cevapları da içerir). birkaç gün önce bunu açtım: stackoverflow.com/questions/4097044/pdf-search-on-the-iphone Herhangi bir ipucunuz var mı?
pt2ph8

Bunu henüz kendim ele almadım, bu yüzden rastgele fikirler bloğuna işaret etmekten başka bir şey söyleyemedim: random-ideas.net/posts/42 Gönderi için teşekkürler, tüm PDF sorunlarını bir araya getirmeye çalışıyorum yer.
Luke Mcneice

8
Benim şirkette biz Pdf render, gösterim vb için kullanılan bir üçüncü taraf çözüm denir PSPDFKit, ucuz değil, ama değer: pspdfkit.com
János

1
+1 Açık kaynak pdf görüntüleyicim için bu yararlı ipuçlarını takip ettim Swifty PDF github.com/prcela/SwiftyPDF
Prcela

Yanıtlar:


103

Aşağıdakiler hariç, aynı yaklaşımı kullanarak bu tür bir uygulama geliştirdim:

  • Oluşturulan görüntüyü diskte önbelleğe alıyorum ve her zaman ayrı bir iş parçacığında önceden iki ila üç görüntü oluşturuyorum.
  • Bir bindirmeyle değil UIImage, zum 1 olduğunda görüntüyü katmana çiziyorum. Bu uyarılar bellek uyarıları verildiğinde otomatik olarak serbest bırakılacak.

Kullanıcı yakınlaştırmaya başladığında CGPDFPage, uygun CTM'yi kullanarak alıp oluşturuyorum. İçindeki kod - (void)drawLayer: (CALayer*)layer inContext: (CGContextRef) contextşöyle:

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);
    }
}

konu, nesneyi barındıran nesnedir CGPDFDocumentRef. pdfDocÖzelliğe eriştiğim parçayı senkronize ediyorum çünkü onu serbest bırakıyorum ve memoryWarnings alırken yeniden oluşturuyorum. O görünüyor CGPDFDocumentRefnesne ben kurtulmak için nasıl bulamadık bazı iç önbelleğe alma yapmak.


1
kullanıcı Yakınlaştırmaya başladığında yaklaşımınız nedir?
Luke Mcneice

2
@ Luke: Gönderiyi cevaplamak için değiştirdim
VdesmedT

1
Bunun için çok teşekkürler ve CGPDFDocumentRef önbellekleme hakkında ipucu.
Luke Mcneice

Sadece hızlı bir soru: Ölçek pdf olduğunda neden pdfPageRef alıyorsunuz ve dönüştürüyorsunuz? çünkü dönüşümü oluşturmadan önce bir baseImage (bg worker (işçi) öğesinden gelen resim?)
Luke Mcneice

@ Luke: Lütfen yapabileceğiniz herhangi bir performans iyileştirmesini buraya gönderin. Teşekkür ederim !
VdesmedT

67

Basit ve etkili bir PDF görüntüleyici için, yalnızca sınırlı işlevsellik gerektiğinde, artık (iOS 4.0+) QuickLook çerçevesini kullanabilirsiniz:

İlk olarak, QuickLook.frameworkve ile bağlantı kurmanız gerekir#import <QuickLook/QuickLook.h>;

Daha sonra, viewDidLoadtembel başlatma yöntemlerinden birinde veya herhangi birinde:

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

Evet, bu kavramsal olarak bir UIWebView kullanmakla aynıdır. Eğer bu kadar kolay olsaydı CGPDF * 'nin nasıl kullanılacağını anlamak için saatler harcamayız.
pt2ph8

5
Evet tabi. Kesinlikle tam bir çözüm olarak sunmuyorum. Ancak bu sorunun bazı okuyucuları, bazı amaçlar için bunun makul bir çözüm olduğunun farkında olmayabilir. Bunu netleştirmek için cevap güncellendi.
Joshua J. McKinnon

6
Bunun için +1. Öncelikli ilgi, kullanıcının PDF formatında bazı uygulama içi belgeleri görüntülemesine izin vermektir. Arama, vurgulama veya diğer çanlar ve ıslıklardan herhangi birini umursamıyorum - sadece performans gösteren PDF oluşturma.
17'de memmons

2
UIImage + PDF kategorim, yerleşik bir önbellek katmanına sahip hızlı ve saçma bir PDF oluşturucudur. github.com/mindbrix/UIImage-PDF
Mindbrix

6

İOS 11'den bu yana , PDF'leri görüntülemek ve işlemek için PDFKit adlı yerel çerçeveyi kullanabilirsiniz .

PDFKit'i içe aktardıktan sonra a'yı PDFViewyerel veya uzak bir URL ile başlatmalı ve görünümünüzde görüntülemelisiniz.

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

Apple Developer belgelerinde PDFKit hakkında daha fazla bilgi edinin.


-2
 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);
     } }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.