1. ホーム
  2. アイオス

[解決済み】iPhone/iPad/iOS用の高速で無駄のないPDFビューア - ヒントとヒント?

2022-03-25 02:48:37

質問

最近、PDFの描画に関する質問が多いのですが。

そうです。 UIWebView しかし、これでは優れたPDFビューアーに期待されるようなパフォーマンスや機能性を得ることはできません。

PDFのページを描画することができます をCALayerに または をUIImageに変換します。 . Apple には、大きな PDF を描画する方法を示すサンプルコードもあります。 ズーム可能なUIScrollviewで

しかし、同じ問題が何度も出てきます。

UIImageメソッド。

  1. PDFの UIImage 光学的には は、レイヤーアプローチと同様に拡大縮小が可能です。
  2. を生成する際のCPUとメモリの負荷が大きい。 は UIImages から PDFcontext を作成するために使用することを制限/防止します。 新しいズームレベルのリアルタイムレンダリング。

CATiledLayerメソッド。

  1. 大きなオーバーヘッド(時間)が発生する PDFの全ページを CALayer : 個々のタイルのレンダリングが確認できる (tileSize を調整した場合でも)
  2. CALayers 事前に用意できない 時間(画面外にレンダリングされる)。

一般的にPDFビューワーはメモリもかなり重いです。アップルのズーム可能なPDFの例のメモリ使用量をモニターしてもわかるでしょう。

現在のプロジェクトでは、PDFビューアを開発しています。 UIImage のページを別スレッドで表示し(ここでも問題!)、スケールをx1にして表示しています。 CATiledLayer iBooksでは、ページをスクロールすると、低解像度のページが1秒弱表示された後、鮮明なバージョンが表示されるという、二重の意味で似たようなアプローチを取っています。

フォーカスしたページの両側に2ページずつレンダリングして、PDF画像が描画を開始する前にレイヤーをマスクする準備ができるようにしています。

どなたか、Drawing PDFのパフォーマンスやメモリ処理を改善するために、どんな小さなことでも、あるいは明白なことでも、何か見識をお持ちですか? または、ここで議論されている他の問題でもかまいません。

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

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

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

  • は、頻繁に使用される配列をプレースホルダオブジェクトで開始します。 これ

  • を使用するよりも、画像の方がレンダリングが速くなることに注意してください。 CGPDFPageRef

  • 使用方法 NSOperations またはGCD &を使用してください。 ブロック を使用して、事前にページを準備します。 を使用します。

  • コール CGContextSetInterpolationQuality(ctx, kCGInterpolationHigh); CGContextSetRenderingIntent(ctx, kCGRenderingIntentDefault); 以前 CGContextDrawPDFPage 描画時のメモリ使用量を減らすために

  • イニシエーション NSOperations をdocRefで使用するのは悪い考えです(メモリ)。docRefをシングルトンにラップしてください。

  • 不要な NSOperations できる限り、特にメモリを使う場合は、コンテキストを開いたままにしないように注意してください。

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

  • 開いているContextsが不要になったら、すぐに閉じる。

  • メモリの警告を受けたら、DocRefとあらゆるページのキャッシュを解放して再ロードします。

その他のPDFの機能。

ドキュメンテーション

プロジェクト例

解決方法は?

私は、このようなアプリケーションを、.を除いてほぼ同じアプローチで構築したことがあります。

  • 生成された画像をディスクにキャッシュし、常に別スレッドで2~3枚の画像を事前に生成しています。
  • でオーバーレイしない。 UIImage そのタイルは、メモリ警告が出たときに自動的に解放されます。

ユーザがズームを開始するたびに、私は 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 . にアクセスする部分を同期させています。 pdfDoc プロパティを解放し、memoryWarningを受信したときに再作成しているからです。 どうやら CGPDFDocumentRef オブジェクトが内部キャッシュを行うのですが、それを取り除く方法が見つかりませんでした。