go-rfb/image.go
Vasiliy Tolstov f6acfdfdad add ability to check supported status
Signed-off-by: Vasiliy Tolstov <v.tolstov@selfip.ru>
2017-07-14 02:01:24 +03:00

201 lines
4.6 KiB
Go

package vnc
import (
"encoding/binary"
"fmt"
"image"
"strings"
)
//var _ draw.Drawer = (*ServerConn)(nil)
//var _ draw.Image = (*ServerConn)(nil)
// Color represents a single color in a color map.
type Color struct {
pf *PixelFormat
cm *ColorMap
cmIndex uint32 // Only valid if pf.TrueColor is false.
R, G, B uint16
}
// ColorMap represent color map
type ColorMap [256]Color
// NewColor returns a new Color object
func NewColor(pf *PixelFormat, cm *ColorMap) *Color {
return &Color{
pf: pf,
cm: cm,
}
}
// Rectangle represents a rectangle of pixel data
type Rectangle struct {
X, Y uint16
Width, Height uint16
EncType EncodingType
Enc Encoding
}
// String return string representation
func (rect *Rectangle) String() string {
return fmt.Sprintf("rect x: %d, y: %d, width: %d, height: %d, enc: %s", rect.X, rect.Y, rect.Width, rect.Height, rect.EncType)
}
// NewRectangle returns new rectangle
func NewRectangle() *Rectangle {
return &Rectangle{}
}
// Write marshal color to conn
func (clr *Color) Write(c Conn) error {
var err error
pf := c.PixelFormat()
order := pf.order()
pixel := clr.cmIndex
if clr.pf.TrueColor != 0 {
pixel = uint32(clr.R) << pf.RedShift
pixel |= uint32(clr.G) << pf.GreenShift
pixel |= uint32(clr.B) << pf.BlueShift
}
switch pf.BPP {
case 8:
err = binary.Write(c, order, byte(pixel))
case 16:
err = binary.Write(c, order, uint16(pixel))
case 32:
err = binary.Write(c, order, uint32(pixel))
}
return err
}
// Read unmarshal color from conn
func (clr *Color) Read(c Conn) error {
order := clr.pf.order()
var pixel uint32
switch clr.pf.BPP {
case 8:
var px uint8
if err := binary.Read(c, order, &px); err != nil {
return err
}
pixel = uint32(px)
case 16:
var px uint16
if err := binary.Read(c, order, &px); err != nil {
return err
}
pixel = uint32(px)
case 32:
var px uint32
if err := binary.Read(c, order, &px); err != nil {
return err
}
pixel = uint32(px)
}
if clr.pf.TrueColor != 0 {
clr.R = uint16((pixel >> clr.pf.RedShift) & uint32(clr.pf.RedMax))
clr.G = uint16((pixel >> clr.pf.GreenShift) & uint32(clr.pf.GreenMax))
clr.B = uint16((pixel >> clr.pf.BlueShift) & uint32(clr.pf.BlueMax))
} else {
*clr = clr.cm[pixel]
clr.cmIndex = pixel
}
return nil
}
func colorsToImage(x, y, width, height uint16, colors []Color) *image.RGBA64 {
rect := image.Rect(int(x), int(y), int(x+width), int(y+height))
rgba := image.NewRGBA64(rect)
a := uint16(1)
for i, color := range colors {
rgba.Pix[4*i+0] = uint8(color.R >> 8)
rgba.Pix[4*i+1] = uint8(color.R)
rgba.Pix[4*i+2] = uint8(color.G >> 8)
rgba.Pix[4*i+3] = uint8(color.G)
rgba.Pix[4*i+4] = uint8(color.B >> 8)
rgba.Pix[4*i+5] = uint8(color.B)
rgba.Pix[4*i+6] = uint8(a >> 8)
rgba.Pix[4*i+7] = uint8(a)
}
return rgba
}
// Write marshal rectangle to conn
func (rect *Rectangle) Write(c Conn) error {
var err error
if err = binary.Write(c, binary.BigEndian, rect.X); err != nil {
return err
}
if err = binary.Write(c, binary.BigEndian, rect.Y); err != nil {
return err
}
if err = binary.Write(c, binary.BigEndian, rect.Width); err != nil {
return err
}
if err = binary.Write(c, binary.BigEndian, rect.Height); err != nil {
return err
}
if err = binary.Write(c, binary.BigEndian, rect.EncType); err != nil {
return err
}
return rect.Enc.Write(c, rect)
}
// Read unmarshal rectangle from conn
func (rect *Rectangle) Read(c Conn) error {
var err error
if err = binary.Read(c, binary.BigEndian, &rect.X); err != nil {
return err
}
if err = binary.Read(c, binary.BigEndian, &rect.Y); err != nil {
return err
}
if err = binary.Read(c, binary.BigEndian, &rect.Width); err != nil {
return err
}
if err = binary.Read(c, binary.BigEndian, &rect.Height); err != nil {
return err
}
if err = binary.Read(c, binary.BigEndian, &rect.EncType); err != nil {
return err
}
switch rect.EncType {
case EncCopyRect:
rect.Enc = &CopyRectEncoding{}
case EncTight:
rect.Enc = &TightEncoding{}
case EncTightPng:
rect.Enc = &TightPngEncoding{}
case EncRaw:
if strings.HasPrefix(c.Protocol(), "aten") {
rect.Enc = &AtenHermon{}
} else {
rect.Enc = &RawEncoding{}
}
case EncDesktopSizePseudo:
rect.Enc = &DesktopSizePseudoEncoding{}
case EncDesktopNamePseudo:
rect.Enc = &DesktopNamePseudoEncoding{}
case EncXCursorPseudo:
rect.Enc = &XCursorPseudoEncoding{}
case EncAtenHermon:
rect.Enc = &AtenHermon{}
default:
return fmt.Errorf("unsupported encoding %s", rect.EncType)
}
return rect.Enc.Read(c, rect)
}
// Area returns the total area in pixels of the Rectangle
func (rect *Rectangle) Area() int { return int(rect.Width) * int(rect.Height) }