1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * (C) Copyright 2008-2017 Fuzhou Rockchip Electronics Co., Ltd
3*4882a593Smuzhiyun * Author: Mark Yao <mark.yao@rock-chips.com>
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * SPDX-License-Identifier: GPL-2.0+
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun #include <config.h>
8*4882a593Smuzhiyun #include <common.h>
9*4882a593Smuzhiyun #include <malloc.h>
10*4882a593Smuzhiyun #include <asm/unaligned.h>
11*4882a593Smuzhiyun #include <bmp_layout.h>
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #define BMP_RLE8_ESCAPE 0
14*4882a593Smuzhiyun #define BMP_RLE8_EOL 0
15*4882a593Smuzhiyun #define BMP_RLE8_EOBMP 1
16*4882a593Smuzhiyun #define BMP_RLE8_DELTA 2
17*4882a593Smuzhiyun
draw_unencoded_bitmap(uint16_t ** dst,uint8_t * bmap,uint16_t * cmap,uint32_t cnt)18*4882a593Smuzhiyun static void draw_unencoded_bitmap(uint16_t **dst, uint8_t *bmap, uint16_t *cmap,
19*4882a593Smuzhiyun uint32_t cnt)
20*4882a593Smuzhiyun {
21*4882a593Smuzhiyun while (cnt > 0) {
22*4882a593Smuzhiyun *(*dst)++ = cmap[*bmap++];
23*4882a593Smuzhiyun cnt--;
24*4882a593Smuzhiyun }
25*4882a593Smuzhiyun }
26*4882a593Smuzhiyun
draw_encoded_bitmap(uint16_t ** dst,uint16_t c,uint32_t cnt)27*4882a593Smuzhiyun static void draw_encoded_bitmap(uint16_t **dst, uint16_t c, uint32_t cnt)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun uint16_t *fb = *dst;
30*4882a593Smuzhiyun int cnt_8copy = cnt >> 3;
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun cnt -= cnt_8copy << 3;
33*4882a593Smuzhiyun while (cnt_8copy > 0) {
34*4882a593Smuzhiyun *fb++ = c;
35*4882a593Smuzhiyun *fb++ = c;
36*4882a593Smuzhiyun *fb++ = c;
37*4882a593Smuzhiyun *fb++ = c;
38*4882a593Smuzhiyun *fb++ = c;
39*4882a593Smuzhiyun *fb++ = c;
40*4882a593Smuzhiyun *fb++ = c;
41*4882a593Smuzhiyun *fb++ = c;
42*4882a593Smuzhiyun cnt_8copy--;
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun while (cnt > 0) {
45*4882a593Smuzhiyun *fb++ = c;
46*4882a593Smuzhiyun cnt--;
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun *dst = fb;
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun
decode_rle8_bitmap(void * psrc,void * pdst,uint16_t * cmap,int width,int height,int bits,int x_off,int y_off,bool flip)51*4882a593Smuzhiyun static void decode_rle8_bitmap(void *psrc, void *pdst, uint16_t *cmap,
52*4882a593Smuzhiyun int width, int height, int bits, int x_off,
53*4882a593Smuzhiyun int y_off, bool flip)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun uint32_t cnt, runlen;
56*4882a593Smuzhiyun int x = 0, y = 0;
57*4882a593Smuzhiyun int decode = 1;
58*4882a593Smuzhiyun int linesize = width * 2;
59*4882a593Smuzhiyun uint8_t *bmap = psrc;
60*4882a593Smuzhiyun uint8_t *dst = pdst;
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun if (flip) {
63*4882a593Smuzhiyun y = height - 1;
64*4882a593Smuzhiyun dst = pdst + y * linesize;
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun while (decode) {
68*4882a593Smuzhiyun if (bmap[0] == BMP_RLE8_ESCAPE) {
69*4882a593Smuzhiyun switch (bmap[1]) {
70*4882a593Smuzhiyun case BMP_RLE8_EOL:
71*4882a593Smuzhiyun /* end of line */
72*4882a593Smuzhiyun bmap += 2;
73*4882a593Smuzhiyun x = 0;
74*4882a593Smuzhiyun if (flip) {
75*4882a593Smuzhiyun y--;
76*4882a593Smuzhiyun dst -= linesize * 2;
77*4882a593Smuzhiyun } else {
78*4882a593Smuzhiyun y++;
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun break;
81*4882a593Smuzhiyun case BMP_RLE8_EOBMP:
82*4882a593Smuzhiyun /* end of bitmap */
83*4882a593Smuzhiyun decode = 0;
84*4882a593Smuzhiyun break;
85*4882a593Smuzhiyun case BMP_RLE8_DELTA:
86*4882a593Smuzhiyun /* delta run */
87*4882a593Smuzhiyun x += bmap[2];
88*4882a593Smuzhiyun if (flip) {
89*4882a593Smuzhiyun y -= bmap[3];
90*4882a593Smuzhiyun dst -= bmap[3] * linesize;
91*4882a593Smuzhiyun dst += bmap[2] * 2;
92*4882a593Smuzhiyun } else {
93*4882a593Smuzhiyun y += bmap[3];
94*4882a593Smuzhiyun dst += bmap[3] * linesize;
95*4882a593Smuzhiyun dst += bmap[2] * 2;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun bmap += 4;
98*4882a593Smuzhiyun break;
99*4882a593Smuzhiyun default:
100*4882a593Smuzhiyun /* unencoded run */
101*4882a593Smuzhiyun runlen = bmap[1];
102*4882a593Smuzhiyun bmap += 2;
103*4882a593Smuzhiyun if (y >= height || x >= width) {
104*4882a593Smuzhiyun decode = 0;
105*4882a593Smuzhiyun break;
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun if (x + runlen > width)
108*4882a593Smuzhiyun cnt = width - x;
109*4882a593Smuzhiyun else
110*4882a593Smuzhiyun cnt = runlen;
111*4882a593Smuzhiyun draw_unencoded_bitmap((uint16_t **)&dst, bmap,
112*4882a593Smuzhiyun cmap, cnt);
113*4882a593Smuzhiyun x += runlen;
114*4882a593Smuzhiyun bmap += runlen;
115*4882a593Smuzhiyun if (runlen & 1)
116*4882a593Smuzhiyun bmap++;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun } else {
119*4882a593Smuzhiyun /* encoded run */
120*4882a593Smuzhiyun if (y < height) {
121*4882a593Smuzhiyun runlen = bmap[0];
122*4882a593Smuzhiyun if (x < width) {
123*4882a593Smuzhiyun /* aggregate the same code */
124*4882a593Smuzhiyun while (bmap[0] == 0xff &&
125*4882a593Smuzhiyun bmap[2] != BMP_RLE8_ESCAPE &&
126*4882a593Smuzhiyun bmap[1] == bmap[3]) {
127*4882a593Smuzhiyun runlen += bmap[2];
128*4882a593Smuzhiyun bmap += 2;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun if (x + runlen > width)
131*4882a593Smuzhiyun cnt = width - x;
132*4882a593Smuzhiyun else
133*4882a593Smuzhiyun cnt = runlen;
134*4882a593Smuzhiyun draw_encoded_bitmap((uint16_t **)&dst,
135*4882a593Smuzhiyun cmap[bmap[1]], cnt);
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun x += runlen;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun bmap += 2;
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
bmpdecoder(void * bmp_addr,void * pdst,int dst_bpp)144*4882a593Smuzhiyun int bmpdecoder(void *bmp_addr, void *pdst, int dst_bpp)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun int stride, padded_width, bpp, i, width, height;
147*4882a593Smuzhiyun struct bmp_image *bmp = bmp_addr;
148*4882a593Smuzhiyun uint8_t *src = bmp_addr;
149*4882a593Smuzhiyun uint8_t *dst = pdst;
150*4882a593Smuzhiyun bool flip = false;
151*4882a593Smuzhiyun uint16_t *cmap;
152*4882a593Smuzhiyun uint8_t *cmap_base;
153*4882a593Smuzhiyun
154*4882a593Smuzhiyun if (!bmp || !(bmp->header.signature[0] == 'B' &&
155*4882a593Smuzhiyun bmp->header.signature[1] == 'M')) {
156*4882a593Smuzhiyun printf("cat not find bmp file\n");
157*4882a593Smuzhiyun return -1;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun width = get_unaligned_le32(&bmp->header.width);
160*4882a593Smuzhiyun height = get_unaligned_le32(&bmp->header.height);
161*4882a593Smuzhiyun bpp = get_unaligned_le16(&bmp->header.bit_count);
162*4882a593Smuzhiyun padded_width = width & 0x3 ? (width & ~0x3) + 4 : width;
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun if (height < 0)
165*4882a593Smuzhiyun height = 0 - height;
166*4882a593Smuzhiyun else
167*4882a593Smuzhiyun flip = true;
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun cmap_base = src + sizeof(bmp->header);
170*4882a593Smuzhiyun src = bmp_addr + get_unaligned_le32(&bmp->header.data_offset);
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun switch (bpp) {
173*4882a593Smuzhiyun case 8:
174*4882a593Smuzhiyun if (dst_bpp != 16) {
175*4882a593Smuzhiyun printf("can't support covert bmap to bit[%d]\n",
176*4882a593Smuzhiyun dst_bpp);
177*4882a593Smuzhiyun return -1;
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun cmap = malloc(sizeof(cmap) * 256);
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun /* Set color map */
182*4882a593Smuzhiyun for (i = 0; i < 256; i++) {
183*4882a593Smuzhiyun ushort colreg = ((cmap_base[2] << 8) & 0xf800) |
184*4882a593Smuzhiyun ((cmap_base[1] << 3) & 0x07e0) |
185*4882a593Smuzhiyun ((cmap_base[0] >> 3) & 0x001f) ;
186*4882a593Smuzhiyun cmap_base += 4;
187*4882a593Smuzhiyun cmap[i] = colreg;
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun /*
190*4882a593Smuzhiyun * only support convert 8bit bmap file to RGB565.
191*4882a593Smuzhiyun */
192*4882a593Smuzhiyun if (get_unaligned_le32(&bmp->header.compression)) {
193*4882a593Smuzhiyun decode_rle8_bitmap(src, dst, cmap, width, height,
194*4882a593Smuzhiyun bpp, 0, 0, flip);
195*4882a593Smuzhiyun } else {
196*4882a593Smuzhiyun int j;
197*4882a593Smuzhiyun stride = width * 2;
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun if (flip)
200*4882a593Smuzhiyun dst += stride * (height - 1);
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun for (i = 0; i < height; ++i) {
203*4882a593Smuzhiyun for (j = 0; j < width; j++) {
204*4882a593Smuzhiyun *(uint16_t *)dst = cmap[*(src++)];
205*4882a593Smuzhiyun dst += sizeof(uint16_t) / sizeof(*dst);
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun src += (padded_width - width);
208*4882a593Smuzhiyun if (flip)
209*4882a593Smuzhiyun dst -= stride * 2;
210*4882a593Smuzhiyun }
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun free(cmap);
213*4882a593Smuzhiyun break;
214*4882a593Smuzhiyun case 24:
215*4882a593Smuzhiyun if (get_unaligned_le32(&bmp->header.compression)) {
216*4882a593Smuzhiyun printf("can't not support compression for 24bit bmap");
217*4882a593Smuzhiyun return -1;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun stride = ALIGN(width * 3, 4);
220*4882a593Smuzhiyun if (flip)
221*4882a593Smuzhiyun src += stride * (height - 1);
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun for (i = 0; i < height; i++) {
224*4882a593Smuzhiyun memcpy(dst, src, 3 * width);
225*4882a593Smuzhiyun dst += stride;
226*4882a593Smuzhiyun src += stride;
227*4882a593Smuzhiyun if (flip)
228*4882a593Smuzhiyun src -= stride * 2;
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun break;
231*4882a593Smuzhiyun case 16:
232*4882a593Smuzhiyun case 32:
233*4882a593Smuzhiyun default:
234*4882a593Smuzhiyun printf("unsupport bit=%d now\n", bpp);
235*4882a593Smuzhiyun return -1;
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun return 0;
239*4882a593Smuzhiyun }
240