iPhone / iPad / iOS 向けの高速でシンプルな PDF ビューア - ヒントやコツはありますか? 質問する

iPhone / iPad / iOS 向けの高速でシンプルな PDF ビューア - ヒントやコツはありますか? 質問する

最近、PDF の描画に関する質問が多く寄せられています。

はい、 PDF を非常に簡単にレンダリングできますUIWebViewが、優れた PDF ビューアに期待されるパフォーマンスと機能は得られません。

PDFページを描くことができますCALayerにまたはUIImageにAppleは大きなPDFを描画する方法を示すサンプルコードも提供していますズーム可能なUIScrollview

しかし、同じ問題が繰り返し発生しています。

UIImage メソッド:

  1. PDF はUIImageレイヤー アプローチと同様に光学的にスケーリングされません。
  2. UIImagesからの生成時に CPU とメモリが消費されるため、PDFcontextそれを使用して新しいズーム レベルのリアルタイム レンダリングを作成することが制限/禁止されます。

CATiledLayer メソッド:

  1. PDFページ全体を描画するにはかなりのオーバーヘッド(時間)がかかりますCALayer。個々のタイルはレンダリングされて表示されます(tileSizeを調整しても)。
  2. CALayers事前に準備することはできません (画面外でレンダリングされます)。

一般的に、PDF ビューアもメモリをかなり消費します。Apple のズーム可能な PDF サンプルのメモリ使用量も監視してください。

UIImage現在のプロジェクトでは、PDF ビューアを開発しており、別のスレッドでページの一部をレンダリングし(ここでも問題があります)、スケールが x1CATiledLayerのときに表示しています。スケールが 1 を超えるとレンダリングが開始されます。iBooks も同様にダブル テイクのアプローチを採用しており、ページをスクロールすると、鮮明なバージョンが表示される前に、わずか 1 秒未満、ページの低解像度バージョンが表示されます。

PDF イメージが描画を開始する前にレイヤーをマスクする準備ができるように、フォーカスされているページの各側で 2 ページをレンダリングします。フォーカスされているページから +2 ページ離れると、ページは再び破棄されます。

図面 PDF のパフォーマンスやメモリ処理を改善するための、どんなに小さなことでも明らかなことでも、何か洞察をお持ちの方はいらっしゃいますか? あるいは、ここで議論されている他の問題はありますか?

編集:いくつかのヒント (クレジット - Luke Mcneice、VdesmedT、Matt Gallagher、Johann):

  • 可能な場合は、メディアをディスクに保存してください。

  • TiledLayers でレンダリングする場合は、より大きな tileSizes を使用します。

  • 頻繁に使用される配列をプレースホルダーオブジェクトで初期化する、あるいは別の設計アプローチはこれです

  • 画像は、CGPDFPageRef

  • 使用NSOperationsまたはGCD &ブロック事前にページを準備します。

  • 描画中のメモリ使用量を減らすために、CGContextSetInterpolationQuality(ctx, kCGInterpolationHigh); CGContextSetRenderingIntent(ctx, kCGRenderingIntentDefault);前に呼び出します。CGContextDrawPDFPage

  • docRef を使用して初期化するのはNSOperations悪い考えです (メモリ)。docRef をシングルトンにラップします。

  • NSOperations可能であれば、特にメモリを使用する場合は、不要なものをキャンセルし、コンテキストを開いたままにしないように注意してください。

  • ページオブジェクトをリサイクルし、未使用のビューを破棄する

  • 必要なくなったらすぐに開いているコンテキストを閉じます

  • メモリ警告を受け取ったら、DocRefとページキャッシュを解放して再読み込みします。

その他の PDF 機能:

ドキュメンテーション

プロジェクト例

  • Apple/ズームPDF- ズームUIScrollView、、CATiledLayer
  • vfr/リーダー- ズーム、ページングUIScrollView、、CATiledView
  • 眉/葉- 素敵な遷移を伴うページング
  • / スキム- すべてはそう思える (OSX 用の PDF リーダー/エディター)

ベストアンサー1

私は、ほぼ同じアプローチを使用して、次のような種類のアプリケーションを構築しました。

  • 生成されたイメージをディスクにキャッシュし、常に別のスレッドで 2 ~ 3 枚のイメージを事前に生成します。
  • オーバーレイは行わずUIImage、ズームが 1 のときにレイヤーに画像を描画します。メモリ警告が発行されると、これらのタイルは自動的に解放されます。

ユーザーがズームを開始するたびに、 を取得しCGPDFPage、適切な CTM を使用してレンダリングします。 のコードは- (void)drawLayer: (CALayer*)layer inContext: (CGContextRef) context次のようになります。

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

問題は、 を含むオブジェクトですCGPDFDocumentRef。memoryWarnings を受け取ったときに解放して再作成するため、プロパティにアクセスする部分を同期しますpdfDoc。オブジェクトは内部キャッシュを実行しているようですCGPDFDocumentRefが、それを削除する方法がわかりません。

おすすめ記事