okami.mom/ultraviolet
git clone https://git.nkp.pet/okami.mom/ultraviolet
c103292
main
1package main 2 3import ( 4"bytes" 5"encoding/base64" 6"fmt" 7"image" 8"image/color" 9"image/png" 10"log" 11"math/rand" 12"os" 13"path/filepath" 14"strings" 15 16 uv"github.com/charmbracelet/ultraviolet" 17"github.com/charmbracelet/ultraviolet/screen" 18"github.com/charmbracelet/x/ansi" 19"github.com/charmbracelet/x/ansi/iterm2" 20) 21 22func main () { 23t := uv .DefaultTerminal () 24 25if err := t .Start ();err != nil { 26log .Fatalln ("error starting terminal:" ,err ) 27 } 28defer t .Stop () 29 30scr := t .Screen () 31scr .EnterAltScreen () 32 33var keypress string 34var cellWidth ,cellHeight int 35 36tmpDir ,_ := os .MkdirTemp ("" ,"uv-rgbimage-example" ) 37defer os .RemoveAll (tmpDir ) 38 39createEncodedImage := func (w ,h int ,col color.Color )string { 40img := createImage (w * cellWidth ,h * cellHeight ,col ) 41png := imagePng (img ) 42if err := os .WriteFile (filepath .Join (tmpDir ,fmt .Sprintf ("img_%d_%d.png" ,w ,h )),png ,0o644 );err != nil { 43log .Println ("error writing png file:" ,err ) 44 } 45return dataBase64 (png ) 46 } 47 48var imgXOffset ,imgYOffset int 49display := func () { 50screen .Clear (scr ) 51text := fmt .Sprintf ("Press any key to see its value. Press 'ctrl+c' to quit.\n\nLast key pressed: %s" ,keypress ) 52nlines := strings .Count (text ,"\n" )+ 1 53ss := uv .NewStyledString (text ) 54bounds := scr .Bounds () 55if bounds .Empty () { 56return 57 } 58 59center := uv .Rect ( 60 (bounds .Max .X - ss .UnicodeWidth ())/ 2 , 61 (bounds .Max .Y - nlines )/ 2 , 62ss .UnicodeWidth (), 63nlines , 64 ) 65ss .Draw (scr ,center ) 66scr .Render () 67 68const imgW ,imgH = 10 ,5 69col := ansi .IndexedColor (rand .Intn (256 )) 70encodedPngImg := createEncodedImage (imgW ,imgH ,col ) 71centerImg := uv .Rect ( 720 + imgXOffset , 730 + imgYOffset , 74// ((bounds.Max.X-imgW)/2)+imgXOffset, 75// ((bounds.Max.Y-imgH)/2)+imgYOffset, 76imgW , 77imgH , 78 ) 79 80log .Printf ("center image rect: %+v" ,centerImg ) 81 82for y := centerImg .Min .Y ;y < centerImg .Max .Y ;y ++ { 83log .Printf ("setting cell at (%d, %d)" ,centerImg .Min .X ,y ) 84var content string 85if y == centerImg .Min .Y { 86content = ansi .ITerm2 (iterm2.File { 87Name :"img.png" , 88Width :iterm2 .Cells (imgW ), 89Height :iterm2 .Cells (imgH ), 90Content : []byte (encodedPngImg ), 91Inline :true , 92IgnoreAspectRatio :true , 93DoNotMoveCursor :false , 94 })+ 95// ansi.CursorUp(imgH-1) + 96// ansi.CursorForward(imgW+1) 97ansi .CursorPosition (centerImg .Min .X + imgW + 1 ,centerImg .Min .Y + 1 ) 98log .Printf ("content for cell at (%d, %d): %q" ,centerImg .Min .X ,y ,content ) 99 }else { 100content = ansi .CursorForward (imgW ) 101 } 102 103scr .SetCell (centerImg .Min .X ,y ,& uv.Cell { 104Content :content , 105Width :imgW , 106 }) 107 } 108 109scr .Render () 110scr .Flush () 111 } 112 113display () 114 115loop: 116for ev := range t .Events () { 117switch e := ev .(type ) { 118case uv.PixelSizeEvent : 119cellWidth = e .Width / scr .Bounds ().Dx () 120cellHeight = e .Height / scr .Bounds ().Dy () 121case uv.WindowSizeEvent : 122scr .Resize (e .Width ,e .Height ) 123case uv.KeyPressEvent : 124switch e .String () { 125case "ctrl+c" : 126break loop 127case "up" : 128imgYOffset -- 129case "down" : 130imgYOffset ++ 131case "left" : 132imgXOffset -- 133case "right" : 134imgXOffset ++ 135 } 136keypress = e .String () 137 } 138 139display () 140 } 141 142screen .Clear (scr ) 143scr .Render () 144scr .Reset () 145scr .Flush () 146} 147 148func createImage (w ,h int ,col color.Color )* image.RGBA { 149img := image .NewRGBA (image .Rect (0 ,0 ,w ,h )) 150for y := range h { 151for x := range w { 152img .Set (x ,y ,col ) 153 } 154 } 155return img 156} 157 158func imageRgba (img image.Image ) []byte { 159var buf bytes.Buffer 160bounds := img .Bounds () 161for y := bounds .Min .Y ;y < bounds .Max .Y ;y ++ { 162for x := bounds .Min .X ;x < bounds .Max .X ;x ++ { 163r ,g ,b ,a := img .At (x ,y ).RGBA () 164buf .WriteByte (byte (r >> 8 )) 165buf .WriteByte (byte (g >> 8 )) 166buf .WriteByte (byte (b >> 8 )) 167buf .WriteByte (byte (a >> 8 )) 168 } 169 } 170return buf .Bytes () 171} 172 173func imagePng (img image.Image ) []byte { 174var buf bytes.Buffer 175png .Encode (& buf ,img ) 176return buf .Bytes () 177} 178 179func dataBase64 (data []byte )string { 180return base64 .StdEncoding .EncodeToString (data ) 181} 182 183func init () { 184f ,err := os .OpenFile ("uv_debug.log" ,os .O_CREATE | os .O_WRONLY | os .O_APPEND ,0o644 ) 185if err != nil { 186log .Fatalln ("error opening debug log file:" ,err ) 187 } 188log .SetOutput (f ) 189log .SetFlags (log .LstdFlags | log .Lshortfile ) 190}