pax_global_header00006660000000000000000000000064143033332710014511gustar00rootroot0000000000000052 comment=674f6ccf2e8cf1fc65f4368044d0727db1509f36 go-sixel-0.0.5/000077500000000000000000000000001430333327100132425ustar00rootroot00000000000000go-sixel-0.0.5/LICENSE000066400000000000000000000020751430333327100142530ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2021 Yasuhiro Matsumoto Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. go-sixel-0.0.5/README.md000066400000000000000000000015111430333327100145170ustar00rootroot00000000000000# go-sixel DRCS Sixel Encoder/Decoder ![](http://go-gyazo.appspot.com/75ec3ce96dfc573e.png) ## Installation ``` $ go get github.com/mattn/go-sixel ``` You can install gosr (go sixel renderer), gosd (go sixel decoder) with following installation instruction. ``` $ go get github.com/mattn/go-sixel/cmd/gosr $ go get github.com/mattn/go-sixel/cmd/gosd ``` |Command|Description | |-------|--------------------| |gosr |Image renderer | |gosd |Decoder to png | |goscat |Render cats | |gosgif |Render animation GIF| |gosl |Run SL | ## Usage Encode ``` $ cat foo.png | gosr - ``` Decode ``` $ cat foo.drcs | gosd > foo.png ``` Use as library ```go img, _, _ := image.Decode(filename) sixel.NewEncoder(os.Stdout).Encode(img) ``` ## License MIT ## Author Yasuhiro Matsumoto (a.k.a mattn) go-sixel-0.0.5/_example/000077500000000000000000000000001430333327100150345ustar00rootroot00000000000000go-sixel-0.0.5/_example/goswebcam/000077500000000000000000000000001430333327100170035ustar00rootroot00000000000000go-sixel-0.0.5/_example/goswebcam/go.mod000066400000000000000000000003461430333327100201140ustar00rootroot00000000000000module github.com/mattn/go-sixel/_example/goswebcam go 1.18 require ( github.com/mattn/go-sixel v0.0.1 gocv.io/x/gocv v0.31.0 ) require github.com/soniakeys/quant v1.0.0 // indirect replace github.com/mattn/go-sixel => ../.. go-sixel-0.0.5/_example/goswebcam/go.sum000066400000000000000000000012721430333327100201400ustar00rootroot00000000000000github.com/hybridgroup/mjpeg v0.0.0-20140228234708-4680f319790e/go.mod h1:eagM805MRKrioHYuU7iKLUyFPVKqVV6um5DAvCkUtXs= github.com/mattn/go-sixel v0.0.1 h1:rhJSpux2xjsmXdXqY694uiEC0Rwxt6jYoq7Bahqo2xs= github.com/mattn/go-sixel v0.0.1/go.mod h1:zlzhYSuMbLdRdrxfutExxGpC+Pf2uUTJ6GpVQ4LB5dc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/soniakeys/quant v1.0.0 h1:N1um9ktjbkZVcywBVAAYpZYSHxEfJGzshHCxx/DaI0Y= github.com/soniakeys/quant v1.0.0/go.mod h1:HI1k023QuVbD4H8i9YdfZP2munIHU4QpjsImz6Y6zds= gocv.io/x/gocv v0.31.0 h1:BHDtK8v+YPvoSPQTTiZB2fM/7BLg6511JqkruY2z6LQ= gocv.io/x/gocv v0.31.0/go.mod h1:oc6FvfYqfBp99p+yOEzs9tbYF9gOrAQSeL/dyIPefJU= go-sixel-0.0.5/_example/goswebcam/main.go000066400000000000000000000015011430333327100202530ustar00rootroot00000000000000package main import ( "fmt" "log" "os" "os/signal" "time" "github.com/mattn/go-sixel" "gocv.io/x/gocv" ) func main() { webcam, err := gocv.VideoCaptureDevice(0) if err != nil { log.Fatal(err.Error()) } defer webcam.Close() webcam.Set(gocv.VideoCaptureFrameWidth, 300) webcam.Set(gocv.VideoCaptureFrameHeight, 200) loop := true sc := make(chan os.Signal, 1) signal.Notify(sc, os.Interrupt) go func() { <-sc loop = false }() im := gocv.NewMat() fmt.Print("\u001B[?25l") defer fmt.Print("\u001B[?25h") fmt.Print("\x1b[s") enc := sixel.NewEncoder(os.Stdout) for loop { if ok := webcam.Read(&im); !ok { continue } img, err := im.ToImage() if err != nil { continue } fmt.Print("\x1b[u") err = enc.Encode(img) if err != nil { break } time.Sleep(10 * time.Millisecond) } } go-sixel-0.0.5/_example/sixelview/000077500000000000000000000000001430333327100170535ustar00rootroot00000000000000go-sixel-0.0.5/_example/sixelview/go.mod000066400000000000000000000005571430333327100201700ustar00rootroot00000000000000module github.com/mattn/go-sixel/_example/sixelview go 1.18 require ( github.com/mattn/go-gtk v0.0.0-20191030024613-af2e013261f5 github.com/mattn/go-sixel v0.0.1 ) require ( github.com/mattn/go-pointer v0.0.1 // indirect github.com/soniakeys/quant v1.0.0 // indirect github.com/stretchr/testify v1.8.0 // indirect ) replace github.com/mattn/go-sixel => ../.. go-sixel-0.0.5/_example/sixelview/go.sum000066400000000000000000000036661430333327100202210ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/mattn/go-gtk v0.0.0-20191030024613-af2e013261f5 h1:GMB3MVJnxysGrSvjWGsgK8L3XGI3F4etQQq37Py6W5A= github.com/mattn/go-gtk v0.0.0-20191030024613-af2e013261f5/go.mod h1:PwzwfeB5syFHXORC3MtPylVcjIoTDT/9cvkKpEndGVI= github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0= github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= github.com/mattn/go-sixel v0.0.1 h1:rhJSpux2xjsmXdXqY694uiEC0Rwxt6jYoq7Bahqo2xs= github.com/mattn/go-sixel v0.0.1/go.mod h1:zlzhYSuMbLdRdrxfutExxGpC+Pf2uUTJ6GpVQ4LB5dc= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/soniakeys/quant v1.0.0 h1:N1um9ktjbkZVcywBVAAYpZYSHxEfJGzshHCxx/DaI0Y= github.com/soniakeys/quant v1.0.0/go.mod h1:HI1k023QuVbD4H8i9YdfZP2munIHU4QpjsImz6Y6zds= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= go-sixel-0.0.5/_example/sixelview/main.go000066400000000000000000000031121430333327100203230ustar00rootroot00000000000000package main import ( "bytes" "fmt" "github.com/mattn/go-gtk/gdkpixbuf" "github.com/mattn/go-gtk/gtk" "github.com/mattn/go-sixel" "image" "image/png" "os" "path/filepath" ) type Image struct { name string img image.Image } func main() { var images []Image if len(os.Args) == 1 { var in image.Image err := sixel.NewDecoder(os.Stdin).Decode(&in) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } images = append(images, Image{ name: "stdin", img: in}) } else { for _, arg := range os.Args[1:] { f, err := os.Open(arg) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } var in image.Image err = sixel.NewDecoder(f).Decode(&in) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } f.Close() images = append(images, Image{ name: filepath.Base(f.Name()), img: in}) } } gtk.Init(nil) window := gtk.NewWindow(gtk.WINDOW_TOPLEVEL) window.Connect("destroy", gtk.MainQuit) notebook := gtk.NewNotebook() for _, img := range images { var buf bytes.Buffer err := png.Encode(&buf, img.img) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } loader, gerr := gdkpixbuf.NewLoaderWithType("png") if gerr != nil { fmt.Fprintln(os.Stderr, gerr) os.Exit(1) } _, gerr = loader.Write(buf.Bytes()) if gerr != nil { fmt.Fprintln(os.Stderr, gerr) os.Exit(1) } gimg := gtk.NewImage() gimg.SetFromPixbuf(loader.GetPixbuf()) notebook.AppendPage(gimg, gtk.NewLabel(img.name)) } window.Add(notebook) window.SetTitle("SixelViewer") window.ShowAll() gtk.Main() } go-sixel-0.0.5/cmd/000077500000000000000000000000001430333327100140055ustar00rootroot00000000000000go-sixel-0.0.5/cmd/goscat/000077500000000000000000000000001430333327100152655ustar00rootroot00000000000000go-sixel-0.0.5/cmd/goscat/main.go000066400000000000000000000016121430333327100165400ustar00rootroot00000000000000package main import ( "bufio" "encoding/json" "image" _ "image/gif" _ "image/jpeg" _ "image/png" "log" "net/http" "os" "github.com/mattn/go-sixel" ) type item struct { ID string `json:"id"` URL string `json:"url"` Width int `json:"width"` Height int `json:"height"` } func main() { resp, err := http.Get("https://api.thecatapi.com/v1/images/search") if err != nil { log.Fatal(err) } defer resp.Body.Close() var items []item err = json.NewDecoder(resp.Body).Decode(&items) if err != nil { log.Fatal(err) } resp, err = http.Get(items[0].URL) if err != nil { log.Fatal(err) } defer resp.Body.Close() img, _, err := image.Decode(resp.Body) if err != nil { log.Fatal(err, items[0].URL) } buf := bufio.NewWriter(os.Stdout) defer buf.Flush() enc := sixel.NewEncoder(buf) enc.Dither = true err = enc.Encode(img) if err != nil { log.Fatal(err) } } go-sixel-0.0.5/cmd/gosd/000077500000000000000000000000001430333327100147415ustar00rootroot00000000000000go-sixel-0.0.5/cmd/gosd/main.go000066400000000000000000000013071430333327100162150ustar00rootroot00000000000000package main import ( "flag" "fmt" "image" "image/png" "os" "github.com/mattn/go-sixel" ) func main() { flag.Usage = func() { fmt.Println("Usage of " + os.Args[0] + ": gosd [filename]") flag.PrintDefaults() } flag.Parse() var img image.Image err := sixel.NewDecoder(os.Stdin).Decode(&img) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } if flag.NArg() == 0 { err = png.Encode(os.Stdout, img) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } } else { f, err := os.Create(flag.Arg(0)) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } err = png.Encode(f, img) if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } } } go-sixel-0.0.5/cmd/gosgif/000077500000000000000000000000001430333327100152635ustar00rootroot00000000000000go-sixel-0.0.5/cmd/gosgif/main.go000066400000000000000000000033741430333327100165450ustar00rootroot00000000000000package main import ( "fmt" "image" "image/color/palette" "image/draw" "image/gif" "io" "log" "math" "os" "strings" "syscall" "time" "unsafe" "github.com/mattn/go-sixel" ) type window struct { Row uint16 Col uint16 Xpixel uint16 Ypixel uint16 } func main() { var r io.Reader if len(os.Args) > 1 { f, err := os.Open(os.Args[1]) if err != nil { log.Fatal(err) } defer f.Close() r = f } else { r = os.Stdin } g, err := gif.DecodeAll(r) if err != nil { log.Fatal(err) } fmt.Print("\x1b[s") enc := sixel.NewEncoder(os.Stdout) enc.Width = g.Config.Width enc.Height = g.Config.Height var w window _, _, err = syscall.Syscall(syscall.SYS_IOCTL, os.Stdout.Fd(), syscall.TIOCGWINSZ, uintptr(unsafe.Pointer(&w)), ) if w.Xpixel > 0 && w.Ypixel > 0 && w.Col > 0 && w.Row > 0 { height := float64(w.Ypixel) / float64(w.Row) lines := int(math.Ceil(float64(enc.Height) / height)) fmt.Print(strings.Repeat("\n", lines)) fmt.Printf("\x1b[%dA", lines) fmt.Print("\x1b[s") } var back draw.Image if g.BackgroundIndex != 0 { back = image.NewPaletted(g.Image[0].Bounds(), palette.WebSafe) } for { t := time.Now() for j := 0; j < len(g.Image); j++ { fmt.Print("\x1b[u") if back != nil { draw.Draw(back, back.Bounds(), &image.Uniform{g.Image[j].Palette[g.BackgroundIndex]}, image.Pt(0, 0), draw.Src) draw.Draw(back, back.Bounds(), g.Image[j], image.Pt(0, 0), draw.Src) err = enc.Encode(back) } else { err = enc.Encode(g.Image[j]) } if err != nil { return } span := time.Second * time.Duration(g.Delay[j]) / 100 if time.Now().Sub(t) < span { time.Sleep(span) } t = time.Now() } if g.LoopCount != 0 { g.LoopCount-- if g.LoopCount == 0 { break } } } } go-sixel-0.0.5/cmd/gosl/000077500000000000000000000000001430333327100147515ustar00rootroot00000000000000go-sixel-0.0.5/cmd/gosl/main.go000066400000000000000000000016121430333327100162240ustar00rootroot00000000000000package main import ( "bytes" "embed" "image/png" "log" "os" "strings" "time" "github.com/mattn/go-sixel" ) //go:embed public var fs embed.FS func loadImage(fs embed.FS, n string) []byte { f, err := fs.Open(n) if err != nil { log.Fatal(err) } defer f.Close() img, err := png.Decode(f) if err != nil { log.Fatal(err) } var buf bytes.Buffer err = sixel.NewEncoder(&buf).Encode(img) if err != nil { log.Fatal(err) } return buf.Bytes() } func main() { var img [4][]byte img[0] = loadImage(fs, "public/data01.png") img[1] = loadImage(fs, "public/data02.png") img[2] = loadImage(fs, "public/data03.png") img[3] = img[1] w := os.Stdout w.Write([]byte("\x1b[?25l\x1b[s")) for i := 0; i < 70; i++ { w.Write([]byte("\x1b[u")) w.Write([]byte(strings.Repeat(" ", i))) w.Write(img[i%4]) w.Sync() time.Sleep(100 * time.Millisecond) } w.Write([]byte("\r\x1b[?25h")) } go-sixel-0.0.5/cmd/gosl/public/000077500000000000000000000000001430333327100162275ustar00rootroot00000000000000go-sixel-0.0.5/cmd/gosl/public/data01.png000066400000000000000000000136221430333327100200130ustar00rootroot00000000000000PNG  IHDR22?gAMA a =iCCPicmxڝSgTS=BKKoR RBTi@숨"q"Ay((6T}7o9g}>F`DdJ<6.'w T @- m@n8P $ B2r22 t%[j;eOv$(S*@@&X`(ʑs`̔`)d` SGE3(xW\!Sd咔Tn!\]x87CP؄ ee3FvD9;:;8:|?E񋖴e /B_TBfgk+ m_ _׃  2r<[&q?.wL'bPGKĹi ˒$ IHk`~B[P. %w߂1w0hْ 4P6h>؀#;x̆P8XBHLC.,UP%BZF8-p<^0 o`A2DX6b"ֈ#Ef!~H0!H "ERd5R#U^9E.!==F~C>@٨jڡ\ Bh G h%ZBѳڋ>G03l0.Bx,c˱b6b#{";!0 $,",'̈́ Ba$nD>1B%+uc[!\H8Ri D:C!d6ٚA% ry;4:yBP)xR@\ RƩjTS5*.Qkmԫ8MfNEhhFyC+:nDw%JaEz=Ca1J~=+&ib3 z9c; _EBZY U| գWUGԨjfj<5rjjwY/i544D4i01VjYYlۜgK߱٣34545Ojr0qpns>Lћ=Ejkh4km8ndn4ר1͘klŸx$dI}S)4ti[3sf-fCZ||L OE57-I\t˝׬P+'Tj֨zu44ii50lmrlll9-/L6u}wϰ0ۡ7G+GcWLor ]3:B:;}rvq;7:$pesø܋DW'\߻9)܎n~}hLڙFY4xx>2yy z[zy~c#9[;vi{o?$L 10(pS_ȯvlvG#(2*IU<- 999-(yr`GryPGTԊ OR%y;mzh􉌘LJfbq4]ڑ#z-ںhT$Fg* Ki\˙S.7:hz4k]BX"\Ҿp骥}˼],OZ޾xEኁ+J_S}Ay1 W XPR$/}uuu맯߾sr}IERaofbC2]Ioot\<s--.zbFmmmMo*VOuw)y}׮zKv#swo}}9Fv~N~:],k@ Ç]FƽMpXy>t(h?8:V܌4/nmImmk9>x{{۱mDI͓eh OM?=vFvflŞ}> uzwq%K/s/\qu'u;w7_uzZ[̞S={M+=; wz˸~+?R{TXqϖ?7:zA?q)iŠ`Љak=x.{>>R/;^XW_FcG^_NVJ3^=~fm;wsw~08姶ANdNL\I 2 cHRMz&u0`:pQ<bKGDC pHYs\F\FCA IDATh޽ytSǿvYb[} h ФғC{&t3d:NOII9m4)tL$BĀYalw"ٲlZ~1f?Ͻw},tUylCBU*,C>;?Og?T|YNƲ-S@jkT[sA4璥PGH.ȱ|synvQ70һy DxG5pu2CnƇNR(¾@$7Ìaoo߲̺ǘ]R>J˛iRttt#H2kFc[ x& 9|)vohZ. |m̝Ol|(aɌ!Jnr <)4/֖Fu-xfZ4*iN#cY&&nSyxj.ޤSk`+odGݻL.^%YXUfJ!\&/_;|;aA& G<֬(|e^Rƃ,aXP\R >J)c_DXTmeظ/&,J)@>X^T.T.1#@ch8Fڿk.TWW_JƁcYP H$,Aanzɘ]ȂB_zoʪzsɎg_ug-p9w@BUp";;qZ-.zL00&R(g.Te D9x}ٷmx'`|`ӎ琛 Bɓ'=B(OGpʍNtɐJex\ޫ_ ?- 0 B.\*If[lCQ̙XC}KvlZLKgH;֜8quuuO30”ŵuT PUNM GQfX1f`ҖݑKfJů(PRLZ1;aPZZ5\ nrXx(e: 8PEÚmyTRd)]ã㱃"úVw٬;ظ/?+umСPȤ0!0XVvk}UU***@  : X@"ڻըbpeͫˬr3]o| #UeַmVx>gbjr[ eY4Ϡӱ}c%ʋsR=9CJRrL ow\&E] C@)5}e]+Yڟ?dA)eP@C/å3fE!*J 3As 2XY;PJ!8pk;\kh1D^.r -7/#TQֳhr2J)Gy*4g KA%Rt(,,SC͟g.}FjrªGǩG(e~ars2+W?`E$""%IJ)XE.)z%HWcaj0aPe*D)D!N 5u{D(230|8x>,1',c^Ra0̭;S Җנ{ C GF$djК h5*tM._q\±(F ܬk\M]f+Rps_ێg.50'jqܬin@qqҸW~ˌ 0{ ^0mЁNt-+D"Aa03.@!^2K-hGYiZ:D)v >I0 !"SyCw4uHh B)G<9U @1⹿߃'{ nQ gC6!HJ ĹRC$0KX`bB(赣fCOۃYӡcy-ҢA]RchC =Ã7PO"9A7Af Ӥ9=@iZQB..xoJ[OIO+;R9f;7&H$*`8{jϐõ`PJ1HAob3vJ!N@a}w\; o=%H" 9G{WX> 4ׄ(fȴu\A>4? ˜3Ysdu1[D2?)@ZIENDB`go-sixel-0.0.5/cmd/gosl/public/data02.png000066400000000000000000000136021430333327100200120ustar00rootroot00000000000000PNG  IHDR22?gAMA a =iCCPicmxڝSgTS=BKKoR RBTi@숨"q"Ay((6T}7o9g}>F`DdJ<6.'w T @- m@n8P $ B2r22 t%[j;eOv$(S*@@&X`(ʑs`̔`)d` SGE3(xW\!Sd咔Tn!\]x87CP؄ ee3FvD9;:;8:|?E񋖴e /B_TBfgk+ m_ _׃  2r<[&q?.wL'bPGKĹi ˒$ IHk`~B[P. %w߂1w0hْ 4P6h>؀#;x̆P8XBHLC.,UP%BZF8-p<^0 o`A2DX6b"ֈ#Ef!~H0!H "ERd5R#U^9E.!==F~C>@٨jڡ\ Bh G h%ZBѳڋ>G03l0.Bx,c˱b6b#{";!0 $,",'̈́ Ba$nD>1B%+uc[!\H8Ri D:C!d6ٚA% ry;4:yBP)xR@\ RƩjTS5*.Qkmԫ8MfNEhhFyC+:nDw%JaEz=Ca1J~=+&ib3 z9c; _EBZY U| գWUGԨjfj<5rjjwY/i544D4i01VjYYlۜgK߱٣34545Ojr0qpns>Lћ=Ejkh4km8ndn4ר1͘klŸx$dI}S)4ti[3sf-fCZ||L OE57-I\t˝׬P+'Tj֨zu44ii50lmrlll9-/L6u}wϰ0ۡ7G+GcWLor ]3:B:;}rvq;7:$pesø܋DW'\߻9)܎n~}hLڙFY4xx>2yy z[zy~c#9[;vi{o?$L 10(pS_ȯvlvG#(2*IU<- 999-(yr`GryPGTԊ OR%y;mzh􉌘LJfbq4]ڑ#z-ںhT$Fg* Ki\˙S.7:hz4k]BX"\Ҿp骥}˼],OZ޾xEኁ+J_S}Ay1 W XPR$/}uuu맯߾sr}IERaofbC2]Ioot\<s--.zbFmmmMo*VOuw)y}׮zKv#swo}}9Fv~N~:],k@ Ç]FƽMpXy>t(h?8:V܌4/nmImmk9>x{{۱mDI͓eh OM?=vFvflŞ}> uzwq%K/s/\qu'u;w7_uzZ[̞S={M+=; wz˸~+?R{TXqϖ?7:zA?q)iŠ`Љak=x.{>>R/;^XW_FcG^_NVJ3^=~fm;wsw~08姶ANdNL\I 2 cHRMz&u0`:pQ<bKGDC pHYs\F\FCA IDATh޽Yip[u{B, NDJ4EZ"idɭeRܑk'uո3Ǚqt<ؕݩtrlVl9J+Yi iR nP)K" =~ιGΖeN34n./n88RGBFg>y*J {C(QԺd=6ݗm(/9ZY8#=bMٲZp29\cQ͌\>xFlln#p3nWK{+'?l>V*cpHYQSOz7L:gl`G`0R̯gу.(:cr8Ʃ=rC-p`Yǣ{v>}o*9j2 C`ADaƁC߄\.[sU8q, v>œvU Z2IMtBF ! t=z`kJRv@ffQ㭷ނW"Ub4ZR*T G>( .\@po ڒ'~c[],[rϑH4 BP(A`]]rssQlDQU< Q+ӳѤYB(`ozOy\2gA Ω?3hii /˲8l*AEi~S)$?) k?{ /[n.SmxĎ]{`ZQMjn Ab~* Pl#G8^GOHc0003-)y$R[QYOsmi#O,sرg102X4Zk>~S0o\Gv o!l+yx<15j-ΝO&dŪ2Gv|0gvWT;Ɯ={غu+Z@H@98]PHI@!;UBmYѥ`,6{ !J olؤnG}'5j%&E;|0v;jjjPkW]7TZ742-EMQ^pFUQS3F+n ڭ-E9&*r6*7550xoocjFK@!6V ۋ ;{Ʋ#G(FSZ=?BYa\eg!,ˢ-R)j%e2dRUJ3^ #BkS]@RGl)ѿ24*NE!qO#ŎJהA0<Ø+X+J)d223OLw6lwۆ@ EP+P^ !P)yԕe`)z/y,dX >|Ɲ^VlEFtȸ+bnHk7>QM )-)Ҹ In˂eYSY'IQ"͠Ü/܇5ĭ ?a ,Ъ`/Jg.Y6mYVVflkkHsss1]酭wkz)!wF/QKT~G#DYYʥ Zύ9xf=?rϭ'SfJ SݑH ]gFd25~ChbxbƝcFJ`Y6X,1 HTB(%i? $3GX+% $w8ǥdݬjH._w\xlA-B}A:9vq}&8$F}P)Bf<^_ $QJ#֠|(p,/(joow\LU'ޞv@0EOXD)s~D"ۀRa>j~sŦWӞHsggɁQg?WY7euʒ#jU䗄cWee9r5eوhDﭑo9~ca'VSPSc?;n[ϟh=?,\.``2> Ҝ/0{;C& SKݞh,6 &+bxsi׮]C4 nYpr:k}O?IENDB`go-sixel-0.0.5/cmd/gosl/public/data03.png000066400000000000000000000136511430333327100200170ustar00rootroot00000000000000PNG  IHDR22?gAMA a =iCCPicmxڝSgTS=BKKoR RBTi@숨"q"Ay((6T}7o9g}>F`DdJ<6.'w T @- m@n8P $ B2r22 t%[j;eOv$(S*@@&X`(ʑs`̔`)d` SGE3(xW\!Sd咔Tn!\]x87CP؄ ee3FvD9;:;8:|?E񋖴e /B_TBfgk+ m_ _׃  2r<[&q?.wL'bPGKĹi ˒$ IHk`~B[P. %w߂1w0hْ 4P6h>؀#;x̆P8XBHLC.,UP%BZF8-p<^0 o`A2DX6b"ֈ#Ef!~H0!H "ERd5R#U^9E.!==F~C>@٨jڡ\ Bh G h%ZBѳڋ>G03l0.Bx,c˱b6b#{";!0 $,",'̈́ Ba$nD>1B%+uc[!\H8Ri D:C!d6ٚA% ry;4:yBP)xR@\ RƩjTS5*.Qkmԫ8MfNEhhFyC+:nDw%JaEz=Ca1J~=+&ib3 z9c; _EBZY U| գWUGԨjfj<5rjjwY/i544D4i01VjYYlۜgK߱٣34545Ojr0qpns>Lћ=Ejkh4km8ndn4ר1͘klŸx$dI}S)4ti[3sf-fCZ||L OE57-I\t˝׬P+'Tj֨zu44ii50lmrlll9-/L6u}wϰ0ۡ7G+GcWLor ]3:B:;}rvq;7:$pesø܋DW'\߻9)܎n~}hLڙFY4xx>2yy z[zy~c#9[;vi{o?$L 10(pS_ȯvlvG#(2*IU<- 999-(yr`GryPGTԊ OR%y;mzh􉌘LJfbq4]ڑ#z-ںhT$Fg* Ki\˙S.7:hz4k]BX"\Ҿp骥}˼],OZ޾xEኁ+J_S}Ay1 W XPR$/}uuu맯߾sr}IERaofbC2]Ioot\<s--.zbFmmmMo*VOuw)y}׮zKv#swo}}9Fv~N~:],k@ Ç]FƽMpXy>t(h?8:V܌4/nmImmk9>x{{۱mDI͓eh OM?=vFvflŞ}> uzwq%K/s/\qu'u;w7_uzZ[̞S={M+=; wz˸~+?R{TXqϖ?7:zA?q)iŠ`Љak=x.{>>R/;^XW_FcG^_NVJ3^=~fm;wsw~08姶ANdNL\I 2 cHRMz&u0`:pQ<bKGDC pHYs\F\FCA IDATh޽{pT}ǿ޻{>/=V[Z@,8 iMgڙI=tL3ImvƝ8 gxFHA zڗVjwIE~99W,L}seUicPa\LJ|!mOP[^o.ο1l9=0l9"J\xc󟪩,:h4TY_LVl'cn=!7FNh5M !c>{aB^|Yxi,}J!=+=C(#_Ǡ=nz/S3ÿUα=k^ ˲h]ota,)Dy#6rٝ18r~ <#us`C潇EEEOx'O /< c1l2! }f6r~Wt c}a.2k+//:ecM +f-?o?%;15JJJikkCgg'Ř Eg4:6iijDfgQ[b\p+zg3a :s߾wW$˂<phw6ֵo(}ZRwvrQ<łzy2N}ك 4(9q;-B-j eHS+Ja95:!Da* Y\AX$ (@WEt!4v6֠Xc?&s9 ,rnB& 8趍ށT] E* 2JJ!<9&_υ`4=7 VA_RѴ/oAZnJRa⼭M͐$i-(XE. &FY:%iq,2Z غ1 DP BqPţgm}nKl1Ѹōy syYZpl]*Bq18/tdQ⢈o%<~86M'BתQ@;'!$IwP)f?yMMMl>rȧ;1Vveg$YbQ AQ^.I'AoR@A=˪ۃgZحj, Y&A?|e8DQw#, e)|+ΛTޱ?Jp}r?kJy1@]5B~ndXqΤd17VR RB@q%:YQQ y}G G5ey]Iw+3{ xfVomobքr["=}?MNR 5K3m'/^Ą77OoZ.chnHMkANVW^w}ZN[,RJ=YpYhar`E"2mm6j)d*ym>I$%(PBOH<đߞ|b20A$*!F$$iA 0A(aqLM&8NXV7# Ą$iԪ B?r9b`YݔAIF耲PJLN8ƔnʮE!Td$dXي)0 ,!Dw] }rZNϽ莝Wk rB5f$f@;P$XrIEJi,~-8;yŢajs{]Wo^tHW:Y?/\?awERs RTT3Ry#6OI$X+̢.0$`<|g_!$5WJm<&x ../.. go-sixel-0.0.5/cmd/gosr/go.sum000066400000000000000000000006341430333327100161150ustar00rootroot00000000000000github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966 h1:lTG4HQym5oPKjL7nGs+csTgiDna685ZXjxijkne828g= github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966/go.mod h1:Mid70uvE93zn9wgF92A/r5ixgnvX8Lh68fxp9KQBaI0= github.com/soniakeys/quant v1.0.0 h1:N1um9ktjbkZVcywBVAAYpZYSHxEfJGzshHCxx/DaI0Y= github.com/soniakeys/quant v1.0.0/go.mod h1:HI1k023QuVbD4H8i9YdfZP2munIHU4QpjsImz6Y6zds= go-sixel-0.0.5/cmd/gosr/main.go000066400000000000000000000043051430333327100162340ustar00rootroot00000000000000package main import ( "bufio" "flag" "fmt" "image" _ "image/gif" _ "image/jpeg" _ "image/png" "math" "os" "github.com/BurntSushi/graphics-go/graphics" "github.com/mattn/go-sixel" ) var ( fBlur = flag.String("blur", "", "Blur image by [Dev,Size]") fResize = flag.String("resize", "", "Resize image by [WxH]") fRotate = flag.Float64("rotate", 0.0, "Rotate image by [N] deg") ) func render(filename string) error { var f *os.File var err error if filename != "-" { f, err = os.Open(filename) if err != nil { return err } defer f.Close() } else { f = os.Stdin } img, _, err := image.Decode(f) if err != nil { return err } if *fResize != "" { var w, h uint fmt.Sscanf(*fResize, "%dx%d", &w, &h) rx := float64(img.Bounds().Dx()) / float64(w) ry := float64(img.Bounds().Dy()) / float64(h) if rx < ry { w = uint(float64(img.Bounds().Dx()) / ry) } else { h = uint(float64(img.Bounds().Dy()) / rx) } tmp := image.NewNRGBA64(image.Rect(0, 0, int(w), int(h))) err = graphics.Scale(tmp, img) if err != nil { return err } img = tmp } if *fRotate != 0.0 { d := math.Sqrt(math.Pow(float64(img.Bounds().Dx()), 2) + math.Pow(float64(img.Bounds().Dy()), 2)) sin, cos := math.Sincos(math.Atan2(float64(img.Bounds().Dx()), float64(img.Bounds().Dy())) + *fRotate) if sin < cos { sin = cos } else { cos = sin } tmp := image.NewNRGBA64(image.Rect(0, 0, int(cos*d), int(sin*d))) err = graphics.Rotate(tmp, img, &graphics.RotateOptions{*fRotate}) if err != nil { return err } img = tmp } if *fBlur != "" { var d float64 var s int fmt.Sscanf(*fBlur, "%f,%d", &d, &s) tmp := image.NewNRGBA64(img.Bounds()) err = graphics.Blur(tmp, img, &graphics.BlurOptions{d, s}) if err != nil { return err } img = tmp } buf := bufio.NewWriter(os.Stdout) defer buf.Flush() enc := sixel.NewEncoder(buf) enc.Dither = true return enc.Encode(img) } func main() { flag.Usage = func() { fmt.Println("Usage of " + os.Args[0] + ": gosr [images]") flag.PrintDefaults() } flag.Parse() if flag.NArg() == 0 { flag.Usage() os.Exit(1) } for _, arg := range flag.Args() { err := render(arg) if err != nil { fmt.Fprintln(os.Stderr, err) } } } go-sixel-0.0.5/go.mod000066400000000000000000000001251430333327100143460ustar00rootroot00000000000000module github.com/mattn/go-sixel go 1.16 require github.com/soniakeys/quant v1.0.0 go-sixel-0.0.5/go.sum000066400000000000000000000002531430333327100143750ustar00rootroot00000000000000github.com/soniakeys/quant v1.0.0 h1:N1um9ktjbkZVcywBVAAYpZYSHxEfJGzshHCxx/DaI0Y= github.com/soniakeys/quant v1.0.0/go.mod h1:HI1k023QuVbD4H8i9YdfZP2munIHU4QpjsImz6Y6zds= go-sixel-0.0.5/sixel.go000066400000000000000000000271271430333327100147260ustar00rootroot00000000000000package sixel import ( "bufio" "bytes" "errors" "fmt" "image" "image/color" "image/draw" "io" "os" "github.com/soniakeys/quant/median" ) // Encoder encode image to sixel format type Encoder struct { w io.Writer // Dither, if true, will dither the image when generating a paletted version // using the Floyd–Steinberg dithering algorithm. Dither bool // Width is the maximum width to draw to. Width int // Height is the maximum height to draw to. Height int // Colors sets the number of colors for the encoder to quantize if needed. // If the value is below 2 (e.g. the zero value), then 255 is used. // A color is always reserved for alpha, so 2 colors give you 1 color. Colors int } // NewEncoder return new instance of Encoder func NewEncoder(w io.Writer) *Encoder { return &Encoder{w: w} } const ( specialChNr = byte(0x6d) specialChCr = byte(0x64) ) // Encode do encoding func (e *Encoder) Encode(img image.Image) error { nc := e.Colors // (>= 2, 8bit, index 0 is reserved for transparent key color) if nc < 2 { nc = 255 } width, height := img.Bounds().Dx(), img.Bounds().Dy() if width == 0 || height == 0 { return nil } if e.Width > 0 { width = e.Width } if e.Height > 0 { height = e.Height } var paletted *image.Paletted // fast path for paletted images if p, ok := img.(*image.Paletted); ok && len(p.Palette) < int(nc) { paletted = p } else { // make adaptive palette using median cut alogrithm q := median.Quantizer(nc - 1) paletted = q.Paletted(img) if e.Dither { // copy source image to new image with applying floyd-stenberg dithering draw.FloydSteinberg.Draw(paletted, img.Bounds(), img, image.Point{}) } else { draw.Draw(paletted, img.Bounds(), img, image.Point{}, draw.Over) } } // use on-memory output buffer for improving the performance var w io.Writer if _, ok := e.w.(*os.File); ok { w = bytes.NewBuffer(make([]byte, 0, 1024*32)) } else { w = e.w } // DECSIXEL Introducer(\033P0;0;8q) + DECGRA ("1;1): Set Raster Attributes w.Write([]byte{0x1b, 0x50, 0x30, 0x3b, 0x30, 0x3b, 0x38, 0x71, 0x22, 0x31, 0x3b, 0x31}) for n, v := range paletted.Palette { r, g, b, _ := v.RGBA() r = r * 100 / 0xFFFF g = g * 100 / 0xFFFF b = b * 100 / 0xFFFF // DECGCI (#): Graphics Color Introducer fmt.Fprintf(w, "#%d;2;%d;%d;%d", n+1, r, g, b) } buf := make([]byte, width*nc) cset := make([]bool, nc) ch0 := specialChNr for z := 0; z < (height+5)/6; z++ { // DECGNL (-): Graphics Next Line if z > 0 { w.Write([]byte{0x2d}) } for p := 0; p < 6; p++ { y := z*6 + p for x := 0; x < width; x++ { _, _, _, alpha := img.At(x, y).RGBA() if alpha != 0 { idx := paletted.ColorIndexAt(x, y) + 1 cset[idx] = false // mark as used buf[width*int(idx)+x] |= 1 << uint(p) } } } for n := 1; n < nc; n++ { if cset[n] { continue } cset[n] = true // DECGCR ($): Graphics Carriage Return if ch0 == specialChCr { w.Write([]byte{0x24}) } // select color (#%d) if n >= 100 { digit1 := n / 100 digit2 := (n - digit1*100) / 10 digit3 := n % 10 c1 := byte(0x30 + digit1) c2 := byte(0x30 + digit2) c3 := byte(0x30 + digit3) w.Write([]byte{0x23, c1, c2, c3}) } else if n >= 10 { c1 := byte(0x30 + n/10) c2 := byte(0x30 + n%10) w.Write([]byte{0x23, c1, c2}) } else { w.Write([]byte{0x23, byte(0x30 + n)}) } cnt := 0 for x := 0; x < width; x++ { // make sixel character from 6 pixels ch := buf[width*n+x] buf[width*n+x] = 0 if ch0 < 0x40 && ch != ch0 { // output sixel character s := 63 + ch0 for ; cnt > 255; cnt -= 255 { w.Write([]byte{0x21, 0x32, 0x35, 0x35, s}) } if cnt == 1 { w.Write([]byte{s}) } else if cnt == 2 { w.Write([]byte{s, s}) } else if cnt == 3 { w.Write([]byte{s, s, s}) } else if cnt >= 100 { digit1 := cnt / 100 digit2 := (cnt - digit1*100) / 10 digit3 := cnt % 10 c1 := byte(0x30 + digit1) c2 := byte(0x30 + digit2) c3 := byte(0x30 + digit3) // DECGRI (!): - Graphics Repeat Introducer w.Write([]byte{0x21, c1, c2, c3, s}) } else if cnt >= 10 { c1 := byte(0x30 + cnt/10) c2 := byte(0x30 + cnt%10) // DECGRI (!): - Graphics Repeat Introducer w.Write([]byte{0x21, c1, c2, s}) } else if cnt > 0 { // DECGRI (!): - Graphics Repeat Introducer w.Write([]byte{0x21, byte(0x30 + cnt), s}) } cnt = 0 } ch0 = ch cnt++ } if ch0 != 0 { // output sixel character s := 63 + ch0 for ; cnt > 255; cnt -= 255 { w.Write([]byte{0x21, 0x32, 0x35, 0x35, s}) } if cnt == 1 { w.Write([]byte{s}) } else if cnt == 2 { w.Write([]byte{s, s}) } else if cnt == 3 { w.Write([]byte{s, s, s}) } else if cnt >= 100 { digit1 := cnt / 100 digit2 := (cnt - digit1*100) / 10 digit3 := cnt % 10 c1 := byte(0x30 + digit1) c2 := byte(0x30 + digit2) c3 := byte(0x30 + digit3) // DECGRI (!): - Graphics Repeat Introducer w.Write([]byte{0x21, c1, c2, c3, s}) } else if cnt >= 10 { c1 := byte(0x30 + cnt/10) c2 := byte(0x30 + cnt%10) // DECGRI (!): - Graphics Repeat Introducer w.Write([]byte{0x21, c1, c2, s}) } else if cnt > 0 { // DECGRI (!): - Graphics Repeat Introducer w.Write([]byte{0x21, byte(0x30 + cnt), s}) } } ch0 = specialChCr } } // string terminator(ST) w.Write([]byte{0x1b, 0x5c}) // copy to given buffer if _, ok := e.w.(*os.File); ok { w.(*bytes.Buffer).WriteTo(e.w) } return nil } // Decoder decode sixel format into image type Decoder struct { r io.Reader } // NewDecoder return new instance of Decoder func NewDecoder(r io.Reader) *Decoder { return &Decoder{r} } // Decode do decoding from image func (e *Decoder) Decode(img *image.Image) error { buf := bufio.NewReader(e.r) _, err := buf.ReadBytes('\x1B') if err != nil { if err == io.EOF { err = nil } return err } c, err := buf.ReadByte() if err != nil { return err } switch c { case 'P': _, err := buf.ReadString('q') if err != nil { return err } default: return errors.New("Invalid format: illegal header") } colors := map[uint]color.Color{ // 16 predefined color registers of VT340 0: sixelRGB(0, 0, 0), 1: sixelRGB(20, 20, 80), 2: sixelRGB(80, 13, 13), 3: sixelRGB(20, 80, 20), 4: sixelRGB(80, 20, 80), 5: sixelRGB(20, 80, 80), 6: sixelRGB(80, 80, 20), 7: sixelRGB(53, 53, 53), 8: sixelRGB(26, 26, 26), 9: sixelRGB(33, 33, 60), 10: sixelRGB(60, 26, 26), 11: sixelRGB(33, 60, 33), 12: sixelRGB(60, 33, 60), 13: sixelRGB(33, 60, 60), 14: sixelRGB(60, 60, 33), 15: sixelRGB(80, 80, 80), } dx, dy := 0, 0 dw, dh, w, h := 0, 0, 200, 200 pimg := image.NewNRGBA(image.Rect(0, 0, w, h)) var cn uint data: for { c, err = buf.ReadByte() if err != nil { if err == io.EOF { err = nil } return err } if c == '\r' || c == '\n' || c == '\b' { continue } switch { case c == '\x1b': c, err = buf.ReadByte() if err != nil { return err } if c == '\\' { break data } case c == '"': params := []int{} for { var i int n, err := fmt.Fscanf(buf, "%d", &i) if err == io.EOF { return err } if n == 0 { i = 0 } params = append(params, i) c, err = buf.ReadByte() if err != nil { return err } if c != ';' { break } } if len(params) >= 4 { if w < params[2] { w = params[2] } if h < params[3]+6 { h = params[3] + 6 } pimg = expandImage(pimg, w, h) } err = buf.UnreadByte() if err != nil { return err } case c == '$': dx = 0 case c == '!': err = buf.UnreadByte() if err != nil { return err } var nc uint var c byte n, err := fmt.Fscanf(buf, "!%d%c", &nc, &c) if err != nil { return err } if n != 2 || c < '?' || c > '~' { return fmt.Errorf("invalid format: illegal repeating data tokens '!%d%c'", nc, c) } if w <= dx+int(nc)-1 { w *= 2 pimg = expandImage(pimg, w, h) } m := byte(1) c -= '?' for p := 0; p < 6; p++ { if c&m != 0 { for q := 0; q < int(nc); q++ { pimg.Set(dx+q, dy+p, colors[cn]) } if dh < dy+p+1 { dh = dy + p + 1 } } m <<= 1 } dx += int(nc) if dw < dx { dw = dx } case c == '-': dx = 0 dy += 6 if h <= dy+6 { h *= 2 pimg = expandImage(pimg, w, h) } case c == '#': err = buf.UnreadByte() if err != nil { return err } var nc, csys uint var r, g, b uint var c byte n, err := fmt.Fscanf(buf, "#%d%c", &nc, &c) if err != nil { return err } if n != 2 { return fmt.Errorf("invalid format: illegal color specifier '#%d%c'", nc, c) } if c == ';' { n, err := fmt.Fscanf(buf, "%d;%d;%d;%d", &csys, &r, &g, &b) if err != nil { return err } if n != 4 { return fmt.Errorf("invalid format: illegal color specifier '#%d;%d;%d;%d;%d'", nc, csys, r, g, b) } if csys == 1 { colors[nc] = sixelHLS(r, g, b) } else { colors[nc] = sixelRGB(r, g, b) } } else { err = buf.UnreadByte() if err != nil { return err } } cn = nc if _, ok := colors[cn]; !ok { return fmt.Errorf("invalid format: undefined color number %d", cn) } default: if c >= '?' && c <= '~' { if w <= dx { w *= 2 pimg = expandImage(pimg, w, h) } m := byte(1) c -= '?' for p := 0; p < 6; p++ { if c&m != 0 { pimg.Set(dx, dy+p, colors[cn]) if dh < dy+p+1 { dh = dy + p + 1 } } m <<= 1 } dx++ if dw < dx { dw = dx } break } return errors.New("invalid format: illegal data tokens") } } rect := image.Rect(0, 0, dw, dh) tmp := image.NewNRGBA(rect) draw.Draw(tmp, rect, pimg, image.Point{0, 0}, draw.Src) *img = tmp return nil } func sixelRGB(r, g, b uint) color.Color { return color.NRGBA{uint8(r * 0xFF / 100), uint8(g * 0xFF / 100), uint8(b * 0xFF / 100), 0xFF} } func sixelHLS(h, l, s uint) color.Color { var r, g, b, max, min float64 /* https://wikimedia.org/api/rest_v1/media/math/render/svg/17e876f7e3260ea7fed73f69e19c71eb715dd09d */ /* https://wikimedia.org/api/rest_v1/media/math/render/svg/f6721b57985ad83db3d5b800dc38c9980eedde1d */ if l > 50 { max = float64(l) + float64(s)*(1.0-float64(l)/100.0) min = float64(l) - float64(s)*(1.0-float64(l)/100.0) } else { max = float64(l) + float64(s*l)/100.0 min = float64(l) - float64(s*l)/100.0 } /* sixel hue color ring is roteted -120 degree from nowdays general one. */ h = (h + 240) % 360 /* https://wikimedia.org/api/rest_v1/media/math/render/svg/937e8abdab308a22ff99de24d645ec9e70f1e384 */ switch h / 60 { case 0: /* 0 <= hue < 60 */ r = max g = min + (max-min)*(float64(h)/60.0) b = min break case 1: /* 60 <= hue < 120 */ r = min + (max-min)*(float64(120-h)/60.0) g = max b = min break case 2: /* 120 <= hue < 180 */ r = min g = max b = min + (max-min)*(float64(h-120)/60.0) break case 3: /* 180 <= hue < 240 */ r = min g = min + (max-min)*(float64(240-h)/60.0) b = max break case 4: /* 240 <= hue < 300 */ r = min + (max-min)*(float64(h-240)/60.0) g = min b = max break case 5: /* 300 <= hue < 360 */ r = max g = min b = min + (max-min)*(float64(360-h)/60.0) break default: } return sixelRGB(uint(r), uint(g), uint(b)) } func expandImage(pimg *image.NRGBA, w, h int) *image.NRGBA { b := pimg.Bounds() if w < b.Max.X { w = b.Max.X } if h < b.Max.Y { h = b.Max.Y } tmp := image.NewNRGBA(image.Rect(0, 0, w, h)) draw.Draw(tmp, b, pimg, image.Point{0, 0}, draw.Src) return tmp }