/***********************************************************************
* 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. 转载:oracle RAC集群启动和关闭

    http://www.cnblogs.com/yhfssp/p/8184761.html oracle 11G RAC集群启动和关闭: 1.停止数据库 $srvctl stop database –d ...

  2. Qt_OpenGL_教程

    1. 中文版: Qt OpenGL教程 http://blog.csdn.net/myths_0/article/details/24431597 http://qiliang.net/old/neh ...

  3. JQuery 自己主动触发事件

    经常使用模拟 有时候,须要通过模拟用户操作,来达到单击的效果.比如在用户进入页面后,就触发click事件,而不须要用户去主动单击. 在JQuery中.能够使用trigger()方法完毕模拟操作.比如能 ...

  4. C#一套简单的单例系统

    单例基类 public class CSingletonBase<TYPE> { public static TYPE Singleton { get { return m_singlet ...

  5. centos7: iptables保存(配置完nginx的web规则后)

    centos7: iptables保存(配置完nginx的web规则后) 以本地虚拟机为例: 添加规则:入站规则 iptables -I INPUT -p tcp --dport 80 -j ACCE ...

  6. python-day18--匿名函数

    一.lambda表达式 1.匿名函数的核心:一些简单的需要用函数去解决的问题,匿名函数的函数体只有一行 2.参数可以有多个,用逗号隔开 3.返回值和正常的函数一样可以是任意的数据类型 4.练习: 请把 ...

  7. ccf画图

    问题描述 在一个定义了直角坐标系的纸上,画一个(x1,y1)到(x2,y2)的矩形指将横坐标范围从x1到x2,纵坐标范围从y1到y2之间的区域涂上颜色. 下图给出了一个画了两个矩形的例子.第一个矩形是 ...

  8. IIS Web 服务器/ASP.NET 运行原理基本知识概念整理

     前言:      记录 IIS 相关的笔记还是从公司笔试考核题开始的,问 Application Pool 与 AppDomain 的区别?      促使我对进程池进了知识的学习,所以记录一下学习 ...

  9. bzoj1650

    题解: 二分答案 然后贪心 代码: #include<bits/stdc++.h> using namespace std; ; int n,m,l,a[N]; int pd(int x) ...

  10. bzoj1089

    题解: 递推 f[i]=f[i-1]^n+1 ans=f[d]-f[d-1] 代码: #include<bits/stdc++.h> using namespace std; int n, ...