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 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 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 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 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[0] << 8) & 0xf800) | 184 ((cmap_base[1] << 3) & 0x07e0) | 185 ((cmap_base[2] >> 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