Skip to content

magick_cli: mermaid-generated SVGs fail to convert (stroke-dasharray !important, empty font-family) #374

Description

@boiiiboi

Environment

  • image.nvim: 88351f1 (latest master)
  • Neovim: v0.12.3
  • ImageMagick: 7.1.2-26 CLI (magick_cli processor)
  • librsvg / rsvg-convert: 2.62.3 (installed, configured as ImageMagick SVG delegate)
  • OS: macOS 26.5.1 (Apple Silicon, Darwin 25.5.0)

What happens

Opening a markdown file that embeds mermaid-generated SVGs (produced by @mermaid-js/mermaid-cli) triggers repeated error notifications at convert_to_png:

Lua callback:
...nvim/lazy/image.nvim/lua/image/processors/magick_cli.lua:76: magick: non-conforming drawing primitive definition `stroke-dasharray' @ error/draw.c/RenderMVGContent/4661.

stack traceback:
        [C]: in function 'error'
        ...processors/magick_cli.lua:76: in function <...processors/magick_cli.lua:75>
        [C]: in function 'wait'
        ...processors/magick_cli.lua:85: in function 'convert_to_png'
        ...lazy/image.nvim/lua/image/image.lua:326: in function <...>
        [C]: in function 'pcall'
        ...image.nvim/lua/image/utils/document.lua:202: in function 'fn'

Different mermaid diagrams surface different symptoms from the same coder:

  • Flowchart with any dashed edge → non-conforming drawing primitive 'stroke-dasharray'
  • Diagrams with default text styles → unable to read font '' @ error/annotate.c/RenderFreetype/1665

Root cause

Default mmdc output contains CSS that ImageMagick's built-in MSVG coder cannot parse:

  • stroke-dasharray:9,5!important — the MSVG coder does not understand CSS's !important modifier and rejects the whole primitive
  • font-family: with an empty value — the MSVG coder passes the empty string to FreeType

convert_to_png in magick_cli.lua spawns magick <path> png:<out> unconditionally. Even when the ImageMagick SVG delegate points at rsvg-convert, ImageMagick 7 (at least the Homebrew build without pango/wmf) still selects its internal MSVG coder for these SVGs, so the delegate never runs.

rsvg-convert handles the exact same SVGs without any problem.

Reproduce without Neovim

mkdir -p /tmp/msvg-repro && cd /tmp/msvg-repro
cat > flow.mmd <<'MMD'
flowchart LR
  A -.-> B
  B --> C
MMD
npx --yes @mermaid-js/mermaid-cli -i flow.mmd -o flow.svg

magick flow.svg /tmp/out.png
# → magick: non-conforming drawing primitive definition `stroke-dasharray' @ error/draw.c/RenderMVGContent/4661.

rsvg-convert flow.svg -o /tmp/out.png  # ← works, produces a valid PNG

Proposal

For SVG inputs, prefer rsvg-convert (when available) over magick <svg> png:<out>. This is symmetrical to the fix suggested in #370 for identify — same underlying issue (ImageMagick's internal SVG coder is unreliable), different call site.

A user-side workaround that avoids any upstream change is possible today via the existing integrations.markdown.resolve_image_path hook — pre-convert SVGs with rsvg-convert into a cached PNG and hand the PNG path to image.nvim:

integrations = {
  markdown = {
    resolve_image_path = function(document_path, image_url, fallback)
      if image_url:sub(1, 10) == 'data:image' then
        -- (reproduce the base64 branch that resolve_image_path bypasses)
        ...
      end
      local path = fallback(document_path, image_url)
      if type(path) ~= 'string' then return path end
      if path:lower():match('%.svg$') and vim.fn.executable('rsvg-convert') == 1 then
        local stat = vim.uv.fs_stat(path)
        if not stat then return path end
        local cache_dir = vim.fn.stdpath('cache') .. '/image_nvim_svg'
        vim.fn.mkdir(cache_dir, 'p')
        local key = vim.fn.sha256(path .. ':' .. tostring(stat.mtime.sec))
        local png = cache_dir .. '/' .. key .. '.png'
        if vim.uv.fs_stat(png) == nil then
          vim.fn.system({ 'rsvg-convert', path, '-o', png })
          if vim.v.shell_error ~= 0 then return path end
        end
        return png
      end
      return path
    end,
  },
},

I confirmed this eliminates the crash on the same mermaid SVGs. A similar branch inside magick_cli.convert_to_png (detect .svg → shell out to rsvg-convert when present, fall back to magick) would fix it for all users without configuration.

Related


Report drafted with Claude Code; issue is real and reproducible with the commands above.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions