md2html.py 技術ドキュメント

プログラムの動作

md2html.py は、LaTeX形式の数式を含むMarkdownファイルを、MathJaxとインラインCSSが埋め込まれたスタンドアロンのHTMLファイルに変換するPythonスクリプトです。このプログラムの主な目的は、技術文書や研究ノートなど、数式を多用するMarkdownコンテンツをウェブブラウザで簡単に閲覧できる形式にすることです。

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

  • MarkdownからHTMLへの変換: Python-Markdown ライブラリを使用してMarkdownコンテンツをHTMLに変換します。

  • LaTeX数式のサポート: pymdownx.arithmatex 拡張機能を利用することで、Markdown内のLaTeX数式(インライン $...$ およびブロック $$...$$)を適切に抽出し、MathJaxが処理できるようにHTML内に埋め込みます。

  • MathJaxの統合: 最新のMathJax v3 CDN(Content Delivery Network)をHTMLファイルに挿入し、ブラウザ側でLaTeX数式を高品質にレンダリングできるようにします。

  • CSSの適用:

    • ダークモードを考慮したシンプルなデフォルトCSSスタイルをHTMLファイルにインラインで埋め込みます。

    • ユーザーは --css-file オプションで独自のCSSファイルを指定してデフォルトスタイルを上書きできます。

    • --no-css オプションを使用すると、CSSを一切埋め込まない設定も可能です。

  • タイトル自動生成: 生成されるHTMLファイルの <title> タグの内容は、MarkdownファイルのYAMLメタデータ(title: キー)または最初のH1見出しから自動的に取得されます。これらがない場合は、入力ファイル名が使用されます。

このプログラムは、数式を含む技術文書を共有・公開する際に、読者が特別な環境設定なしで内容を閲覧できるHTMLを生成することで、手間を省くことを目指しています。

原理

md2html.py は、Pythonの複数のライブラリと技術を組み合わせて機能を実現しています。

  1. Markdown解析と数式パススルー:

    • Pythonの markdown ライブラリがMarkdownテキストをHTMLに変換する主要なエンジンとして機能します。

    • 特に重要なのは pymdownx.arithmatex 拡張機能です。この拡張機能は、Markdownテキスト内にあるLaTeX形式の数式を識別し、Markdownパーサーがそれらを通常のテキストとして扱ってHTMLタグに変換してしまわないように保護します。具体的には、インライン数式 $E=mc^2$ やブロック数式 $$ \int_0^\infty e^{-x^2} dx = \frac{\sqrt{\pi}}{2} $$ を、MathJaxが認識できる class="arithmatex" を持つ <span> または <div> タグで囲まれた形式に変換します。これにより、数式自体はHTMLエンティティに変換されずにそのまま保持されます。

  2. HTMLテンプレートとコンテンツ埋め込み:

    • プログラムは HTML_TEMPLATE という文字列定数としてHTMLの基本的な構造を持っています。このテンプレートには、{lang}{title}{css_block}{mathjax_url}{body} のプレースホルダが含まれています。

    • Markdownから変換されたHTMLコンテンツは {body} に挿入されます。

    • CSSスタイルは、<style> タグで囲まれ {css_block} に挿入されます。

    • MathJaxのスクリプトタグは、指定されたURL {mathjax_url} を使用して {mathjax_url} に挿入され、CDNからMathJaxライブラリを読み込みます。

  3. MathJaxの設定とレンダリング:

    • 生成されるHTMLには、MathJaxのJavaScript設定が埋め込まれています。この設定は、MathJaxがどのHTML要素内の数式を処理すべきかを指示します。

      window.MathJax = {
        tex: {
          inlineMath: [['$', '$'], ['\\(', '\\)']],
          displayMath: [['$$', '$$'], ['\\[', '\\]']],
          processEscapes: true,
          tags: 'ams'
        },
        options: {
          processHtmlClass: 'arithmatex', // pymdownx.arithmatexが生成するクラス
          ignoreHtmlClass: '.*'
        }
      };
      
    • processHtmlClass: 'arithmatex' の設定により、MathJaxは class="arithmatex" を持つHTML要素内でのみ数式を検索し、レンダリングします。これは pymdownx.arithmatex が生成するHTML構造と連携しています。

    • ブラウザがこのHTMLファイルを読み込むと、埋め込まれたMathJaxスクリプトがCDNから読み込まれ、ページ内の class="arithmatex" 要素内のLaTeXコードを検出し、視覚的に美しい数式に変換して表示します。

  4. タイトル自動検出:

    • derive_title 関数は、入力MarkdownテキストからHTMLのタイトルを決定します。

    • まず、正規表現 r'(?mi)^title:\s*(.+)$' を使用して、Markdownファイルの先頭付近にあるYAML形式の title: ... メタデータを検索します。

    • 見つからない場合は、正規表現 r'(?m)^#\s+(.+?)\s*$' を使用して、最初のH1見出し (# 見出し) を検索します。

    • どちらも見つからない場合は、入力Markdownファイルのファイル名(拡張子なし)がフォールバックとして使用されます。

これらのメカニズムにより、ユーザーはMarkdownで記述された数式を含むドキュメントを、ブラウザで直接表示できるHTML形式に簡単に変換できます。

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

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

  • markdown: MarkdownテキストをHTMLに変換するための主要なライブラリ。

  • pymdown-extensions: markdown ライブラリの拡張機能のコレクション。特に、LaTeX数式を処理するための pymdownx.arithmatex を含みます。

これらのライブラリは pip コマンドを使用して簡単にインストールできます。

pip install markdown pymdown-extensions

必要な入力ファイル

md2html.py は、以下の種類のファイルを入力として受け取ります。

  1. Markdownファイル:

    • 必須: 変換の対象となるMarkdownファイルです。通常は .md または .markdown 拡張子を持ちます。

    • ファイルの内容は標準的なMarkdown構文に従います。

    • LaTeX形式の数式を記述できます。

      • インライン数式: $ で囲みます。例: $E=mc^2$

      • ブロック数式: $$ で囲みます。例: $$ \int_0^\infty e^{-x^2} dx = \frac{\sqrt{\pi}}{2} $$

    • HTMLのタイトルを自動生成するために、ファイル内にYAML形式の title: メタデータ、またはH1見出し(# タイトル)を含めることができます。

    例 (example.md):

    ---
    title: 量子力学入門
    ---
    # 量子力学の基本
    
    量子力学は、ミクロな世界の物理現象を記述する理論です。
    有名なアインシュタインの質量とエネルギーの等価式は $E=mc^2$ で表されます。
    
    シュレーディンガー方程式は次のように記述されます。
    
    $$
    i\hbar \frac{\partial}{\partial t} \Psi(\mathbf{r}, t) = \left( -\frac{\hbar^2}{2m} \nabla^2 + V(\mathbf{r}, t) \right) \Psi(\mathbf{r}, t)
    $$
    
    波動関数 $\Psi$ は、粒子の状態を表します。
    
  2. CSSファイル (オプション):

    • --css-file オプションを指定した場合に読み込まれるカスタムCSSファイルです。通常は .css 拡張子を持ちます。

    • このファイルの内容が、生成されるHTMLにインラインスタイルとして埋め込まれ、デフォルトのスタイルを上書きします。

    例 (custom.css):

    body {
        font-family: Georgia, serif;
        color: #333;
        background-color: #f8f8f8;
    }
    h1 {
        color: #0056b3;
    }
    

生成される出力ファイル

md2html.py は、指定された出力パスに以下の単一のファイルを生成します。

  • HTMLファイル:

    • ファイル名: --output (-o) オプションで指定されたパスとファイル名(通常は .html 拡張子)。

    • 内容:

      • 入力Markdownファイルから変換されたHTMLコンテンツ。

      • MathJaxライブラリをCDNから読み込むための <script> タグと、MathJaxのレンダリング設定。

      • デフォルトの組み込みCSS、または --css-file で指定されたカスタムCSS(あるいは --no-css 指定時はCSSなし)が <style> タグとしてインラインで埋め込まれます。

      • <!DOCTYPE html><html lang="..."<head><body> などの標準的なHTML構造を含みます。

      • HTMLの <title> は、Markdownファイルの内容から自動生成されるか、--title オプションで指定されたものが使用されます。

    • 特徴: 生成されるHTMLファイルは、MathJaxやCSSなどの必要なリソースがすべて埋め込まれているため、完全にスタンドアロンです。インターネット接続があればMathJaxが数式をレンダリングし、それ以外のコンテンツはローカルファイルとして開くだけで適切に表示されます。これにより、他のユーザーとの共有が非常に容易になります。

    例: output.html (部分的な構造)

    <!DOCTYPE html>
    <html lang="ja">
    <head>
      <meta charset="utf-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1" />
      <meta name="generator" content="md2html_mathjax.py" />
      <title>量子力学入門</title>
      <style>
    /* ... 組み込みまたはカスタムのCSSスタイル ... */
      </style>
      <script>
        // MathJax config: process only elements with class 'arithmatex'
        window.MathJax = { /* ... */ };
      </script>
      <script id="MathJax-script" defer src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"></script>
    </head>
    <body>
    <h1>量子力学の基本</h1>
    <p>量子力学は、ミクロな世界の物理現象を記述する理論です。
    有名なアインシュタインの質量とエネルギーの等価式は <span class="arithmatex">\(E=mc^2\)</span> で表されます。</p>
    <p>シュレーディンガー方程式は次のように記述されます。</p>
    <div class="arithmatex">\[
    i\hbar \frac{\partial}{\partial t} \Psi(\mathbf{r}, t) = \left( -\frac{\hbar^2}{2m} \nabla^2 + V(\mathbf{r}, t) \right) \Psi(\mathbf{r}, t)
    \]</div>
    <p>波動関数 <span class="arithmatex">\(\Psi\)</span> は、粒子の状態を表します。</p>
    </body>
    </html>
    

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

md2html.py は、コマンドライン引数を使用して動作を制御します。

python md2html.py input.md -o output.html [OPTIONS]

引数

  • input_md:

    • 必須

    • 入力となるMarkdownファイルのパスを指定します。

オプション

  • -o <path>, --output <path>:

    • 必須

    • 生成されるHTMLファイルの出力パスとファイル名を指定します。

  • --title <text>:

    • HTMLの <title> タグの内容を明示的に指定します。

    • このオプションが指定されない場合、MarkdownファイルのYAMLメタデータ、最初のH1見出し、または入力ファイル名からタイトルが自動的に決定されます。

  • --lang <code_string>:

    • 生成されるHTMLの <html> タグの lang 属性を指定します(例: en, ja)。

    • デフォルトは ja です。

  • --mathjax-url <url>:

    • 使用するMathJax v3バンドルのURLを指定します。

    • デフォルトは https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js です。

  • --css-file <path>:

    • 組み込みのデフォルトCSSの代わりに、指定されたパスのCSSファイルを読み込み、HTMLに埋め込みます。

  • --no-css:

    • このフラグを指定すると、組み込みのCSSもカスタムCSSも埋め込まれません。HTMLはCSSなしで生成されます。

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

以下の例では、まず入力となるMarkdownファイルを作成し、次に md2html.py を使用して変換し、その結果を説明します。

  1. 入力Markdownファイルの作成: my_document.md という名前で以下の内容のファイルを作成します。

    ---
    title: フーリエ変換の応用
    ---
    # フーリエ変換
    
    フーリエ変換は、時間領域の信号を周波数領域に変換するための重要な数学的ツールです。
    これは信号処理、画像処理、量子力学など、多くの分野で応用されています。
    
    連続フーリエ変換は次式で定義されます。
    
    $$
    F(\omega) = \mathcal{F}\{f(t)\} = \int_{-\infty}^{\infty} f(t) e^{-i\omega t} dt
    $$
    
    ここで $f(t)$ は時間領域の関数、$F(\omega)$ は周波数領域の関数、
    $i$ は虚数単位、$t$ は時間、$\omega$ は角周波数です。
    逆フーリエ変換は $f(t) = \mathcal{F}^{-1}\{F(\omega)\} = \frac{1}{2\pi} \int_{-\infty}^{\infty} F(\omega) e^{i\omega t} d\omega$ となります。
    
    これは、任意の周期関数がサインとコサインの和で表現できるというフーリエ級数に起源を持ちます。
    
  2. 基本的な変換: このMarkdownファイルを document.html に変換します。タイトルはMarkdownファイルから自動的に抽出されます。

    python md2html.py my_document.md -o document.html
    
    • 実行結果: [OK] Wrote: .../document.html のようなメッセージが表示され、document.html ファイルが生成されます。

    • document.html をウェブブラウザで開くと、MarkdownコンテンツがHTMLとして表示され、LaTeX数式がMathJaxによってきれいにレンダリングされます。ブラウザのタブには「フーリエ変換の応用」というタイトルが表示されます。

  3. カスタムタイトルと英語の言語指定: --title オプションでHTMLのタイトルを明示的に指定し、--lang オプションで言語を英語 (en) に設定します。

    python md2html.py my_document.md -o document_en.html --title "Applications of Fourier Transform" --lang en
    
    • 実行結果: document_en.html が生成されます。ブラウザで開くと、タブのタイトルは「Applications of Fourier Transform」となり、HTMLの <html> タグには lang="en" が設定されます。MathJaxによる数式レンダリングは同様に行われます。

  4. カスタムCSSファイルの適用: まず、custom.css という名前で以下の内容のファイルを作成します。

    body {
        background-color: #e0f2f7; /* 薄い水色の背景 */
        color: #0d47a1; /* 濃い青色のテキスト */
        font-family: "Noto Sans JP", sans-serif;
    }
    h1 {
        color: #c62828; /* 赤色の見出し */
        border-bottom: 2px solid #c62828;
        padding-bottom: 5px;
    }
    /* 数式のフォントサイズを少し大きくする */
    .arithmatex {
        font-size: 1.1em;
    }
    

    次に、このカスタムCSSを適用してHTMLを生成します。

    python md2html.py my_document.md -o document_custom_css.html --css-file custom.css
    
    • 実行結果: document_custom_css.html が生成されます。ブラウザで開くと、背景色、テキスト色、見出しの色、数式のフォントサイズなどが custom.css で指定したスタイルに沿って変更されて表示されます。デフォルトのスタイルは適用されません。

これらの使用例は、md2html.py がMarkdownとLaTeX数式をウェブフレンドリーなHTMLに変換するための柔軟なツールであることを示しています。