complete tight png

Signed-off-by: Vasiliy Tolstov <v.tolstov@selfip.ru>
This commit is contained in:
Василий Толстов 2017-06-18 19:42:41 +03:00
parent 49c704bc67
commit 1413d28267
9 changed files with 513 additions and 120 deletions

View File

@ -4,6 +4,11 @@ import (
"bytes"
"encoding/binary"
"fmt"
"image"
"image/color"
"image/draw"
"image/png"
"io"
)
// EncodingType represents a known VNC encoding type.
@ -24,26 +29,292 @@ const (
EncUltra2 EncodingType = 10
EncJPEG EncodingType = 21
EncJRLE EncodingType = 22
//EncRichCursor EncodingType = 0xFFFFFF11
//EncPointerPos EncodingType = 0xFFFFFF18
//EncLastRec EncodingType = 0xFFFFFF20
EncTRLE EncodingType = 15
EncZRLE EncodingType = 16
EncJPEGQualityLevelPseudo10 EncodingType = -23
EncJPEGQualityLevelPseudo9 EncodingType = -24
EncJPEGQualityLevelPseudo8 EncodingType = -25
EncJPEGQualityLevelPseudo7 EncodingType = -26
EncJPEGQualityLevelPseudo6 EncodingType = -27
EncJPEGQualityLevelPseudo5 EncodingType = -28
EncJPEGQualityLevelPseudo4 EncodingType = -29
EncJPEGQualityLevelPseudo3 EncodingType = -30
EncJPEGQualityLevelPseudo2 EncodingType = -31
EncJPEGQualityLevelPseudo1 EncodingType = -32
EncColorPseudo EncodingType = -239
EncDesktopSizePseudo EncodingType = -223
EncLastRectPseudo EncodingType = -224
EncCompressionLevel10 EncodingType = -247
EncCompressionLevel9 EncodingType = -248
EncCompressionLevel8 EncodingType = -249
EncCompressionLevel7 EncodingType = -250
EncCompressionLevel6 EncodingType = -251
EncCompressionLevel5 EncodingType = -252
EncCompressionLevel4 EncodingType = -253
EncCompressionLevel3 EncodingType = -254
EncCompressionLevel2 EncodingType = -255
EncCompressionLevel1 EncodingType = -256
EncQEMUPointerMotionChangePseudo EncodingType = -257
EncQEMUExtendedKeyEventPseudo EncodingType = -258
EncTightPng EncodingType = -260
EncExtendedDesktopSizePseudo EncodingType = -308
EncXvpPseudo EncodingType = -309
EncFencePseudo EncodingType = -312
EncContinuousUpdatesPseudo EncodingType = -313
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
)
type Encoding interface {
Type() EncodingType
Read(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 {
n |= (1 << pos)
return n
}
func clrBit(n uint8, pos uint8) uint8 {
n = n &^ (1 << pos)
return n
}
func hasBit(n uint8, pos uint8) bool {
v := n & (1 << pos)
return (v > 0)
}
func getBit(n uint8, pos uint8) uint8 {
n = n & (1 << pos)
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 := bytes.NewBuffer(nil)
if err := png.Encode(buf, enc.Image); err != nil {
return err
}
if err := writeTightLength(c, buf.Len()); err != nil {
return err
}
if _, err := io.Copy(c, buf); 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:
buf := bytes.NewBuffer(nil)
l, err := readTightLength(c)
if err != nil {
return err
}
_, err = io.CopyN(buf, c, int64(l))
if err != nil {
return err
}
enc.Image, err = png.Decode(buf)
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 {
buf := bytes.NewBuffer(nil)
defer buf.Reset()
@ -58,16 +329,7 @@ func (enc *RawEncoding) Write(c Conn, rect *Rectangle) error {
if err := binary.Write(buf, binary.BigEndian, bytes); err != nil {
return err
}
/*
if _, err := buf.Write(bytes); err != nil {
return err
}
*/
}
fmt.Printf("w %d\n", n)
//return binary.Write(c, binary.BigEndian, buf.Bytes())
fmt.Printf("w %v\n", buf.Bytes())
_, err := c.Write(buf.Bytes())
return err
}
@ -80,13 +342,11 @@ func (enc *RawEncoding) Read(c Conn, rect *Rectangle) error {
bytesPerPixel := int(pf.BPP / 8)
n := rect.Area() * bytesPerPixel
data := make([]byte, n)
fmt.Printf("r %d\n", n)
if err := binary.Read(c, binary.BigEndian, &data); err != nil {
return err
}
buf.Write(data)
defer buf.Reset()
fmt.Printf("r %v\n", buf.Bytes())
colors := make([]Color, rect.Area())
for y := uint16(0); y < rect.Height; y++ {
for x := uint16(0); x < rect.Width; x++ {
@ -105,7 +365,8 @@ func (enc *RawEncoding) Read(c Conn, rect *Rectangle) error {
func (*RawEncoding) Type() EncodingType { return EncRaw }
// DesktopSizePseudoEncoding represents a desktop size message from the server.
type DesktopSizePseudoEncoding struct{}
type DesktopSizePseudoEncoding struct {
}
func (*DesktopSizePseudoEncoding) Type() EncodingType { return EncDesktopSizePseudo }
@ -113,7 +374,6 @@ func (*DesktopSizePseudoEncoding) Type() EncodingType { return EncDesktopSizePse
func (*DesktopSizePseudoEncoding) Read(c Conn, rect *Rectangle) error {
c.SetWidth(rect.Width)
c.SetHeight(rect.Height)
return nil
}

View File

@ -4,46 +4,59 @@ package vnc
import "fmt"
const (
_EncodingType_name_0 = "EncClientRedirect"
_EncodingType_name_1 = "EncColorPseudo"
_EncodingType_name_2 = "EncDesktopSizePseudo"
_EncodingType_name_3 = "EncRawEncCopyRectEncRRE"
_EncodingType_name_4 = "EncCoRREEncHextileEncZlibEncTightEncZlibHexEncUltra1EncUltra2"
_EncodingType_name_5 = "EncTRLEEncZRLE"
_EncodingType_name_6 = "EncJPEGEncJRLE"
)
const _EncodingType_name = "EncContinuousUpdatesPseudoEncFencePseudoEncClientRedirectEncXvpPseudoEncExtendedDesktopSizePseudoEncTightPngEncQEMUExtendedKeyEventPseudoEncQEMUPointerMotionChangePseudoEncCompressionLevel1EncCompressionLevel2EncCompressionLevel3EncCompressionLevel4EncCompressionLevel5EncCompressionLevel6EncCompressionLevel7EncCompressionLevel8EncCompressionLevel9EncCompressionLevel10EncColorPseudoEncLastRectPseudoEncDesktopSizePseudoEncJPEGQualityLevelPseudo1EncJPEGQualityLevelPseudo2EncJPEGQualityLevelPseudo3EncJPEGQualityLevelPseudo4EncJPEGQualityLevelPseudo5EncJPEGQualityLevelPseudo6EncJPEGQualityLevelPseudo7EncJPEGQualityLevelPseudo8EncJPEGQualityLevelPseudo9EncJPEGQualityLevelPseudo10EncRawEncCopyRectEncRREEncCoRREEncHextileEncZlibEncTightEncZlibHexEncUltra1EncUltra2EncTRLEEncZRLEEncJPEGEncJRLE"
var (
_EncodingType_index_0 = [...]uint8{0, 17}
_EncodingType_index_1 = [...]uint8{0, 14}
_EncodingType_index_2 = [...]uint8{0, 20}
_EncodingType_index_3 = [...]uint8{0, 6, 17, 23}
_EncodingType_index_4 = [...]uint8{0, 8, 18, 25, 33, 43, 52, 61}
_EncodingType_index_5 = [...]uint8{0, 7, 14}
_EncodingType_index_6 = [...]uint8{0, 7, 14}
)
var _EncodingType_map = map[EncodingType]string{
-313: _EncodingType_name[0:26],
-312: _EncodingType_name[26:40],
-311: _EncodingType_name[40:57],
-309: _EncodingType_name[57:69],
-308: _EncodingType_name[69:97],
-260: _EncodingType_name[97:108],
-258: _EncodingType_name[108:137],
-257: _EncodingType_name[137:169],
-256: _EncodingType_name[169:189],
-255: _EncodingType_name[189:209],
-254: _EncodingType_name[209:229],
-253: _EncodingType_name[229:249],
-252: _EncodingType_name[249:269],
-251: _EncodingType_name[269:289],
-250: _EncodingType_name[289:309],
-249: _EncodingType_name[309:329],
-248: _EncodingType_name[329:349],
-247: _EncodingType_name[349:370],
-239: _EncodingType_name[370:384],
-224: _EncodingType_name[384:401],
-223: _EncodingType_name[401:421],
-32: _EncodingType_name[421:447],
-31: _EncodingType_name[447:473],
-30: _EncodingType_name[473:499],
-29: _EncodingType_name[499:525],
-28: _EncodingType_name[525:551],
-27: _EncodingType_name[551:577],
-26: _EncodingType_name[577:603],
-25: _EncodingType_name[603:629],
-24: _EncodingType_name[629:655],
-23: _EncodingType_name[655:682],
0: _EncodingType_name[682:688],
1: _EncodingType_name[688:699],
2: _EncodingType_name[699:705],
4: _EncodingType_name[705:713],
5: _EncodingType_name[713:723],
6: _EncodingType_name[723:730],
7: _EncodingType_name[730:738],
8: _EncodingType_name[738:748],
9: _EncodingType_name[748:757],
10: _EncodingType_name[757:766],
15: _EncodingType_name[766:773],
16: _EncodingType_name[773:780],
21: _EncodingType_name[780:787],
22: _EncodingType_name[787:794],
}
func (i EncodingType) String() string {
switch {
case i == -311:
return _EncodingType_name_0
case i == -239:
return _EncodingType_name_1
case i == -223:
return _EncodingType_name_2
case 0 <= i && i <= 2:
return _EncodingType_name_3[_EncodingType_index_3[i]:_EncodingType_index_3[i+1]]
case 4 <= i && i <= 10:
i -= 4
return _EncodingType_name_4[_EncodingType_index_4[i]:_EncodingType_index_4[i+1]]
case 15 <= i && i <= 16:
i -= 15
return _EncodingType_name_5[_EncodingType_index_5[i]:_EncodingType_index_5[i+1]]
case 21 <= i && i <= 22:
i -= 21
return _EncodingType_name_6[_EncodingType_index_6[i]:_EncodingType_index_6[i+1]]
default:
return fmt.Sprintf("EncodingType(%d)", i)
if str, ok := _EncodingType_map[i]; ok {
return str
}
return fmt.Sprintf("EncodingType(%d)", i)
}

View File

@ -22,10 +22,17 @@ func main() {
Height: 600,
VersionHandler: vnc.ServerVersionHandler,
SecurityHandler: vnc.ServerSecurityHandler,
SecurityHandlers: []vnc.SecurityHandler{&vnc.ClientAuthNone{}},
SecurityHandlers: []vnc.SecurityHandler{
&vnc.ClientAuthVeNCrypt02Plain{Username: []byte("test"), Password: []byte("test")},
&vnc.ClientAuthNone{},
},
ClientInitHandler: vnc.ServerClientInitHandler,
ServerInitHandler: vnc.ServerServerInitHandler,
Encodings: []vnc.Encoding{&vnc.RawEncoding{}},
Encodings: []vnc.Encoding{
&vnc.TightPngEncoding{},
&vnc.CopyRectEncoding{},
&vnc.RawEncoding{},
},
PixelFormat: vnc.PixelFormat32bit,
ClientMessageCh: schClient,
ServerMessageCh: schServer,
@ -57,9 +64,9 @@ func main() {
log.Fatalf("Error dial. %v", err)
}
scfg.Width = cc.Width()
scfg.Height = cc.Height()
scfg.PixelFormat = cc.PixelFormat()
// scfg.Width = cc.Width()
// scfg.Height = cc.Height()
// scfg.PixelFormat = cc.PixelFormat()
go vnc.Serve(context.Background(), ln, scfg)
defer cc.Close()
@ -75,28 +82,28 @@ func main() {
case msg := <-schClient:
switch msg.Type() {
case vnc.SetEncodingsMsgType:
msg0 := &vnc.SetPixelFormat{
PF: *vnc.PixelFormat32bit,
var encTypes []vnc.EncodingType
for _, enc := range scfg.Encodings {
encTypes = append(encTypes, enc.Type())
}
msg0 := &vnc.SetEncodings{
Encodings: encTypes,
}
cchClient <- msg0
encRaw := &vnc.RawEncoding{}
msg1 := &vnc.SetEncodings{
Encodings: []vnc.EncodingType{encRaw.Type()},
}
cchClient <- msg1
/*
msg2 := &vnc.FramebufferUpdateRequest{
Inc: 0,
X: 0,
Y: 0,
if scfg.Width != cc.Width() || scfg.Height != cc.Height() {
msg1 := &vnc.FramebufferUpdate{
Rects: []*vnc.Rectangle{&vnc.Rectangle{
Width: cc.Width(),
Height: cc.Height(),
EncType: vnc.EncDesktopSizePseudo,
Enc: &vnc.DesktopSizePseudoEncoding{},
},
},
}
schServer <- msg1
}
cchClient <- msg2
*/
case vnc.SetPixelFormatMsgType:
cchClient <- msg
default:
cchClient <- msg
}

View File

@ -198,6 +198,9 @@ func ServerSecurityHandler(cfg *ServerConfig, c Conn) error {
if err := binary.Write(c, binary.BigEndian, []byte(authErr.Error())); err != nil {
return err
}
if err := c.Flush(); err != nil {
return err
}
return authErr
}

View File

@ -115,7 +115,6 @@ func colorsToImage(x, y, width, height uint16, colors []Color) *image.RGBA64 {
// Marshal implements the Marshaler interface.
func (r *Rectangle) Write(c Conn) error {
var err error
fmt.Printf("w rect %#+v\n", r)
if err = binary.Write(c, binary.BigEndian, r.X); err != nil {
return err
}
@ -157,10 +156,17 @@ func (r *Rectangle) Read(c Conn) error {
return err
}
switch r.EncType {
case EncCopyRect:
r.Enc = &CopyRectEncoding{}
case EncTight:
r.Enc = &TightEncoding{}
case EncTightPng:
r.Enc = &TightPngEncoding{}
case EncRaw:
r.Enc = &RawEncoding{}
default:
return fmt.Errorf("unsupported encoding %s", r.EncType)
}
fmt.Printf("r rect %#+v\n", r)
return r.Enc.Read(c, r)
}

View File

@ -1,6 +1,7 @@
package vnc
import (
"bytes"
"crypto/des"
"encoding/binary"
"fmt"
@ -74,6 +75,10 @@ func (*ServerAuthNone) Auth(c Conn) error {
return nil
}
func (*ClientAuthVeNCrypt02Plain) Type() SecurityType {
return SecTypeVeNCrypt
}
func (*ClientAuthVeNCrypt02Plain) SubType() SecuritySubType {
return SecSubTypeVeNCrypt02Plain
}
@ -85,10 +90,52 @@ type ClientAuthVeNCrypt02Plain struct {
}
func (auth *ClientAuthVeNCrypt02Plain) Auth(c Conn) error {
if err := binary.Write(c, binary.BigEndian, []uint8{0, 2}); err != nil {
return err
}
if err := c.Flush(); err != nil {
return err
}
var (
major, minor uint8
)
if err := binary.Read(c, binary.BigEndian, &major); err != nil {
return err
}
if err := binary.Read(c, binary.BigEndian, &minor); err != nil {
return err
}
res := uint8(1)
if major == 0 && minor == 2 {
res = uint8(0)
}
if err := binary.Write(c, binary.BigEndian, res); err != nil {
return err
}
c.Flush()
if err := binary.Write(c, binary.BigEndian, uint8(1)); err != nil {
return err
}
if err := binary.Write(c, binary.BigEndian, auth.SubType()); err != nil {
return err
}
if err := c.Flush(); err != nil {
return err
}
var secType SecuritySubType
if err := binary.Read(c, binary.BigEndian, &secType); err != nil {
return err
}
if secType != auth.SubType() {
binary.Write(c, binary.BigEndian, uint8(1))
c.Flush()
return fmt.Errorf("invalid sectype")
}
if len(auth.Password) == 0 || len(auth.Username) == 0 {
return fmt.Errorf("Security Handshake failed; no username and/or password provided for VeNCryptAuth.")
}
/*
if err := binary.Write(c, binary.BigEndian, uint32(len(auth.Username))); err != nil {
return err
}
@ -104,8 +151,30 @@ func (auth *ClientAuthVeNCrypt02Plain) Auth(c Conn) error {
if err := binary.Write(c, binary.BigEndian, auth.Password); err != nil {
return err
}
*/
var (
uLength, pLength uint32
)
if err := binary.Read(c, binary.BigEndian, &uLength); err != nil {
return err
}
if err := binary.Read(c, binary.BigEndian, &pLength); err != nil {
return err
}
return c.Flush()
username := make([]byte, uLength)
password := make([]byte, pLength)
if err := binary.Read(c, binary.BigEndian, &username); err != nil {
return err
}
if err := binary.Read(c, binary.BigEndian, &password); err != nil {
return err
}
if !bytes.Equal(auth.Username, username) || !bytes.Equal(auth.Password, password) {
return fmt.Errorf("invalid username/password")
}
return nil
}
// ServerAuthVNC is the standard password authentication. See 7.2.2.

View File

@ -156,7 +156,6 @@ func (*FramebufferUpdate) Read(c Conn) (ServerMessage, error) {
if err := binary.Read(c, binary.BigEndian, &msg.NumRect); err != nil {
return nil, err
}
fmt.Printf("%#+v\n", msg)
for i := uint16(0); i < msg.NumRect; i++ {
rect := &Rectangle{}
if err := rect.Read(c); err != nil {
@ -164,15 +163,10 @@ func (*FramebufferUpdate) Read(c Conn) (ServerMessage, error) {
}
msg.Rects = append(msg.Rects, rect)
}
fmt.Printf("r fb %d %d %v\n", msg.NumRect, uint16(len(msg.Rects)), msg.Rects)
if msg.NumRect != uint16(len(msg.Rects)) {
panic("rects not equal")
}
return &msg, nil
}
func (msg *FramebufferUpdate) Write(c Conn) error {
fmt.Printf("w fb %d %d %v\n", msg.NumRect, uint16(len(msg.Rects)), msg.Rects)
if err := binary.Write(c, binary.BigEndian, msg.Type()); err != nil {
return err
}
@ -341,14 +335,12 @@ func (c *ServerConn) Handle() error {
if err := binary.Read(c, binary.BigEndian, &messageType); err != nil {
return err
}
fmt.Printf("srv r %s\n", messageType)
msg, ok := clientMessages[messageType]
if !ok {
return fmt.Errorf("unsupported message-type: %v", messageType)
}
parsedMsg, err := msg.Read(c)
fmt.Printf("srv r %#+v\n", parsedMsg)
if err != nil {
fmt.Printf("srv err %s\n", err.Error())
return err

View File

@ -0,0 +1,27 @@
// Code generated by "stringer -type=TightCompression"; DO NOT EDIT.
package vnc
import "fmt"
const (
_TightCompression_name_0 = "TightCompressionBasic"
_TightCompression_name_1 = "TightCompressionFillTightCompressionJPEGTightCompressionPNG"
)
var (
_TightCompression_index_0 = [...]uint8{0, 21}
_TightCompression_index_1 = [...]uint8{0, 20, 40, 59}
)
func (i TightCompression) String() string {
switch {
case i == 0:
return _TightCompression_name_0
case 8 <= i && i <= 10:
i -= 8
return _TightCompression_name_1[_TightCompression_index_1[i]:_TightCompression_index_1[i+1]]
default:
return fmt.Sprintf("TightCompression(%d)", i)
}
}

16
tightfilter_string.go Normal file
View File

@ -0,0 +1,16 @@
// Code generated by "stringer -type=TightFilter"; DO NOT EDIT.
package vnc
import "fmt"
const _TightFilter_name = "TightFilterCopyTightFilterPaletteTightFilterGradient"
var _TightFilter_index = [...]uint8{0, 15, 33, 52}
func (i TightFilter) String() string {
if i >= TightFilter(len(_TightFilter_index)-1) {
return fmt.Sprintf("TightFilter(%d)", i)
}
return _TightFilter_name[_TightFilter_index[i]:_TightFilter_index[i+1]]
}