最近、PDF の描画に関する質問が多く寄せられています。
はい、 PDF を非常に簡単にレンダリングできますUIWebView
が、優れた PDF ビューアに期待されるパフォーマンスと機能は得られません。
PDFページを描くことができますCALayerにまたはUIImageにAppleは大きなPDFを描画する方法を示すサンプルコードも提供していますズーム可能なUIScrollview
しかし、同じ問題が繰り返し発生しています。
UIImage メソッド:
- PDF は
UIImage
レイヤー アプローチと同様に光学的にスケーリングされません。 UIImages
からの生成時に CPU とメモリが消費されるため、PDFcontext
それを使用して新しいズーム レベルのリアルタイム レンダリングを作成することが制限/禁止されます。
CATiledLayer メソッド:
- PDFページ全体を描画するにはかなりのオーバーヘッド(時間)がかかります
CALayer
。個々のタイルはレンダリングされて表示されます(tileSizeを調整しても)。 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 機能:
PDF 内のリンクを取得する(そしてここそしてここ)
リンクのターゲットを取得する(配列からページ番号を取得
/Dest
)
生のテキストを取得する(そしてここそしてここそしてここ(ポジショニング重視)
検索中(そしてここ) (すべての PDF で動作するわけではありません (一部の PDF では奇妙な文字が表示されることがあります。エンコードの問題だと思いますが、よくわかりません) -Credit BrainFeeder)
CALayer とオフスクリーンレンダリング- 高速かつスムーズに表示するために次のページをレンダリングします
ドキュメンテーション
- Quartz PDFオブジェクト(メタ情報、注釈、サムネイルに使用)
- Abobe 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
が、それを削除する方法がわかりません。