PYMUPDF.ioPyMuPDFによるテキスト抽出 著者

PyMuPDFを探索する:PDFにおける画像の処理

ハラルド・リーダー(Harald Lieder)- 2022年12月20日火曜日


この記事は、PyMuPDFの機能に関するシリーズの一部です。

PyMuPDFは、MuPDFのPythonバインディングです。MuPDFは、軽量なPDF、XPS、電子書籍ビューア、レンダラー、およびツールキットです。PyMuPDFとMuPDFは、Artifex Software, Inc.によってメンテナンスおよび開発が行われています

(Py-) MuPDFは、PDF、XPS、OpenXPS、CBZ、MOBI、EPUB、およびFB2(電子書籍)形式のファイルにアクセスできます。また、そのパフォーマンスの高さとレンダリング品質の高さで知られています。

PyMuPDFのホームページはGitHubにあります。pip install pymupdfを使用して、PyPIからインストールすることができます。

要約

PDFのテキスト抽出や挿入に加えて、同様の方法で画像を扱うこともしばしば求められます。

これらのすべての状況において、PyMuPDFは助けになります。

画像の抽出

これには少なくとも2つの方法があります。

メソッド1は、PDFに限らず、すべてのドキュメントタイプで利用できます。画像は、PyMuPDFの記事 「PyMuPDFによるテキスト抽出」 で説明されているいくつかのページテキスト抽出のバリアントの一部として提供されます。

一般的なコーディングパターンは次のようなものです:

    
    doc = fitz.open("some.file")  # open some supported document

    # iterate over the pages
    for page in doc:
        img_number = 0  # for enumerating images per page
        # iterate over the image blocks
        for block in page.get_text("dict")["blocks"]:
            # skip if no image block
            if block["type"] != 1:
                continue
            # build filename, like 'img17-3.jpg'
            name = f"img{page.number}-{img_number}.{block['ext']}"
            out = open(name, "wb")
            out.write(block["image"])  # write the binary content
            out.close()
            img_number += 1  # increase image counter
    

各画像ブロックには多くのメタデータが含まれており、関連する画像を選択したり、潜在的な重複を回避したりするのに役立ちます。

メソッド2はPDFドキュメントにのみ適用されます。テキストの抽出や個々のページへのアクセスは必要ありません。PDF固有の情報を使用できるためです。

PDFのオブジェクト定義を反復処理し、画像オブジェクトのみを選択します。ページへのアクセスを回避することで、PDFの内部構造が正しくない場合でも画像を正常に抽出することができます。PDFの損傷は残念ながら稀ではなく、インターネット経由での不完全なダウンロードによってほとんど発生します。

    
    doc = fitz.open("some.pdf")  # open the PDF

    xreflen = doc.get_xreflength()  # count of all objects in file
    # we will iterate through all objects in the PDF and select images
    for i in range(1, xreflen):  # do not access item 0 of the table
        if doc.xref_get_key(i, "Subtype")[1] != "/Image":  # check if image
            continue  # not an image, skip
        # this is an image!
        img = doc.extract_image(i)  # extract it and store its content
        # build filename, like 'img-4711.png'
        name = f"img-{i}.{img['ext']}"
        out = open(name, "wb")
        out.write(img["image"])  # write the binary content
        out.close()
    

PDFドキュメントでは、このタスクの他のバリエーションも利用可能です。最良の結果を得るために選択できるスクリプトを作成しました:

画像の挿入

PDFページに画像を表示して改善したいですか? または、すべてのページの左上隅に会社のロゴを配置したいですか? または、透かしを追加したいですか?

これらすべては、PyMuPDFのPageクラスのinsert_image()メソッドを使用して実行できます。

このメソッドは、3つの異なるソースからの入力をサポートしています:画像ファイル、メモ内の画像、およびMuPDF独自の画像形式であるPixmap。

画像は、ページ上の指定された矩形に挿入することができます。その矩形は任意のサイズであり、その幅と高さの比率は画像と異なる場合もあります。

画像は、その中心と矩形の中心が一致するようにスケーリングされて配置されます。

オプションで、90度、180度、または270度の画像回転も選択できます。

画像挿入プロセスの最適なパフォーマンスを実現するために、多くの注意が払われています:

どちらの場合でも、既存の画像への参照がページのオブジェクト定義に配置されます。

したがって、たとえ100,000ページにロゴを挿入しても、高速かつファイルサイズの影響は最小限に抑えられます!

これがメソッドの呼び出しパターンの重要な部分です:

    
    page.insert_image(
        rect,  # the desired rectangle
        filename=filename,  # image file
        stream=buffer,  # image in memory
        pixmap=pixmap,  # image from pixmap
        rotate=angle,  # 0, 90, 180, 270
        xref=0,  # >0 refers to an existing image
        # more parameters
    )
    

画像の置き換えまたは削除

いくつかの使用例があります。例としては:

PDFに埋め込まれた画像を置換または削除するために、以下の手順を使用することができます。

新しい画像は、古い画像が表示されていた場所、つまり古い画像を使用しているすべてのページに表示されます。新しい画像は、どこでも同じ矩形領域をカバーします。

各ページのレンダリング指示は変更を実現せず、従って以前と同じアスペクト比を仮定します。もし変更があれば、新しい画像は何らかの方法で歪んで表示されることになります。

このタスクを実行するためには、以下のアイテムが必要です:

  1. ファイル replacer.py から img_replace メソッドをインポートします。
  2. 古い画像の xref を知る必要があります。
  3. 1つのPDFのページが必要です。通常は古い画像が表示されるページですが、必須ではありません。
  4. 新しい画像が必要です。これはファイル名、メモリ内の画像データ、または Pixmap 形式のいずれかで提供できます。

それから、以下の手順を実行するだけです:

    
    import fitz
    from replacer import img_replace

    doc = fitz.open("your.pdf")
    page = doc[nnn]  # any page of doc
    # ----------------------------------------
    # find out the xref of the old image
    # see some hints further down
    # ----------------------------------------
    filename = "image.jpg"  # some image
    # or equivalently a bytes object containing it
    # or equivalently a fitz.Pixmap
    img_replace(page, xref,
        filename=filename,  # or one of the following:
        stream=None,  # alternatively
        pixmap=None,  # alternatively
    )
    doc.save("your-new.pdf",garbage=4)  # save changed PDF
    

古い画像を xref削除するには、上記のスニペットを以下のように変更してください:

    
    pix = fitz.Pixmap(fitz.csGRAY, (0, 0, 1, 1), 1)  # small pixmap
    pix.clear_with()  # empty its content
    img_replace(page,xref,
        pixmap=pix,
    )
    

ここでは、小さな(2 x 2)の透明なPixmapを作成し、それを元の画像と置き換えるために使用しました。このPixmapは見えないため、画像が表示されていない場合と同じ効果があります。全体として、ファイルでは200バイト未満の容量が必要です。

画像のXREFの検索

では、画像のクロスリファレンス番号(xref)をどのように見つけることができるでしょうか?

次のように、ページに表示される画像のリストを作成します:

    
    In [1]: import fitz
    In [2]: doc = fitz.open("original.pdf")
    In [3]: page = doc[0]
    In [4]: page.get_images()
    Out[4]: [(46, 0, 439, 501, 8, 'DeviceRGB', '', 'fzImg0', 'FlateDecode')]
    

ここでは簡単です:このページには1つの画像しかありませんし、そのxrefは46です。もし複数の画像がある場合、表示位置(境界ボックス - bbox)を以下のように表示します:

    
    In [5]: for item in page.get_images():
       ...:  xref = item[0]
       ...:  print(xref, page.get_image_rects(xref))
       ...:
    46 [Rect(200.00001525878906, 240.63067626953125,
             497.6600341796875, 580.3292236328125)]
    

おそらく、画像がページのどこに表示されているかを知っているため、適切なxrefを見つけることができます。

画像の位置を変更する

画像を挿入する際、それがページ上でどのように見えるかを事前に予測することは難しい場合があります。

正しい位置に配置されていますか?矩形は十分に大きいですか?他のコンテンツとの重なりはありますか?

ここで、あなたをサポートするためのGUIスクリプトを開発しました。

使用するには、最新バージョンのwxPythonをインストールする必要があります(python -m pip install wxpython)。それから、単にスクリプトを起動します。

それによってPDFを選択することができ、準備が整います!ページをめくり、既存の画像を選択したり、画像ファイルから選んで新しい画像を挿入したりすることができます。

画像をページ上で移動したり、表示矩形のサイズを変更したり、画像を完全に削除したりすることができます。

以下は、インターフェースのビジュアルイメージです。

まとめ

この記事では、PyMuPDFの画像処理機能について概要を提供しました。

PyMuPDFでは、MuPDFでサポートされているすべてのドキュメントタイプから画像を抽出することができます。これには、PDF、XPS、EPUB、MOBI、HTMLやXMLなどのインターネット形式などが含まれます。

画像の挿入はPDFファイルに対して可能です。

既存のPDF文書内の画像を置換、削除、または再配置するためのツールが存在します。

PyMuPDFは、大規模かつ高機能なドキュメント処理のPythonパッケージです。優れたパフォーマンスと高品質なレンダリングに加えて、その優れた ドキュメンテーション でも知られています。PDF版のドキュメントは現在、420ページ以上(レターサイズ)あり、そのうち70ページ以上がHow-To形式のレシピに充てられています。必読の価値があるでしょう。

もう1つの知識源は、ユーティリティリポジトリです。PDFを扱う際に何をする予定があっても、そこでスタートを切るためのいくつかのサンプルスクリプトを見つけることができるでしょう。

PyMuPDFに関する質問がある場合は、#pymupdf Discordチャンネルで開発者に連絡することができます。開発者は、ご質問に対してガイダンスやサポートを提供することができます。