Get file mode transmission working for unmodified PNG

This commit is contained in:
Kovid Goyal 2023-01-01 12:01:20 +05:30
parent ce4c71c465
commit 5562a4d52f
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
6 changed files with 125 additions and 23 deletions

View File

@ -159,11 +159,6 @@ func on_initialize() (string, error) {
cc.SetAction(graphics.GRT_action_delete).SetDelete(graphics.GRT_free_visible) cc.SetAction(graphics.GRT_action_delete).SetDelete(graphics.GRT_free_visible)
cc.WriteWithPayloadToLoop(lp, nil) cc.WriteWithPayloadToLoop(lp, nil)
} }
if opts.TransferMode != "detect" {
return "", nil
}
query_in_flight = true
lp.AddTimer(time.Duration(opts.DetectionTimeout*float64(time.Second)), false, on_detect_timeout) lp.AddTimer(time.Duration(opts.DetectionTimeout*float64(time.Second)), false, on_detect_timeout)
g := func(t graphics.GRT_t, payload string) uint32 { g := func(t graphics.GRT_t, payload string) uint32 {
iid += 1 iid += 1
@ -181,9 +176,13 @@ func on_initialize() (string, error) {
go run_worker() go run_worker()
} }
} }
if opts.TransferMode != "detect" {
return "", nil
}
query_in_flight = true
direct_query_id = g(graphics.GRT_transmission_direct, "123") direct_query_id = g(graphics.GRT_transmission_direct, "123")
tf, err := graphics.MakeTemp() tf, err := graphics.CreateTempInRAM()
if err == nil { if err == nil {
file_query_id = g(graphics.GRT_transmission_tempfile, tf.Name()) file_query_id = g(graphics.GRT_transmission_tempfile, tf.Name())
temp_files_to_delete = append(temp_files_to_delete, tf.Name()) temp_files_to_delete = append(temp_files_to_delete, tf.Name())
@ -397,6 +396,10 @@ func main(cmd *cli.Command, o *Options, args []string) (rc int, err error) {
return return
} }
if opts.Hold { if opts.Hold {
fmt.Print("\r")
if opts.Place != "" {
fmt.Println()
}
tui.HoldTillEnter(false) tui.HoldTillEnter(false)
} }
return 0, nil return 0, nil

View File

@ -147,7 +147,8 @@ type image_data struct {
format_uppercase string format_uppercase string
available_width, available_height int available_width, available_height int
needs_scaling, needs_conversion bool needs_scaling, needs_conversion bool
frames []image_frame frames []*image_frame
image_number uint32
// for error reporting // for error reporting
err error err error
@ -155,7 +156,7 @@ type image_data struct {
} }
func set_basic_metadata(imgd *image_data) { func set_basic_metadata(imgd *image_data) {
imgd.frames = make([]image_frame, 0, 32) imgd.frames = make([]*image_frame, 0, 32)
imgd.available_width = int(screen_size.WidthPx) imgd.available_width = int(screen_size.WidthPx)
imgd.available_height = 10 * imgd.canvas_height imgd.available_height = 10 * imgd.canvas_height
if place != nil { if place != nil {
@ -179,7 +180,8 @@ func report_error(source_name, msg string, err error) {
func make_output_from_input(imgd *image_data, f *opened_input) { func make_output_from_input(imgd *image_data, f *opened_input) {
bb, ok := f.file.(*BytesBuf) bb, ok := f.file.(*BytesBuf)
frame := &imgd.frames[0] frame := image_frame{}
imgd.frames = append(imgd.frames, &frame)
frame.width = imgd.canvas_width frame.width = imgd.canvas_width
frame.height = imgd.canvas_height frame.height = imgd.canvas_height
if ok { if ok {

View File

@ -3,32 +3,57 @@
package icat package icat
import ( import (
"bytes"
"errors" "errors"
"fmt" "fmt"
"io" "io"
"kitty/tools/tui/graphics" "kitty/tools/tui/graphics"
"kitty/tools/utils"
"kitty/tools/utils/shm" "kitty/tools/utils/shm"
"math/rand"
"os" "os"
"path/filepath"
) )
var _ = fmt.Print var _ = fmt.Print
func gc_for_image(imgd *image_data) *graphics.GraphicsCommand { func gc_for_image(imgd *image_data, data_size, frame_num int, frame *image_frame) *graphics.GraphicsCommand {
gc := graphics.GraphicsCommand{}
gc.SetDataSize(uint64(data_size)).SetAction(graphics.GRT_action_transmit_and_display)
gc.SetDataWidth(uint64(frame.width)).SetDataHeight(uint64(frame.height))
gc.SetQuiet(graphics.GRT_quiet_silent)
if z_index != 0 {
gc.SetZIndex(z_index)
}
if imgd.image_number != 0 {
gc.SetImageNumber(imgd.image_number)
}
switch imgd.format_uppercase {
case "PNG":
gc.SetFormat(graphics.GRT_format_png)
default:
gc.SetFormat(graphics.GRT_format_rgb)
case "RGBA":
gc.SetFormat(graphics.GRT_format_rgba)
}
return &gc
} }
func transmit_shm(imgd *image_data, frame_num int, frame *image_frame) error { func transmit_shm(imgd *image_data, frame_num int, frame *image_frame) (err error) {
var data_size int var data_size int
var mmap shm.MMap
if frame.in_memory_bytes == nil { if frame.in_memory_bytes == nil {
f, err := os.Open(frame.filename) f, err := os.Open(frame.filename)
if err != nil { if err != nil {
return err return fmt.Errorf("Failed to open image data output file: %s with error: %w", frame.filename, err)
} }
defer f.Close() defer f.Close()
sz, _ := f.Seek(0, io.SeekEnd) sz, _ := f.Seek(0, io.SeekEnd)
f.Seek(0, io.SeekStart) f.Seek(0, io.SeekStart)
mmap, err := shm.CreateTemp("icat-*", uint64(sz)) mmap, err = shm.CreateTemp("icat-*", uint64(sz))
if err != nil { if err != nil {
return err return fmt.Errorf("Failed to create a SHM file for transmission: %w", err)
} }
defer mmap.Close() defer mmap.Close()
dest := mmap.Slice() dest := mmap.Slice()
@ -40,24 +65,81 @@ func transmit_shm(imgd *image_data, frame_num int, frame *image_frame) error {
break break
} }
mmap.Unlink() mmap.Unlink()
return err return fmt.Errorf("Failed to read data from image output data file: %w", err)
} }
} }
data_size = len(mmap.Slice()) - len(dest) data_size = len(mmap.Slice()) - len(dest)
} else { } else {
mmap, err := shm.CreateTemp("icat-*", uint64(len(frame.in_memory_bytes))) mmap, err = shm.CreateTemp("icat-*", uint64(len(frame.in_memory_bytes)))
if err != nil { if err != nil {
return err return fmt.Errorf("Failed to create a SHM file for transmission: %w", err)
} }
defer mmap.Close() defer mmap.Close()
data_size = copy(mmap.Slice(), frame.in_memory_bytes) data_size = copy(mmap.Slice(), frame.in_memory_bytes)
} }
gc := gc_for_image(imgd, data_size, frame_num, frame)
gc.SetTransmission(graphics.GRT_transmission_sharedmem)
gc.WriteWithPayloadToLoop(lp, utils.UnsafeStringToBytes(mmap.Name()))
return nil
} }
func transmit_file(imgd *image_data, frame_num int, frame *image_frame) error { func transmit_file(imgd *image_data, frame_num int, frame *image_frame) (err error) {
var data_size int
is_temp := false
fname := ""
if frame.in_memory_bytes == nil {
is_temp = frame.filename_is_temporary
fname, err = filepath.Abs(frame.filename)
if err != nil {
return fmt.Errorf("Failed to convert image data output file: %s to absolute path with error: %w", frame.filename, err)
}
frame.filename = "" // so it isnt deleted in cleanup
s, err := os.Stat(fname)
if err != nil {
return fmt.Errorf("Failed to stat() image data output file: %s with error: %w", fname, err)
}
data_size = int(s.Size())
} else {
data_size = len(frame.in_memory_bytes)
f, err := graphics.CreateTempInRAM()
if err != nil {
return fmt.Errorf("Failed to create a temp file for image data transmission: %w", err)
}
_, err = bytes.NewBuffer(frame.in_memory_bytes).WriteTo(f)
f.Close()
if err != nil {
return fmt.Errorf("Failed to write image data to temp file for transmission: %w", err)
}
is_temp = true
fname = f.Name()
}
gc := gc_for_image(imgd, data_size, frame_num, frame)
if is_temp {
gc.SetTransmission(graphics.GRT_transmission_tempfile)
} else {
gc.SetTransmission(graphics.GRT_transmission_file)
}
gc.WriteWithPayloadToLoop(lp, utils.UnsafeStringToBytes(fname))
return nil
} }
func transmit_stream(imgd *image_data, frame_num int, frame *image_frame) error { func transmit_stream(imgd *image_data, frame_num int, frame *image_frame) (err error) {
data := frame.in_memory_bytes
if data == nil {
f, err := os.Open(frame.filename)
if err != nil {
return fmt.Errorf("Failed to open image data output file: %s with error: %w", frame.filename, err)
}
data, err = io.ReadAll(f)
f.Close()
if err != nil {
return fmt.Errorf("Failed to read data from image output data file: %w", err)
}
}
gc := gc_for_image(imgd, len(data), frame_num, frame)
gc.WriteWithPayloadToLoop(lp, data)
return nil
} }
func transmit_image(imgd *image_data) { func transmit_image(imgd *image_data) {
@ -79,7 +161,6 @@ func transmit_image(imgd *image_data) {
f = transmit_shm f = transmit_shm
case "stream": case "stream":
f = transmit_stream f = transmit_stream
return
} }
} }
if f == nil && transfer_by_memory == supported && imgd.frames[0].in_memory_bytes != nil { if f == nil && transfer_by_memory == supported && imgd.frames[0].in_memory_bytes != nil {
@ -91,8 +172,11 @@ func transmit_image(imgd *image_data) {
if f == nil { if f == nil {
f = transmit_stream f = transmit_stream
} }
if len(imgd.frames) > 1 {
imgd.image_number = rand.Uint32()
}
for frame_num, frame := range imgd.frames { for frame_num, frame := range imgd.frames {
err := f(imgd, frame_num, &frame) err := f(imgd, frame_num, frame)
if err != nil { if err != nil {
print_error("Failed to transmit %s with error: %v", imgd.source_name, err) print_error("Failed to transmit %s with error: %v", imgd.source_name, err)
} }

View File

@ -14,14 +14,25 @@ import (
"kitty/tools/tui/loop" "kitty/tools/tui/loop"
"kitty/tools/utils" "kitty/tools/utils"
"kitty/tools/utils/shm"
) )
var _ = fmt.Print var _ = fmt.Print
func MakeTemp() (*os.File, error) { func CreateTemp() (*os.File, error) {
return os.CreateTemp("", "tty-graphics-protocol-*") return os.CreateTemp("", "tty-graphics-protocol-*")
} }
func CreateTempInRAM() (*os.File, error) {
if shm.SHM_DIR != "" {
f, err := os.CreateTemp(shm.SHM_DIR, "tty-graphics-protocol-*")
if err == nil {
return f, err
}
}
return CreateTemp()
}
// Enums {{{ // Enums {{{
type GRT_a int type GRT_a int
@ -523,7 +534,7 @@ func (self *GraphicsCommand) AsAPC(payload []byte) string {
} }
func (self *GraphicsCommand) WriteWithPayloadTo(o io.StringWriter, payload []byte) (err error) { func (self *GraphicsCommand) WriteWithPayloadTo(o io.StringWriter, payload []byte) (err error) {
const compression_threshold = 1024 const compression_threshold = 2048
if len(payload) == 0 { if len(payload) == 0 {
return self.serialize_to(o, "") return self.serialize_to(o, "")
} }

View File

@ -4,3 +4,4 @@ package shm
const SHM_NAME_MAX = 30 const SHM_NAME_MAX = 30
const SHM_REQUIRED_PREFIX = "" const SHM_REQUIRED_PREFIX = ""
const SHM_DIR = ""

View File

@ -4,3 +4,4 @@ package shm
const SHM_NAME_MAX = 1023 const SHM_NAME_MAX = 1023
const SHM_REQUIRED_PREFIX = "/" const SHM_REQUIRED_PREFIX = "/"
const SHM_DIR = ""