最近在开发中要在aboot中显示一张图片。但是发现aboot中显示图片不是直接拿图片文件来显示的,而是把一个16进制的数据序列依次往屏幕上搬运,就可以了。
那问题是,怎么把一张图片转换成16进制的数据序列?
在网上也找了一些资料,也咨询了一些同事,最后终于搞定,下面把相关的做法写下来备忘。
我们的aboot中显示方式只支持24bit bmp图片,所以要先看一下拿到的图片是不是这种格式。不是的话,就先用小画家或更高级的工具转成这种格式。然后,到ubuntu下运行命令:
这个命令会把图片转换成16进制数字,写进一个头文件logo.h,这个头文件中会有一个数组,和一个表示数组长度(也就是bmp文件长度)的变量。xxd -i logo.bmp logo.h
logo.h:
好了,已经拿到16进制的数据序列了,这就是我们要用的数据序列吗?不!还有好几步要做:unsigned char logo_bmp[] = { 0x42, 0x4d, 0xde, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, 0x22, 0x01, 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0x0e, 0x00, 0x00, 0xc4, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ... 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; unsigned int logo_bmp_len = 117214;
1. 了解bmp图片格式的知道,这个数组的前面一段是文件头信息,但是aboot中不需要这一段,所以要把它删除。
2. 另外,bmp图片如果每一行的字节数不是4的倍数,就会在每一行的最后添加若干字节空数据以对齐。这个空数据也要删除。
以 24bit bmp: 134X290 为例:
图片每一行134个像素,每个像素3个字节,所以每一行是134*3 == 402个字节,bmp会在每一行的最后添加两个字节来对齐。我们就要把这两个字节删除。
到这里可以了吗?还是没有,如果你试一下,就会发现,显示出来的图片是头向下倒过来的!因为bmp的数据就是从下往上存的。知道这一点,你可以一开始就在windows上把图片先做一个180度旋转,否则,就还要做下面两步处理:
3.反转整张图,即把数组的数组头尾互换一下。
4.做完步骤3,你会发现图片的颜色不对了!怎么回事? 是啊,R,B的位置也换了,R、G、B各占一个字节,所以还要每三个字节,就要把R和B的位置换一下。
好了,大功告成!
不过只是对左右对称的图片是可以的,如果左右不对称,则要先把图片转个180度,然后,只做上面的前两步,就可以了。
(其实旋转以后左右是反的,看下一篇:http://blog.csdn.net/jorney_dong/article/details/17419703)
下面看一下具体处理图片的代码:
main.c:
#include <stdio.h> //TO_DO ++++++++ #include "logo.h" //bmp width, height int bytes_per_bpp = 3; int bmp_width = 134; int bmp_height = 290; unsigned int file_len = 117214; unsigned char *bmp_file_data = logo_bmp; #define REVERT_BMP 1 //revert the bmp: 1, don't revert: 0 //TO_DO -------- /*bmp文件的前部是文件头信息,aboot中画图不需要这些 * 1 删除文件头信息, * * 以 24bit bmp: 134X290 为例 * 图片每一行134个像素,每个像素3个字节,所以每一行是134*3 == 402个字节, * bmp会在每一行的最后添加两个字节对齐。 * aboot中要用这个图片的话, * 2.要把每行最后的两个对齐字节删除 * * 每行最后的两个字节删除以后 * 因为bmp本身的图片是倒的, * 3.反转整张图 * * 反转整张图以后,R和B也互换了,导致颜色不对 * R、G、B各占一个字节, * 4.这里是使其中的R 和 B互换。 * * 所以,如果把拿到手的图片先在windows上做一下180度的旋转, * 应该可以省略步骤3和4,把上面的 REVERT_BMP 设定为0 即可。 */ int main() { unsigned int i = 0; unsigned int j = 0; unsigned int bmp_info_len = 0; unsigned int temp = 0; unsigned int actual_data_len = 0; unsigned char result_arry[file_len]; unsigned char result_arry2[file_len]; unsigned int data_bytes_per_row = (bmp_width*bytes_per_bpp); unsigned int total_bytes_per_row = 0; unsigned int null_bytes_per_row = 0; unsigned int array_len = 0; if(data_bytes_per_row%4 != 0) { null_bytes_per_row = 4-data_bytes_per_row%4; } total_bytes_per_row = data_bytes_per_row + null_bytes_per_row;//total bytes per row bmp_info_len = file_len - total_bytes_per_row*bmp_height;//bmp file info len,or len to delete printf("file_len:---------------> %d \n",file_len); printf("bmp_info_len:-----------> %d \nnull_bytes_per_row:-----> %d\n",bmp_info_len,null_bytes_per_row); //1 删除文件头信息, for(i=bmp_info_len,j=0;i<file_len;i++,j++) { result_arry2[j] = bmp_file_data[i]; } array_len = j; printf("step 1 over.\n"); printf("data total_bytes:-------> %d \n",file_len-bmp_info_len); printf("total_bytes_per_row:----> %d \n",total_bytes_per_row); //in data <-- bmp_file_data[..] //2.删除每行最后的若干个字节,存于result_arry2 for(i=1,j=0;i<=array_len;i++) { //delete null data at the end of row result_arry[j] = result_arry2[i-1]; j++; if(i%total_bytes_per_row==0) { j -= null_bytes_per_row; } }// out data to -->result_arry[..] printf("step 2 over.\n"); array_len = j; #if REVERT_BMP //3.这里是反转整张图 for(i=0,j=0;i<array_len;i++,j++) { result_arry2[j] = result_arry[array_len-i-1]; } printf("step 3 over.\n"); //in data <-- result_arry[..] //4. R、G、B各占一个字节,这里是使其中的R 和 B互换。 for(i=0,j=0;i<array_len;) { result_arry[j] = result_arry2[i+2]; result_arry[j+1] = result_arry2[i+1]; result_arry[j+2] = result_arry2[i]; i += 3; j += 3; } printf("step 4 over.\n"); #endif printf("actual data array_len:---> %d \n",array_len); FILE* fout = fopen("resutfile.h","w+"); if (fout == NULL) { printf("Failed to open\n"); return; } for (i=0;i<array_len;) { fprintf(fout,"0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, \n", result_arry[i],result_arry[i+1],result_arry[i+2],result_arry[i+3], result_arry[i+4],result_arry[i+5],result_arry[i+6],result_arry[i+7], result_arry[i+8],result_arry[i+9],result_arry[i+10],result_arry[i+11]); i +=12; } if (fclose(fout) != 0) { printf("Failed to close \n"); return; } }
上面已经说过处理的步骤,这里再说一下上面代码的用法:
0.在ubuntu下运行命令:xxd -i logo.bmp logo.h
看main.c中的 TO_DO 段,填写相应的信息:
1.在main.c中引用上面生成的头文件
2.把bmp文件的信息:宽,高,在main.c填写好。
3.把这个头文件logo.h中的数组长度赋给变量file_len.
4.把这个头文件logo.h中的数组地址赋给(unsigned char *bmp_file_data).
5.定义 REVERT_BMP 的值,如果在这里要图片反转一下,就设1, 如果已经是反转的图片,就设0.
6.把logo.h放在main程序所在的路径
7.编译:
gcc -o main main.c
8.执行:
./main
就会生成一个resultfile.h,这个文件的内容就是最后aboot中要用的bmp图片的数据。