147 lines
3.2 KiB
Go
147 lines
3.2 KiB
Go
package main
|
|
|
|
import (
|
|
"image"
|
|
"image/color"
|
|
_ "image/gif"
|
|
_ "image/jpeg"
|
|
_ "image/png"
|
|
"log"
|
|
"math"
|
|
"os"
|
|
|
|
termbox "github.com/nsf/termbox-go"
|
|
)
|
|
|
|
var palette color.Palette = []color.Color{
|
|
attrColor(termbox.ColorBlack),
|
|
attrColor(termbox.ColorRed),
|
|
attrColor(termbox.ColorGreen),
|
|
attrColor(termbox.ColorYellow),
|
|
attrColor(termbox.ColorBlue),
|
|
attrColor(termbox.ColorMagenta),
|
|
attrColor(termbox.ColorCyan),
|
|
attrColor(termbox.ColorWhite),
|
|
}
|
|
|
|
func upgrade(palette color.Palette) color.Palette {
|
|
for i := 16; i <= 255; i++ {
|
|
palette = append(palette, attrColor(i))
|
|
}
|
|
return palette
|
|
}
|
|
|
|
type attrColor termbox.Attribute
|
|
|
|
var base = [...]uint8{0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff}
|
|
|
|
func (c attrColor) RGBA() (r, g, b, a uint32) {
|
|
switch termbox.Attribute(c) {
|
|
case termbox.ColorBlack:
|
|
return 0, 0, 0, math.MaxUint16
|
|
case termbox.ColorRed:
|
|
return math.MaxUint16, 0, 0, math.MaxUint16
|
|
case termbox.ColorGreen:
|
|
return 0, math.MaxUint16, 0, math.MaxUint16
|
|
case termbox.ColorYellow:
|
|
return math.MaxUint16, math.MaxUint16, 0, math.MaxUint16
|
|
case termbox.ColorBlue:
|
|
return 0, 0, math.MaxUint16, math.MaxUint16
|
|
case termbox.ColorMagenta:
|
|
return math.MaxUint16, 0, math.MaxUint16, math.MaxUint16
|
|
case termbox.ColorCyan:
|
|
return 0, math.MaxUint16, math.MaxUint16, math.MaxUint16
|
|
case termbox.ColorWhite:
|
|
return math.MaxUint16, math.MaxUint16, math.MaxUint16, math.MaxUint16
|
|
}
|
|
|
|
switch {
|
|
case c >= 16 && c <= 231:
|
|
c -= 16
|
|
rgba := color.RGBA{R: base[(c/36)%6], G: base[(c/6)%6], B: base[c%6], A: 0xff}
|
|
return rgba.RGBA()
|
|
case c >= 232 && c <= 255:
|
|
x := uint8(0x08 + 0xa*(c-232))
|
|
rgba := color.RGBA{R: x, G: x, B: x, A: 0xff}
|
|
return rgba.RGBA()
|
|
}
|
|
|
|
panic("not found")
|
|
}
|
|
|
|
func fit(w, h, iw, ih int) (sw, sh int) {
|
|
if w >= iw && h >= ih {
|
|
// image is smaller than screen
|
|
return iw, ih
|
|
} else if w >= iw {
|
|
// image is taller than the screen
|
|
return iw * h / ih, h
|
|
} else if h >= ih {
|
|
// image is skinnier than the screen
|
|
return w, ih * w / iw
|
|
} else {
|
|
sw, sh = iw*h/ih, h
|
|
if sw <= w {
|
|
return sw, sh
|
|
}
|
|
return w, ih * w / iw
|
|
}
|
|
}
|
|
|
|
func draw(img image.Image) {
|
|
w, h := termbox.Size()
|
|
iw, ih := img.Bounds().Max.X, img.Bounds().Max.Y
|
|
sw, sh := fit(w, h, iw*2, ih)
|
|
termbox.Clear(termbox.ColorDefault, termbox.ColorDefault)
|
|
for y := 0; y < h; y++ {
|
|
for x := 0; x < w; x++ {
|
|
if x >= sw || y >= sh {
|
|
termbox.SetCell(x, y, ' ', termbox.ColorDefault, termbox.ColorDefault)
|
|
continue
|
|
}
|
|
xi := x * img.Bounds().Max.X / sw
|
|
yi := y * img.Bounds().Max.Y / sh
|
|
a := palette.Convert(img.At(xi, yi))
|
|
if at, ok := a.(attrColor); ok {
|
|
termbox.SetCell(x, y, ' ', termbox.ColorDefault,
|
|
termbox.Attribute(at))
|
|
}
|
|
}
|
|
}
|
|
termbox.Flush()
|
|
}
|
|
|
|
func main() {
|
|
fname := os.Args[1]
|
|
|
|
f, err := os.Open(fname)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
defer f.Close()
|
|
|
|
img, _, err := image.Decode(f)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
err = termbox.Init()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer termbox.Close()
|
|
|
|
if termbox.SetOutputMode(termbox.Output256) == termbox.Output256 {
|
|
palette = upgrade(palette)
|
|
}
|
|
|
|
lw, lh := termbox.Size()
|
|
draw(img)
|
|
termbox.PollEvent()
|
|
termbox.Flush()
|
|
if w, h := termbox.Size(); lw != w || lh != h {
|
|
lw, lh = w, h
|
|
draw(img)
|
|
}
|
|
}
|