/***********************************************************************
* 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. Linux中CentOS6.5 64位 系统下安装docker步骤

    CentOS6.5 64位    (docker目前仅支持64位)内核必须在3.10及以上 1. uname -r  查看内核版本 2. 升级内核到3.10版本(带aufs模块)    cd /etc ...

  2. HDU2017新生赛 友好整数

    思路: 很简单的一个状态压缩,比赛时没想出来. 最多只有2^10个状态,n^2暴力一下也就1e6. 代码: #include<bits/stdc++.h> using namespace ...

  3. Web端主流框架,jquery、angular、react、vue

    不得不说,前端技术发展非常迅速,时不多久就有一个新的东西冒出来,并且迅速膨胀发展,让旁观者眼花缭乱,让开发者目眩神迷,但总体上来说,这波互联网大浪潮带动了前端技术的大发展,给曾经那些苦苦挣扎于DOM操 ...

  4. 3-13《元编程》第5章Class Definitions 3-14(5-4Singleton Classes,2小时)3-15(3小时✅)

    类宏 环绕别名 singleton class Class就是增强的模块,类定义也就是模块定义. 5.1 Class Definitions Demystified 5.11 Inside Class ...

  5. 我的Java学习笔记 -开发环境搭建

    开始学习Java~ 一.Java简介 Java编程语言是一种简单.面向对象.分布式.解释型.健壮安全.与系统无关.可移植.高性能.多线程和动态的语言. Java分为三个体系: JavaSE(J2SE) ...

  6. DZY Loves Colors CodeForces - 444C (线段树势能分析)

    大意:有$n$个格子, 初始$i$位置的颜色为$i$, 美丽值为0, 有两种操作 将区间$[l,r]$内的元素全部改为$x$, 每个元素的美丽值增加$|x-y|$, $y$为未改动时的值 询问区间$[ ...

  7. 11g adg 环境搭建实施手册-0908

    11g adg 环境搭建实施手册-0908 2017年8月30日 9:16 11g adg 环境搭建实施手册-0824 2017年8月24日 10:18 ####################### ...

  8. dp入门求最大公共子序列

    #include "bits/stdc++.h" using namespace std; ],b[]; ][]; int main() { cin >> a > ...

  9. 第一个 MVC 应用程序(下半部分)

    2.4 创建一个简单的数据录入应用程序 本章的其余部分将通过一个简单的数据录入应用程序来考查 MVC 的更多基本特性.本小节打算分步进行,目的是演示 MVC 的运用. B1.设计一个数据模型 在 MV ...

  10. STM32F103各PIN脚封装图

    1.36PIN 2.48PIN 3.64PIN 4.100PIN STM32ZET6详细pin脚图