okami.mom/ultraviolet

git clone https://git.nkp.pet/okami.mom/ultraviolet

Ayman Bagabaschore(examples): update rgbimage example to remove commented out codec103292

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