https://github.com/zebbeni/ansipx
A golang library to convert image files to ansi art
https://github.com/zebbeni/ansipx
ansi-art ascii ascii-art bubbletea bubbletea-tui gif-animation image-to-text text-user-interface
Last synced: 3 months ago
JSON representation
A golang library to convert image files to ansi art
- Host: GitHub
- URL: https://github.com/zebbeni/ansipx
- Owner: Zebbeni
- License: mit
- Created: 2026-04-01T18:33:40.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2026-04-02T14:41:53.000Z (3 months ago)
- Last Synced: 2026-04-04T22:41:14.648Z (3 months ago)
- Topics: ansi-art, ascii, ascii-art, bubbletea, bubbletea-tui, gif-animation, image-to-text, text-user-interface
- Language: Go
- Homepage: https://zebbeni.itch.io/ansizalizer
- Size: 32.2 KB
- Stars: 3
- Watchers: 0
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# ansipx
A Go library for converting images to ANSI art. Renders images as colored terminal text using ASCII characters, Unicode block characters, or custom character sets. Supports static images and animated GIFs.
## Demos
### Unicode Half Blocks (default)

### ASCII Characters

### Limited Palette with Dithering

## Install
```
go get github.com/Zebbeni/ansipx
```
## Usage
```go
package main
import (
"fmt"
"github.com/Zebbeni/ansipx"
)
func main() {
// Render with default settings (Unicode half-blocks, true color, fit 50x40)
result, err := ansipx.RenderFile("photo.png", ansipx.DefaultOptions())
if err != nil {
panic(err)
}
fmt.Print(result)
}
```
### With a palette
```go
opts := ansipx.DefaultOptions()
opts.TrueColor = false
opts.Palette = color.Palette{
colorful.MustParseHex("#000000"),
colorful.MustParseHex("#626262"),
colorful.MustParseHex("#ffffff"),
}
result, _ := ansipx.RenderFile("photo.png", opts)
fmt.Print(result)
```
### ASCII mode
```go
opts := ansipx.DefaultOptions()
opts.CharacterMode = ansipx.Ascii
opts.AsciiCharSet = ansipx.AsciiAll
result, _ := ansipx.RenderFile("photo.png", opts)
fmt.Print(result)
```
### Custom characters
```go
opts := ansipx.DefaultOptions()
opts.CharacterMode = ansipx.Custom
opts.CustomChars = []rune(".:+#@")
opts.SelectionMode = ansipx.DarkVariance // map by brightness (dark to light)
// opts.SelectionMode = ansipx.LightVariance // map by brightness (light to dark)
// opts.SelectionMode = ansipx.Repeat // cycle through chars
// opts.SelectionMode = ansipx.Random // pick at random (use RandomSeed for determinism)
result, _ := ansipx.RenderFile("photo.png", opts)
fmt.Print(result)
```
### From an `image.Image`
```go
img, _, _ := image.Decode(reader)
result, err := ansipx.Render(img, ansipx.DefaultOptions())
```
### Animated GIFs
```go
frames, err := ansipx.RenderGIF("animation.gif", ansipx.DefaultOptions())
if err != nil {
panic(err)
}
for _, frame := range frames {
fmt.Print("\033[H") // move cursor to top-left
fmt.Print(frame.Content)
time.Sleep(frame.Delay)
}
```
### Alpha transparency
```go
opts := ansipx.DefaultOptions()
opts.OutputAlpha = true // transparent pixels render as empty space
opts.AlphaThreshold = 0.5 // pixels with alpha below 0.5 are treated as transparent
opts.TrimAlpha = true // crop transparent borders from output
result, _ := ansipx.RenderFile("sprite.png", opts)
fmt.Print(result)
```
When alpha is enabled with Unicode block characters, partially transparent cells automatically select the best-fit block character (from the full set of quarter, half, three-quarter, and full blocks) to render only the opaque sub-pixels with foreground color while leaving the transparent portion as background.
### Text style
```go
opts := ansipx.DefaultOptions()
opts.TextStyle = ansipx.TextStyle{
Bold: true,
Italic: true,
Underline: true,
}
result, _ := ansipx.RenderFile("photo.png", opts)
fmt.Print(result)
```
### Solid background color
```go
bg := colorful.MustParseHex("#1a1a2e")
opts := ansipx.DefaultOptions()
opts.SolidBackgroundColor = &bg
result, _ := ansipx.RenderFile("photo.png", opts)
fmt.Print(result)
```
## Options
### Size
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `SizeMode` | `SizeMode` | `Fit` | `Fit` preserves aspect ratio, `Fill` crops to fill, `Stretch` fills exact dimensions |
| `Width` | `int` | `50` | Output width in characters |
| `Height` | `int` | `40` | Output height in characters |
| `CharRatio` | `float64` | `0.46` | Terminal character width-to-height ratio |
### Characters
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `CharacterMode` | `CharacterMode` | `Unicode` | `Ascii`, `Unicode`, or `Custom` |
| `AsciiCharSet` | `AsciiCharSet` | `AsciiAZ` | `AsciiAZ`, `AsciiNums`, `AsciiSpec`, `AsciiAll` |
| `UnicodeCharSet` | `UnicodeCharSet` | `UnicodeHalf` | `UnicodeFull`, `UnicodeHalf`, `UnicodeQuarter`, `UnicodeShadeLight/Med/Heavy` |
| `CustomChars` | `[]rune` | `nil` | Characters for custom mode |
| `SelectionMode` | `SelectionMode` | `DarkVariance` | How chars map to pixels: `DarkVariance`, `LightVariance`, `Repeat`, `Random` |
| `RandomSeed` | `int64` | `0` | Seed for deterministic Random mode (same seed = same pattern per frame) |
| `VarianceThreshold` | `float64` | `0` | 0-1: below this normalized variance, render a space instead of a character |
| `SolidBackgroundColor` | `*colorful.Color` | `nil` | If set, use this as bg for FG-only character modes |
### Color
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `TrueColor` | `bool` | `true` | Use 24-bit RGB. Set `false` for palette mode |
| `Palette` | `color.Palette` | `nil` | Color palette for palette mode |
| `AdaptToPalette` | `bool` | `false` | Remap image color range to palette range before matching |
### Adjustments
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `Brightness` | `int` | `0` | Brightness adjustment (-100 to 100) |
| `Contrast` | `int` | `0` | Contrast adjustment (-100 to 100) |
### Advanced
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `Sampling` | `SamplingFunction` | `NearestNeighbor` | `NearestNeighbor`, `Bicubic`, `Bilinear`, `Lanczos2`, `Lanczos3`, `MitchellNetravali` |
| `Dithering` | `bool` | `false` | Enable dithering (palette mode only) |
| `Serpentine` | `bool` | `false` | Use serpentine scanning for error diffusion dithering |
| `DitherMode` | `DitherMode` | `DitherModeMatrix` | `DitherModeMatrix`, `DitherModeBayer`, `DitherModeClusteredDot` |
| `DitherMatrix` | `DitherMatrix` | `FloydSteinberg` | Error diffusion matrix (14 options including `Atkinson`, `Burkes`, `Stucki`, etc.) |
| `BayerSize` | `uint` | `4` | Bayer matrix size (must be power of 2) |
| `DitherStrength` | `float32` | `1.0` | Dithering strength for Bayer and ClusteredDot modes |
| `ClusteredDotMatrix` | `ClusteredDotMatrix` | `ClusteredDot4x4` | Clustered dot matrix (13 options) |
### Text Style
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `TextStyle` | `TextStyle` | `{}` | ANSI text attributes: `Bold`, `Italic`, `Underline`, `Strikethrough` |
### Alpha
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `OutputAlpha` | `bool` | `true` | Preserve transparent pixels as spaces |
| `TrimAlpha` | `bool` | `false` | Crop transparent borders from output |
| `AlphaThreshold` | `float64` | `0` | 0-1: pixels with alpha below this are treated as transparent (0 = only fully transparent, 1 = all transparent) |
## Dependencies
- [go-colorful](https://github.com/lucasb-eyer/go-colorful) -- color space math
- [resize](https://github.com/nfnt/resize) -- image resampling
- [dither](https://github.com/makeworld-the-better-one/dither) -- error diffusion and ordered dithering
No terminal UI dependencies. Output is raw ANSI escape sequences.