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

## やりたいこと

- 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フォルダに画像があるものとして記述を行う**

2. ドキュメント作成後、ConvertAll.batを実行し、word形式で出力する

   - word形式への変換はpandocを使用する

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

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



## Git Bashをインストールする

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

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



## mermaidをインストールする

参考：[mermaid.jsのフローチャートの書き方](https://ryuta46.com/516)



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 のテキストファイルを書き出す](http://neos21.hatenablog.com/entry/2016/03/27/231512) ](http://neos21.hatenablog.com/entry/2016/03/27/231512)



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

- ファイル名を引数で受け取る
- 出力するファイル名を「元の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

![実行前](https://qiita-image-store.s3.amazonaws.com/0/323052/9e4d1f32-2566-6f4e-f95a-68293e4723bf.png)


実行後のファイル一覧

```
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が増えていることが確認できる



![実行後](https://qiita-image-store.s3.amazonaws.com/0/323052/2cd3126d-e4a8-293e-c670-d121b332cc57.png)

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



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