package termutil import ( "image" "math" "strings" "github.com/liamg/darktile/internal/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) } }