Skip to content

Instantly share code, notes, and snippets.

@sug0
Last active August 1, 2020 18:04
Show Gist options
  • Select an option

  • Save sug0/e9307c6ad16a4a6640a3bb3088851ff7 to your computer and use it in GitHub Desktop.

Select an option

Save sug0/e9307c6ad16a4a6640a3bb3088851ff7 to your computer and use it in GitHub Desktop.
Image to braille art converter
// $ mkdir braille
// $ cd braille
// $ go mod init braille
// $ <... copy this file into main.go>
// $ go build
// $ curl -sf <some image> | ./braille -width 100 -height 100 -lum 128
package main
import (
"os"
"fmt"
"flag"
"bufio"
"bytes"
"image"
"image/draw"
_ "image/png"
_ "image/jpeg"
"github.com/bamiaux/rez"
_ "github.com/hullerob/go.farbfeld"
)
var lum byte
var inv rune
var iinv bool
var width, height, llum int
func main() {
flag.IntVar(&width, "width", 20, "The width of the image.")
flag.IntVar(&height, "height", 20, "The height of the image.")
flag.IntVar(&llum, "lum", 128, "The lum of the image.")
flag.BoolVar(&iinv, "inv", false, "Invert colors.")
flag.Parse()
if width % 2 != 0 {
panic("width % 2 != 0")
}
if height % 4 != 0 {
panic("height % 4 != 0")
}
if iinv {
inv = 1
} else {
inv = 0
}
lum = byte(llum & 0xff)
imgIface, _, err := image.Decode(bufio.NewReader(os.Stdin))
if err != nil {
panic(err)
}
if _, ok := imgIface.(*image.Gray); !ok {
newIface := image.NewGray(imgIface.Bounds())
draw.Draw(newIface, imgIface.Bounds(), imgIface, image.Pt(0, 0), draw.Over)
imgIface = newIface
}
im := image.NewGray(image.Rect(0, 0, width, height))
err = rez.Convert(im, imgIface, rez.NewBilinearFilter())
if err != nil {
panic(err)
}
var buf bytes.Buffer
for y := 0; y < height; y += 4 {
for x := 0; x < width; x += 2 {
var bits rune
bits |= runeValue(im.Pix[(y+0)*width + (x+0)]) << 0
bits |= runeValue(im.Pix[(y+0)*width + (x+1)]) << 3
bits |= runeValue(im.Pix[(y+1)*width + (x+0)]) << 1
bits |= runeValue(im.Pix[(y+1)*width + (x+1)]) << 4
bits |= runeValue(im.Pix[(y+2)*width + (x+0)]) << 2
bits |= runeValue(im.Pix[(y+2)*width + (x+1)]) << 5
bits |= runeValue(im.Pix[(y+3)*width + (x+0)]) << 6
bits |= runeValue(im.Pix[(y+3)*width + (x+1)]) << 7
fmt.Fprintf(&buf, "%c", 0x2800 | bits)
}
fmt.Fprintln(&buf)
}
os.Stdout.Write(buf.Bytes())
}
func runeValue(y byte) rune {
if y < lum {
return 1 ^ inv
}
return 0 ^ inv
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment