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 <command.h> 8 #include <log.h> 9 #include <config.h> 10 #include <common.h> 11 #include <malloc.h> 12 #include <asm/unaligned.h> 13 #include <bmp_layout.h> 14 15 #define BMP_RLE8_ESCAPE 0 16 #define BMP_RLE8_EOL 0 17 #define BMP_RLE8_EOBMP 1 18 #define BMP_RLE8_DELTA 2 19 20 static void draw_unencoded_bitmap(uint16_t **dst, uint8_t *bmap, uint16_t *cmap, 21 uint32_t cnt) 22 { 23 while (cnt > 0) { 24 *(*dst)++ = cmap[*bmap++]; 25 cnt--; 26 } 27 } 28 29 static void draw_encoded_bitmap(uint16_t **dst, uint16_t c, uint32_t cnt) 30 { 31 uint16_t *fb = *dst; 32 int cnt_8copy = cnt >> 3; 33 34 cnt -= cnt_8copy << 3; 35 while (cnt_8copy > 0) { 36 *fb++ = c; 37 *fb++ = c; 38 *fb++ = c; 39 *fb++ = c; 40 *fb++ = c; 41 *fb++ = c; 42 *fb++ = c; 43 *fb++ = c; 44 cnt_8copy--; 45 } 46 while (cnt > 0) { 47 *fb++ = c; 48 cnt--; 49 } 50 *dst = fb; 51 } 52 53 static void decode_rle8_bitmap(void *psrc, void *pdst, uint16_t *cmap, 54 int width, int height, int bits, int x_off, 55 int y_off, bool flip) 56 { 57 uint32_t cnt, runlen; 58 int x = 0, y = 0; 59 int decode = 1; 60 int linesize = width * 2; 61 uint8_t *bmap = psrc; 62 uint8_t *dst = pdst; 63 64 if (flip) { 65 y = height - 1; 66 dst = pdst + y * linesize; 67 } 68 69 while (decode) { 70 if (bmap[0] == BMP_RLE8_ESCAPE) { 71 switch (bmap[1]) { 72 case BMP_RLE8_EOL: 73 /* end of line */ 74 bmap += 2; 75 x = 0; 76 if (flip) { 77 y--; 78 dst -= linesize * 2; 79 } else { 80 y++; 81 } 82 break; 83 case BMP_RLE8_EOBMP: 84 /* end of bitmap */ 85 decode = 0; 86 break; 87 case BMP_RLE8_DELTA: 88 /* delta run */ 89 x += bmap[2]; 90 if (flip) { 91 y -= bmap[3]; 92 dst -= bmap[3] * linesize; 93 dst += bmap[2] * 2; 94 } else { 95 y += bmap[3]; 96 dst += bmap[3] * linesize; 97 dst += bmap[2] * 2; 98 } 99 bmap += 4; 100 break; 101 default: 102 /* unencoded run */ 103 runlen = bmap[1]; 104 bmap += 2; 105 if (y >= height || x >= width) { 106 decode = 0; 107 break; 108 } 109 if (x + runlen > width) 110 cnt = width - x; 111 else 112 cnt = runlen; 113 draw_unencoded_bitmap((uint16_t **)&dst, bmap, 114 cmap, cnt); 115 x += runlen; 116 bmap += runlen; 117 if (runlen & 1) 118 bmap++; 119 } 120 } else { 121 /* encoded run */ 122 if (y < height) { 123 runlen = bmap[0]; 124 if (x < width) { 125 /* aggregate the same code */ 126 while (bmap[0] == 0xff && 127 bmap[2] != BMP_RLE8_ESCAPE && 128 bmap[1] == bmap[3]) { 129 runlen += bmap[2]; 130 bmap += 2; 131 } 132 if (x + runlen > width) 133 cnt = width - x; 134 else 135 cnt = runlen; 136 draw_encoded_bitmap((uint16_t **)&dst, 137 cmap[bmap[1]], cnt); 138 } 139 x += runlen; 140 } 141 bmap += 2; 142 } 143 } 144 } 145 146 static void dump_bmp_dib_head(void *bmp_addr) 147 { 148 struct bmp_image *bmp = bmp_addr; 149 150 debug("########## BMP DIB_HEAD ##########\n" 151 "Width : %u\n" 152 "Height : %u\n" 153 "Bpp : %u\n" 154 "Compression method : %u\n" 155 "Image size : %u\n" 156 "Colors in palette : %u\n" 157 "##################################\n", 158 bmp->header.width, 159 bmp->header.height, 160 bmp->header.bit_count, 161 bmp->header.compression, 162 bmp->header.image_size, 163 bmp->header.colors_used); 164 } 165 166 int bmpdecoder(void *bmp_addr, void *pdst, int dst_bpp) 167 { 168 int i, j; 169 int stride, padded_width, bpp, width, height; 170 struct bmp_image *bmp = bmp_addr; 171 uint8_t *src = bmp_addr; 172 uint8_t *dst = pdst; 173 bool flip = false; 174 uint16_t *cmap; 175 uint8_t *cmap_base; 176 177 if (!bmp || !(bmp->header.signature[0] == 'B' && 178 bmp->header.signature[1] == 'M')) { 179 printf("Error: Invalid bmp file.\n"); 180 return -1; 181 } 182 dump_bmp_dib_head(bmp); 183 width = get_unaligned_le32(&bmp->header.width); 184 height = get_unaligned_le32(&bmp->header.height); 185 bpp = get_unaligned_le16(&bmp->header.bit_count); 186 padded_width = width & 0x3 ? (width & ~0x3) + 4 : width; 187 188 if (height < 0) 189 height = 0 - height; 190 else 191 flip = true; 192 193 cmap_base = src + sizeof(bmp->header); 194 src = bmp_addr + get_unaligned_le32(&bmp->header.data_offset); 195 196 switch (bpp) { 197 case 8: 198 if (dst_bpp != 16) { 199 printf("Error: Target pixel's bpp is not 16bit.\n"); 200 201 return -1; 202 } 203 cmap = malloc(sizeof(cmap) * 256); 204 205 /* Set color map */ 206 for (i = 0; i < 256; i++) { 207 ushort colreg = ((cmap_base[0] << 8) & 0xf800) | 208 ((cmap_base[1] << 3) & 0x07e0) | 209 ((cmap_base[2] >> 3) & 0x001f) ; 210 cmap_base += 4; 211 cmap[i] = colreg; 212 } 213 /* 214 * only support convert 8bit bmap file to RGB565. 215 */ 216 if (get_unaligned_le32(&bmp->header.compression)) { 217 decode_rle8_bitmap(src, dst, cmap, width, height, 218 bpp, 0, 0, flip); 219 } else { 220 stride = width * 2; 221 222 if (flip) 223 dst += stride * (height - 1); 224 225 for (i = 0; i < height; ++i) { 226 for (j = 0; j < width; j++) { 227 *(uint16_t *)dst = cmap[*(src++)]; 228 dst += sizeof(uint16_t) / sizeof(*dst); 229 } 230 src += (padded_width - width); 231 if (flip) 232 dst -= stride * 2; 233 } 234 } 235 free(cmap); 236 break; 237 case 16: 238 if (get_unaligned_le32(&bmp->header.compression)) { 239 printf("Error: Failed to decompression bmp file.\n"); 240 241 return -1; 242 } 243 stride = ALIGN(width * bpp / 8, 4); 244 if (flip) 245 src += stride * (height - 1); 246 for (i = 0; i < height; i++) { 247 for (j = 0; j < width; j++) { 248 ushort color = (src[1] << 8) | src[0]; 249 250 color = (((color & 0x7c00) << 1) | 251 ((color & 0x03e0) << 1) | 252 (color & 0x001f)); 253 *(uint16_t *)dst = color; 254 src += 2; 255 dst += 2; 256 } 257 src += (padded_width - width); 258 if (flip) 259 src -= stride * 2; 260 } 261 break; 262 case 24: 263 if (get_unaligned_le32(&bmp->header.compression)) { 264 printf("Error: Failed to decompression bmp file.\n"); 265 266 return -1; 267 } 268 stride = ALIGN(width * 3, 4); 269 if (flip) 270 src += stride * (height - 1); 271 272 for (i = 0; i < height; i++) { 273 memcpy(dst, src, 3 * width); 274 dst += stride; 275 src += stride; 276 if (flip) 277 src -= stride * 2; 278 } 279 break; 280 case 32: 281 if (get_unaligned_le32(&bmp->header.compression)) { 282 printf("Error: Failed to decompression bmp file.\n"); 283 284 return -1; 285 } 286 stride = ALIGN(width * 4, 4); 287 if (flip) 288 src += stride * (height - 1); 289 290 for (i = 0; i < height; i++) { 291 memcpy(dst, src, 4 * width); 292 dst += stride; 293 src += stride; 294 if (flip) 295 src -= stride * 2; 296 } 297 break; 298 default: 299 printf("Error: Can't decode this bmp file with bit=%d\n", bpp); 300 return -1; 301 } 302 303 return 0; 304 } 305