/***********************************************************************
* U-Boot_bmp_logo_hacking
* 声明:
* 1. 该源代码来自myzr_android4_2_2_1_1_0.tar.bz2中的:
* bootable/bootloader/uboot-imx/tools/bmp_logo.c
* 2. 通过阅读该源码可以知道大致如何解析bmp图片,以及一些自动生成
* 的文件是如何做到的,如一些自动生成.h和.c文件;
* 3. 阅读该源码技能需求:
* 1. bmp图片的格式的一些基本信息;
* 2. 类Unix系统编程;
* 3. C语言;
* 4. 本源程序的阅读技巧:
* 1. 本人是用了vim + ctags;
* 2. 如果您是在windows下,传说中是可以是用Source Insight;
* 3. 找main函数开始阅读;
*
* 2015-4-19 周日 晴 深圳 南山 西丽平山村 曾剑锋
**********************************************************************/ /**
* 源程序中仅仅是用了#include "compiler.h",由于我们仅仅需要本文件,
* 所以本人注释了那一行,添加以下本文件需要用到的头文件
*/
//#include "compiler.h"
#include <errno.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h> /**
* 用于大致描述一个bmp图片的结构体
*/
typedef struct bitmap_s { /* bitmap description */
uint16_t width;
uint16_t height;
uint8_t palette[*];
uint8_t *data;
} bitmap_t; /**
* 默认的颜色映射的大小
*/
#define DEFAULT_CMAP_SIZE 16 /* size of default color map */ /*
* Neutralize little endians.
* bmp图片用的好象是小端的存储方式
*/
uint16_t le_short(uint16_t x)
{
uint16_t val;
uint8_t *p = (uint8_t *)(&x); val = (*p++ & 0xff) << ;
val |= (*p & 0xff) << ; return val;
} /**
* 在文件的当前位置,偏移多少个字节
*/
void skip_bytes (FILE *fp, int n)
{
while (n-- > )
fgetc (fp);
} /**
* 错误输出函数,输出到标准错误输出
*/
__attribute__ ((__noreturn__))
int error (char * msg, FILE *fp)
{
fprintf (stderr, "ERROR: %s\n", msg); fclose (fp); exit (EXIT_FAILURE);
} int main (int argc, char *argv[])
{
/**
* 局部变量说明:
* 1. i : for循环计数;
* 2. x : 字符暂存变量,for循环计数;
* 3. fp : 打开的bmp文件指针;
* 4. bmp : 用于存储bmp一些数据的数据结构;
* 5. b : 指向上面bmp数据结构的指针;
* 6. data_offset : bmp数据区相对文件头的偏移;
* 7. n_colors : 实际使用了多少种颜色
*/
int i, x;
FILE *fp;
bitmap_t bmp;
bitmap_t *b = &bmp;
uint16_t data_offset, n_colors; /**
* 命令行参数个数检查
*/
if (argc < ) {
fprintf (stderr, "Usage: %s file\n", argv[]);
exit (EXIT_FAILURE);
} /**
* 以二进制只读的方式打开bmp文件
*/
if ((fp = fopen (argv[], "rb")) == NULL) {
perror (argv[]);
exit (EXIT_FAILURE);
} /**
* 检查是否是bmp图片
*/
if (fgetc (fp) != 'B' || fgetc (fp) != 'M')
error ("Input file is not a bitmap", fp); /*
* read width and height of the image, and the number of colors used;
* ignore the rest
*/
/**
* 前面的'B','M'占用了2个字节,
* 2字节 + 8字节 = 10字节,
* 这时文件指针正好指向11字节(保存bmp数据偏移的位置)
*/
skip_bytes (fp, );
if (fread (&data_offset, sizeof (uint16_t), , fp) != )
error ("Couldn't read bitmap data offset", fp);
skip_bytes (fp, ); /**
* 前面的'B','M'占用了2个字节,
* 2字节 + 8字节 = 10字节,
* 10字节 + 2字节 = 12字节,
* 12字节 + 6字节 = 18字节,
* 这时文件指针正好指向19字节(保存bmp宽的位置)
*/
if (fread (&b->width, sizeof (uint16_t), , fp) != )
error ("Couldn't read bitmap width", fp);
skip_bytes (fp, ); /**
* 前面的'B','M'占用了2个字节,
* 2字节 + 8字节 = 10字节,
* 10字节 + 2字节 = 12字节,
* 12字节 + 6字节 = 18字节,
* 18字节 + 2字节 = 20字节,
* 20字节 + 2字节 = 22字节,
* 这时文件指针正好指向23字节(保存bmp高的位置)
*/
if (fread (&b->height, sizeof (uint16_t), , fp) != )
error ("Couldn't read bitmap height", fp);
skip_bytes (fp, ); /**
* 前面的'B','M'占用了2个字节,
* 2字节 + 8字节 = 10字节,
* 10字节 + 2字节 = 12字节,
* 12字节 + 6字节 = 18字节,
* 18字节 + 2字节 = 20字节,
* 20字节 + 2字节 = 22字节,
* 22字节 + 2字节 = 24字节,
* 24字节 + 22字节 = 46字节,
* 这时文件指针正好指向47字节(保存bmp图实际是用的颜色数)
* skip_bytes (fp, 6); --> 跳出位图信息头
*/
if (fread (&n_colors, sizeof (uint16_t), , fp) != )
error ("Couldn't read bitmap colors", fp);
skip_bytes (fp, ); /*
* Repair endianess.
* 防止数据出现大小不兼容的问题
*/
data_offset = le_short(data_offset);
b->width = le_short(b->width);
b->height = le_short(b->height);
n_colors = le_short(n_colors); /* assume we are working with an 8-bit file */
/**
* 防止颜色数太小,或太大
*/
if ((n_colors == ) || (n_colors > - DEFAULT_CMAP_SIZE)) {
/* reserve DEFAULT_CMAP_SIZE color map entries for default map */
n_colors = - DEFAULT_CMAP_SIZE;
} /**
* 打印出一些注释信息和宏定义数据
*/
printf ("/*\n"
" * Automatically generated by \"tools/bmp_logo\"\n"
" *\n"
" * DO NOT EDIT\n"
" *\n"
" */\n\n\n"
"#ifndef __BMP_LOGO_H__\n"
"#define __BMP_LOGO_H__\n\n"
"#define BMP_LOGO_WIDTH\t\t%d\n"
"#define BMP_LOGO_HEIGHT\t\t%d\n"
"#define BMP_LOGO_COLORS\t\t%d\n"
"#define BMP_LOGO_OFFSET\t\t%d\n"
"\n",
b->width, b->height, n_colors,
DEFAULT_CMAP_SIZE); /* allocate memory */
/**
* 采用内存分配的方式,获取data的存储空间
*/
if ((b->data = (uint8_t *)malloc(b->width * b->height)) == NULL)
error ("Error allocating memory for file", fp); /* read and print the palette information */
/**
* 以下是一个输出结果示例:
* unsigned short bmp_logo_palette[] = {
* 0x0FFF, 0x0DDE, 0x026B, 0x026B, 0x0FFF, 0x0FFF, 0x048C, 0x026B,
* 0x026B, 0x0BDE, 0x047C, 0x027B, 0x09BE, 0x026B, 0x0EEF, 0x037B,
* 0x08AD, 0x0DEF, 0x027B, 0x069D, 0x0CDE, 0x0ACE, 0x08BD, 0x07AD,
* 0x027B, 0x058C, 0x037B, 0x0CDE, 0x06AD, 0x037C,
* };
*/
printf ("unsigned short bmp_logo_palette[] = {\n"); for (i=; i<n_colors; ++i) {
b->palette[(int)(i*+)] = fgetc(fp); //个人查资料认为是blue
b->palette[(int)(i*+)] = fgetc(fp); //个人查资料认为是green
b->palette[(int)(i*+)] = fgetc(fp); //个人查资料认为是red
x=fgetc(fp); /**
* 输出的结果正好和读出来的结果相反,主要是因为
* 读取时,后面的高位,输出时先输出的是高位
* 另外这里还考虑到格式化对齐的问题,主要是
* 方便阅读输出的数据.
*/
printf ("%s0x0%X%X%X,%s",
((i%) == ) ? "\t" : " ",
(b->palette[(int)(i*+)] >> ) & 0x0F,
(b->palette[(int)(i*+)] >> ) & 0x0F,
(b->palette[(int)(i*+)] >> ) & 0x0F,
((i%) == ) ? "\n" : ""
);
} /* seek to offset indicated by file header */
/**
* 感觉这行代码不应该放这里,应该放到下面2行后面去比较合理
*/
fseek(fp, (long)data_offset, SEEK_SET); /* read the bitmap; leave room for default color map */
printf ("\n");
printf ("};\n"); printf ("\n"); /**
* 1. 以下是输出结果示例:
* unsigned char bmp_logo_bitmap[] = {
* 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
* 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
* ......
* 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
* 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
* }
* 2. 位图数据记录顺序是在扫描行内是从左到右,扫描行之间是从下到上,
* Windows规定一个扫描行所占的字节数必须是4的倍数,不足以0填充;
* 3. i = (b->height-1)*b->width : 相当于跳到数组的左下脚
*/
printf ("unsigned char bmp_logo_bitmap[] = {\n");
for (i=(b->height-)*b->width; i>=; i-=b->width) {
for (x = ; x < b->width; x++) {
b->data[(uint16_t) i + x] = (uint8_t) fgetc (fp) \
+ DEFAULT_CMAP_SIZE; //不知道这里为什么需要加这个参数
}
}
fclose (fp); /**
* 输出bmp数据
*/
for (i=; i<(b->height*b->width); ++i) {
if ((i%) == )
putchar ('\t');
printf ("0x%02X,%c",
b->data[i],
((i%) == ) ? '\n' : ' '
);
}
printf ("\n"
"};\n\n"
"#endif /* __BMP_LOGO_H__ */\n"
); return ();
}

随机推荐

  1. 【Golang 接口自动化08】使用标准库httptest完成HTTP请求的Mock测试

    前言 Mock是一个做自动化测试永远绕不过去的话题.本文主要介绍使用标准库net/http/httptest完成HTTP请求的Mock的测试方法. 可能有的小伙伴不太了解mock在实际自动化测试过程中 ...

  2. Python 运算符重载

    https://www.cnblogs.com/hotbaby/p/4913363.html

  3. WPF使用Webbrowser操作网页的主要代码

    1,引用mshtml.dll using mshtml; 2,获取元素属性值 IHTMLDocument2 doc2=(IHTMLDocument)webbrowser1.Document; IHTM ...

  4. Linux 强制安装rpm 包

    Linux 强制安装rpm 包 2014年12月12日 10:21 [root@ilearndb1 Server]# rpm -ivh  unixODBC-devel-2.*  --nodeps -- ...

  5. dp练习(9)——最大乘积

    1017 乘积最大 2000年NOIP全国联赛普及组NOIP全国联赛提高组  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解       题目描述 Desc ...

  6. SQL Server日志清空方法

    1.清空日志:DUMP   TRANSACTION   databasename   WITH   NO_LOG 2.截断事务日志:BACKUP   LOG   databasename   WITH ...

  7. 附录A——面向对象基础

    在学习设计模式之前,C#语言中一些基本的面向对象的知识还是应该具备的,比如像继承.多态,接口.抽象类,集合.泛型等. A.2 类与实例 什么是对象? 一切事物(事和物)都是对象,对象就是可以看到.感觉 ...

  8. 信号处理函数的返回sigsetjmp/siglongjmp

    由于在信号处理期间自动屏蔽了正在被处理的信号,而使用setjmp/longjmp跳出信号处理程序时又不会自动将 信号屏蔽码修改会原来的屏蔽码,从而引起该信号被永久屏蔽. 可以使用sigsetjmp/s ...

  9. kill word out e ef en em

        1● e 2● ef 出,出来   3● en 4● em 使~进入状态,包围,进入~之中  

  10. cas 认证管理器

    CAS-默认的认证管理器:AuthenticationManagerImpl <bean id="authenticationManager" class="org ...