この Lua フィルタは、Pandoc 文書内の Mermaid コードブロックを自動的に SVG 画像に変換するためのフィルタです。mermaid-cli (mmdc) を使用して Mermaid 記法をレンダリングし、生成された SVG ファイルを最適化して文書に埋め込みます。
CodeBlock = function(el)
local code_class = el.classes[1] or ""
local lang, filename = code_class:match("^([^:]+):(.+)$")
if not lang then
lang = code_class
end
-- コード種別判定
if lang ~= "mermaid" then
return el
endmermaid または mermaid:filename 形式をサポート-- caption 属性があれば優先してキャプションに
local caption = el.attributes["caption"]
if caption then
el.attributes["caption"] = nil
elseif filename then
filename = filename:gsub("%.[mM][mM][dD]$", "")
caption = filename
endcaption 属性が指定されていればそれを使用function utf8_to_active_cp(text)
local os_name = os.getenv("OS")
if not os_name or not string.match(os_name:lower(), "windows") then
return text -- Linux環境ではそのまま
end
-- PowerShellを使用してUTF-8からアクティブコードページに変換
local temp_file = create_temp_file()
-- ... PowerShell経由でのエンコーディング変換処理
endlocal MMDC_CMD
if package.config:sub(1,1) == '\\' then -- Windows
MMDC_CMD = "\\node_modules\\.bin\\mmdc.cmd"
else -- Unix-like systems
MMDC_CMD = "/mmdc-wrapper.sh"
endlocal image_filename = string.format("mermaid_%s.svg", utils.sha1(el.text))
local mmd_filename = string.format("mermaid_%s.mmd", utils.sha1(el.text))os.execute(string.format("cd %s && \"%s\" -i %s -o %s -b transparent | grep -v -E \"Generating|deprecated|Store is a function\"",
_resource_dir, _root_dir .. MMDC_CMD, _mmd_filename, _image_filename)).mmd ファイルを作成-b transparent)Mermaid-CLI で生成される SVG には以下の問題がある:
width="100%" で出力されるmax-width が設定されているが、固定サイズが必要な場面で問題となるwidth="100%" による予期しないスケーリングを防止する。
local viewBox = svg_content:match('viewBox="([^"]+)"')
if viewBox then
local _, _, w, h = viewBox:match("([%-%d%.]+) ([%-%d%.]+) ([%d%.]+) ([%d%.]+)")
width = w
height = h
end処理内容:
viewBox 属性から実際の描画領域サイズを取得viewBox="-50 -10 485 259" の場合、幅 485px、高さ 259px を抽出patched_svg = patched_svg:gsub('(<svg[^>]-)style="([^"]*)"', function(svg_tag, style)
-- max-width を削除
style = style:gsub("max%-width:[^;]*;? ?", "")
-- width / height を削除
style = style:gsub("width:[^;]*;?", "")
style = style:gsub("height:[^;]*;?", "")
-- 末尾に width / height 追加
return string.format('%sstyle="width:%spx; height:%spx; %s"', svg_tag, width, height, style)
end, 1)処理内容:
style 属性のみを対象 (end, 1 で最初の要素のみ)max-width、既存の width、height プロパティを削除patched_svg = patched_svg
:gsub('(<svg[^>]*)%swidth="[^"]*"', '%1', 1)
:gsub('(<svg[^>]*)%sheight="[^"]*"', '%1', 1)
:gsub('(<svg)', '%1 width="' .. width .. 'px" height="' .. height .. 'px"', 1)処理内容:
width、height 属性を削除width、height 属性を追加補正前:
<svg aria-roledescription="sequence" role="graphics-document document"
viewBox="-50 -10 485 259"
style="max-width: 485px; background-color: transparent;"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
width="100%"
id="my-svg">補正後:
<svg width="485px" height="259px"
aria-roledescription="sequence" role="graphics-document document"
viewBox="-50 -10 485 259"
style="width:485px; height:259px; background-color: transparent;"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
id="my-svg">