108
package main
import (
"fmt"
"github.com/nfnt/resize"
"golang.org/x/term"
"image"
_ "image/jpeg"
_ "image/png"
"math"
"os"
"strings"
)
func getTermSize() (int, int) {
W, H, err := term.GetSize(int(os.Stdout.Fd()))
if err != nil || !(W > 0 && H > 0) {
fmt.Fprintln(os.Stderr, "fatal: could not get terminal size")
os.Exit(1)
}
return W, H
}
func (img *Immg) FitSize(W, H int) {
y := float64(img.Img.Bounds().Dy())
x := float64(img.Img.Bounds().Dx())
w := float64(W)
h := float64(H)*2 - 1
if x > w {
y = y * w / x
x = w
}
if y > h {
x = x * h / y
y = h
}
img.Img = resize.Resize(uint(math.Round(x)), uint(math.Round(y)), img.Img, resize.MitchellNetravali)
}
func (img *Immg) OpenImg(path string) error {
file, err := os.Open(path)
if err != nil {
return fmt.Errorf("error opening file: %s", path)
}
defer file.Close()
img.Img, _, err = image.Decode(file)
if err != nil {
return fmt.Errorf("error decoding file: %s", path)
}
return nil
}
type Immg struct {
Img image.Image
X int
Y int
}
func (img *Immg) ForX() {
img.X = 0
for img.X < 2*(img.Img.Bounds().Dx()) {
img.Doalp()
img.X++
img.Doalp()
img.X++
fmt.Print("▀\033[0m")
}
}
func (img *Immg) Print() {
img.Y = img.Img.Bounds().Min.Y
for img.Y < img.Img.Bounds().Max.Y {
img.ForX()
fmt.Println()
img.Y += 2
}
}
func (img *Immg) Doalp() {
r, g, b, _ := img.Img.At(img.Img.Bounds().Min.X+img.X/2, img.Y+img.X%2).RGBA()
fmt.Printf("\033[%d8;2;%d;%d;%dm", 3+(img.X%2), r>>8, g>>8, b>>8)
}
func main() {
if len(os.Args) < 2 {
fmt.Fprintln(os.Stderr, "fatal: no image specified")
os.Exit(1)
}
W, H := getTermSize()
var img Immg
var err error
for _, path := range os.Args[1:] {
if strings.HasPrefix(path, "-") && len(path) == 2 && '1' <= path[1] && path[1] <= '9' {
W *= (int(path[1]) - '0')
W /= 10
H *= (int(path[1]) - '0')
H /= 10
continue
}
err = img.OpenImg(path)
if err != nil {
fmt.Fprintf(os.Stderr, "error opening image: %s\n", path)
continue
}
img.FitSize(W, H)
img.Print()
}
}