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