decoder.go 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. package kitty
  2. import (
  3. "compress/zlib"
  4. "fmt"
  5. "image"
  6. "image/color"
  7. "image/png"
  8. "io"
  9. )
  10. // Decoder is a decoder for the Kitty graphics protocol. It supports decoding
  11. // images in the 24-bit [RGB], 32-bit [RGBA], and [PNG] formats. It can also
  12. // decompress data using zlib.
  13. // The default format is 32-bit [RGBA].
  14. type Decoder struct {
  15. // Uses zlib decompression.
  16. Decompress bool
  17. // Can be one of [RGB], [RGBA], or [PNG].
  18. Format int
  19. // Width of the image in pixels. This can be omitted if the image is [PNG]
  20. // formatted.
  21. Width int
  22. // Height of the image in pixels. This can be omitted if the image is [PNG]
  23. // formatted.
  24. Height int
  25. }
  26. // Decode decodes the image data from r in the specified format.
  27. func (d *Decoder) Decode(r io.Reader) (image.Image, error) {
  28. if d.Decompress {
  29. zr, err := zlib.NewReader(r)
  30. if err != nil {
  31. return nil, fmt.Errorf("failed to create zlib reader: %w", err)
  32. }
  33. defer zr.Close() //nolint:errcheck
  34. r = zr
  35. }
  36. if d.Format == 0 {
  37. d.Format = RGBA
  38. }
  39. switch d.Format {
  40. case RGBA, RGB:
  41. return d.decodeRGBA(r, d.Format == RGBA)
  42. case PNG:
  43. return png.Decode(r)
  44. default:
  45. return nil, fmt.Errorf("unsupported format: %d", d.Format)
  46. }
  47. }
  48. // decodeRGBA decodes the image data in 32-bit RGBA or 24-bit RGB formats.
  49. func (d *Decoder) decodeRGBA(r io.Reader, alpha bool) (image.Image, error) {
  50. m := image.NewRGBA(image.Rect(0, 0, d.Width, d.Height))
  51. var buf []byte
  52. if alpha {
  53. buf = make([]byte, 4)
  54. } else {
  55. buf = make([]byte, 3)
  56. }
  57. for y := 0; y < d.Height; y++ {
  58. for x := 0; x < d.Width; x++ {
  59. if _, err := io.ReadFull(r, buf[:]); err != nil {
  60. return nil, fmt.Errorf("failed to read pixel data: %w", err)
  61. }
  62. if alpha {
  63. m.SetRGBA(x, y, color.RGBA{buf[0], buf[1], buf[2], buf[3]})
  64. } else {
  65. m.SetRGBA(x, y, color.RGBA{buf[0], buf[1], buf[2], 0xff})
  66. }
  67. }
  68. }
  69. return m, nil
  70. }