split encodings

Signed-off-by: Vasiliy Tolstov <v.tolstov@selfip.ru>
This commit is contained in:
Василий Толстов 2017-06-26 13:20:39 +03:00
parent 87294a7677
commit 1ec2df07e9
6 changed files with 295 additions and 282 deletions

View File

@ -2,13 +2,6 @@ package vnc
import ( import (
"bytes" "bytes"
"encoding/binary"
"fmt"
"image"
"image/color"
"image/draw"
"image/png"
"io"
"sync" "sync"
) )
@ -65,27 +58,6 @@ const (
EncClientRedirect EncodingType = -311 EncClientRedirect EncodingType = -311
) )
//go:generate stringer -type=TightCompression
type TightCompression uint8
const (
TightCompressionBasic TightCompression = 0
TightCompressionFill TightCompression = 8
TightCompressionJPEG TightCompression = 9
TightCompressionPNG TightCompression = 10
)
//go:generate stringer -type=TightFilter
type TightFilter uint8
const (
TightFilterCopy TightFilter = 0
TightFilterPalette TightFilter = 1
TightFilterGradient TightFilter = 2
)
var bPool = sync.Pool{ var bPool = sync.Pool{
New: func() interface{} { New: func() interface{} {
// The Pool's New function should generally only return pointer // The Pool's New function should generally only return pointer
@ -101,70 +73,6 @@ type Encoding interface {
Write(Conn, *Rectangle) error Write(Conn, *Rectangle) error
} }
type CopyRectEncoding struct {
SX, SY uint16
}
func (CopyRectEncoding) Type() EncodingType { return EncCopyRect }
func (enc *CopyRectEncoding) Read(c Conn, rect *Rectangle) error {
if err := binary.Read(c, binary.BigEndian, &enc.SX); err != nil {
return err
}
if err := binary.Read(c, binary.BigEndian, &enc.SY); err != nil {
return err
}
return nil
}
func (enc *CopyRectEncoding) Write(c Conn, rect *Rectangle) error {
if err := binary.Write(c, binary.BigEndian, enc.SX); err != nil {
return err
}
if err := binary.Write(c, binary.BigEndian, enc.SY); err != nil {
return err
}
return nil
}
type RawEncoding struct {
Colors []Color
}
type TightEncoding struct{}
func (*TightEncoding) Type() EncodingType { return EncTight }
func (enc *TightEncoding) Write(c Conn, rect *Rectangle) error {
return nil
}
func (enc *TightEncoding) Read(c Conn, rect *Rectangle) error {
return nil
}
type TightCC struct {
Compression TightCompression
Filter TightFilter
}
func readTightCC(c Conn) (*TightCC, error) {
var ccb uint8 // compression control byte
if err := binary.Read(c, binary.BigEndian, &ccb); err != nil {
return nil, err
}
cmp := TightCompression(ccb >> 4)
switch cmp {
case TightCompressionBasic:
return &TightCC{TightCompressionBasic, TightFilterCopy}, nil
case TightCompressionFill:
return &TightCC{TightCompressionFill, TightFilterCopy}, nil
case TightCompressionPNG:
return &TightCC{TightCompressionPNG, TightFilterCopy}, nil
}
return nil, fmt.Errorf("unknown tight compression %d", cmp)
}
func setBit(n uint8, pos uint8) uint8 { func setBit(n uint8, pos uint8) uint8 {
n |= (1 << pos) n |= (1 << pos)
return n return n
@ -184,193 +92,3 @@ func getBit(n uint8, pos uint8) uint8 {
n = n & (1 << pos) n = n & (1 << pos)
return n return n
} }
func writeTightCC(c Conn, tcc *TightCC) error {
var ccb uint8 // compression control byte
switch tcc.Compression {
case TightCompressionFill:
ccb = setBit(ccb, 7)
case TightCompressionJPEG:
ccb = setBit(ccb, 7)
ccb = setBit(ccb, 4)
case TightCompressionPNG:
ccb = setBit(ccb, 7)
ccb = setBit(ccb, 5)
}
return binary.Write(c, binary.BigEndian, ccb)
}
func (enc *TightPngEncoding) Write(c Conn, rect *Rectangle) error {
if err := writeTightCC(c, enc.TightCC); err != nil {
return err
}
cmp := enc.TightCC.Compression
switch cmp {
case TightCompressionPNG:
buf := bPool.Get().(*bytes.Buffer)
buf.Reset()
defer bPool.Put(buf)
pngEnc := &png.Encoder{CompressionLevel: png.BestSpeed}
//pngEnc := &png.Encoder{CompressionLevel: png.NoCompression}
if err := pngEnc.Encode(buf, enc.Image); err != nil {
return err
}
if err := writeTightLength(c, buf.Len()); err != nil {
return err
}
if _, err := buf.WriteTo(c); err != nil {
return err
}
case TightCompressionFill:
var tpx TightPixel
r, g, b, _ := enc.Image.At(0, 0).RGBA()
tpx.R = uint8(r)
tpx.G = uint8(g)
tpx.B = uint8(b)
if err := binary.Write(c, binary.BigEndian, tpx); err != nil {
return err
}
default:
return fmt.Errorf("unknown tight compression %d", cmp)
}
return nil
}
type TightPixel struct {
R uint8
G uint8
B uint8
}
type TightPngEncoding struct {
TightCC *TightCC
Image image.Image
}
func (*TightPngEncoding) Type() EncodingType { return EncTightPng }
func (enc *TightPngEncoding) Read(c Conn, rect *Rectangle) error {
tcc, err := readTightCC(c)
if err != nil {
return err
}
enc.TightCC = tcc
cmp := enc.TightCC.Compression
switch cmp {
case TightCompressionPNG:
l, err := readTightLength(c)
if err != nil {
return err
}
enc.Image, err = png.Decode(io.LimitReader(c, int64(l)))
if err != nil {
return err
}
case TightCompressionFill:
var tpx TightPixel
if err := binary.Read(c, binary.BigEndian, &tpx); err != nil {
return err
}
enc.Image = image.NewRGBA(image.Rect(0, 0, 1, 1))
enc.Image.(draw.Image).Set(0, 0, color.RGBA{R: tpx.R, G: tpx.G, B: tpx.B, A: 1})
default:
return fmt.Errorf("unknown compression %d", cmp)
}
return nil
}
func writeTightLength(c Conn, l int) error {
var buf []uint8
buf = append(buf, uint8(l&0x7F))
if l > 0x7F {
buf[0] |= 0x80
buf = append(buf, uint8((l>>7)&0x7F))
if l > 0x3FFF {
buf[1] |= 0x80
buf = append(buf, uint8((l>>14)&0xFF))
}
}
return binary.Write(c, binary.BigEndian, buf)
}
func readTightLength(c Conn) (int, error) {
var length int
var err error
var b uint8
if err = binary.Read(c, binary.BigEndian, &b); err != nil {
return 0, err
}
length = int(b) & 0x7F
if (b & 0x80) == 0 {
return length, nil
}
if err = binary.Read(c, binary.BigEndian, &b); err != nil {
return 0, err
}
length |= (int(b) & 0x7F) << 7
if (b & 0x80) == 0 {
return length, nil
}
if err = binary.Read(c, binary.BigEndian, &b); err != nil {
return 0, err
}
length |= (int(b) & 0xFF) << 14
return length, nil
}
func (enc *RawEncoding) Write(c Conn, rect *Rectangle) error {
var err error
for _, clr := range enc.Colors {
if err = clr.Write(c); err != nil {
break
}
}
return err
}
// Read implements the Encoding interface.
func (enc *RawEncoding) Read(c Conn, rect *Rectangle) error {
var err error
pf := c.PixelFormat()
cm := c.ColorMap()
colors := make([]Color, rect.Area())
Loop:
for y := uint16(0); y < rect.Height; y++ {
for x := uint16(0); x < rect.Width; x++ {
color := NewColor(pf, cm)
if err = color.Read(c); err != nil {
break Loop
}
colors[int(y)*int(rect.Width)+int(x)] = *color
}
}
enc.Colors = colors
return err
}
func (*RawEncoding) Type() EncodingType { return EncRaw }
// DesktopSizePseudoEncoding represents a desktop size message from the server.
type DesktopSizePseudoEncoding struct {
}
func (*DesktopSizePseudoEncoding) Type() EncodingType { return EncDesktopSizePseudo }
// Read implements the Encoding interface.
func (*DesktopSizePseudoEncoding) Read(c Conn, rect *Rectangle) error {
c.SetWidth(rect.Width)
c.SetHeight(rect.Height)
return nil
}
func (enc *DesktopSizePseudoEncoding) Write(c Conn, rect *Rectangle) error {
return nil
}

29
encoding_copyrect.go Normal file
View File

@ -0,0 +1,29 @@
package vnc
import "encoding/binary"
type CopyRectEncoding struct {
SX, SY uint16
}
func (CopyRectEncoding) Type() EncodingType { return EncCopyRect }
func (enc *CopyRectEncoding) Read(c Conn, rect *Rectangle) error {
if err := binary.Read(c, binary.BigEndian, &enc.SX); err != nil {
return err
}
if err := binary.Read(c, binary.BigEndian, &enc.SY); err != nil {
return err
}
return nil
}
func (enc *CopyRectEncoding) Write(c Conn, rect *Rectangle) error {
if err := binary.Write(c, binary.BigEndian, enc.SX); err != nil {
return err
}
if err := binary.Write(c, binary.BigEndian, enc.SY); err != nil {
return err
}
return nil
}

15
encoding_desktopsize.go Normal file
View File

@ -0,0 +1,15 @@
package vnc
// DesktopSizePseudoEncoding represents a desktop size message from the server.
type DesktopSizePseudoEncoding struct{}
func (*DesktopSizePseudoEncoding) Type() EncodingType { return EncDesktopSizePseudo }
// Read implements the Encoding interface.
func (*DesktopSizePseudoEncoding) Read(c Conn, rect *Rectangle) error {
return nil
}
func (enc *DesktopSizePseudoEncoding) Write(c Conn, rect *Rectangle) error {
return nil
}

38
encoding_raw.go Normal file
View File

@ -0,0 +1,38 @@
package vnc
type RawEncoding struct {
Colors []Color
}
func (enc *RawEncoding) Write(c Conn, rect *Rectangle) error {
var err error
for _, clr := range enc.Colors {
if err = clr.Write(c); err != nil {
break
}
}
return err
}
// Read implements the Encoding interface.
func (enc *RawEncoding) Read(c Conn, rect *Rectangle) error {
var err error
pf := c.PixelFormat()
cm := c.ColorMap()
colors := make([]Color, rect.Area())
Loop:
for y := uint16(0); y < rect.Height; y++ {
for x := uint16(0); x < rect.Width; x++ {
color := NewColor(pf, cm)
if err = color.Read(c); err != nil {
break Loop
}
colors[int(y)*int(rect.Width)+int(x)] = *color
}
}
enc.Colors = colors
return err
}
func (*RawEncoding) Type() EncodingType { return EncRaw }

127
encoding_tight.go Normal file
View File

@ -0,0 +1,127 @@
package vnc
import (
"encoding/binary"
"fmt"
)
//go:generate stringer -type=TightCompression
type TightCompression uint8
const (
TightCompressionBasic TightCompression = 0
TightCompressionFill TightCompression = 8
TightCompressionJPEG TightCompression = 9
TightCompressionPNG TightCompression = 10
)
//go:generate stringer -type=TightFilter
type TightFilter uint8
const (
TightFilterCopy TightFilter = 0
TightFilterPalette TightFilter = 1
TightFilterGradient TightFilter = 2
)
type TightEncoding struct{}
func (*TightEncoding) Type() EncodingType { return EncTight }
func (enc *TightEncoding) Write(c Conn, rect *Rectangle) error {
return nil
}
func (enc *TightEncoding) Read(c Conn, rect *Rectangle) error {
return nil
}
type TightCC struct {
Compression TightCompression
Filter TightFilter
}
func readTightCC(c Conn) (*TightCC, error) {
var ccb uint8 // compression control byte
if err := binary.Read(c, binary.BigEndian, &ccb); err != nil {
return nil, err
}
cmp := TightCompression(ccb >> 4)
switch cmp {
case TightCompressionBasic:
return &TightCC{TightCompressionBasic, TightFilterCopy}, nil
case TightCompressionFill:
return &TightCC{TightCompressionFill, TightFilterCopy}, nil
case TightCompressionPNG:
return &TightCC{TightCompressionPNG, TightFilterCopy}, nil
}
return nil, fmt.Errorf("unknown tight compression %d", cmp)
}
func writeTightCC(c Conn, tcc *TightCC) error {
var ccb uint8 // compression control byte
switch tcc.Compression {
case TightCompressionFill:
ccb = setBit(ccb, 7)
case TightCompressionJPEG:
ccb = setBit(ccb, 7)
ccb = setBit(ccb, 4)
case TightCompressionPNG:
ccb = setBit(ccb, 7)
ccb = setBit(ccb, 5)
}
return binary.Write(c, binary.BigEndian, ccb)
}
type TightPixel struct {
R uint8
G uint8
B uint8
}
func writeTightLength(c Conn, l int) error {
var buf []uint8
buf = append(buf, uint8(l&0x7F))
if l > 0x7F {
buf[0] |= 0x80
buf = append(buf, uint8((l>>7)&0x7F))
if l > 0x3FFF {
buf[1] |= 0x80
buf = append(buf, uint8((l>>14)&0xFF))
}
}
return binary.Write(c, binary.BigEndian, buf)
}
func readTightLength(c Conn) (int, error) {
var length int
var err error
var b uint8
if err = binary.Read(c, binary.BigEndian, &b); err != nil {
return 0, err
}
length = int(b) & 0x7F
if (b & 0x80) == 0 {
return length, nil
}
if err = binary.Read(c, binary.BigEndian, &b); err != nil {
return 0, err
}
length |= (int(b) & 0x7F) << 7
if (b & 0x80) == 0 {
return length, nil
}
if err = binary.Read(c, binary.BigEndian, &b); err != nil {
return 0, err
}
length |= (int(b) & 0xFF) << 14
return length, nil
}

86
encoding_tightpng.go Normal file
View File

@ -0,0 +1,86 @@
package vnc
import (
"bytes"
"encoding/binary"
"fmt"
"image"
"image/color"
"image/draw"
"image/png"
"io"
)
func (enc *TightPngEncoding) Write(c Conn, rect *Rectangle) error {
if err := writeTightCC(c, enc.TightCC); err != nil {
return err
}
cmp := enc.TightCC.Compression
switch cmp {
case TightCompressionPNG:
buf := bPool.Get().(*bytes.Buffer)
buf.Reset()
defer bPool.Put(buf)
pngEnc := &png.Encoder{CompressionLevel: png.BestSpeed}
//pngEnc := &png.Encoder{CompressionLevel: png.NoCompression}
if err := pngEnc.Encode(buf, enc.Image); err != nil {
return err
}
if err := writeTightLength(c, buf.Len()); err != nil {
return err
}
if _, err := buf.WriteTo(c); err != nil {
return err
}
case TightCompressionFill:
var tpx TightPixel
r, g, b, _ := enc.Image.At(0, 0).RGBA()
tpx.R = uint8(r)
tpx.G = uint8(g)
tpx.B = uint8(b)
if err := binary.Write(c, binary.BigEndian, tpx); err != nil {
return err
}
default:
return fmt.Errorf("unknown tight compression %d", cmp)
}
return nil
}
type TightPngEncoding struct {
TightCC *TightCC
Image image.Image
}
func (*TightPngEncoding) Type() EncodingType { return EncTightPng }
func (enc *TightPngEncoding) Read(c Conn, rect *Rectangle) error {
tcc, err := readTightCC(c)
if err != nil {
return err
}
enc.TightCC = tcc
cmp := enc.TightCC.Compression
switch cmp {
case TightCompressionPNG:
l, err := readTightLength(c)
if err != nil {
return err
}
enc.Image, err = png.Decode(io.LimitReader(c, int64(l)))
if err != nil {
return err
}
case TightCompressionFill:
var tpx TightPixel
if err := binary.Read(c, binary.BigEndian, &tpx); err != nil {
return err
}
enc.Image = image.NewRGBA(image.Rect(0, 0, 1, 1))
enc.Image.(draw.Image).Set(0, 0, color.RGBA{R: tpx.R, G: tpx.G, B: tpx.B, A: 1})
default:
return fmt.Errorf("unknown compression %d", cmp)
}
return nil
}