長い PDF のサムネイルを作成し、最初にピクセルとメモリを計算します
長い PDF サムネイルによって発生するメモリ オーバーフローの問題を目指して、DPI とピクセル メモリ変換ロジックが分析されます。 PyMuPDF の安全なレンダリング コードの例、合成データの検証方法、および製品受け入れチェックリストを提供し、文書翻訳ワークフローの視覚的な品質検査ベンチマークとしてそれらを使用する方法を説明します。
200 ページのエンジニアリング図面のサムネイルをバッチ生成すると、30 ページに達したときにスクリプトが OOM によりシステムによって強制終了されました。これは、多くの開発者が長いドキュメントを初めて処理するときに遭遇する典型的な障害です。通常、問題はライブラリ自体にあるのではなく、ラスタライズ プロセスの一時メモリ フットプリントを過小評価していることにあります。 A3 ページを 150 DPI の RGB イメージとしてレンダリングすると、元のピクセル データだけで約 35MB が必要になります。ピックスマップがループ内で時間内に解放されなかった場合、またはアルファ チャネルが誤って開かれた場合、メモリのピークは数秒で GB レベルを超える可能性があります。
この記事は、長い PDF をバッチ処理する必要がある開発者向けに書かれています。これを読むと、各フレームのリソース予算を計算し、より安全な方法でサムネイルをページごとにレンダリングし、どの結果を手動で確認する必要があるかを知ることができます。この記事の例は合成サンプルを使用して実証されており、コードは隔離された環境でチェックされていますが、これはすべての実際のファイルや製品の効果を保証するものではありません。重要な書類を処理する前に、原本を保管し、本文の境界と許容事項に従って確認してください。
長い PDF サムネイルのメモリ オーバーフローを回避するにはどうすればよいですか?一文の結論
まず、DPI とピクセル数に基づいて各ページのメモリ バジェットを計算し、次に RGB モードでページごとにレンダリングし、時間内に各フレームのバッファを解放します。
| あなたの状況 | 推奨される実践方法 | 理由 |
|---|---|---|
| サムネイルをバッチで生成する | ページごとにレンダリングし、レンダリング後すぐに Pixmap をリリースします | ループ内の解放されていないバッファにより、常駐メモリが理論値を大幅に超えます。 |
| プレビューするだけで、透明な背景は必要ありません | alpha=Falseを設定し、RGBを使用します | RGBA ピクセルあたり 4 バイト、A4 144 DPI で ~33% 増加 |
| ページが回転する可能性があります | まず回転後の実際の長方形を取得し、ピクセル サイズを計算します。 | 元の幅と高さを計算すると、トリミングまたはストレッチが行われます。 |
| DPI またはページ サイズの入力例外 | レンダリング前に DPI とページ サイズの範囲を確認する | DPI が大きすぎると、1 ページで数百 MB を消費する可能性があります |
| 暗号化されているページ、破損しているページ、または複雑なベクター グラフィックスが含まれているページ | スキップするか特別な処理を行うかは手動の判断に任せます。 | 自動化スクリプトはサイレントに失敗することがよくあります |
ピクセル サイズとメモリ使用量の正確な変換
レンダリング API を呼び出す前に、物理次元からバイトへのマッピングを確立します。
物理的な寸法からピクセルまで
- PDF ページ サイズはポイント単位で測定され、1 ポイントは 1/72 インチに相当します。座標系の表記についてはPyMuPDF 座標 座標系の説明を参照してください。
- DPI ラスタライズを指定した場合、実際のピクセルの幅と高さは
int(page_width_pt / 72 dpi)とint(page_height_pt / 72 dpi)になります。
・A4標準紙(595×842ドット)を例にとると、144DPIで生成される画像サイズは1190×1684ピクセルとなります。
メモリ使用量を見積もる方法
- RGB カラースペースはピクセルあたり 3 バイト、RGBA は 4 バイトです。
- 上記の A4 を例にとると、RGB モードの 1 フレームの非圧縮データは約 6.0MB (1190×1684×3)ですが、アルファ チャンネルをオンにすると 8.0MB に増加し、約 33% 増加します。
- サムネイル プレビュー シーンでは、透明な背景オーバーレイが必要でない限り、アルファ チャネルを常に無効にする必要があります。
- バッチ サイクルでは、前のフレームのバッファがガベージ コレクターによって時間内にクリアされなかった場合、実際の常駐メモリは理論値の数倍になる可能性があります。
合成例の入力範囲と予想される動作
メモリ制御ロジックを検証するために、再現不可能な実際のファイルに依存するのではなく、制御された合成入力のセットを構築しました。
正しく入力してください
正しい入力には、既知の寸法の仮想ページ、明示的な DPI パラメータ、およびアルファをオフにするフラグが含まれている必要があります。たとえば、100×100 ポイントの正方形のページを作成し、72 DPI で RGB イメージとしてレンダリングすると、予想される出力は 100×100 ピクセル、30,000 バイトのバッファーになります。
よくある入力エラー
- 負の DPI またはゼロ DPI: 一部のライブラリは例外をスローしますが、より危険なのは、上限をチェックせずに非常に大きな値 (1200 など)を渡すことです。現時点では、単一ページのレンダリングで数百 MB のメモリが消費され、後続のページにスペースを割り当てることができなくなる可能性があります。
- ページを回転: ページを 90 度回転した後も元の幅と高さに基づいてバッファーが計算される場合、トリミングまたはストレッチが行われます。
処理方法は、レンダリング前にアサーションを追加することです。DPI は 0 より大きく、事前に設定されたしきい値未満である必要があり (記事では例として 300 が使用されています)、ページ サイズは妥当な範囲を超えてはなりません (記事では例として A0 が使用されています)。これらのしきい値は業界標準ではなく、実行環境の利用可能なメモリに基づいたエンジニアリング上の制約です。
PyMuPDF ページごとのレンダリングの安全な実装
次の例は、メモリに制約のある環境でサムネイルを安全に生成する方法を示しています。このコードでは PyMuPDF を使用しているため、pymupdf>=1.24.0 をインストールする必要があります。すべての操作はメモリ内で完了し、外部ファイルに依存しません。レンダリングで使用される Page.get_pixmap パラメーターの説明については、PyMuPDF Page.get_pixmap 公式ドキュメントを参照してください。この例は、教育目的で構築された合成シナリオです。独自のロックされた依存関係環境で検証を実行してください。
import pymupdf
def generate_thumbnail_safe(doc_bytes: bytes, dpi: int = 144) -> bytes:
"""安全生成首页缩略图,含资源预算校验"""
assert 0 < dpi <= 300, "DPI must be in (0, 300]"
doc = pymupdf.open(stream=doc_bytes, filetype="pdf")
try:
page = doc[0]
rect = page.rect
# 计算旋转后实际尺寸
if page.rotation in (90, 270):
width_px = int(rect.height * dpi / 72)
height_px = int(rect.width * dpi / 72)
else:
width_px = int(rect.width * dpi / 72)
height_px = int(rect.height * dpi / 72)
# 内存预算检查(假设最大允许50MB)
mem_estimate = width_px * height_px * 3
assert mem_estimate < 50 * 1024 * 1024, f"Estimated {mem_estimate}B exceeds limit"
pix = page.get_pixmap(dpi=dpi, alpha=False)
thumbnail_bytes = pix.tobytes("png")
pix = None # 显式释放
return thumbnail_bytes
finally:
doc.close()
# 合成测试:创建100x100点空白PDF
blank_pdf = pymupdf.open()
page = blank_pdf.new_page(width=100, height=100)
blank_bytes = blank_pdf.tobytes()
blank_pdf.close()
result = generate_thumbnail_safe(blank_bytes, dpi=72)
assert len(result) > 0, "Thumbnail generation failed"
重要なポイントは次のとおりです。
- 冗長チャネルを避けるには、
alpha=Falseを使用します。 - 回転状態に基づいてピクセル寸法を再計算します。
- レンダリング前にメモリを見積もり、ハード キャップを設定します。
- レンダリング直後に Pixmap 参照を null にします。
これらの対策は波及効果がないことを保証するものではありませんが、予測可能な範囲内でリスクを制御することは可能です。
受け入れ基準と手動レビューの境界
コードが実行できるという事実は、それが運用準備が整っていることを意味するものではありません。次の表は、実際の展開で注意が必要な受け入れ項目をリストし、自動化がカバーできる範囲と手動介入が必要なシナリオを区別します。
| 現象を観察する | 自動処理 | 手動レビューのトリガー条件 |
|---|---|---|
| サムネイルが真っ黒または真っ白 | Pixmap が空ではなく、分散がしきい値を超えていることを確認してください | 連続3ページ異常、または最初と最後のページが異常です。 |
| レンダリング時間が急激に増加する | 単一ページ時間を記録、平均の 2 倍を超えるアラーム | 1 ページに 5 秒以上かかるか、合計時間が予想より 30% 長くなります。 |
| メモリのピークが限界に近づいている | 自動的に DPI を下げて再試行します | ダウングレード後も失敗するか、画質が許容できない |
| ページのコンテンツがありません | テキストブロック数とメタデータを比較する | 主要な章のサムネイルが空白または間違った場所に表示される |
| ページが不均衡に回転しました | アスペクト比がソースファイルと一致しているかどうかを確認します | 設計図面または表文書の変形 |
この表は、コード デモンストレーション レベルでのリソース制御にのみ適用されます。エンドツーエンドの効果を受け入れるには、色の精度やフォント埋め込みの完全性などのビジネス上の側面も考慮する必要があります。暗号化された PDF、破損したファイル、または複雑なベクター グラフィックスを含むページに遭遇すると、自動化されたスクリプトが警告なしに失敗することがよくあります。この場合、スキップするか特殊な処理を行うかを手動で判断する必要があります。
ドキュメントの翻訳にチェックリストを使用する
サムネイルの後に文書を翻訳する必要がある場合は、最初にページ順序、ソースの場所、テキストの整合性をチェックしてから、同じ感度を下げたサンプルを翻訳プロセスに送信することをお勧めします。翻訳後も、タイトル、本文、イラストが正しく対応しているか確認する必要があります。文章が滑らかかどうかだけを確認することはできません。
OmniDoc (製品ポータル)はマルチフォーマット文書翻訳ポータルを提供しており、公式 Web サイトでは OCR、用語集、対訳比較機能が導入されています。ファイルから直接作業したいチームにとって、これは実際のサンプルを使用して評価する価値のあるパスです。アップロード許可のある感度を下げたファイルを使用し、この記事のチェック項目を使用して結果を確認してください。この記事では、OmniDoc がオープン ソース ライブラリや内部アルゴリズムを使用しているという主張はなく、この例が製品パフォーマンス テストに代わるものでもありません。
📊 コアの比較
| カラーモード | ピクセルあたりのバイト数 | A4 シングルフレーム(144 DPI) | 該当するシナリオ |
|---|---|---|---|
| RGB | 3 | 6.0MB | 背景が透明でないサムネイル プレビュー |
| RGBA | 4 | 8.0MB | 透明な背景オーバーレイが必要 |
🎯 どの方法があなたに適していますか?
サムネイルをすばやく生成する必要がある場合
RGB モードを使用し、アルファをオフにし、ページごとにレンダリングして、適切なタイミングで Pixmap をリリースします。
透明な背景オーバーレイが必要な場合
より高いメモリ使用量を受け入れ、必要に応じて DPI を下げるかバッチ処理を行ってレンダリングする前にピークを推定します。
暗号化されたまたは複雑なベクター ファイルを扱う場合
自動化されたスクリプトに完全に依存しないでください。失敗したページを手動で判断して、スキップするか特別に処理するかを決定する必要があります。
❓ よくある質問 (FAQ)
1. 数十ページを処理した後、スクリプトがシステムによって強制終了されるのはなぜですか?
ほとんどの場合、ライブラリ自体に欠陥があるのではなく、ラスタライズの瞬間的なメモリ使用量が過小評価されており、ループ内で Pixmap の解放が間に合わないことが原因です。ピーク値は数秒以内に GB レベルを超える場合があります。
2. サムネイルのアルファ チャネルをオフにする必要があるのはなぜですか?
透明な背景オーバーレイが必要でない限り、Alpha はメモリを追加するだけです。 144 DPI の A4 を例にとると、1 フレームは 6.0MB から 8.0MB に増加します。
3. 回転したページが変形するのはなぜですか?
バッファーが依然として元の幅と高さに基づいて計算されている場合、レンダリング結果が切り取られたり引き伸ばされたりする可能性があります。実際の回転された長方形は、ピクセル寸法を計算する前に取得する必要があります。
4. DPI 制限は 300 でなければなりませんか?
不確かな。この記事の 300 というしきい値は、業界標準ではなくしきい値の例であり、実行環境の利用可能なメモリに基づいて設定する必要があります。
5. サンプル チェックに合格した後、コードをオンラインに公開できますか?
できません。コードが実行できるという事実は、それが運用環境で使用できることを意味するものではありません。境界条件は、受け入れリストに従って、実際の、ただし感度を下げた長い文書でレビューする必要があります。
📝 概要
コードを記述する前に、リソースの予算を明確に計算する必要があります。ページごとのレンダリング、タイムリーなリリース、パラメータの検証が不可欠です。自動化はリソース制御の問題のほとんどをカバーできますが、色、フォント、複雑なページについては依然として手動による確認が必要です。


