チュートリアル¶
このチュートリアルでは、PythonでのPyMuPDF、MuPDFのステップバイステップの使用方法を紹介します。
MuPDFはPDFだけでなく、XPS、OpenXPS、CBZ、CBR、FB2、EPUB形式もサポートしており、PyMuPDFも同様です[1]。ただし、簡潔さのために、ここではPDFファイルについてのみ話を進めます。本当にPDFファイルのみがサポートされている場所では、明示的にその旨を記述します。
このイントロダクションに加えて、ぜひ PyMuPDF の YouTube チャンネル もご覧ください。以下の内容の多くが、YouTubeの「ショート動画」や長編動画の形式で紹介されています。
バインディングのインポート¶
MuPDFへのPythonバインディングは、このインポート文によって利用可能になります。また、ここではあなたのバージョンを確認する方法も示します:
>>> import pymupdf
>>> print(pymupdf.__doc__)
PyMuPDF 1.16.0: Python bindings for the MuPDF 1.16.0 library.
Version date: 2019-07-28 07:30:14.
Built for Python 3.7 on win32 (64-bit).
fitz という名前についての注意事項¶
このライブラリのPythonのトップレベルインポート名は "fitz" です。 これには歴史的な理由があります:
これには歴史的な理由があります:
MuPDFの元々のレンダリングライブラリは Libart と呼ばれていました。
「 Artifex SoftwareがMuPDFプロジェクトを取得した後、開発の焦点は新しいモダンなグラフィックスライブラリ "Fitz"の開発に移りました。 Fitzの開発に移りました。Fitzは元々古くなったGhostscriptグラフィックスライブラリを置き換えるためのR&Dプロジェクトとして意図されていましたが、代わりにMuPDFを駆動するレンダリングエンジンになりました。」* ( Wikipedia より引用 ) 。
注釈
Use of legacy name fitz can fail if defunct pypi.org package fitz is installed; see インストール後の問題.
ドキュメントの開く¶
サポートされているドキュメント にアクセスするには、次の文で開く必要があります:
doc = pymupdf.open(filename) # or pymupdf.Document(filename)
これにより、 Document (ドキュメント) オブジェクトdocが作成されます。filenameは、既存のファイルの名前を指定するPythonの文字列(または pathlib.Path )である必要があります。
また、メモリデータからドキュメントを開くことや、新しい空のPDFを作成することも可能です。詳細については、 Document (ドキュメント) を参照してください。 Document (ドキュメント) はコンテキストマネージャとしても使用できます。
ドキュメントには多くの属性と関数が含まれています。その中には、メタ情報(「author」や「subject」など)、総ページ数、アウトライン、暗号化情報などがあります。
いくつかの Document (ドキュメント) メソッドと属¶
メソッド / 属性 |
説明 |
|---|---|
ページ数 (int) |
|
メタデータ (dict) |
|
目次を取得する (list) |
|
Page (ページ) を読む |
メタデータへのアクセス¶
PyMuPDFは標準的なメタデータを完全にサポートしています。 Document.metadata はPythonの辞書で、次のキーが含まれています。これはすべてのドキュメントタイプで利用可能ですが、すべてのエントリが常にデータを含むわけではありません。それらの意味や形式の詳細については、対応するマニュアルを参照してください。例えば、PDFの場合は Adobe PDFリファレンス を参照してください。さらなる情報は Document (ドキュメント) の章でも見つけることができます。メタデータのフィールドは文字列または None です(特に指定がない場合)。また、それらのすべてが常に意味のあるデータを含んでいるわけではないことにも注意してください。
キー |
値 |
|---|---|
producer |
プロデューサー(生成ソフトウェア) |
format |
形式:'PDF-1.4'、'EPUB'など |
encryption |
暗号化方法(適用されている場合) |
author |
author |
modDate |
最終更新日 |
keywords |
keywords |
title |
title |
creationDate |
作成日 |
creator |
作成アプリケーション |
subject |
subject |
注釈
PDFバージョン1.4以降のPDFドキュメントには、これらの標準的なメタデータに加えて、いわゆる「メタデータストリーム」(streamも参照)が含まれていることがあります。このようなストリームに含まれる情報はXMLでコード化されています。PyMuPDFは意図的にこの目的のためにXMLコンポーネントを含んでいないため( PyMuPDF Xml class クラスは Story (ストーリー) オブジェクトのDOMコンテンツにアクセスするためのヘルパークラスです)、その情報への直接的なアクセスをサポートしていません。しかし、 lxml などのパッケージを使用してストリーム全体を抽出し、検査または変更し、その結果をPDFに再格納することはできます。必要な場合は、このデータを完全に削除することもできます。
注釈
リポジトリには、metadata import(PDF only) および metadata export をCSVファイルに行うための2つのユーティリティスクリプトがあります
アウトラインと一緒に作業する¶
アウトライン(または「ブックマーク」とも呼ばれる)を取得する最も簡単な方法は、そのドキュメントの目次を読み込むことです:
toc = doc.get_toc()
これにより、Pythonのリストであるリスト [[lvl, title, page, ...], ...] が返されます。これは、本に見られる伝統的な目次に非常によく似たものです。
lvl はエントリーの階層レベル(1から開始)を示し、title はエントリーのタイトル、page はページ番号(1から始まる)を示します。その他のパラメータはブックマークのターゲットの詳細を説明します。
注釈
リポジトリ内には、CSVファイルから目次をインポートおよびエクスポートするためのユーティリティスクリプトが2つあります。詳細は、 toc import (PDF only) および toc export をご覧ください。
ページの操作¶
Page (ページ) の処理はMuPDFの機能の中核です。
ページをラスターまたはベクター(SVG)イメージにレンダリングすることができます。オプションでズーム、回転、シフト、またはシアーを行うこともできます
テキストと画像を多くの形式で抽出し、テキスト文字列を検索することができます。
PDFドキュメントの場合、さらに多くのメソッドが利用可能で、テキストや画像をページに追加することができます
最初に Page (ページ) を作成する必要があります。これは Document (ドキュメント) のメソッドです:
page = doc.load_page(pno) # loads page number 'pno' of the document (0-based)
page = doc[pno] # the short form
ここでは、どんな整数 -∞ < pno < page_count でも可能です。負の数は末尾から逆に数えますので、doc[-1] はPythonのシーケンスと同様に最後のページになります
より高度な方法として、ドキュメントをそのページの イテレータ として使用することもできます:
for page in doc:
# do something with 'page'
# ... or read backwards
for page in reversed(doc):
# do something with 'page'
# ... or even use 'slicing'
for page in doc.pages(start, stop, step):
# do something with 'page'
ページを取得したら、通常は次のようなことを行います:
リンク、注釈、またはフォームフィールドをページで調査する¶
リンクは、ドキュメントがビューアソフトウェアで表示されるときに「ホットエリア」として表示されます。カーソルが手のシンボルを示すときにクリックすると、通常、そのホットエリアにエンコードされたターゲットに移動します。以下はすべてのリンクを取得する方法です:
# get all links on a page
links = page.get_links()
links はPythonの辞書のリストです。詳細は Page.get_links() を参照してください。
また、一度に1つのリンクを生成するイテレータを使用することもできます:
for link in page.links():
# do something with 'link'
PDFドキュメントのページを扱う場合、注釈(Annot (注釈))やフォームフィールド(Widget (ウィジェット))も存在する場合があります。それぞれに独自のイテレータがあります:
for annot in page.annots():
# do something with 'annot'
for field in page.widgets():
# do something with 'field'
ページのレンダリング¶
以下の例は、ページの内容をラスター画像として作成します:
pix = page.get_pixmap()
pix はページのRGBイメージを含む Pixmap オブジェクトです。このイメージは多くの目的に使用する準備ができています。Page.get_pixmap() メソッドには、画像を制御するためのさまざまなオプションが用意されています:解像度/DPI、カラースペース(例えば、グレースケールイメージや減色カラースキームのイメージを作成するために)、透明度、回転、ミラーリング、シフト、シアーなどがあります。例えば、RGBAイメージ(アルファチャネルを含むイメージ)を作成する場合は、pix = page.get_pixmap(alpha=True) と指定します。
Pixmap には、以下で参照されるいくつかのメソッドと属性が含まれています。その中には、ピクセル単位の整数である幅、高さ(それぞれピクセル単位)および stride (1つの水平イメージラインのバイト数)があります。属性 samples は、イメージデータを表すバイトの長方形領域(Pythonの bytes オブジェクト)を表します。
注釈
Page.get_svg_image() を使用することで、ページのベクターイメージを作成することもできます。詳細については、Vector Image Support page ページを参照してください。
ページのイメージをファイルに保存する¶
簡単にページのイメージをPNGファイルに保存できます:
pix.save(f"page-{page.number}.png")
GUIでイメージを表示する¶
GUIダイアログマネージャーでも使用できます。 Pixmap.samples は、すべてのピクセルのバイトの領域をPythonのbytesオブジェクトとして表します。以下はいくつかの例ですが、さらに多くの例は examples ディレクトリで見つけることができます。
wxPython¶
RGB(A)のピクセルマップに対する調整や、可能な場合はwxPythonのリリースに特有の詳細については、関連するドキュメントを参照してください。
if pix.alpha:
bitmap = wx.Bitmap.FromBufferRGBA(pix.width, pix.height, pix.samples)
else:
bitmap = wx.Bitmap.FromBuffer(pix.width, pix.height, pix.samples)
Tkinter¶
Pillow documentation ドキュメントのセクション3.19も参照してください。
from PIL import Image, ImageTk
# set the mode depending on alpha
mode = "RGBA" if pix.alpha else "RGB"
img = Image.frombytes(mode, [pix.width, pix.height], pix.samples)
tkimg = ImageTk.PhotoImage(img)
以下の方法では、Pillowを使用しないようにしています。
# remove alpha if present
pix1 = pymupdf.Pixmap(pix, 0) if pix.alpha else pix # PPM does not support transparency
imgdata = pix1.tobytes("ppm") # extremely fast!
tkimg = tkinter.PhotoImage(data = imgdata)
もし、サポートされている任意のドキュメントをページ送りで表示する完全なTkinterスクリプトをお探しでしたら、こちらがあります! また、このスクリプトではページをズームインすることもでき、Python 2または3で動作します。非常に便利な純粋なPythonパッケージである PySimpleGUI が必要です。
PyQt4, PyQt5, PySide¶
Pillowドキュメントのセクション3.16も参照してください。
from PIL import Image, ImageQt
# set the mode depending on alpha
mode = "RGBA" if pix.alpha else "RGB"
img = Image.frombytes(mode, [pix.width, pix.height], pix.samples)
qtimg = ImageQt.ImageQt(img)
Pillowを使用せずに進めることもできます。幸運なことに、QtのQImageはネイティブなPythonポインタをサポートしているので、以下はQtイメージを作成する推奨される方法です。
from PyQt5.QtGui import QImage
# set the correct QImage format depending on alpha
fmt = QImage.Format_RGBA8888 if pix.alpha else QImage.Format_RGB888
qtimg = QImage(pix.samples_ptr, pix.width, pix.height, fmt)
テキストや画像を抽出する¶
ページのすべてのテキスト、画像、およびその他の情報を、さまざまな形式や詳細レベルで抽出することもできます。:
text = page.get_text(opt)
異なるフォーマットを得るために、以下の文字列のうち1つをoptに使用できます [2]:
"text": (デフォルト) 行送りのプレーンテキスト。書式設定やテキストの位置の詳細、画像は含まれません。
"blocks": テキストブロック(段落)のリストを生成します。
"words": 単語(スペースを含まない文字列)のリストを生成します。
"html": 画像を含むページの完全な視覚的バージョンを作成します。これはインターネットブラウザで表示できます。
"dict" / "json": HTMLと同じ情報レベルですが、Pythonの辞書またはJSON文字列として提供されます。その構造の詳細については、
TextPage.extractDICT()を参照してください。"rawdict" / "rawjson": "dict" / "json"のスーパーセットです。これにはXMLのような文字の詳細情報も含まれます。その構造の詳細については、
TextPage.extractRAWDICT()を参照してください。"xhtml": TEXTバージョンのテキスト情報レベルを含み、画像も含まれます。インターネットブラウザでも表示できます。
"xml": 画像は含まれませんが、各テキスト文字までの完全な位置とフォント情報を含みます。XMLモジュールを使用して解釈することができます。
これらの代替方法の出力のイメージを示すために、テキストの例抽出を行いました。付録1: テキスト抽出の詳細 を参照してください
テキストを検索す¶
特定のテキスト文字列がページのどこに現れるかを正確に調べることができます。:
areas = page.search_for("mupdf")
このコードは、"mupdf"(大文字と小文字を区別しない)という文字列が含まれる各領域を囲む長方形( Rect (矩形) 参照)のリストを生成します。この情報を使って、それらの領域を強調表示したり(PDFのみ)、文書のクロスリファレンスを作成したりすることができます。
また、共同作業:DisplayList と TextPage という章、およびデモプログラム demo.py と demo-lowlevel.py も参照してください。これらには、TextPage (テキストページ) 、 Device (デバイス) 、DisplayList(ディスプレイリスト) クラスをより直接的に制御する方法に関する詳細な情報が含まれています。例えば、パフォーマンスを考慮する必要がある場合などに役立ちます
ストーリー: HTMLソースからPDFを生成する¶
ストーリークラスはPyMuPDFバージョン1.21.0の新機能です。これはMuPDFの Story (ストーリー) インターフェースに対するサポートを表しています。
以下はArtifexのRobin Wattsによる書籍「MuPDF Explored」からの引用です。
ストーリーは、ドキュメントライターなどのデバイスで使用するためのスタイル付きコンテンツを簡単にレイアウトする方法を提供します。ストーリーという概念は、デスクトップパブリッシングから来ており、それ自体が新聞から取り入れられています。伝統的な新聞のレイアウトを考えると、複数の列や複数のページにわたって配置されたさまざまなニュース記事(ストーリー)で構成されています。
それに応じて、MuPDFでは、テキストのフローとスタイリング情報を表すためにストーリーを使用しています。ストーリーのユーザーは、ストーリーをレイアウトするための矩形のシーケンスを提供し、配置されたテキストを出力デバイスに描画できます。これにより、テキスト自体(ストーリー)がテキストを配置する領域(レイアウト)から分離されるという概念が保持されます
注釈
ストーリーは、インターネットブラウザといくつかの点で似ています。それは忠実にHTMLハイパーテキストとオプションのスタイルシート(CSS)を解析してレンダリングします。ただし、出力されるのはPDFであり、ウェブページではありません。
ストーリーを作成する際には、最大3つの異なる情報源からの入力が考慮されます。これらのすべてのアイテムはオプションです。
HTMLソースコード:Pythonの文字列として提供されるか、 Xml のメソッドを使用してスクリプトによって作成されます。
CSS(カスケーディングスタイルシート)ソースコード:Pythonの文字列として提供されます。CSSは、ウェブページにおけるように、スタイリング情報(テキストフォントサイズ、色など)を提供するために使用できます。もちろん、この文字列はファイルから読み込むこともできます。
DOMが画像を参照する場合や、標準の PDFベース14フォント 、CJKフォント、およびPyMuPDFバイナリに生成されたNOTOフォント以外のテキストフォントを使用する場合、 Archive (アーカイブ) を使用する必要があります。
この API では、望むスタイル情報を含めて、DOMを完全にゼロから作成することができます。また、提供されたHTMLを変更したり拡張したりするためにも使用できます。テキストは削除や置換ができ、スタイルも変更できます。データベースから抽出されたテキストを追加して、テンプレートのようなHTMLドキュメントを作成することもできます。
文法的に完全なHTMLドキュメントを提供する必要はありません。例えば <b>Hello<i>World!</i></b> のような断片も完全に受け入れられ、多くの場合、構文エラーは自動的に修正されます。
HTMLが完成したと見なされた後、それを使用してPDF文書を作成できます。これは新しい DocumentWriter(ドキュメントライター) クラスを介して行われます。プログラマーはそのメソッドを呼び出して新しい空のページを作成し、Story (ストーリー) に矩形を渡してそれらを埋めることができます。
Story (ストーリー) は、書き込まれる待機中のコンテンツがあるかどうかを示す完了コードを返します。コンテンツのどの部分がどの矩形またはどのページに配置されるかは、Story (ストーリー) 自体によって自動的に決定されます。矩形を提供すること以外では影響を与えることはできません。
典型的な使用例については、 Stories recipes レシピをご覧ください。
PDFメンテナンス¶
PDFはPyMuPDFを使用して変更できる唯一のドキュメントタイプです。他のファイルタイプは読み取り専用です。
ただし、任意のドキュメント(画像を含む)をPDFに変換し、変換結果にすべてのPyMuPDF機能を適用することができます。 Document.convert_to_pdf() で詳細を確認できます。また、任意のサポートされているドキュメントをPDFに変換できるデモスクリプト pdf-converter.py も確認してください。
Document.save() は常に現在の(変更された可能性のある)PDFをディスクに保存します。
通常、新しいファイルに保存するか、既存のファイルに変更内容を追加するか(「増分保存」)を選択できます。増分保存は非常に高速な場合があります。
以下にPDFドキュメントを操作する方法を示しますが、これに限らず、詳細は次の章でさらに見つけることができます。
ページの修正、作成、再配置、および削¶
PDFの**ページツリー** (すべてのページを記述する構造)を操作するためには、いくつかの方法があります。
Document.delete_page() と Document.delete_pages() はページを削除します。
Document.copy_page() 、 Document.fullcopy_page() 、 Document.move_page() は、ページを同じドキュメント内の他の場所にコピーしたり移動したりします。
Document.select() はPDFを選択したページに縮小します。パラメータは[3]のページ番号のシーケンスで、保持したいページの番号を指定します。これらの整数はすべて範囲 0 <= i < page_count にある必要があります。実行されると、このリストに含まれていないすべてのページが削除されます。残ったページは指定した順序通りに(指定回数分!)現れます。
したがって、次のような簡単な方法で新しいPDFを作成できます:
最初または最後の10ページ
奇数ページのみまたは偶数ページのみ(両面印刷用)
特定のテキストを含むまたは含まないページ
ページの順序を逆にする
... など、思いつく限りのことができます。
保存された新しいドキュメントには、まだ有効なリンク、注釈、およびブックマークが含まれています(選択したページを指すか、あるいは外部リソースを指すかを問わず)。
Document.insert_page() および Document.new_page() は新しいページを挿入します。
さらに、ページ自体はさまざまな方法で変更できます(ページの回転、注釈とリンクの維持、テキストと画像の挿入など)
PDF文書の結合と分割¶
メソッド Document.insert_pdf() は異なるPDF文書間でページをコピーします。以下は簡単な結合の例です( doc1 と doc2 は開かれたPDF文書です):
# append complete doc2 to the end of doc1
doc1.insert_pdf(doc2)
以下は、 doc1 を分割するスニペットです。最初の10ページと最後の10ページを含む新しいドキュメントを作成します。
doc2 = pymupdf.open() # new empty PDF
doc2.insert_pdf(doc1, to_page = 9) # first 10 pages
doc2.insert_pdf(doc1, from_page = len(doc1) - 10) # last 10 pages
doc2.save("first-and-last-10.pdf")
Document (ドキュメント) の章にはさらに詳細が記載されています。また、 PDFjoiner.py も確認してください。
データの埋め込み¶
PDFはZIPアーカイブのように、任意のデータ(実行可能ファイル、他のPDF、テキストファイル、バイナリファイルなど)をコンテナとして使用できます。
PyMuPDF fully supports this feature via Document (ドキュメント) embfile_* methods and attributes. For some detail read 付録2:埋め込みファイルに関する考慮事項, consult the Wiki on dealing with embedding files, or the example scripts embedded-copy.py, embedded-export.py, embedded-import.py, and embedded-list.py.
保存¶
前述のように、 Document.save() は常にドキュメントを現在の状態で保存します。
オプション incremental=True を指定することで、変更を元のPDFに書き戻すことができます。このプロセスは(通常)非常に高速です。変更は元のファイルに追加されるため、完全に書き直す必要がありません。
Document.save() のオプションは、MuPDFのコマンドラインユーティリティmutool cleanのオプションと対応しています。以下の表を参照してください。
保存オプション |
mutool |
効果 |
|---|---|---|
garbage=1 |
g |
未使用のオブジェクトをガベージコレクションします |
garbage=2 |
gg |
1に加えて、xrefテーブルをコンパクトにします |
garbage=3 |
ggg |
2に加えて、重複したオブジェクトをマージします |
garbage=4 |
gggg |
3に加えて、重複したストリームの内容をマージします |
clean=True |
cs |
コンテンツストリームをクリーンアップしてサニタイズします |
deflate=True |
z |
非圧縮のストリームをdeflate圧縮します |
deflate_images=True |
i |
画像ストリームをdeflate圧縮します |
deflate_fonts=True |
f |
フォントファイルストリームをdeflate圧縮します |
ascii=True |
a |
バイナリデータをASCII形式に変換します |
linear=True |
l |
線形化バージョンを作成します |
expand=True |
d |
すべてのストリームを解凍します |
注釈
For an explanation of terms like object, stream, xref consult the 用語集 chapter.
例えば、 mutool clean -ggggz file.pdf は優れた圧縮結果をもたらします。これは doc.save(filename, garbage=4, deflate=True) に対応しています。
クローズ¶
プログラムが継続する間に、基になるファイルの制御をOSに戻すために、ドキュメントを「クローズ」することがしばしば望まれます。
これは Document.close() メソッドによって実現できます。基になるファイルをクローズするだけでなく、ドキュメントに関連するバッファ領域も解放されます。
さらなる情報¶
また、PyMuPDFの Wiki ページもご覧ください。特に、サイドバーのタイトル「Recipes」の下に名前が挙げられているものは、15以上のトピックが「How-To」スタイルで書かれています。
Recipes: Table of Contents をご覧ください。
脚注
