GitHub - kevin-cantwell/dotmatrix: Encodes images to a "dot matrix" pattern using braille unicode characters.

3 min read Original article ↗

Go Reference

Convert images to Unicode braille art for terminal display.

Features

  • Encode JPEG, PNG, GIF, and BMP images as braille Unicode characters
  • Animated GIF support with proper frame timing and disposal methods
  • MP4 video playback with H.264 decoding
  • Embedded subtitle rendering for MP4 files (mov_text format)
  • Native webcam capture on macOS (AVFoundation)
  • Image adjustments: gamma, brightness, contrast, sharpening
  • Floyd-Steinberg dithering for grayscale preservation
  • Automatic scaling to fit terminal dimensions

Installation

Homebrew (macOS/Linux)

brew install kevin-cantwell/tap/dotmatrix

Pre-built Binaries

Download from GitHub Releases. Binaries are available for:

  • Linux (amd64)
  • macOS (arm64, amd64)

macOS users: The binaries are not signed with an Apple Developer account. After downloading, remove the quarantine attribute:

xattr -d com.apple.quarantine dotmatrix

Install with Go

go install github.com/kevin-cantwell/dotmatrix/cmd/dotmatrix@latest

macOS users: The binary may be killed immediately due to an invalid code signature. If this happens, re-sign it:

codesign --force --sign - $(go env GOPATH)/bin/dotmatrix

Building from Source

Building from source requires FFmpeg 8.x development libraries and CGO. Pre-built binaries have FFmpeg statically linked and require no runtime dependencies.

macOS:

brew install ffmpeg pkg-config
CGO_ENABLED=1 go build -o dotmatrix ./cmd/dotmatrix

Ubuntu/Debian:

# FFmpeg 8.x may need to be built from source if not available in repos
sudo apt-get install libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libswresample-dev libavdevice-dev
CGO_ENABLED=1 go build -o dotmatrix ./cmd/dotmatrix

Usage

Command Line

# From file
dotmatrix image.png

# From URL
dotmatrix https://example.com/image.jpg

# From stdin
curl -s https://example.com/image.jpg | dotmatrix

# With options
dotmatrix --invert --sharpen 50 image.png

# Play MP4 video (subtitles are displayed if embedded)
dotmatrix video.mp4

# Play MP4 at specific framerate
dotmatrix --fps 15 video.mp4

# Capture from webcam (macOS only)
dotmatrix --webcam

# Webcam with options
dotmatrix --webcam --invert --fps 15

As a Library

package main

import (
    "image"
    "os"

    "github.com/kevin-cantwell/dotmatrix"
)

func main() {
    img, _, _ := image.Decode(os.Stdin)
    dotmatrix.Print(os.Stdout, img)
}

Options

Flag Description
--invert, -i Invert colors (for dark backgrounds)
--gamma, -g Adjust gamma: negative darkens, positive lightens
--brightness, -b Adjust brightness (-100 to 100)
--contrast, -c Adjust contrast (-100 to 100)
--sharpen, -s Sharpen image
--mirror, -m Flip image horizontally
--mono Disable Floyd-Steinberg dithering
--webcam, -w Capture from webcam (macOS only)
--framerate, --fps Set playback framerate
--mimeType, --mime Override auto-detected MIME type

Examples

Sharpened Image

dotmatrix --sharpen 100 face.jpg
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣿⣜⢽⡺⣿⣿⣺⣿⣏⣿⣿⣿⣿⢿⣟⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣾⣿⣿⣿⣿⣿⣿⣿⣿⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣜⡞⣧⢅⢳⡙⣼⣻⡢⡺⡼⣻⢞⡯⣟⣽⢻⡿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣻⣯⣿⣿⣿⡿⡿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡜⣖⢔⠕⢸⡳⡢⡱⠅⡞⣽⠱⢳⢫⡟⡞⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣱⣿⣿⣵⡿⣿⣟⡿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣽⣷⢿⡽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
⣿⣿⣿⡿⡽⣿⢿⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣮⢣⢫⠀⠣⠂⢘⠐⢁⢊⠠⠉⢎⢎⢣⢿⡻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡏⡼⡜⡾⡯⡫⢽⢽⣗⢟⣿⣿⣿⣿⣿⣿⣿⣟⡮⣟⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿
⣿⣿⡿⡭⡺⣫⣟⡷⣟⢾⢽⢿⣟⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣎⠄⢊⢂⠠⠈⠄⠂⠀⢁⢑⠁⢜⡧⡗⢡⢮⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣜⢜⢌⢊⠈⣄⢜⢿⡫⣿⣿⣿⣿⣿⣿⣿⡿⡱⣻⢟⣿⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿

Animated GIF

Animated GIFs play directly in the terminal with proper timing:

Animated GIF example

Note: Terminal refresh rates vary. The default macOS Terminal.app works well; iTerm2 may have slower refresh rates.

MP4 Subtitles

MP4 files with embedded subtitles (mov_text/tx3g format) will display subtitles overlaid at the bottom of the video. Subtitles are:

  • Automatically extracted and timed to video playback
  • Centered and wrapped to fit the terminal width
  • Rendered over the braille output while preserving surrounding pixels

How It Works

Dotmatrix uses Unicode Braille Patterns (U+2800 to U+28FF) to represent images. Each braille character encodes a 2x4 pixel grid, allowing 256 possible patterns per character.

Processing pipeline:

  1. Decode - Parse input (JPEG, PNG, GIF, BMP, or MP4 video)
  2. Filter - Apply brightness, contrast, gamma, sharpening adjustments
  3. Scale - Resize to fit terminal dimensions (2 pixels per column, 4 pixels per row)
  4. Dither - Convert to monochrome using Floyd-Steinberg diffusion
  5. Encode - Map each 2x4 pixel block to a braille character
  6. Render - Output braille characters with newlines (for video, frames are rendered in sequence)

The Floyd-Steinberg dithering algorithm distributes quantization errors to neighboring pixels, preserving the appearance of grayscale gradients in the monochrome output.

License

MIT