master
parent
997c725752
commit
67b7cd4579
21
go.mod
21
go.mod
|
|
@ -6,3 +6,24 @@ require (
|
|||
github.com/google/uuid v1.3.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/charmbracelet/bubbletea v0.12.0 // indirect
|
||||
github.com/containerd/console v1.0.1 // indirect
|
||||
github.com/disintegration/gift v1.1.2 // indirect
|
||||
github.com/disintegration/imageorient v0.0.0-20180920195336-8147d86e83ec // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.0.3 // indirect
|
||||
github.com/mattn/go-isatty v0.0.12 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
github.com/muesli/termenv v0.7.4 // indirect
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 // indirect
|
||||
github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 // indirect
|
||||
github.com/trashhalo/imgcat v1.2.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee // indirect
|
||||
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 // indirect
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 // indirect
|
||||
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634 // indirect
|
||||
golang.org/x/text v0.3.0 // indirect
|
||||
)
|
||||
|
|
|
|||
43
go.sum
43
go.sum
|
|
@ -1,5 +1,48 @@
|
|||
github.com/charmbracelet/bubbletea v0.12.0 h1:/pUHp1GWRDyK1TJAWkXrnRH1u8Xc5076oH/J0NHxH+M=
|
||||
github.com/charmbracelet/bubbletea v0.12.0/go.mod h1:3gZkYELUOiEUOp0bTInkxguucy/xRbGSOcbMs1geLxg=
|
||||
github.com/containerd/console v1.0.1 h1:u7SFAJyRqWcG6ogaMAx3KjSTy1e3hT9QxqX7Jco7dRc=
|
||||
github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw=
|
||||
github.com/disintegration/gift v1.1.2 h1:9ZyHJr+kPamiH10FX3Pynt1AxFUob812bU9Wt4GMzhs=
|
||||
github.com/disintegration/gift v1.1.2/go.mod h1:Jh2i7f7Q2BM7Ezno3PhfezbR1xpUg9dUg3/RlKGr4HI=
|
||||
github.com/disintegration/imageorient v0.0.0-20180920195336-8147d86e83ec h1:YrB6aVr9touOt75I9O1SiancmR2GMg45U9UYf0gtgWg=
|
||||
github.com/disintegration/imageorient v0.0.0-20180920195336-8147d86e83ec/go.mod h1:K0KBFIr1gWu/C1Gp10nFAcAE4hsB7JxE6OgLijrJ8Sk=
|
||||
github.com/google/goterm v0.0.0-20190703233501-fc88cf888a3f/go.mod h1:nOFQdrUlIlx6M6ODdSpBj1NVA+VgLC6kmw60mkw34H4=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac=
|
||||
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/muesli/termenv v0.7.2/go.mod h1:ct2L5N2lmix82RaY3bMWwVu/jUFc9Ule0KGDCiKYPh8=
|
||||
github.com/muesli/termenv v0.7.4 h1:/pBqvU5CpkY53tU0vVn+xgs2ZTX63aH5nY+SSps5Xa8=
|
||||
github.com/muesli/termenv v0.7.4/go.mod h1:pZ7qY9l3F7e5xsAOS0zCew2tME+p7bWeBkotCEcIIcc=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 h1:HunZiaEKNGVdhTRQOVpMmj5MQnGnv+e8uZNu3xFLgyM=
|
||||
github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564/go.mod h1:afMbS0qvv1m5tfENCwnOdZGOF8RGR/FsZ7bvBxQGZG4=
|
||||
github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 h1:m59mIOBO4kfcNCEzJNy71UkeF4XIx2EVmL9KLwDQdmM=
|
||||
github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9/go.mod h1:mvWM0+15UqyrFKqdRjY6LuAVJR0HOVhJlEgZ5JWtSWU=
|
||||
github.com/trashhalo/imgcat v1.2.0 h1:vUwdvOqcAxjrqBMH63KQbOKXWcrwy7xFt5l3nfE8K6Q=
|
||||
github.com/trashhalo/imgcat v1.2.0/go.mod h1:oa4z1WA6THdqcwPKp3VFMe/7CZzzrOfDY3mRTePxtOQ=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee h1:4yd7jl+vXjalO5ztz6Vc1VADv+S/80LGJmyl1ROJ2AI=
|
||||
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 h1:QelT11PB4FXiDEXucrfNckHoFxwt8USGY1ajP1ZF5lM=
|
||||
golang.org/x/image v0.0.0-20200927104501-e162460cd6b5/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200916030750-2334cc1a136f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634 h1:bNEHhJCnrwMKNMmOx3yAynp5vs5/gRy+XWFtZFu7NBM=
|
||||
golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/trashhalo/imgcat"
|
||||
)
|
||||
|
||||
func View(image string) {
|
||||
model := imgcat.NewModel([]string{image})
|
||||
p := tea.NewProgram(model)
|
||||
p.EnterAltScreen()
|
||||
defer p.ExitAltScreen()
|
||||
if err := p.Start(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestView(t *testing.T) {
|
||||
if os.Getenv("INTEGRATION") == "" {
|
||||
t.SkipNow()
|
||||
}
|
||||
View("./testdata/tofugu.d/a-hiragana-0.png")
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
module gogs.inhome.blapointe.com/anki.d/testdata/draw.d
|
||||
|
||||
go 1.19
|
||||
|
||||
require github.com/nsf/termbox-go v1.1.1
|
||||
|
||||
require github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/nsf/termbox-go v1.1.1 h1:nksUPLCb73Q++DwbYUBEglYBRPZyoXJdrj5L+TkjyZY=
|
||||
github.com/nsf/termbox-go v1.1.1/go.mod h1:T0cTdVuOwf7pHQNtfhnEbzHbcNyCEcVU4YPpouCbVxo=
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
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)
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,8 @@
|
|||
# Unreadable: 1×2 (high resolution, slowest rendering, without double horizontal resolution)
|
||||
char_w=5
|
||||
char_h=8
|
||||
char_w=1
|
||||
char_h=2
|
||||
|
||||
# If file doesn't exist, then die with 'No such file or directory' exit code
|
||||
if [ ! -f "$1" ]
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 2.0 KiB |
Loading…
Reference in New Issue