Visualiseur PDF rapide et allégé pour iPhone / iPad / iOs - conseils et astuces?

il y a eu beaucoup de Questions récemment sur les dessins PDF.

Oui, vous pouvez rendre les PDF très facilement avec un UIWebView , mais cela ne donne pas la performance et la fonctionnalité que vous attendez d'un bon lecteur PDF.

vous pouvez dessiner une page PDF à un CALayer ou à un UIImage . Apple ont même le code d'exemple pour montrer comment tirer un grand PDF dans un Zoomable UIScrollview

mais les mêmes problèmes continuent de surgir.

Méthode UIImage:

  1. PDF dans un UIImage ne pas optiquement échelle ainsi qu'une approche par couches.
  2. le CPU et la mémoire ont frappé sur la génération le UIImages d'un PDFcontext limites/empêche de l'utiliser pour créer un rendu en temps réel des nouveaux niveaux de zoom.

CATiledLayer Method:

  1. ) dessin D'une pleine page PDF à un CALayer : des carreaux individuels peuvent être vus Rendu (même avec un tweak tileSize)
  2. CALayers ne peut être préparé avant temps (rendu hors écran).

généralement, les lecteurs PDF sont assez lourds de mémoire aussi. Même surveiller l'utilisation de la mémoire d'apple exemple de fichier PDF zoomable.

dans mon projet actuel, je développe un visualiseur PDF et je rends une UIImage d'une page dans un thread séparé (problèmes ici aussi! et présenter ce que l'échelle est x1. CATiledLayer , le rendu des coups de pied dans une fois que la balance est >1. iBooks adopte une approche double take similaire comme si vous faites défiler les pages, vous pouvez voir une version basse res de la page pendant un peu moins d'une seconde avant qu'une version nette n'apparaisse.

Im rendu 2 pages de chaque côté de la page en mise au point afin que L'image PDF soit prête à masquer la couche avant qu'elle ne commence à dessiner.Les Pages sont à nouveau détruites lorsqu'elles sont à +2 pages de la page ciblée.

est-ce que quelqu'un a une idée, aussi petite ou évidente soit-elle, pour améliorer la performance/ Gestion de la mémoire des dessins PDF? ou toutes autres questions abordées ici?

EDIT: Quelques Conseils (Crédit-Luke Mcneice,VdesmedT, Matt Gallagher, Johann):

  • enregistrez n'importe quel support sur le disque lorsque vous le pouvez.

  • utiliser des tileSizes plus grands si rendu sur les couches de tiled

  • dans les tableaux fréquemment utilisés avec des objets placeholder, alternativement une autre approche de conception est celle-ci

  • notez que les images seront plus rapides qu'un CGPDFPageRef

  • utilisez NSOperations ou GCD & blocs pour préparer les pages à l'avance de temps.

  • appeler CGContextSetInterpolationQuality(ctx, kCGInterpolationHigh); CGContextSetRenderingIntent(ctx, kCGRenderingIntentDefault); avant CGContextDrawPDFPage pour réduire l'utilisation de la mémoire tout en dessinant

  • init avec votre NSOperations avec un docRef est une mauvaise idée (de mémoire), enveloppez-la docRef en Singleton.

  • annuler inutile NSOperations quand vous le pouvez, surtout s'ils utiliseront la mémoire, méfiez-vous de laisser les contextes ouverts!

  • recycler les objets de la page et détruire les vues inutilisées

  • fermez tous les contextes ouverts dès que vous n'en avez pas besoin

  • sur la réception des avertissements de mémoire libérer et recharger le DocRef et toutes les pages Caches

autres caractéristiques PDF:

Documentation

exemples de projets

363
demandé sur Luke Mcneice 2010-10-08 14:23:10
la source

4 ответов

j'ai de construire ce genre de demande à l'aide approximativement la même approche à l'exception de :

  • je cache l'image générée sur le disque et génèrent toujours deux ou trois images à l'avance dans un thread séparé.
  • Je ne superpose pas avec un UIImage mais dessine l'image dans la couche lorsque le zoom est 1. Ces tuiles seront libérées automatiquement lorsque des avertissements de mémoire seront émis.

Chaque fois que l'utilisateur commence à zoomer, j'acquiers le CGPDFPage et je le rends en utilisant le CTM approprié. Le code dans - (void)drawLayer: (CALayer*)layer inContext: (CGContextRef) context est comme :

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

est l'objet du CGPDFDocumentRef . Je synchronise la partie où j'accède à la propriété pdfDoc parce que je la relâche et je la recrée en recevant memoryWarnings. Il semble que l'objet CGPDFDocumentRef effectue une mise en cache interne dont je n'ai pas trouvé le moyen de me débarrasser.

103
répondu VdesmedT 2013-06-11 14:03:59
la source

pour une visualisation PDF simple et efficace, lorsque vous n'avez besoin que de fonctionnalités limitées, vous pouvez maintenant (iOS 4.0+) utiliser le cadre QuickLook:

tout d'abord, vous devez faire un lien vers QuickLook.framework et #import <QuickLook/QuickLook.h>;

ensuite, dans viewDidLoad ou dans l'une des méthodes d'initialisation paresseuses:

QLPreviewController *previewController = [[QLPreviewController alloc] init];
previewController.dataSource = self;
previewController.delegate = self;
previewController.currentPreviewItemIndex = indexPath.row;
[self presentModalViewController:previewController animated:YES];
[previewController release];
65
répondu Joshua J. McKinnon 2018-04-18 00:27:32
la source

depuis iOS 11 , vous pouvez utiliser le cadre natif appelé PDFKit pour afficher et manipuler des fichiers PDF.

après avoir importé PDFKit, vous devriez initialiser un PDFView avec une URL locale ou distante et l'afficher dans votre vue.

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

pour en savoir plus sur PDFKit, consultez la documentation D'Apple Developer.

4
répondu the4kman 2018-02-08 17:07:29
la source
 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
répondu Kuldeep singh 2013-06-21 15:45:05
la source

Autres questions sur