forked from amitbet/vnc2video
-
Notifications
You must be signed in to change notification settings - Fork 2
/
pixel_format.go
136 lines (117 loc) · 3.7 KB
/
pixel_format.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// Implementation of RFC 6143 §7.4 Pixel Format Data Structure.
package vnc2video
import (
"bytes"
"encoding/binary"
"fmt"
"io"
)
var (
// PixelFormat8bit returns 8 bit pixel format
PixelFormat8bit = NewPixelFormat(8)
// PixelFormat16bit returns 16 bit pixel format
PixelFormat16bit = NewPixelFormat(16)
// PixelFormat32bit returns 32 bit pixel format
PixelFormat32bit = NewPixelFormat(32)
// PixelFormatAten returns pixel format used in Aten IKVM
PixelFormatAten = NewPixelFormatAten()
)
// PixelFormat describes the way a pixel is formatted for a VNC connection
type PixelFormat struct {
BPP uint8 // bits-per-pixel
Depth uint8 // depth
BigEndian uint8 // big-endian-flag
TrueColor uint8 // true-color-flag
RedMax, GreenMax, BlueMax uint16 // red-, green-, blue-max (2^BPP-1)
RedShift, GreenShift, BlueShift uint8 // red-, green-, blue-shift
_ [3]byte // padding
}
const pixelFormatLen = 16
// NewPixelFormat returns a populated PixelFormat structure
func NewPixelFormat(bpp uint8) PixelFormat {
bigEndian := uint8(0)
// rgbMax := uint16(math.Exp2(float64(bpp))) - 1
rMax := uint16(255)
gMax := uint16(255)
bMax := uint16(255)
var (
tc = uint8(1)
rs, gs, bs uint8
depth uint8
)
switch bpp {
case 8:
tc = 0
depth = 8
rs, gs, bs = 0, 0, 0
case 16:
depth = 16
rs, gs, bs = 0, 4, 8
case 32:
depth = 24
// rs, gs, bs = 0, 8, 16
rs, gs, bs = 16, 8, 0
}
return PixelFormat{bpp, depth, bigEndian, tc, rMax, gMax, bMax, rs, gs, bs, [3]byte{}}
}
// NewPixelFormatAten returns Aten IKVM pixel format
func NewPixelFormatAten() PixelFormat {
return PixelFormat{16, 15, 0, 1, (1 << 5) - 1, (1 << 5) - 1, (1 << 5) - 1, 10, 5, 0, [3]byte{}}
}
// Marshal implements the Marshaler interface
func (pf PixelFormat) Marshal() ([]byte, error) {
// Validation checks.
switch pf.BPP {
case 8, 16, 32:
default:
return nil, fmt.Errorf("Invalid BPP value %v; must be 8, 16, or 32", pf.BPP)
}
if pf.Depth < pf.BPP {
return nil, fmt.Errorf("Invalid Depth value %v; cannot be < BPP", pf.Depth)
}
switch pf.Depth {
case 8, 16, 32:
default:
return nil, fmt.Errorf("Invalid Depth value %v; must be 8, 16, or 32", pf.Depth)
}
// Create the slice of bytes
buf := bPool.Get().(*bytes.Buffer)
buf.Reset()
defer bPool.Put(buf)
if err := binary.Write(buf, binary.BigEndian, &pf); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// Read reads from an io.Reader, and populates the PixelFormat
func (pf PixelFormat) Read(r io.Reader) error {
buf := make([]byte, pixelFormatLen)
if _, err := io.ReadAtLeast(r, buf, pixelFormatLen); err != nil {
return err
}
return pf.Unmarshal(buf)
}
// Unmarshal implements the Unmarshaler interface
func (pf PixelFormat) Unmarshal(data []byte) error {
buf := bPool.Get().(*bytes.Buffer)
buf.Reset()
defer bPool.Put(buf)
if _, err := buf.Write(data); err != nil {
return err
}
if err := binary.Read(buf, binary.BigEndian, &pf); err != nil {
return err
}
return nil
}
// String implements the fmt.Stringer interface
func (pf PixelFormat) String() string {
return fmt.Sprintf("{ bpp: %d depth: %d big-endian: %d true-color: %d red-max: %d green-max: %d blue-max: %d red-shift: %d green-shift: %d blue-shift: %d }",
pf.BPP, pf.Depth, pf.BigEndian, pf.TrueColor, pf.RedMax, pf.GreenMax, pf.BlueMax, pf.RedShift, pf.GreenShift, pf.BlueShift)
}
func (pf PixelFormat) order() binary.ByteOrder {
if pf.BigEndian == 1 {
return binary.BigEndian
}
return binary.LittleEndian
}