A Go library that converts images (PNG, JPEG, BMP) into ASCII art, with an optional RGB sine-wave color gradient via the companion waverunner API.
go run ./src -color ./src/images/jetski.pnggo get github.com/dchill72/jetskiimport "github.com/dchill72/jetski"
f, _ := os.Open("photo.png")
defer f.Close()
art, err := jetski.Convert(f, jetski.Options{Width: 120})
fmt.Print(art)func Convert(r io.Reader, opts Options) (string, error)Decodes an image from r and returns a newline-delimited ASCII-art string. Height is derived automatically from the image's aspect ratio and a terminal font-aspect correction (characters are ~2× taller than wide).
func ConvertGrid(r io.Reader, opts Options) ([][]byte, error)Same as Convert but returns the raw [][]byte character grid instead of a string. Pass the grid to Colorize to apply an RGB gradient, or to GridToString to get a plain string later without re-decoding the image.
| Field | Type | Default | Description |
|---|---|---|---|
Width |
int |
80 |
Output column count. Height is computed to preserve aspect ratio. |
Chars |
string |
"@#$*+=~-:.\ "` |
Luminance ramp, darkest character first. Ignored when Renderer is set. |
Renderer |
Renderer |
nil |
Custom per-pixel function func(r, g, b uint8) string. Receives original RGB; overrides Chars, Gamma, Equalize, and Brightness. |
Brightness |
float64 |
0.5 |
Overall luminance offset. 0.0 = darkest, 0.5 = neutral, 1.0 = lightest. Zero value treated as 0.5. |
Gamma |
float64 |
0 |
Power-curve on luminance. <1 brightens, >1 darkens. 0 and 1 are identity. |
Equalize |
bool |
false |
Histogram-equalizes luminance before mapping. Best for images whose tones are concentrated in a narrow band (e.g. low-contrast photos). |
Brightness, Gamma, and Equalize only affect the built-in grayscale renderer. They are applied in this order: equalize → gamma → brightness.
@ # $ * + = ~ - : . ` (space)
█ ▓ ▓ ▒ ▒ ░ ░ ░ · ·
Twelve characters chosen for maximum visual weight separation between adjacent steps. Supply your own via Chars — fewer characters produces harder contrast; more produces smoother gradients.
Renderer gives full control over per-pixel output, including ANSI colour codes:
art, _ := jetski.Convert(f, jetski.Options{
Width: 100,
Renderer: func(r, g, b uint8) string {
// emit the pixel's true colour as ANSI 24-bit foreground
luma := 0.299*float64(r) + 0.587*float64(g) + 0.114*float64(b)
chars := "@#$*+=~-:." + "` "
ch := chars[int(luma)*len(chars)/256]
return fmt.Sprintf("\x1b[38;2;%d;%d;%dm%c\x1b[0m", r, g, b, ch)
},
})f, _ := os.Open("photo.png")
defer f.Close()
grid, err := jetski.ConvertGrid(f, jetski.Options{
Width: 120,
Equalize: true,
})
if err != nil {
log.Fatal(err)
}
colored := waverunner.Colorize(grid, jetski.WaveOptions{
Angle: 45,
Period: 24,
Range: 0.8,
})
fmt.Print(colored)Increment Phase each frame to scroll the gradient:
grid, _ := jetski.ConvertGrid(f, jetski.Options{Width: 100, Equalize: true})
for phase := 0.0; ; phase += 0.15 {
fmt.Print("\x1b[H") // move cursor to top-left
fmt.Print(waverunner.Colorize(grid, jetski.WaveOptions{
Angle: 45,
Period: 20,
Phase: phase,
Range: 1.0,
}))
time.Sleep(50 * time.Millisecond)
}A small command-line program in src/ exercises the full API:
go run ./src/ [flags] <image>
Flags:
-width int output column width (default 80)
-brightness float luminance shift: 0.0 dark → 0.5 neutral → 1.0 light (default 0.5)
-gamma float power curve: <1 lighter, >1 darker, 0=off
-equalize apply histogram equalization
-color apply RGB wave gradient (requires a terminal with 24-bit colour)
-angle float wave angle in degrees (default 45)
-phase float wave phase offset in radians (default 0)
-period float wave period in character cells (default 16)
-saturation float colour saturation 0–1 (default 1)
Example images live in src/images/.
# plain grayscale
go run ./src/ src/images/photo.png
# equalized with a brightness boost
go run ./src/ -equalize -brightness 0.6 src/images/photo.png
# diagonal rainbow gradient
go run ./src/ -color -equalize -angle 45 -period 30 src/images/photo.png
# desaturated vertical gradient, wider output
go run ./src/ -color -equalize -angle 90 -saturation 0.5 -width 140 src/images/photo.png| Format | Notes |
|---|---|
| PNG | via image/png |
| JPEG | via image/jpeg |
| BMP | via golang.org/x/image/bmp |
Any format registered with Go's image package before calling Convert / ConvertGrid will also work.

