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, bool flip) 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 uint16_t *cmap; 174 uint8_t *cmap_base; 175 176 if (!bmp || !(bmp->header.signature[0] == 'B' && 177 bmp->header.signature[1] == 'M')) { 178 printf("Error: Invalid bmp file.\n"); 179 return -1; 180 } 181 dump_bmp_dib_head(bmp); 182 width = get_unaligned_le32(&bmp->header.width); 183 height = get_unaligned_le32(&bmp->header.height); 184 bpp = get_unaligned_le16(&bmp->header.bit_count); 185 padded_width = width & 0x3 ? (width & ~0x3) + 4 : width; 186 187 if (height < 0) { 188 height = 0 - height; 189 flip = false; 190 } 191 cmap_base = src + sizeof(bmp->header); 192 src = bmp_addr + get_unaligned_le32(&bmp->header.data_offset); 193 194 switch (bpp) { 195 case 8: 196 if (dst_bpp != 16) { 197 printf("Error: Target pixel's bpp is not 16bit.\n"); 198 199 return -1; 200 } 201 cmap = malloc(sizeof(cmap) * 256); 202 203 /* Set color map */ 204 for (i = 0; i < 256; i++) { 205 ushort colreg = ((cmap_base[0] << 8) & 0xf800) | 206 ((cmap_base[1] << 3) & 0x07e0) | 207 ((cmap_base[2] >> 3) & 0x001f) ; 208 cmap_base += 4; 209 cmap[i] = colreg; 210 } 211 /* 212 * only support convert 8bit bmap file to RGB565. 213 */ 214 if (get_unaligned_le32(&bmp->header.compression)) { 215 decode_rle8_bitmap(src, dst, cmap, width, height, 216 bpp, 0, 0, flip); 217 } else { 218 stride = width * 2; 219 220 if (flip) 221 dst += stride * (height - 1); 222 223 for (i = 0; i < height; ++i) { 224 for (j = 0; j < width; j++) { 225 *(uint16_t *)dst = cmap[*(src++)]; 226 dst += sizeof(uint16_t) / sizeof(*dst); 227 } 228 src += (padded_width - width); 229 if (flip) 230 dst -= stride * 2; 231 } 232 } 233 free(cmap); 234 break; 235 case 16: 236 if (get_unaligned_le32(&bmp->header.compression)) { 237 printf("Error: Failed to decompression bmp file.\n"); 238 239 return -1; 240 } 241 stride = ALIGN(width * bpp / 8, 4); 242 if (flip) 243 src += stride * (height - 1); 244 for (i = 0; i < height; i++) { 245 for (j = 0; j < width; j++) { 246 ushort color = (src[1] << 8) | src[0]; 247 248 color = (((color & 0x7c00) << 1) | 249 ((color & 0x03e0) << 1) | 250 (color & 0x001f)); 251 *(uint16_t *)dst = color; 252 src += 2; 253 dst += 2; 254 } 255 src += (padded_width - width); 256 if (flip) 257 src -= stride * 2; 258 } 259 break; 260 case 24: 261 if (get_unaligned_le32(&bmp->header.compression)) { 262 printf("Error: Failed to decompression bmp file.\n"); 263 264 return -1; 265 } 266 stride = ALIGN(width * 3, 4); 267 if (flip) 268 src += stride * (height - 1); 269 270 for (i = 0; i < height; i++) { 271 memcpy(dst, src, 3 * width); 272 dst += stride; 273 src += stride; 274 if (flip) 275 src -= stride * 2; 276 } 277 break; 278 case 32: 279 if (get_unaligned_le32(&bmp->header.compression)) { 280 printf("Error: Failed to decompression bmp file.\n"); 281 282 return -1; 283 } 284 stride = ALIGN(width * 4, 4); 285 if (flip) 286 src += stride * (height - 1); 287 288 for (i = 0; i < height; i++) { 289 memcpy(dst, src, 4 * width); 290 dst += stride; 291 src += stride; 292 if (flip) 293 src -= stride * 2; 294 } 295 break; 296 default: 297 printf("Error: Can't decode this bmp file with bit=%d\n", bpp); 298 return -1; 299 } 300 301 return 0; 302 } 303