erm/app/darktile/termutil/sixel.go

106 lines
2.0 KiB
Go

package termutil
import (
"image"
"math"
"strings"
"tuxpa.in/t/erm/app/darktile/sixel"
)
type Sixel struct {
X uint16
Y uint64 // raw line
Width uint64
Height uint64
Image image.Image
}
type VisibleSixel struct {
ViewLineOffset int
Sixel Sixel
}
func (b *Buffer) addSixel(img image.Image, widthCells int, heightCells int) {
b.sixels = append(b.sixels, Sixel{
X: b.CursorColumn(),
Y: b.cursorPosition.Line,
Width: uint64(widthCells),
Height: uint64(heightCells),
Image: img,
})
if b.modes.SixelScrolling {
b.cursorPosition.Line += uint64(heightCells)
}
}
func (b *Buffer) clearSixelsAtRawLine(rawLine uint64) {
var filtered []Sixel
for _, sixelImage := range b.sixels {
if sixelImage.Y+sixelImage.Height-1 >= rawLine && sixelImage.Y <= rawLine {
continue
}
filtered = append(filtered, sixelImage)
}
b.sixels = filtered
}
func (b *Buffer) GetVisibleSixels() []VisibleSixel {
firstLine := b.convertViewLineToRawLine(0)
lastLine := b.convertViewLineToRawLine(b.viewHeight - 1)
var visible []VisibleSixel
for _, sixelImage := range b.sixels {
if sixelImage.Y+sixelImage.Height-1 < firstLine {
continue
}
if sixelImage.Y > lastLine {
continue
}
visible = append(visible, VisibleSixel{
ViewLineOffset: int(sixelImage.Y) - int(firstLine),
Sixel: sixelImage,
})
}
return visible
}
func (t *Terminal) handleSixel(readChan chan MeasuredRune) (renderRequired bool) {
var data []rune
var inEscape bool
for {
r := <-readChan
switch r.Rune {
case 0x1b:
inEscape = true
continue
case 0x5c:
if inEscape {
img, err := sixel.Decode(strings.NewReader(string(data)), t.theme.DefaultBackground())
if err != nil {
return false
}
w, h := t.windowManipulator.CellSizeInPixels()
cw := int(math.Ceil(float64(img.Bounds().Dx()) / float64(w)))
ch := int(math.Ceil(float64(img.Bounds().Dy()) / float64(h)))
t.activeBuffer.addSixel(img, cw, ch)
return true
}
}
inEscape = false
data = append(data, r.Rune)
}
}