stegterm/internal/stego/kitty.go
2026-09-14 11:00:27 +03:00

52 lines
2.7 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package stego
import (
"encoding/base64"
"fmt"
"strings"
)
// KittyEscape кодирует PNG-байты в escape-последовательность протокола
// Kitty graphics — Konsole его понимает (это уже выяснялось раньше, на
// другом проекте, где графические протоколы работали в Konsole, но не
// в Alacritty).
//
// ЧЕСТНАЯ ОГОВОРКА, серьёзнее обычной: сама генерация escape-кода по
// спецификации протокола — то, что я действительно знаю и могу
// аргументировать (a=T — передать и сразу отобразить одним действием;
// f=100 — формат PNG, протокол умеет декодировать его сам, кодировать
// в сырой RGBA не нужно; t=d — данные идут прямо в escape-последовательности,
// не через файл; чанки по 4096 base64-байт — так требует спецификация
// для больших изображений). А вот что произойдёт, когда bubbletea в
// alt-screen режиме в следующий раз перерисует экран поверх уже
// показанной Kitty-картинки — я предсказать не могу совсем: там нет
// реального терминала, чтобы проверить. Другие непроверенные места в
// проекте (например, зависимость на sqlite) — это "может не
// скомпилироваться, поправишь по ошибке компилятора". Здесь другое:
// код скомпилируется и, скорее всего, отработает без паники, вопрос
// только в том, что увидишь на экране — и тут я честно не знаю. Отсюда
// клавиша ctrl+v на вкладке Steganography — передать escape-код заново,
// если картинку перекрыло перерисовкой TUI.
func KittyEscape(pngData []byte) string {
b64 := base64.StdEncoding.EncodeToString(pngData)
const chunkSize = 4096
var b strings.Builder
for i := 0; i < len(b64); i += chunkSize {
end := i + chunkSize
if end > len(b64) {
end = len(b64)
}
chunk := b64[i:end]
more := 0
if end < len(b64) {
more = 1
}
if i == 0 {
fmt.Fprintf(&b, "\x1b_Ga=T,f=100,t=d,m=%d;%s\x1b\\", more, chunk)
} else {
fmt.Fprintf(&b, "\x1b_Gm=%d;%s\x1b\\", more, chunk)
}
}
return b.String()
}