LoginSignup
15
19

More than 5 years have passed since last update.

Markdownで書いたmermaidのflowchartをpng形式でexportする

Posted at

やりたいこと

  • Markdownで書いているmermaid形式ののflowchartをpng形式でexportする(そのまま)
  • なおかつ、exportをbatを「ポン」とクリックするだけで実行する

環境

  • Windows 7 64bit
  • Git Bash

背景

  • Markdownで仕様書を書いている中、「flowchartもMarkdownで書けないかなー」と思う
  • mermaidを使えばflowchartが書けることが判明
  • しかし、図として保存することができないことが判明
  • というわけで何とかできないか?と思う

というわけで、色々調べたところできると判明

手順をまとめる

前提

今回Markdownで書いているドキュメントの構成を以下に示す

Top
│  ConvertAll.bat
│  output.docx
│  
├─000_Cover
│  │  00_Cover.md
│  │  
│  └─image
│          000_Cover.png
│          
├─010_Chapter1
│  │  00_Chapter1.md
│  │  
│  └─image
│          010_Chapter1.png
│          
├─020_Chapter2
│  │  00_Chapter2.md
│  │  020_FlowChart1.mmd
│  │  020_FlowChart2.mmd
│  │  
│  └─image
│          020_Chapter2.png
│          020_FlowChart1.png
│          020_FlowChart2.png
・
・
・
│          
└─image
        000_Cover.png
        01_Chapter.png
        020_Chapter1.png
        020_Chapter2.png

利用手順は以下の通り(太字は今回追加する手順)

  1. 各フォルダを作成し、章ごとにドキュメントを作成する
  • ドキュメントに使う画像は各image配下に格納する
  • フローチャートは.mmdファイルで作成する
  • .mmdファイルで作成したフローチャートは画像化(.png)し、imageフォルダに格納
  • ドキュメントではあらかじめ、imageフォルダに画像があるものとして記述を行う
  1. ドキュメント作成後、ConvertAll.batを実行し、word形式で出力する
  • word形式への変換はpandocを使用する

  • .mmdから.png変換はConvertAll.batで行う

  1. これらは全てGitで管理し、変更をトレースできるようにしておく

Git Bashをインストールする

Git Bashが無い場合はインストールをする

インストールについては他の方の記事をご参考に

mermaidをインストールする

参考:mermaid.jsのフローチャートの書き方

Git Bashを起動し、以下のコマンドを実行する

$ npm install -g mermaid
$ npm install -g mermaid.cli

または

$ yarn global add mermaid
$ yarn global add mermaid.cli

インストール先は以下のようになっている(と思う)ので、環境変数:Pathを通しておく

C:\Users\<your-user>\AppData\Roaming\npm

Pathを通したら、mmdc.cmdが実行できるかを確認する

コマンドプロンプトを立ち上げ、以下のコマンドを実行する

$ mmdc.cmd -V

バージョンが表示されればOK

これでmermaidのインストールは終わり

試しにファイルを変換してみてもいい

ファイルを変換するときのコマンドは以下の通り

$ mmdc.cmd -i input.mmd -o output.png

Markdownで書いたflowchartをpngに変換する

Markdownで書いたflowchartを先ほどのmmdc.cmdを使ってpngに直接変換することはできない

以下はmermaidで記述したフローチャートの例

~~~mermaid
graph LR
    A[東京] -- 新幹線 --> B((大阪))
    B -- 在来線--> C{奈良}
    C--> |湯豆腐を食べに| E[京都]
    C --> |ふぐ刺しを食べに| F[山口]
    C --> |きれいな海を見に| G[和歌山]
    C --> |合掌造りを見に| H[岐阜]
    C --> |ゆっくり温泉に入りに| I[兵庫]
    C --> |しまなみ街道を走りに| J[愛媛]
~~

この時、mmdc.cmdを使って変換をかける際に必要なのは2行目から10行目まで

つまり、ヘッダーとフッターの波線3つは不要になる

mmdc.cmdへファイルを投入する時には、このフッターとヘッターを削除する処理が必要となる

フッターとヘッターを削除する処理

元々コマンドプロンプトで行えないかと調査を実施

「最初の行を削除する」は可能だが、「最後の行を削除する」ができそうに無いため、他のツールを選ぶ

純粋の上記の処理をするだけならjavaでも良いが、以下の理由で却下

  • ソースの差分しか管理できない
  • 実行時にコンパイルの手間が入る

結局はVB Scriptを使用することに決定

下記のサイトが非常に参考になるため、ソースを使用させていただく

ADODB.Stream で BOM なし UTF-8 のテキストファイルを書き出す

ここに以下の処理を加えていく

  • ファイル名を引数で受け取る
  • 出力するファイル名を「元のmmdファイル名」拡張子は「.mmmd」で作る
  • 元のファイルからヘッダー、フッターを抜いたファイルを作る
  • imageフォルダ配下に出力する画像ファイル名を「元のmmdファイル名」拡張子は「.png」で作る
  • .mmmdファイルをmmdc.cmdに叩き込み、.pngファイルにする
  • 処理終了後、.mmmdファイルを削除する

以上の処理を組み込んだソースは以下の通り

CopyMMDFile.vbs


' 読み込みファイルはコマンドライン引数で受け取る
Dim fileName
fileName = Wscript.Arguments(0)
Dim input
Set input = CreateObject("ADODB.Stream")
input.Type = 2    ' 1:バイナリ・2:テキスト
input.Charset = "UTF-8"    ' 文字コード指定
input.Open    ' Stream オブジェクトを開く
input.LoadFromFile fileName    ' ファイルを読み込む

' 一時書き出しファイルの指定 (テキストモードで BOM 付き UTF-8 を一時的に保持しておく)
Dim preOut
Set preOut = CreateObject("ADODB.Stream")
preOut.Type = 2
preOut.Charset = "UTF-8"
preOut.Open

' 読み込みファイルから1行ずつ読み込み、一時書き出しファイルに書き出すのを最終行まで繰り返す
Dim records
Do Until input.EOS
  Dim lineStr
  lineStr = input.ReadText(-2)    ' -1:全行読み込み・-2:一行読み込み
  If (0 = InStr(lineStr, "~~~")) Then
    preOut.WriteText lineStr, 1    ' 0:文字列のみ書き込み・1:文字列 + 改行を書き込み
  End If
Loop

' バイナリモードにする
preOut.Position = 0
preOut.Type = 1    'バイナリモードにする
preOut.Position = 3    ' 先頭3バイト = BOM をスキップする

' バイナリデータを読み込む
Dim bin
bin = preOut.Read    ' バイナリモードでないと Read できない

' 書き出しファイルの指定 (読み込んだバイナリデータをバイナリデータとしてファイルに出力する)
Dim output
Set output = CreateObject("ADODB.Stream")
output.Type = 1
output.Open
output.Write(bin)

' 出力するファイル名を作成する
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")
Dim simpleFileName
simpleFileName = fso.GetBaseName(fileName)
Dim directoryName
directoryName = fso.GetParentFolderName(fileName)
Dim mmmdFileName
mmmdFileName = fso.BuildPath(directoryName, simpleFileName + ".mmmd")
Dim imageFileName
imageFileName = fso.BuildPath(directoryName, fso.BuildPath("image", simpleFileName + ".png"))

WScript.Echo imageFileName

' 書き出しファイルの保存
output.SaveToFile mmmdFileName , 2    ' 1:指定ファイルがなければ新規作成・2:ファイルがある場合は上書き

' Stream を閉じる
input.Close
preOut.Close
output.Close

' mmdc.cmd を実行する
Set objShell = CreateObject("WScript.Shell")
objShell.Run "mmdc.cmd -i " + mmmdFileName + " -o " + imageFileName + " > res.log", 0, true

' .mmmdファイルを削除する
fso.DeleteFile(mmmdFileName)

あとはConvertAll.batに全てのmmdファイルに対して、CopyMMDFile.vbsをコールするように追記

実行

いざ実行

実行前のファイル一覧

Top
│  ConvertAll.bat
│  CopyMMDFile.vbs
│  
├─000_Cover
│  │  00_Cover.md
│  │  
│  └─image
│          000_Cover.png
│          
├─010_Chapter1
│  │  00_Chapter1.md
│  │  
│  └─image
│          010_Chapter1.png
│          
├─020_Chapter2
│  │  00_Chapter2.md
│  │  020_FlowChart.mmd
│  │  
│  └─image
│          020_Chapter2.png
│          
└─image

変換対象のファイルは020_FlowChart.mmd

実行前

実行後のファイル一覧

Top
│  ConvertAll.bat
│  CopyMMDFile.vbs
│  
├─000_Cover
│  │  00_Cover.md
│  │  
│  └─image
│          000_Cover.png
│          
├─010_Chapter1
│  │  00_Chapter1.md
│  │  
│  └─image
│          010_Chapter1.png
│          
├─020_Chapter2
│  │  00_Chapter2.md
│  │  020_FlowChart.mmd
│  │  
│  └─image
│          020_Chapter2.png
│          020_FlowChart.png
│          
└─image
        000_Cover.png
        010_Chapter1.png
        020_Chapter2.png
        020_FlowChart.png

020_FlowChart.pngが増えていることが確認できる

実行後

画像として出力できていることが確認できる

※間違い等ありましたらコメントにてご指摘お願いします!

15
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
19