Penampil PDF Cepat dan Bersandar untuk iPhone / iPad / iOs - tips dan petunjuk?

369

Ada banyak pertanyaan baru-baru ini tentang menggambar PDF.

Ya, Anda dapat membuat PDF dengan sangat mudah dengan UIWebViewtetapi ini tidak dapat memberikan kinerja dan fungsionalitas yang Anda harapkan dari penampil PDF yang baik.

Anda bisa menggambar halaman PDF ke CALayer atau ke UIImage . Apple bahkan memiliki kode sampel untuk menunjukkan cara menggambar PDF besar di ZoomIS UIScrollview

Namun masalah yang sama terus muncul.

Metode UIImage:

  1. PDF dalam UIImageskala tidak optik serta pendekatan Layer.
  2. CPU dan memori menekan pada menghasilkan UIImagesdari PDFcontext batas / mencegah menggunakannya untuk membuat rendering tingkat-baru baru tingkat zoom.

Metode CATiledLayer:

  1. Ada Overhead yang signifikan (waktu) menggambar halaman PDF penuh ke CALayer: ubin individu dapat dilihat rendering (bahkan dengan tweak tileSize)
  2. CALayers tidak dapat dipersiapkan sebelumnya (ditampilkan di luar layar).

Secara umum, pemirsa PDF juga memiliki memori yang cukup besar. Bahkan memantau penggunaan memori contoh PDF yang dapat diperbesar dari apel.

Dalam proyek saya saat ini, saya sedang mengembangkan penampil PDF dan saya merender UIImagehalaman dari utas yang terpisah (masalah di sini juga!) Dan menyajikannya sementara skalanya adalah x1. CATiledLayerrender tendangan dalam satu kali skalanya> 1. iBooks mengambil pendekatan pengambilan ganda yang serupa seolah-olah Anda menggulir halaman, Anda dapat melihat versi res halaman yang lebih rendah hanya kurang dari satu detik sebelum versi yang tajam muncul.

Saya membuat 2 halaman setiap sisi halaman dalam fokus sehingga gambar PDF siap untuk menutupi lapisan sebelum mulai menggambar. Halaman dihancurkan lagi ketika mereka +2 halaman dari halaman fokus.

Adakah yang punya wawasan, betapapun kecil atau jelasnya untuk meningkatkan kinerja / penanganan memori dari Menggambar PDF? atau masalah lain yang dibahas di sini?

EDIT: Some Tips (Kredit- Luke Mcneice, VdesmedT, Matt Gallagher, Johann):

  • Simpan media apa saja ke disk saat Anda bisa.

  • Gunakan Ukuran tile yang lebih besar jika melakukan rendering pada TiledLayers

  • init sering digunakan array dengan objek penampung, atau pendekatan desain lain adalah yang satu ini

  • Perhatikan bahwa gambar akan merender lebih cepat dari a CGPDFPageRef

  • Gunakan NSOperationsatau GCD & Blok untuk menyiapkan halaman sebelumnya.

  • panggil CGContextSetInterpolationQuality(ctx, kCGInterpolationHigh); CGContextSetRenderingIntent(ctx, kCGRenderingIntentDefault);sebelumnya CGContextDrawPDFPageuntuk mengurangi penggunaan memori saat menggambar

  • init'ing Anda NSOperationsdengan docRef adalah ide yang buruk (memori), bungkus docRef menjadi singleton.

  • Batalkan yang tidak perlu NSOperationsKetika Anda bisa, terutama jika mereka akan menggunakan memori, berhati-hatilah membiarkan konteks tetap terbuka!

  • Daur ulang objek halaman dan hancurkan tampilan yang tidak digunakan

  • Tutup semua Konteks terbuka segera setelah Anda tidak membutuhkannya

  • saat menerima peringatan memori lepaskan dan muat ulang DocRef dan Cache halaman apa saja

Fitur PDF lainnya:

Dokumentasi

Contoh proyek

Luke Mcneice
sumber
berkomentar untuk memastikan peeps mendapatkan notifikasi edit
Luke Mcneice
+1 dan terima kasih telah menambahkan semua info ini, berharap saya memilikinya ketika saya mengembangkan pembaca saya;) juga terima kasih telah menambahkan pertanyaan saya tentang anotasi PDF (juga berisi jawaban dengan kode sampel). beberapa hari yang lalu saya membuka ini: stackoverflow.com/questions/4097044/pdf-search-on-the-iphone Anda punya tip?
pt2ph8
Saya belum membahas ini sendiri, jadi saya tidak bisa mengatakan apa pun selain mengarahkan Anda ke blog gagasan acak: random-ideas.net/posts/42 Terima kasih atas posnya, saya mencoba mengumpulkan semua masalah PDF dalam satu tempat.
Luke Mcneice
8
Di perusahaan saya, kami menggunakan rendering Pdf, notasi, dll. Solusi pihak ke-3 yang disebut PSPDFKit, itu tidak murah, tetapi berharga: pspdfkit.com
János
1
+1 Saya mengikuti kiat bermanfaat ini untuk penampil open source pdf Swifty PDF github.com/prcela/SwiftyPDF
Prcela

Jawaban:

103

Saya telah membangun semacam aplikasi menggunakan pendekatan yang sama kecuali:

  • Saya cache gambar yang dihasilkan pada disk dan selalu menghasilkan dua hingga tiga gambar di muka di utas terpisah.
  • Saya tidak overlay dengan UIImagetetapi menggambar gambar di layer ketika zoom adalah 1. Ubin-ubin itu akan dirilis secara otomatis ketika peringatan memori dikeluarkan.

Setiap kali pengguna mulai melakukan zoom, saya memperoleh CGPDFPagedan membuatnya menggunakan CTM yang sesuai. Kode dalam - (void)drawLayer: (CALayer*)layer inContext: (CGContextRef) contextseperti:

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

masalah adalah objek containg itu CGPDFDocumentRef. Saya menyinkronkan bagian di mana saya mengakses pdfDocproperti karena saya melepaskannya dan membuatnya kembali ketika menerima memoryWarnings. Tampaknya CGPDFDocumentRefobjek melakukan caching internal yang saya tidak menemukan cara untuk menyingkirkannya.

VdesmedT
sumber
1
apa pendekatan Anda ketika pengguna mulai Zooming?
Luke Mcneice
2
@ Lukas: Saya telah memodifikasi posting untuk menjawab
VdesmedT
1
Terima kasih banyak untuk ini, dan tip tentang caching CGPDFDocumentRef.
Luke Mcneice
Hanya pertanyaan singkat: mengapa Anda mendapatkan pdfPageRef dan mentransformasikannya ketika skalanya 1.0? karena saya melihat bahwa Anda menggambar baseImage (gambar dari pekerja bg?) sebelum Anda membuat transformasi.
Luke Mcneice
@ Lukas: Posting di sini setiap peningkatan kinerja yang bisa Anda lakukan. Terima kasih !
VdesmedT
67

Untuk penampil PDF yang sederhana dan efektif, saat Anda hanya memerlukan fungsionalitas terbatas, sekarang Anda dapat (iOS 4.0+) menggunakan kerangka kerja QuickLook:

Pertama, Anda harus menautkan ke QuickLook.frameworkdan#import <QuickLook/QuickLook.h>;

Setelah itu, dalam salah satu viewDidLoadatau salah satu metode inisialisasi malas:

QLPreviewController *previewController = [[QLPreviewController alloc] init];
previewController.dataSource = self;
previewController.delegate = self;
previewController.currentPreviewItemIndex = indexPath.row;
[self presentModalViewController:previewController animated:YES];
[previewController release];
Joshua J. McKinnon
sumber
Ya, ini secara konseptual sama dengan menggunakan UIWebView. Kami tidak akan menghabiskan waktu berjam-jam untuk mencari tahu bagaimana menggunakan barang CGPDF * jika itu semudah itu.
pt2ph8
5
Ya, tentu. Saya tentu tidak menyajikannya sebagai solusi lengkap. Tetapi beberapa pembaca pertanyaan ini mungkin tidak menyadari bahwa, untuk beberapa tujuan, ini adalah solusi yang masuk akal. Memperbarui jawaban untuk memperjelasnya.
Joshua J. McKinnon
6
+1 untuk ini. Minat utama saya adalah mengizinkan pengguna untuk melihat beberapa dokumentasi dalam aplikasi yang dalam format PDF. Saya tidak peduli tentang pencarian, penyorotan atau lonceng dan peluit lainnya - cukup rendering PDF berkinerja tinggi.
memmons
2
Kategori UIImage + PDF saya adalah renderer PDF tanpa basa-basi cepat dengan lapisan cache bawaan. github.com/mindbrix/UIImage-PDF
Mindbrix
6

Sejak iOS 11 , Anda dapat menggunakan kerangka kerja asli yang disebut PDFKit untuk menampilkan dan memanipulasi PDF.

Setelah mengimpor PDFKit, Anda harus menginisialisasi PDFViewdengan URL lokal atau jauh dan menampilkannya dalam tampilan Anda.

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

Baca lebih lanjut tentang PDFKit dalam dokumentasi Pengembang Apple.

rev the4kman
sumber
-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);
     } }
Kuldeep singh
sumber