373 votes

Visionneuse PDF rapide et simple pour iPhone / iPad / iOs - conseils et astuces?

Il y a eu beaucoup de Questions récemment à propos du dessin PDF.

Oui, vous pouvez afficher des fichiers PDF très facilement avec un UIWebView mais ce cant donner les performances et les fonctionnalités que vous attendez d'un bon lecteur de PDF.

Vous pouvez dessiner une page PDF pour une CALayer ou à une UIImage. Apple même avoir un exemple de code pour montrer comment dessiner un grand PDF dans un Zoomable UIScrollview

Mais les mêmes questions à garder à fuser.

UIImage Méthode:

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

CATiledLayer Méthode:

  1. Il ya une Surcharge importante (temps) dessin pleine page PDF pour une CALayer: carreaux individuels peut être vu de rendu (même avec un taillecarreau tweak)
  2. CALayers ne peut pas être préparé à l'avance de temps (rendu hors de l'écran).

Généralement des lecteurs de PDF sont très lourdes sur la mémoire trop. Même surveiller l'utilisation de la mémoire de la pomme de zoomable PDF exemple.

Dans mon projet actuel, je suis le développement d'une visionneuse PDF et je suis rendu un UIImage d'une page dans un thread séparé (questions ici aussi!) et de le présenter même si l'échelle est x1. CATiledLayer le rendu des coups de pied dans une fois que la balance est >1. iBooks prend un semblable double approche que si vous faites défiler les pages, vous pouvez voir une baisse des res version de la page pour seulement moins d'une seconde avant qu'un croustillant de version s'affiche.

Im rendu 2 pages de chaque côté de la page, dans l'accent, de sorte que l'image PDF est prêt à masquer le calque avant de commencer le dessin.Les Pages sont détruits lorsqu'ils sont +2 pages à l'écart de la page.

Quelqu'un aurait-il des idées, n'importe comment petit ou évident pour améliorer la performance/ gestion de la mémoire de Dessin PDF? ou toutes autres questions abordées ici?

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

  • Enregistrer tous les médias sur le disque quand vous le pouvez.

  • L'utilisation de plus grandes tileSizes si le rendu sur TiledLayers

  • init fréquemment utilisé des tableaux avec des objets de l'espace réservé, alternitively une autre approche de la conception est ce un

  • Notez que les images de rendu plus rapide qu'un CGPDFPageRef

  • Utiliser NSOperations ou PGCD et des Blocs de préparer les pages à venir de temps.

  • appelez CGContextSetInterpolationQuality(ctx, kCGInterpolationHigh); CGContextSetRenderingIntent(ctx, kCGRenderingIntentDefault); avant CGContextDrawPDFPage afin de réduire l'utilisation de la mémoire pendant le dessin

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

  • Annuler inutile NSOperations Quand vous le pouvez, surtout si ils vont être à l'aide de la mémoire, méfiez-vous de laisser des contextes ouverts!

  • Recycler des objets de page en faisant pointeur de swaps ou de détruire inutilisés vues

  • Fermez tous les Contextes dès que vous n'en avez pas besoin

  • sur réception de l'avertissement de mémoire de libérer et de recharger la DocRef et n'importe quelle page Caches

D'autres Fonctionnalités de PDF:

La Documentation

Exemple de projets

103voto

VdesmedT Points 6831

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 n'ai pas de superposition avec un UIImage mais au lieu de dessiner l'image dans la couche lorsque le zoom est 1. Les tuiles seront publiés automatiquement lorsque la mémoire des avertissements sont émis.

Chaque fois que l'utilisateur de lancer le zoom, j'acquiers de l' CGPDFPage et l'afficher à l'aide de la CTM. Le code en - (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);
    }
}

question est l'objet contenant l' CGPDFDocumentRef. - Je synchroniser la partie où j'ai accès à l' pdfDoc bien parce que je le libérer et de le recréer lors de la réception de memoryWarnings. Il semble que l' CGPDFDocumentRef objet de faire à l'interne de la mise en cache que je n'ai pas trouver comment se débarrasser de.

67voto

Pour un lecteur PDF simple et efficace, lorsque vous avez besoin uniquement des fonctionnalités limitées, vous pouvez maintenant (iOS 4.0 +) utilisez le cadre QuickLook :

Vous devez lier contre et

-2voto

Kuldeep singh Points 10
 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);
     } }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X