forked from sugyan/ttygif
-
Notifications
You must be signed in to change notification settings - Fork 0
/
pixmap.go
151 lines (121 loc) · 3.33 KB
/
pixmap.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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package xwd
import (
"encoding/binary"
"image"
"image/color"
"io"
)
type Pixmap interface {
At(x, y int) color.Color
Bounds() image.Rectangle
ColorModel() color.Model
}
// pixmapRaw is used if the image's data is stored raw, as in each pixel
// stores it's own color.
type pixmapRaw struct {
header *FileHeader
pixels []Color
}
// pixmapMapped is used if the image's data is colormapped, e.g.
// each pixel is a "pointer" to a value of the corresponding color map.
type pixmapMapped struct {
header *FileHeader
colors *ColorMap
pixels []uint8
}
func ReadPixmap(r io.Reader, h *FileHeader, colors *ColorMap) (Pixmap, error) {
if h.IsMapped() {
debugf("this is a mapped pixmap")
return readPixmapMapped(r, h, colors)
} else { //nolint:golint,revive // looks way better like this
debugf("this is a raw pixmap")
return readPixmapRaw(r, h)
}
}
func readPixmapRaw(r io.Reader, h *FileHeader) (*pixmapRaw, error) {
if h.BitsPerPixel != 24 {
return nil, &UnsupportedError{"color depth", i32toa(h.BitsPerPixel)}
}
buf := make([]byte, 4)
discard := make([]byte, h.BytesPerLine-h.WindowWidth*h.BitsPerPixel/8)
var cu uint32
var cl Color
pixmap := pixmapRaw{h, make([]Color, h.PixmapWidth*h.PixmapHeight)}
var rs, gs, bs int = shiftwidth(h.RedMask), shiftwidth(h.GreenMask), shiftwidth(h.BlueMask)
var i uint32
var x, y uint32
for y = 0; y < h.PixmapHeight; y++ {
for x = 0; x < h.PixmapWidth; x++ {
_, err := r.Read(buf[1:4])
if err != nil {
return nil, &IOError{err, "reading pixmap"}
}
cu = binary.BigEndian.Uint32(buf)
cl = Color{
Pixel: i, Flags: 7, Padding: 0,
Red: uint16(((cu & h.RedMask) >> rs) << 8),
Green: uint16(((cu & h.GreenMask) >> gs) << 8),
Blue: uint16(((cu & h.BlueMask) >> bs) << 8),
}
pixmap.pixels[i] = cl
i++
}
_, err := r.Read(discard) // discard line ending
if err != nil {
return nil, &IOError{err, "reading pixmap"}
}
}
return &pixmap, nil
}
func shiftwidth(mask uint32) int {
if mask == 0 {
return 0
}
for i := 0; i < 32; i++ {
if mask&0b1 != 0 {
return i
}
mask = mask >> 1
}
return 0
}
func readPixmapMapped(r io.Reader, h *FileHeader, colors *ColorMap) (*pixmapMapped, error) {
var pix pixmapMapped
pix.header = h
pix.colors = colors
pix.pixels = make([]uint8, h.PixmapWidth*h.PixmapHeight)
debugf("Going to read %d bytes", h.PixmapWidth*h.PixmapHeight*colormapKeySize)
buf := make([]byte, h.PixmapWidth*h.PixmapHeight*colormapKeySize)
_, err := r.Read(buf)
if err != nil {
return nil, &IOError{err, "reading pixmap"}
}
var i, x, y uint32
for y = 0; y < h.PixmapHeight; y++ {
for x = 0; x < h.PixmapWidth; x++ {
pix.pixels[i] = buf[i*colormapKeySize]
i++
}
}
return &pix, nil
}
func (p *pixmapRaw) At(x, y int) color.Color {
return &p.pixels[y*int(p.header.PixmapWidth)+x]
}
func (p *pixmapRaw) Bounds() image.Rectangle {
return image.Rect(0, 0, int(p.header.PixmapWidth), int(p.header.PixmapHeight))
}
func (p *pixmapRaw) ColorModel() color.Model {
return color.RGBAModel
}
func (p *pixmapMapped) At(x, y int) color.Color {
id := p.pixels[y*int(p.header.PixmapWidth)+x]
c := p.colors.Get(int(id))
return &c
}
func (p *pixmapMapped) Bounds() image.Rectangle {
return image.Rect(0, 0, int(p.header.PixmapWidth), int(p.header.PixmapHeight))
}
func (p *pixmapMapped) ColorModel() color.Model {
return color.RGBAModel
}