files2md_tags.py 技術ドキュメント

プログラムの動作

files2md_tags.py は、指定されたファイルパターンに基づいてファイルを処理し、Markdown形式のドキュメントセクションを生成するPythonスクリプトです。このスクリプトの主な目的は、画像ファイルからサムネイルを自動生成し、それらを含むMarkdownの画像一覧を作成すること、および画像以外のデータファイルへのリンク一覧を作成することです。生成される出力は、Sphinxや一般的なMarkdownパーサーでそのまま利用できる形式になっています。

主な機能:

  • ワイルドカードのサポート: 複数のワイルドカードパターン(例: *.png, data_*.txt)を受け取り、マッチするすべてのファイルを処理します。

  • ファイル種別の自動判別: ファイルの拡張子に基づいて、画像ファイルとデータファイルを自動的に判別します。

  • サムネイル生成: 画像ファイルに対して、指定された幅のアスペクト比を維持したサムネイル画像を生成します。

  • 条件付きサムネイル更新: 既存のサムネイルが存在する場合、元の画像が新しい場合にのみ更新する(--updateオプション)、または強制的に上書きする(--overwriteオプション)機能を提供します。

  • Markdown出力: 処理された画像ファイルに対してはサムネイル付きの画像リンクと元の画像へのリンクを含む「生成された画像一覧」セクションを、データファイルに対してはファイル名へのリンクを含む「生成されたデータファイル」セクションを標準出力に出力します。

解決する課題:

  • ドキュメント作成時における画像ファイルのサムネイル作成と、それらのMarkdown形式での記述の手間を削減します。

  • 多数の画像やデータファイルを扱うプロジェクトで、手動でのリストアップやリンク作成の煩雑さを解消し、一貫した形式での出力を行います。

原理

files2md_tags.py は、ファイルパスの操作、画像処理、および文字列フォーマットを組み合わせて機能します。

  1. ファイルパスの展開と重複排除:

    • expand_patterns 関数は、引数で与えられた複数のワイルドカードパターンを glob.glob() を使用して展開します。

    • 展開されたファイルパスは pathlib.Path オブジェクトに変換され、set を利用して重複が排除されます。これにより、複数のパターンにマッチするファイルが二重に処理されるのを防ぎます。

    • 最終的なリストはソートされ、一貫性のある処理順序を保証します。

  2. ファイル種別の判定:

    • is_image_file 関数は、ファイルの拡張子が定義済みの画像拡張子セット(.png, .jpg, .gif など)に含まれるかどうかをチェックすることで、ファイルが画像であるかを判定します。

    • is_thumbnail_file 関数は、ファイル名が -s で終わるかどうかをチェックすることで、すでにサムネイルとして生成されたファイルかどうかを判定し、処理対象から除外します。

  3. サムネイル生成:

    • make_thumbnail 関数は、Pillow (PIL) ライブラリを使用して画像ファイルを処理します。

    • 元の画像を開き、指定されたターゲット幅 (width) に基づいて、アスペクト比を維持した新しい高さを計算します。この計算は以下の数式に基づいています。 $\(h_{new} = \max(1, \text{int}(h_{orig} \cdot (\text{width}_{target} / w_{orig})))\)\( ここで、\)w_{orig}\( と \)h_{orig}\( は元の画像の幅と高さ、\)width_{target}\( は目標とするサムネイルの幅、\)h_{new}$ は計算されるサムネイルの高さです。max(1, ...) は、計算された高さが0以下になることを防ぎます。

    • Image.resize() メソッドに Image.LANCZOS フィルタを指定することで、高品質なリサイズを行います。

    • サムネイルファイルが存在する場合、--overwrite オプションが指定されていれば無条件に上書きし、--update オプションが指定されていれば、元の画像の最終更新日時 (src.stat().st_mtime) がサムネイルのそれよりも新しい場合にのみ更新します。

  4. Markdown出力フォーマット:

    • format_data_section 関数は、データファイルのリストを受け取り、各ファイルに対してMarkdown形式のリンク [ファイル名](ファイル名) を含む「生成されたデータファイル」セクションの文字列を生成します。

    • format_image_section 関数は、画像ファイルのリストを受け取り、各画像に対してサムネイル画像へのリンク付きの画像タグ ![代替テキスト](サムネイルファイル名) と、元の画像へのリンク [link](元ファイル名) を含む「生成された画像一覧」セクションの文字列を生成します。

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

files2md_tags.py は、画像処理のために非標準ライブラリである Pillow を必要とします。

Pillow のインストールは、Pythonのパッケージマネージャーである pip を使用して行います。

pip install Pillow

必要な入力ファイル

このプログラムは、以下の種類のファイルを期待します。

  • 画像ファイル: 以下の拡張子を持つファイルが画像として扱われ、サムネイルが生成されます。

    • .png, .jpg, .jpeg, .gif, .bmp, .tif, .tiff, .webp

  • データファイル: 上記以外のすべてのファイルはデータファイルとして扱われ、Markdownリンクが生成されます。

入力ファイルは、コマンドライン引数として1つ以上のワイルドカードパターンで指定されます。パターンにマッチするファイルが検索され、処理されます。

生成される出力ファイル

files2md_tags.py は、以下の種類のファイルと情報を生成します。

  • サムネイル画像ファイル:

    • 元の画像ファイル名に -s というサフィックスが追加されたファイル名で、元の画像と同じディレクトリに保存されます。

    • 例: my_photo.jpgmy_photo-s.jpg

    • これらのファイルは、Markdown出力で画像タグのソースとして使用されます。

  • 標準出力へのMarkdownテキスト:

    • 処理の結果として、以下の2つのセクションを含むMarkdown形式のテキストが標準出力に出力されます。

      • ## 生成された画像一覧: 各画像ファイルのサムネイル画像へのリンク付き画像タグと、元の画像ファイルへのリンクが含まれます。

      • ## 生成されたデータファイル: 各データファイルへのMarkdownリンクが含まれます。

    • これらのセクションは、適宜空行で区切られて出力されます。

    • もし処理対象のファイルが一つもない場合は、「一致するファイルがありませんでした。」というメッセージが出力されます。

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

files2md_tags.py は、以下の形式でコマンドラインから実行します。

python files2md_tags.py [-h] [--width WIDTH] [--update {0,1}] [--overwrite {0,1}] patterns [patterns ...]

引数:

  • patterns (位置引数, 必須): 一つ以上のワイルドカードパターン(例: *.png, data/*.txt)を指定します。これらのパターンにマッチするファイルが処理対象となります。

  • --width WIDTH: 生成されるサムネイル画像の幅をピクセル単位で指定します。高さはアスペクト比を維持して自動的に計算されます。デフォルト値は 200 ピクセルです。

  • --update {0,1}: 1 を指定すると、元の画像ファイルの最終更新日時が既存のサムネイルファイルよりも新しい場合にのみサムネイルを更新します。0 を指定すると、この機能は無効になります(デフォルト値は 0)。

  • --overwrite {0,1}: 1 を指定すると、既存のサムネイルファイルを無条件に上書きします。0 を指定すると、既存のサムネイルファイルは上書きされません(デフォルト値は 0)。

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

以下のファイルがカレントディレクトリにあると仮定します。

  • example_image_01.png (2000x1500px)

  • example_image_02.jpg (1000x800px)

  • report.pdf

  • notes.txt


1. 基本的な実行例 (画像とデータファイル)

画像をサムネイル化し、データファイルへのリンクと共にMarkdownを生成します。

python files2md_tags.py *.png *.jpg *.pdf *.txt

実行結果の説明:

example_image_01-s.png (200x150px) と example_image_02-s.jpg (200x160px) というサムネイルファイルが生成されます(デフォルトの --width 200 の場合)。 その後、標準出力に以下のMarkdownテキストが出力されます。

## 生成されたデータファイル
[notes.txt](notes.txt)

[report.pdf](report.pdf)


## 生成された画像一覧

### example_image_01
![example_image_01](example_image_01-s.png)
[link](example_image_01.png)

### example_image_02
![example_image_02](example_image_02-s.jpg)
[link](example_image_02.jpg)

2. サムネイル幅を指定して、既存ファイルを強制上書きする例

サムネイルの幅を 150 ピクセルに設定し、すでにサムネイルが存在する場合でも強制的に上書きします。

python files2md_tags.py --width 150 --overwrite 1 *.png *.jpg

実行結果の説明:

example_image_01-s.pngexample_image_02-s.jpg が幅 150 ピクセルで再生成(または新規生成)されます。 --overwrite 1 のため、既存のサムネイルがあっても、その内容が新しい設定で更新されます。 標準出力には、上記例1と同様の形式で、ただしサムネイル画像タグの参照先が新しいサムネイルに基づくMarkdownが出力されます。 コンソールには以下のようなメッセージも表示されます。

[生成] example_image_01-s.png
[生成] example_image_02-s.jpg

## 生成された画像一覧

### example_image_01
![example_image_01](example_image_01-s.png)
[link](example_image_01.png)

### example_image_02
![example_image_02](example_image_02-s.jpg)
[link](example_image_02.jpg)

3. マッチするファイルが存在しない場合

指定したパターンに一致するファイルが一つも存在しない場合。

python files2md_tags.py --width 100 non_existent_file_*.jpg

実行結果の説明:

サムネイルは生成されず、標準出力には以下のメッセージが出力されます。

一致するファイルがありませんでした。