1 /***********************************************************************
2 * U-Boot_bmp_logo_hacking
3 * :
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 }