-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathrle.go
382 lines (333 loc) · 10.6 KB
/
rle.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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
package go_bitmap
import (
"bytes"
"image"
"image/color"
"io"
"github.com/GoFeGroup/go-bitmap/glog"
)
const (
g_MaskRegularRunLength = 0x1F
g_MaskLiteRunLength = 0x0F
g_MaskSpecialFgBg1 = 0x03
g_MaskSpecialFgBg2 = 0x05
// opcode>>=5,count=opcode&0x1F:input[0]+32
REGULAR_BG_RUN = 0x00 // opcode=FILL
REGULAR_FG_RUN = 0x01 // opcode=MIX
REGULAR_FGBG_IMAGE = 0x02 // count=(code&0xF)<<3:input[0]+1,opcode=FOM
REGULAR_COLOR_RUN = 0x03 // opcode=COLOR
REGULAR_COLOR_IMAGE = 0x04 // opcode=COPY
// >> shift >> 4
LITE_SET_FG_FG_RUN = 0x0C // count=code&0xF:count=input[0]+16,opcode=MIX_SET
LITE_SET_FG_FGBG_IMAGE = 0x0D // count=(code&0xF)<<3:input[0]+1,opcode=FOM_SET
LITE_DITHERED_RUN = 0x0E // count=code&0xF:count=input[0]+16,opcode=BICOLOR
// no >> shift
MEGA_MEGA_BG_RUN = 0xF0 // count=input[0]|(input[1]<<8),opcode=FILL
MEGA_MEGA_FG_RUN = 0xF1 // count=input[0]|(input[1]<<8),opcode=MIX
MEGA_MEGA_FGBG_IMAGE = 0xF2 // count=input[0]|(input[1]<<8),opcode=FOM
MEGA_MEGA_COLOR_RUN = 0xF3 // count=input[0]|(input[1]<<8),opcode=COLOR
MEGA_MEGA_COLOR_IMAGE = 0xF4 // count=input[0]|(input[1]<<8),opcode=COPY
MEGA_MEGA_SET_FG_RUN = 0xF6 // count=input[0]|(input[1]<<8),opcode=MIX_SET
MEGA_MEGA_SET_FGBG_IMAGE = 0xF7 // count=input[0]|(input[1]<<8),opcode=FOM_SET
MEGA_MEGA_DITHERED_RUN = 0xF8 // count=input[0]|(input[1]<<8),opcode=BICOLOR,input=2
SPECIAL_FGBG_1 = 0xF9 // count=8,opcode=SPECIAL_FGBG_1
SPECIAL_FGBG_2 = 0xFA // count=8,opcode=SPECIAL_FGBG_2
SPECIAL_WHITE = 0xFD // count=1,opcode=WHITE
SPECIAL_BLACK = 0xFE // count=1,opcode=BLACK
)
var codeMap = map[uint8]string{
0x00: "REGULAR_BG_RUN",
0x01: "REGULAR_FG_RUN",
0x02: "REGULAR_FGBG_IMAGE",
0x03: "REGULAR_COLOR_RUN",
0x04: "REGULAR_COLOR_IMAGE",
0x0C: "LITE_SET_FG_FG_RUN",
0x0D: "LITE_SET_FG_FGBG_IMAGE",
0x0E: "LITE_DITHERED_RUN",
0xF0: "MEGA_MEGA_BG_RUN",
0xF1: "MEGA_MEGA_FG_RUN",
0xF2: "MEGA_MEGA_FGBG_IMAGE",
0xF3: "MEGA_MEGA_COLOR_RUN",
0xF4: "MEGA_MEGA_COLOR_IMAGE",
0xF6: "MEGA_MEGA_SET_FG_RUN",
0xF7: "MEGA_MEGA_SET_FGBG_IMAGE",
0xF8: "MEGA_MEGA_DITHERED_RUN",
0xF9: "SPECIAL_FGBG_1",
0xFA: "SPECIAL_FGBG_2",
0xFD: "SPECIAL_WHITE",
0xFE: "SPECIAL_BLACK",
}
var colorWhiteMap = map[int]uint32{8: 0xFF, 15: 0x7FFF, 16: 0xFFFF, 24: 0xFFFFFF}
// 获取白色像素
func getColorWhite(bpp int) uint32 {
if white, ok := colorWhiteMap[bpp]; ok {
return white
} else {
Throwf("invalid bpp: %v", bpp)
return 0
}
}
var pixelSizeMap = map[int]int{8: 1, 15: 2, 16: 2, 24: 3}
func getPixelSize(bpp int) int {
if size, ok := pixelSizeMap[bpp]; ok {
return size
} else {
Throwf("invalid bpp: %v", bpp)
return 0
}
}
// 获取黑色像素
func getColorBlack() uint32 {
return 0x000000
}
// extract codeId
func extractCodeId(header uint8) uint8 {
switch header & 0xF0 {
case 0xF0: // mega&special
return header
case 0xC0, 0xD0, 0xE0: // lite form
return header >> 4
default:
return header >> 5
}
}
func extractRunLength(code, header uint8, r io.Reader) int {
switch code {
case REGULAR_FGBG_IMAGE: // FOM
if runLength := header & g_MaskRegularRunLength; runLength != 0 {
return int(runLength) << 3
} else {
return int(ReadByte(r)) + 1
}
case LITE_SET_FG_FGBG_IMAGE: // FOM_SET
if runLength := header & g_MaskLiteRunLength; runLength != 0 {
return int(runLength) << 3
} else {
return int(ReadByte(r)) + 1
}
case REGULAR_BG_RUN, REGULAR_FG_RUN, REGULAR_COLOR_RUN, REGULAR_COLOR_IMAGE: //FILL,MIX,COLOR,COPY
if runLength := header & g_MaskRegularRunLength; runLength != 0 {
return int(runLength)
} else {
return int(ReadByte(r)) + 32
}
case LITE_DITHERED_RUN, LITE_SET_FG_FG_RUN: // BICOLOR,MIX_SET
if runLength := header & g_MaskLiteRunLength; runLength != 0 {
return int(runLength)
} else {
return int(ReadByte(r)) + 16
}
case MEGA_MEGA_BG_RUN, MEGA_MEGA_COLOR_IMAGE, MEGA_MEGA_COLOR_RUN, MEGA_MEGA_DITHERED_RUN,
MEGA_MEGA_FG_RUN, MEGA_MEGA_FGBG_IMAGE, MEGA_MEGA_SET_FG_RUN, MEGA_MEGA_SET_FGBG_IMAGE:
return int(ReadShortLE(r))
case SPECIAL_FGBG_1, SPECIAL_FGBG_2:
return 8
default:
//glog.Debug("[DEFAULT] Return 0")
return 0
}
}
// 从流中读取一个像素
func readPixel(r io.Reader, bpp int) uint32 {
switch getPixelSize(bpp) {
case 1:
return uint32(ReadByte(r))
case 2:
return uint32(ReadShortLE(r))
case 3:
return uint32(ReadByte(r)) | uint32(ReadShortLE(r))<<8
}
ThrowError("invalid bpp")
return 0
}
// 写入一个像素
func writePixel(w io.Writer, pixel uint32, bpp int) {
switch getPixelSize(bpp) {
case 1:
WriteByte(w, byte(pixel&0xff))
case 2:
WriteShortLE(w, uint16(pixel&0xffff))
case 3:
WriteByte(w, byte(pixel&0xff))
WriteShortLE(w, uint16((pixel>>8)&0xffff))
default:
Throwf("invalid bpp: %v", bpp)
}
}
// 查找上一行相同位置的像素
func peekPixel(r *bytes.Buffer, rowDelta int, bpp int) uint32 {
if r.Len() >= rowDelta {
pos := r.Len() - rowDelta
return readPixel(bytes.NewReader(r.Bytes()[pos:pos+getPixelSize(bpp)]), bpp)
}
return getColorBlack()
}
// 解压RLE格式Bitmap
func rleDecompress(w, h, bpp int, data []byte) image.Image {
r := bytes.NewReader(data)
whitePixel := getColorWhite(bpp)
blackPixel := getColorBlack()
fgPel := whitePixel // 背景色 --> MIX
dest := new(bytes.Buffer)
insertFgPel := false // for FILL
pixels := 0
for r.Len() > 0 {
codeHeader := ReadByte(r)
code := extractCodeId(codeHeader)
glog.Debugf("code: %s[%#x] codeHeader: %x", codeMap[code], code, codeHeader)
runLength := extractRunLength(code, codeHeader, r)
// Handle Background Run Orders.
if code == REGULAR_BG_RUN || code == MEGA_MEGA_BG_RUN { // FILL
pixels += runLength
glog.Debugf("+++ runLength: %v, pixels: %v", runLength, pixels)
pixel := peekPixel(dest, w*getPixelSize(bpp), bpp) // 查找上一行像素
if insertFgPel { // FILL & lastcode == FILL
writePixel(dest, pixel^fgPel, bpp)
} else { // FILL & lastcode != FILL
writePixel(dest, pixel, bpp)
}
runLength--
for ; runLength > 0; runLength-- {
pixel := peekPixel(dest, w*getPixelSize(bpp), bpp) // 查找上一行像素
writePixel(dest, pixel, bpp)
}
glog.Debugf("--- dest pixels: %v", dest.Len()/getPixelSize(bpp))
insertFgPel = true // set last opcode=FILL
continue
}
insertFgPel = false // set last opcode != FILL
// change 背景色 mix
switch code {
case LITE_SET_FG_FG_RUN, MEGA_MEGA_SET_FG_RUN, // MIX_SET
LITE_SET_FG_FGBG_IMAGE, MEGA_MEGA_SET_FGBG_IMAGE: // FOM_SET
fgPel = readPixel(r, bpp)
glog.Debugf(" -> change fgPel: %x", fgPel)
}
// Process
switch code {
// Handle Foreground Run Orders.
case REGULAR_FG_RUN, MEGA_MEGA_FG_RUN, LITE_SET_FG_FG_RUN, MEGA_MEGA_SET_FG_RUN: // MIX,MIX,MIX_SET,MIX_SET
pixels += runLength
glog.Debugf("+++ runLength: %v, pixels: %v", runLength, pixels)
for ; runLength > 0; runLength-- {
pixel := peekPixel(dest, w*getPixelSize(bpp), bpp) // 查找上一行像素
writePixel(dest, pixel^fgPel, bpp)
}
// Handle Dithered Run Orders.
case LITE_DITHERED_RUN, MEGA_MEGA_DITHERED_RUN: // BICOLOR
pixels += runLength * 2
glog.Debugf("+++ runLength: %v, pixels: %v", runLength, pixels)
pixelA := readPixel(r, bpp)
pixelB := readPixel(r, bpp)
glog.Debugf("pixel: %x %x", pixelA, pixelB)
for ; runLength > 0; runLength-- {
writePixel(dest, pixelA, bpp)
writePixel(dest, pixelB, bpp)
}
// Handle Color Run Orders.
case REGULAR_COLOR_RUN, MEGA_MEGA_COLOR_RUN: // COLOR
pixels += runLength
glog.Debugf("+++ runLength: %v, pixels: %v", runLength, pixels)
pixelA := readPixel(r, bpp)
for ; runLength > 0; runLength-- {
writePixel(dest, pixelA, bpp)
}
// Handle Color Image Orders.
case REGULAR_COLOR_IMAGE, MEGA_MEGA_COLOR_IMAGE: // COPY
pixels += runLength
glog.Debugf("+++ runLength: %v, pixels: %v", runLength, pixels)
readBytes := ReadBytes(r, int(runLength)*getPixelSize(bpp))
WriteBytes(dest, readBytes)
// Handle Foreground/Background Image Orders.
case REGULAR_FGBG_IMAGE, MEGA_MEGA_FGBG_IMAGE, LITE_SET_FG_FGBG_IMAGE, MEGA_MEGA_SET_FGBG_IMAGE: //FOM,FOM,FOM_SET,FOM_SET
pixels += runLength
glog.Debugf("+++ runLength: %v, pixels: %v", runLength, pixels)
for ; runLength > 0; runLength -= 8 {
bitmask := ReadByte(r) // => mask
cBits := 8
if runLength < 8 {
cBits = runLength
}
for ; cBits > 0; cBits-- {
pixel := peekPixel(dest, w*getPixelSize(bpp), bpp) // 查找上一行像素
if bitmask&0x1 > 0 {
pixel ^= fgPel // FIXME
}
writePixel(dest, pixel, bpp)
bitmask >>= 1
}
}
// Handle Special Order 1.
case SPECIAL_FGBG_1:
pixels += 8
glog.Debugf("+++ runLength: %v, pixels: %v", "-", pixels)
cBits := 8
bitmask := g_MaskSpecialFgBg1
for ; cBits > 0; cBits-- {
pixel := peekPixel(dest, w*getPixelSize(bpp), bpp) // 查找上一行像素
if bitmask&0x1 > 0 {
pixel ^= fgPel // FIXME
}
writePixel(dest, pixel, bpp)
bitmask >>= 1
}
// Handle Special Order 2.
case SPECIAL_FGBG_2:
pixels += 8
glog.Debugf("+++ runLength: %v, pixels: %v", "-", pixels)
cBits := 8
bitmask := g_MaskSpecialFgBg2
for ; cBits > 0; cBits-- {
pixel := peekPixel(dest, w*getPixelSize(bpp), bpp) // 查找上一行像素
if bitmask&0x1 > 0 {
pixel ^= fgPel // FIXME
}
writePixel(dest, pixel, bpp)
bitmask >>= 1
}
// Handle White Order.
case SPECIAL_WHITE:
pixels += 1
glog.Debugf("+++ runLength: %v, pixels: %v", "-", pixels)
writePixel(dest, whitePixel, bpp)
// Handle Black Order.
case SPECIAL_BLACK:
pixels += 1
glog.Debugf("+++ runLength: %v, pixels: %v", "-", pixels)
writePixel(dest, blackPixel, bpp)
default:
Throwf("invalid code: %x, codeHeader: %x, runLength: %x, data: %x",
code, codeHeader, runLength, data)
}
}
return pixelsToImage(w, h, bpp, dest.Bytes())
}
func pixelsToImage(w, h, bpp int, data []byte) image.Image {
switch bpp {
case 16:
return rgb565ToImage(w, h, data)
default:
Throwf("bpp [%v] not implement", bpp)
}
return nil
}
func rgb565ToImage(w int, h int, data []byte) image.Image {
img := image.NewRGBA(image.Rect(0, 0, w, h))
r := bytes.NewReader(data)
for y := 1; y <= h; y++ {
for x := 0; x < w; x++ {
pixel := readPixel(r, 16)
// RGB565
r := uint8((pixel&0xF800)>>11) << 3
g := uint8((pixel&0x7E0)>>5) << 2
b := uint8(pixel&0x1F) << 3
img.Set(x, h-y, color.RGBA{R: r, G: g, B: b, A: 255})
}
}
return img
}
// LoadRLE 加载RLE格式的Bitmap数据
func (m *BitMap) LoadRLE(option *Option) *BitMap {
m.Image = rleDecompress(option.Width, option.Height, option.BitPerPixel, option.Data)
return m
}