mdview.py 技術ドキュメント

プログラムの動作

mdview.py は、PythonのTkinterライブラリと tkhtmlview ライブラリを利用して、MarkdownファイルをGUIで表示するためのビューアアプリケーションです。このプログラムの主な目的は、Markdownテキストの閲覧体験を向上させることと、画像の表示サイズやテキストのフォントサイズをユーザーが柔軟に調整できるようにすることです。

主な機能は以下の通りです。

  • Markdownのレンダリング: 指定されたMarkdownファイルを読み込み、markdown ライブラリを使用してHTMLに変換し、GUI上に表示します。コードブロックやテーブルなどの拡張機能もサポートしています。

  • 画像のリサイズ: Markdownファイル内に埋め込まれた画像について、ユーザーが設定した最大表示幅に合わせて自動的にリサイズし、一時的に保存してから表示します。これにより、大きな画像でもビューアの表示領域に収まるように調整されます。

  • フォントサイズ調整: テキストの基準フォントサイズをユーザーが設定できます。見出しのフォントサイズは、基準フォントサイズに基づいて自動的に調整されます。

  • 設定の永続化: ウィンドウのサイズと位置、最後に開いたディレクトリ、画像の表示幅、基準フォントサイズなどの設定を mdview.ini ファイルに保存し、次回起動時に自動的に読み込みます。

  • ファイル操作: GUIメニューからMarkdownファイルを開いたり、現在開いているファイルを再読み込みしたりできます。

このプログラムは、特にMarkdownドキュメントに多くの画像が含まれる場合や、表示環境に応じてフォントサイズを調整したい場合に有用なツールとなります。

原理

mdview.py は、以下の技術とアルゴリズムに基づいて動作します。

MarkdownからHTMLへの変換

プログラムは、Pythonの markdown ライブラリを使用してMarkdownテキストを標準的なHTML形式に変換します。変換後、生成されたHTMLは tkhtmlview ライブラリの HTMLText ウィジェットに渡され、GUI上でレンダリングされます。このとき、fenced_code (コードブロック) や tables (テーブル) といったMarkdown拡張機能も有効にしています。

画像のリサイズと一時保存

  1. 画像パスの抽出: Markdownテキスト内の画像は、正規表現 !\[(.*?)\]\((.*?)\) を用いて抽出されます。これにより、代替テキストと元の画像パスが取得されます。

  2. 絶対パスへの変換: 抽出された画像パスは、Markdownファイルが配置されているディレクトリを基準として絶対パスに変換されます。

  3. リサイズ処理:

    • Pillow (PIL Fork) ライブラリを使用して画像を読み込みます。

    • 画像の元の幅 img.width が、ユーザー設定の self.image_width (最大表示幅) を超える場合、画像をリサイズします。

    • アスペクト比を維持するために、新しい高さは以下の式で計算されます。 $\( \text{new\_height} = \text{img.height} \times \frac{\text{self.image\_width}}{\text{img.width}} \)$

    • リサンプリングアルゴリズムには、高品質なダウンサンプリングを提供する Image.Resampling.LANCZOS が使用されます。

  4. 一時ファイルへの保存: リサイズされた画像は、プログラムの実行ディレクトリに作成される一時ディレクトリ .mdview_temp 内に保存されます。ファイル名にはタイムスタンプが含まれ、重複を避けます。

  5. Markdownパスの置換: 元のMarkdownテキスト内の画像パスは、この一時的に保存されたリサイズ済み画像のパスに置き換えられます。これにより、tkhtmlview が一時ディレクトリ内のリサイズ済み画像をロードして表示します。

  6. 一時ファイルのクリーンアップ: プログラム終了時に、.mdview_temp ディレクトリとその内容がすべて削除されます。

フォントサイズ調整

  1. 基準フォントサイズ: ユーザーが設定する self.font_size が基準フォントサイズとなります。

  2. 全体への適用: 生成されたHTMLテキスト全体は、font-size スタイルが適用された <div> タグで囲まれます。 例: <div style="font-size: 12px;">...HTMLコンテンツ...</div>

  3. 見出しフォントサイズ: HTMLの見出しタグ ( <h1> から <h6> ) に対しては、正規表現 re.sub(r'<h(\d)>(.*?)</h\1>', ...) を使用して、基準フォントサイズに基づいた特定の倍率でフォントサイズが計算され、直接スタイルが適用されます。 例えば、基準フォントサイズが12pxの場合、見出しレベルに応じたフォントサイズは以下のようになります。

    • <h1>: \(12 \times 2.0 = 24 \text{px}\)

    • <h2>: \(12 \times 1.5 = 18 \text{px}\)

    • <h3>: \(12 \times 1.2 = 14 \text{px}\)

    • <h4>: \(12 \times 1.1 = 13 \text{px}\)

    • <h5>: \(12 \times 1.0 = 12 \text{px}\)

    • <h6>: \(12 \times 0.9 = 10 \text{px}\)

設定の永続化

プログラムの設定は、mdview.ini というINIファイル形式で保存されます。 read_ini_file 関数はファイルを読み込み、key=value の形式で記述された設定を辞書に格納します。 write_ini_file 関数は、辞書内の設定を同じ形式でファイルに書き込みます。

必要な非標準ライブラリとインストール方法

mdview.py の実行には、以下の非標準Pythonライブラリが必要です。

  • markdown: MarkdownテキストをHTMLに変換するために使用されます。

  • tkhtmlview: Tkinterアプリケーション内でHTMLコンテンツを表示するために使用されます。

  • Pillow: 画像の読み込み、リサイズ、保存のために使用されます。

これらのライブラリは、Pythonのパッケージマネージャーである pip を使用してインストールできます。コマンドプロンプトやターミナルで以下のコマンドを実行してください。

pip install markdown
pip install tkhtmlview
pip install Pillow

必要な入力ファイル

mdview.py が動作するために期待される入力ファイルは以下の通りです。

  1. Markdownファイル:

    • 拡張子は .md.txt など、任意のテキストファイルが可能です。

    • 内容はMarkdown構文に従って記述されている必要があります。

    • ファイルエンコーディングはUTF-8を想定しています。

    • コマンドライン引数で指定するか、GUIメニューの「ファイル」→「開く...」から選択します。

    • 例: example.md

  2. 画像ファイル:

    • Markdownファイル内に ![alt text](path/to/image.png) の形式で埋め込まれた画像ファイル。

    • JPEG, PNG, GIFなど、Pillow ライブラリがサポートする形式の画像ファイルが使用できます。

    • 画像パスは相対パス、または絶対パスで記述できます。プログラムはMarkdownファイルからの相対パスを基準に画像を解決します。

    • 例: images/diagram.png (Markdownファイルと同じディレクトリの images サブディレクトリ内)

  3. mdview.ini (設定ファイル):

    • このファイルはプログラムの初回起動時に自動生成されるか、または存在しない場合にデフォルト設定で起動します。

    • ユーザーがGUIで設定を変更したり、ウィンドウを移動・リサイズしたりすると、プログラム終了時に自動的に更新・保存されます。

    • 手動で編集することも可能ですが、キーと値のペアが正しい形式 (key=value) である必要があります。

生成される出力ファイル

mdview.py は、実行中に以下のファイルやディレクトリを生成します。

  1. mdview.ini:

    • プログラムの設定を永続化するために、実行ディレクトリに作成されます。

    • 内容は以下のキーと値のペアで構成されます。

      • geometry: Tkinterウィンドウのサイズと位置情報。例: 800x600+100+50

      • last_directory: 最後にMarkdownファイルを開いたディレクトリの絶対パス。

      • image_width: 設定された画像の最大表示幅 (ピクセル)。

      • font_size: 設定された基準フォントサイズ (ピクセル)。

  2. .mdview_temp/ ディレクトリ:

    • 実行ディレクトリ直下に作成される隠しディレクトリです。

    • このディレクトリには、リサイズされた画像ファイルが一時的に保存されます。

    • ファイル名は resized_{タイムスタンプ}_{元のファイル名} の形式になります。

    • プログラムが正常終了する際に、このディレクトリとその内容はすべて自動的に削除されます。

コマンドラインでの使用例 (Usage)

mdview.py は、以下の基本構文でコマンドラインから実行できます。

python mdview.py [FILE] [-w WIDTH] [-f FONT_SIZE]
  • FILE: 表示するMarkdownファイルのパスをオプションで指定します。指定しない場合、GUIが起動し、ファイルを開くよう促すメッセージが表示されます。

  • -w WIDTH, --width WIDTH: 画像の最大表示幅をピクセル単位で指定します。この値を超える幅の画像は、アスペクト比を維持したまま指定幅に縮小されます。

  • -f FONT_SIZE, --font FONT_SIZE: テキストの基準フォントサイズをピクセル単位で指定します。見出しのサイズもこの基準に基づいて自動調整されます。

コマンドラインでの具体的な使用例

1. Markdownファイルを指定せずに起動する

python mdview.py

実行結果: GUIウィンドウが起動し、「コマンドライン引数でファイル名を指定するか、メニューからファイルを開いてください。」というメッセージが表示されます。その後、GUIの「ファイル」メニューからMarkdownファイルを選択して開くことができます。ウィンドウサイズやフォントサイズは mdview.ini またはデフォルト設定が適用されます。

2. 特定のMarkdownファイルを開く

my_document.md というMarkdownファイルを開く場合。

python mdview.py my_document.md

実行結果: my_document.md の内容がGUIウィンドウに表示されます。画像の表示幅とフォントサイズは、mdview.ini ファイルに保存されている設定、またはプログラムのデフォルト設定が適用されます。

3. 画像の表示幅とフォントサイズを指定してMarkdownファイルを開く

report.md を画像幅600ピクセル、基準フォントサイズ14ピクセルで開く場合。

python mdview.py report.md -w 600 -f 14

実行結果: report.md の内容がGUIウィンドウに表示されます。

  • 幅が600ピクセルを超える画像は、アスペクト比を保ったまま600ピクセル幅にリサイズされて表示されます。

  • すべてのテキストの基準フォントサイズが14ピクセルに設定され、見出し(<h1><h6>)もこの14ピクセルを基準としたサイズで表示されます。 これらの設定は、GUIから変更することも可能です。