ios - pour - stocker des pdf sur iphone




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

Il y a eu beaucoup de questions récemment sur le dessin de PDF.

Oui, vous pouvez facilement afficher des PDF avec un UIWebView mais cela ne peut pas donner les performances et les fonctionnalités que vous attendez d'un bon lecteur PDF.

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

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

UIImage Méthode:

  1. Les PDF dans un UIImage ne sont pas optiquement aussi bien qu'une approche Layer.
  2. L'unité centrale et la mémoire sont UIImages la génération des UIImages partir d'un PDFcontext / empêche son utilisation pour créer un rendu en temps réel de nouveaux niveaux de zoom.

Méthode CATiledLayer:

  1. Theres un overhead important (temps) dessiner une page PDF complète à un CALayer : des tuiles individuelles peuvent être vus rendu (même avec un tweak tileSize)
  2. CALayers ne peut pas être préparé à l'avance (rendu hors écran).

Les visionneuses de PDF sont généralement très lourdes de mémoire. Surveillez même l'utilisation de la mémoire de l'exemple PDF zoomable d'Apple.

Dans mon projet actuel, je suis en UIImage de développer une visionneuse de PDF et de rendre un UIImage d'une page dans un fil séparé (problèmes ici aussi!) Et de le présenter alors que l'échelle est x1. CATiledLayer rendu CATiledLayer en jeu une fois que l'échelle est> 1. iBooks adopte une approche similaire à double prise, car si vous faites défiler les pages, vous pouvez voir une version basse résolution de la page pendant moins d'une seconde avant l'apparition d'une version nette.

Je rends 2 pages de chaque côté de la page en cours de 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.

Quelqu'un a-t-il des idées, aussi petites ou évidentes soient-elles, pour améliorer les performances / la gestion de la mémoire de Drawing PDF? ou d'autres questions discutées ici?

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

  • Enregistrez n'importe quel média sur le disque lorsque vous le pouvez.

  • Utilisez des tailles de tiles plus grandes si vous effectuez un rendu sur TiledLayers

  • init les tableaux fréquemment utilisés avec des objets d'espace réservé, alternativement une autre approche de conception est celle-ci

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

  • Utilisez NSOperations ou GCD & Blocks pour préparer les pages à l'avance.

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

  • initer vos NSOperations avec un docRef est une mauvaise idée (mémoire), envelopper le docRef dans un singleton.

  • Annuler les NSOperations inutiles Lorsque vous le pouvez, surtout si vous utilisez de la mémoire, méfiez-vous de laisser les contextes ouverts!

  • Recyclez les objets de page et détruisez les vues inutilisées

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

  • à la réception des avertissements de mémoire, relâchez et rechargez le DocRef et les caches de toutes les pages

Autres fonctionnalités PDF:

Documentation

Exemples de projets


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

Après l'importation de PDFKit, vous devez 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)
}

En savoir plus sur PDFKit dans la documentation du développeur Apple.


J'ai construit ce genre d'application en utilisant approximativement la même approche sauf:

  • Je cache l'image générée sur le disque et génère toujours deux à trois images à l'avance dans un fil séparé.
  • Je ne superpose pas avec un UIImage mais dessine plutôt l'image dans le calque lorsque le zoom est 1. Ces carreaux seront libérés automatiquement lorsque des avertissements de la mémoire sont émis.

Chaque fois que l'utilisateur commence à zoomer, CGPDFPage le CGPDFPage et 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);
    }
}

Le problème est l'objet contenant le CGPDFDocumentRef . Je synchronise la partie où pdfDoc propriété pdfDoc car je la libère et la recréer lors de la réception de memoryWarnings. Il semble que l'objet CGPDFDocumentRef effectue une mise en cache interne que je n'ai pas trouvée comment me débarrasser.


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