U-Boot_bmp_logo_hacking
1 /*********************************************************************** 2 * U-Boot_bmp_logo_hacking 3 * 声明: 4 * 1. 该源代码来自myzr_android4_2_2_1_1_0.tar.bz2中的: 5 * bootable/bootloader/uboot-imx/tools/bmp_logo.c 6 * 2. 通过阅读该源码可以知道大致如何解析bmp图片,以及一些自动生成 7 * 的文件是如何做到的,如一些自动生成.h和.c文件; 8 * 3. 阅读该源码技能需求: 9 * 1. bmp图片的格式的一些基本信息; 10 * 2. 类Unix系统编程; 11 * 3. C语言; 12 * 4. 本源程序的阅读技巧: 13 * 1. 本人是用了vim + ctags; 14 * 2. 如果您是在windows下,传说中是可以是用Source Insight; 15 * 3. 找main函数开始阅读; 16 * 17 * 2015-4-19 周日 晴 深圳 南山 西丽平山村 曾剑锋 18 **********************************************************************/ 19 20 21 22 /** 23 * 源程序中仅仅是用了#include "compiler.h",由于我们仅仅需要本文件, 24 * 所以本人注释了那一行,添加以下本文件需要用到的头文件 25 */ 26 //#include "compiler.h" 27 #include <errno.h> 28 #include <stdlib.h> 29 #include <stdint.h> 30 #include <stdio.h> 31 #include <string.h> 32 33 /** 34 * 用于大致描述一个bmp图片的结构体 35 */ 36 typedef struct bitmap_s { /* bitmap description */ 37 uint16_t width; 38 uint16_t height; 39 uint8_t palette[256*3]; 40 uint8_t *data; 41 } bitmap_t; 42 43 /** 44 * 默认的颜色映射的大小 45 */ 46 #define DEFAULT_CMAP_SIZE 16 /* size of default color map */ 47 48 /* 49 * Neutralize little endians. 50 * bmp图片用的好象是小端的存储方式 51 */ 52 uint16_t le_short(uint16_t x) 53 { 54 uint16_t val; 55 uint8_t *p = (uint8_t *)(&x); 56 57 val = (*p++ & 0xff) << 0; 58 val |= (*p & 0xff) << 8; 59 60 return val; 61 } 62 63 /** 64 * 在文件的当前位置,偏移多少个字节 65 */ 66 void skip_bytes (FILE *fp, int n) 67 { 68 while (n-- > 0) 69 fgetc (fp); 70 } 71 72 /** 73 * 错误输出函数,输出到标准错误输出 74 */ 75 __attribute__ ((__noreturn__)) 76 int error (char * msg, FILE *fp) 77 { 78 fprintf (stderr, "ERROR: %s\n", msg); 79 80 fclose (fp); 81 82 exit (EXIT_FAILURE); 83 } 84 85 int main (int argc, char *argv[]) 86 { 87 /** 88 * 局部变量说明: 89 * 1. i : for循环计数; 90 * 2. x : 字符暂存变量,for循环计数; 91 * 3. fp : 打开的bmp文件指针; 92 * 4. bmp : 用于存储bmp一些数据的数据结构; 93 * 5. b : 指向上面bmp数据结构的指针; 94 * 6. data_offset : bmp数据区相对文件头的偏移; 95 * 7. n_colors : 实际使用了多少种颜色 96 */ 97 int i, x; 98 FILE *fp; 99 bitmap_t bmp; 100 bitmap_t *b = &bmp; 101 uint16_t data_offset, n_colors; 102 103 /** 104 * 命令行参数个数检查 105 */ 106 if (argc < 2) { 107 fprintf (stderr, "Usage: %s file\n", argv[0]); 108 exit (EXIT_FAILURE); 109 } 110 111 /** 112 * 以二进制只读的方式打开bmp文件 113 */ 114 if ((fp = fopen (argv[1], "rb")) == NULL) { 115 perror (argv[1]); 116 exit (EXIT_FAILURE); 117 } 118 119 /** 120 * 检查是否是bmp图片 121 */ 122 if (fgetc (fp) != 'B' || fgetc (fp) != 'M') 123 error ("Input file is not a bitmap", fp); 124 125 /* 126 * read width and height of the image, and the number of colors used; 127 * ignore the rest 128 */ 129 /** 130 * 前面的'B','M'占用了2个字节, 131 * 2字节 + 8字节 = 10字节, 132 * 这时文件指针正好指向11字节(保存bmp数据偏移的位置) 133 */ 134 skip_bytes (fp, 8); 135 if (fread (&data_offset, sizeof (uint16_t), 1, fp) != 1) 136 error ("Couldn't read bitmap data offset", fp); 137 skip_bytes (fp, 6); 138 139 /** 140 * 前面的'B','M'占用了2个字节, 141 * 2字节 + 8字节 = 10字节, 142 * 10字节 + 2字节 = 12字节, 143 * 12字节 + 6字节 = 18字节, 144 * 这时文件指针正好指向19字节(保存bmp宽的位置) 145 */ 146 if (fread (&b->width, sizeof (uint16_t), 1, fp) != 1) 147 error ("Couldn't read bitmap width", fp); 148 skip_bytes (fp, 2); 149 150 /** 151 * 前面的'B','M'占用了2个字节, 152 * 2字节 + 8字节 = 10字节, 153 * 10字节 + 2字节 = 12字节, 154 * 12字节 + 6字节 = 18字节, 155 * 18字节 + 2字节 = 20字节, 156 * 20字节 + 2字节 = 22字节, 157 * 这时文件指针正好指向23字节(保存bmp高的位置) 158 */ 159 if (fread (&b->height, sizeof (uint16_t), 1, fp) != 1) 160 error ("Couldn't read bitmap height", fp); 161 skip_bytes (fp, 22); 162 163 /** 164 * 前面的'B','M'占用了2个字节, 165 * 2字节 + 8字节 = 10字节, 166 * 10字节 + 2字节 = 12字节, 167 * 12字节 + 6字节 = 18字节, 168 * 18字节 + 2字节 = 20字节, 169 * 20字节 + 2字节 = 22字节, 170 * 22字节 + 2字节 = 24字节, 171 * 24字节 + 22字节 = 46字节, 172 * 这时文件指针正好指向47字节(保存bmp图实际是用的颜色数) 173 * skip_bytes (fp, 6); --> 跳出位图信息头 174 */ 175 if (fread (&n_colors, sizeof (uint16_t), 1, fp) != 1) 176 error ("Couldn't read bitmap colors", fp); 177 skip_bytes (fp, 6); 178 179 /* 180 * Repair endianess. 181 * 防止数据出现大小不兼容的问题 182 */ 183 data_offset = le_short(data_offset); 184 b->width = le_short(b->width); 185 b->height = le_short(b->height); 186 n_colors = le_short(n_colors); 187 188 /* assume we are working with an 8-bit file */ 189 /** 190 * 防止颜色数太小,或太大 191 */ 192 if ((n_colors == 0) || (n_colors > 256 - DEFAULT_CMAP_SIZE)) { 193 /* reserve DEFAULT_CMAP_SIZE color map entries for default map */ 194 n_colors = 256 - DEFAULT_CMAP_SIZE; 195 } 196 197 /** 198 * 打印出一些注释信息和宏定义数据 199 */ 200 printf ("/*\n" 201 " * Automatically generated by \"tools/bmp_logo\"\n" 202 " *\n" 203 " * DO NOT EDIT\n" 204 " *\n" 205 " */\n\n\n" 206 "#ifndef __BMP_LOGO_H__\n" 207 "#define __BMP_LOGO_H__\n\n" 208 "#define BMP_LOGO_WIDTH\t\t%d\n" 209 "#define BMP_LOGO_HEIGHT\t\t%d\n" 210 "#define BMP_LOGO_COLORS\t\t%d\n" 211 "#define BMP_LOGO_OFFSET\t\t%d\n" 212 "\n", 213 b->width, b->height, n_colors, 214 DEFAULT_CMAP_SIZE); 215 216 /* allocate memory */ 217 /** 218 * 采用内存分配的方式,获取data的存储空间 219 */ 220 if ((b->data = (uint8_t *)malloc(b->width * b->height)) == NULL) 221 error ("Error allocating memory for file", fp); 222 223 /* read and print the palette information */ 224 /** 225 * 以下是一个输出结果示例: 226 * unsigned short bmp_logo_palette[] = { 227 * 0x0FFF, 0x0DDE, 0x026B, 0x026B, 0x0FFF, 0x0FFF, 0x048C, 0x026B, 228 * 0x026B, 0x0BDE, 0x047C, 0x027B, 0x09BE, 0x026B, 0x0EEF, 0x037B, 229 * 0x08AD, 0x0DEF, 0x027B, 0x069D, 0x0CDE, 0x0ACE, 0x08BD, 0x07AD, 230 * 0x027B, 0x058C, 0x037B, 0x0CDE, 0x06AD, 0x037C, 231 * }; 232 */ 233 printf ("unsigned short bmp_logo_palette[] = {\n"); 234 235 for (i=0; i<n_colors; ++i) { 236 b->palette[(int)(i*3+2)] = fgetc(fp); //个人查资料认为是blue 237 b->palette[(int)(i*3+1)] = fgetc(fp); //个人查资料认为是green 238 b->palette[(int)(i*3+0)] = fgetc(fp); //个人查资料认为是red 239 x=fgetc(fp); 240 241 /** 242 * 输出的结果正好和读出来的结果相反,主要是因为 243 * 读取时,后面的高位,输出时先输出的是高位 244 * 另外这里还考虑到格式化对齐的问题,主要是 245 * 方便阅读输出的数据. 246 */ 247 printf ("%s0x0%X%X%X,%s", 248 ((i%8) == 0) ? "\t" : " ", 249 (b->palette[(int)(i*3+0)] >> 4) & 0x0F, 250 (b->palette[(int)(i*3+1)] >> 4) & 0x0F, 251 (b->palette[(int)(i*3+2)] >> 4) & 0x0F, 252 ((i%8) == 7) ? "\n" : "" 253 ); 254 } 255 256 /* seek to offset indicated by file header */ 257 /** 258 * 感觉这行代码不应该放这里,应该放到下面2行后面去比较合理 259 */ 260 fseek(fp, (long)data_offset, SEEK_SET); 261 262 /* read the bitmap; leave room for default color map */ 263 printf ("\n"); 264 printf ("};\n"); 265 266 printf ("\n"); 267 268 /** 269 * 1. 以下是输出结果示例: 270 * unsigned char bmp_logo_bitmap[] = { 271 * 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 272 * 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 273 * ...... 274 * 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 275 * 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 276 * } 277 * 2. 位图数据记录顺序是在扫描行内是从左到右,扫描行之间是从下到上, 278 * Windows规定一个扫描行所占的字节数必须是4的倍数,不足以0填充; 279 * 3. i = (b->height-1)*b->width : 相当于跳到数组的左下脚 280 */ 281 printf ("unsigned char bmp_logo_bitmap[] = {\n"); 282 for (i=(b->height-1)*b->width; i>=0; i-=b->width) { 283 for (x = 0; x < b->width; x++) { 284 b->data[(uint16_t) i + x] = (uint8_t) fgetc (fp) \ 285 + DEFAULT_CMAP_SIZE; //不知道这里为什么需要加这个参数 286 } 287 } 288 fclose (fp); 289 290 /** 291 * 输出bmp数据 292 */ 293 for (i=0; i<(b->height*b->width); ++i) { 294 if ((i%8) == 0) 295 putchar ('\t'); 296 printf ("0x%02X,%c", 297 b->data[i], 298 ((i%8) == 7) ? '\n' : ' ' 299 ); 300 } 301 printf ("\n" 302 "};\n\n" 303 "#endif /* __BMP_LOGO_H__ */\n" 304 ); 305 306 return (0); 307 }