天天看點

U-Boot_bmp_logo_hacking

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 }