md2img

package module
v1.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 7, 2026 License: MIT Imports: 14 Imported by: 0

README

md2img

Convert Markdown to styled PNG images. No browser, no Python — just a Go binary and Ghostscript.

markdown → goldmark (parser) → gofpdf (PDF) → Ghostscript (PNG)

Install

Homebrew (macOS/Linux)
brew install jmaciasluque/tap/md2img
Pre-built binaries

Download the latest release for your platform from the Releases page.

From source
git clone https://github.com/jmaciasluque/md2img.git
cd md2img
make build    # → ./md2img
make install  # → ~/go/bin/md2img
With Go
go install github.com/jmaciasluque/md2img/cmd/md2img@latest

Dependencies: Ghostscript (gs) must be installed.

# macOS
brew install ghostscript

# Ubuntu/Debian
sudo apt install ghostscript

# Arch
sudo pacman -S ghostscript

Usage

# From stdin
echo "| Name | Score |\n|------|-------|\n| Alice | 95 |" | md2img -o scores.png

# From file
md2img -o output.png input.md

# Default output: /tmp/md2img_output.png
echo "# Hello" | md2img

CLI Flags

Output
Flag Description Default
-o, --output Output file path /tmp/md2img_output.png
-pdf, --pdf Output PDF directly (no Ghostscript needed) false
-trim, --trim Auto-crop whitespace from PNG output false
-trim-padding, --trim-padding Padding around content after trim (mm) 5
-dpi, --dpi PNG resolution (DPI) 200
-version, --version Print version —
Font
Flag Description Default
-font, --font Body font family (Helvetica, Times, Courier) Helvetica
-font-size, --font-size Body font size (points) 11
-heading-font, --heading-font Heading font (empty = same as body) (same as body)
Page Layout
Flag Description Default
-page-w, --page-w Page width in mm 210 (A4)
-page-h, --page-h Page height in mm 297 (A4)
-margin, --margin All margins in mm 15
Colors

All color flags accept hex values: #333366, 333366, or shorthand #fff.

Flag Description Default
-text-color Body text color #282828
-heading-color Heading text color #282850
-table-header-bg Table header background #323250
-table-header-fg Table header text color #C8C8FF
-table-header-font Table header font (same as body)
-table-header-size Table header font size 10
-table-row-even Even table row background #F5F5FA
-table-row-odd Odd table row background #FFFFFF
-code-bg Code block background #F0F0F0
-code-font Code block font Courier
-code-font-size Code block font size 9
-blockquote-line-color Blockquote left border #6464C8
-blockquote-text-color Blockquote text color #646464
-hr-color Horizontal rule color #B4B4B4
Examples
# Dark theme table
echo "| Name | Score |\n|------|-------|\n| Alice | 95 |" | md2img \
  -o dark_table.png \
  -text-color "#E2E8F0" \
  -table-header-bg "#2D3748" \
  -table-header-fg "#E2E8F0" \
  -table-row-even "#1A202C" \
  -table-row-odd "#2D3748"

# US Letter, high resolution
md2img -o report.png -page-w 215.9 -page-h 279.4 -dpi 300 report.md

# Direct PDF output (no Ghostscript needed)
echo "# Title" | md2img -o output.pdf -pdf

# Trim whitespace (tight crop around content)
echo "| A | B |" | md2img -o tight.png -trim

# Trim with custom padding (in mm)
echo "| A | B |" | md2img -o padded.png -trim -trim-padding 10

# Times font, large text
md2img -o big.png -font Times -font-size 16 -heading-font Helvetica input.md

As a library

import md2img "github.com/jmaciasluque/md2img"

// Simple usage
err := md2img.Render("# Hello\n\nWorld.", "output.png")

// With custom config
cfg := md2img.DefaultConfig()
cfg.DPI = 300
cfg.FontFamily = "Times"
cfg.TableHeaderBg = md2img.Color{R: 45, G: 55, B: 72}
cfg.TableHeaderFg = md2img.Color{R: 226, G: 232, B: 240}
cfg.AsPDF = true  // output PDF directly
cfg.Trim = true   // auto-crop whitespace

err := md2img.RenderWithConfig("# Report\n\n| A | B |\n|---|---|\n| 1 | 2 |", "report.pdf", cfg)
Color helpers
// Parse hex colors
c, err := md2img.HexToColor("#333366")

// Or construct directly
c := md2img.Color{R: 51, G: 51, B: 102}

Chat and AI agents

Matrix, Slack, and most chat platforms don't render HTML tables — they weren't built for structured data. If you're an AI agent that needs to present a comparison or summary in a conversation, you're stuck with code blocks (ugly, no alignment) or images.

md2img fills that gap: markdown in, styled PNG out, send it as a message attachment.

# Quick table for a chat message
echo "| Model      | Speed    | Quality |
|------------|----------|---------|
| Qwen3-14B  | 11 tok/s | Good    |
| Gemma3-12B | 13 tok/s | Good    |" | md2img -o /tmp/table.png

# Then send MEDIA:/tmp/table.png in your message

Works for longer reports too:

cat << 'EOF' | md2img -o /tmp/report.png
## Weekly Summary

| Task            | Status  | Hours |
|-----------------|---------|-------|
| Blog post       | Done    | 4     |
| API refactor    | In progress | 6 |
| Deploy staging  | Blocked | 0     |
EOF

Supported Markdown

Element Rendering
Headers (H1–H6) Bold, sized proportionally
Tables Configurable header/row colors, cell borders
Bullet lists * prefix
Numbered lists 1. 2. 3. prefix
Code blocks Monospace font, configurable background
Blockquotes Configurable left border, italic
Horizontal rules Configurable color and thickness
Bold / italic Supported via markdown syntax

Limitations

  • ASCII only — Unicode characters (emojis, em dashes, special symbols) are mapped to ASCII equivalents. Full Unicode support requires embedding a TTF font.
  • No inline images — text-based rendering only.
  • No nested lists — flat lists only.

Examples

Table
cat << 'EOF' | md2img -o comparison.png
## STACKIT vs Scaleway

| Feature    | STACKIT      | Scaleway    |
|------------|--------------|-------------|
| Free Tier  | No           | Yes         |
| Kubernetes | SKE          | Kapsule     |
| Best For   | Government   | Everyone    |
EOF
Code Block
echo '```go
fmt.Println("hello world")
```' | md2img -o code.png
Full Document
md2img -o report.png report.md

Project Structure

md2img/
├── cmd/md2img/     # CLI entry point
│   ├── main.go
│   └── main_test.go
├── render.go       # PDF rendering engine + Config (library API)
├── sanitize.go     # Unicode → ASCII mapping
├── sanitize_test.go
├── render_test.go
├── Makefile
├── .github/workflows/
│   ├── ci.yml      # Build + test + flag tests on macOS & Ubuntu
│   └── release.yml # Multi-platform release builds
└── README.md

How It Works

  1. Parse — goldmark parses Markdown into an AST (with GFM table support)
  2. Render — gofpdf draws the AST onto a PDF page with styled fonts and colors
  3. Convert — Ghostscript rasterizes the PDF to a configurable DPI PNG (or output PDF directly with -pdf)

The binary is ~5MB. Ghostscript is the only external dependency (not needed for -pdf mode).

Development

# Run tests
make test

# Build
make build

# Install locally
make install

# Run benchmarks
go test -bench=. -benchmem -count=3 ./...

# Compare against a previous run
go test -bench=. -benchmem -count=5 ./... | tee new.txt
benchstat old.txt new.txt

License

MIT

Documentation

Index

Constants

This section is empty.

Variables

View Source
var Version = "dev"

Version is set at build time via ldflags.

Functions

func Render

func Render(input, output string) error

Render converts markdown input to a PNG file at the given output path. It requires Ghostscript (gs) to be installed on the system. Uses DefaultConfig(). For custom options, use RenderWithConfig.

func RenderWithConfig added in v1.1.0

func RenderWithConfig(input, output string, cfg Config) error

RenderWithConfig converts markdown input to a PNG or PDF file using the given configuration. If cfg.AsPDF is true, output is a PDF file directly (Ghostscript is not needed). Otherwise, Ghostscript converts the PDF to PNG.

Types

type Color added in v1.1.0

type Color struct {
	R, G, B int
}

Color represents an RGB color with values 0–255.

func HexToColor added in v1.1.0

func HexToColor(s string) (Color, error)

HexToColor parses a hex color string like "#333366" or "333366" into a Color.

type Config added in v1.1.0

type Config struct {
	// Font
	FontFamily string  // "Helvetica", "Times", or "Courier"
	FontSize   float64 // Body text size in points

	// Page
	PageWidth    float64 // Page width in mm (default: 210 = A4)
	PageHeight   float64 // Page height in mm (default: 297 = A4)
	MarginTop    float64 // Top margin in mm
	MarginLeft   float64 // Left margin in mm
	MarginRight  float64 // Right margin in mm
	MarginBottom float64 // Bottom margin in mm (used for page break check)

	// Text colors
	TextColor Color // Default body text color

	// Heading colors and sizes
	HeadingColor Color      // Heading text color
	HeadingSizes [6]float64 // Font sizes for H1–H6
	HeadingFont  string     // Heading font family override ("", same as FontFamily)

	// Table
	TableHeaderBg   Color   // Table header background
	TableHeaderFg   Color   // Table header text color
	TableHeaderFont string  // Table header font family ("", same as FontFamily)
	TableHeaderSize float64 // Table header font size
	TableCellHeight float64 // Row height in mm
	TableRowEven    Color   // Even row background
	TableRowOdd     Color   // Odd row background

	// Code block
	CodeBg         Color   // Code block background
	CodeFont       string  // Code font family (default: "Courier")
	CodeFontSize   float64 // Code font size
	CodeLineHeight float64 // Code line height in mm

	// Blockquote
	BlockquoteLineColor Color  // Left border color
	BlockquoteTextColor Color  // Quote text color
	BlockquoteFont      string // Quote font (default: same as FontFamily, italic)

	// Horizontal rule
	HRColor     Color   // HR line color
	HRLineWidth float64 // HR line thickness in mm

	// Output
	DPI         int     // Ghostscript DPI (default: 200)
	AsPDF       bool    // Output PDF instead of PNG
	Trim        bool    // Auto-crop whitespace from PNG output
	TrimPadding float64 // Padding around content after trim, in mm (default: 5)
}

Config holds all customizable rendering options.

func DefaultConfig added in v1.1.0

func DefaultConfig() Config

DefaultConfig returns a Config with sensible defaults.

Directories

Path Synopsis
cmd
md2img command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL