/***********************************************************************
* 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. 《A_Pancers团队》作业5—团队项目需求改进与系统设计

    一:团队项目需求改进 1. <音乐播放软件需求规格说明书>的不足 在上周的<音乐播放软件需求规格说明书>我们还需要改进的地方有:1.搜索功能:2.界面的简洁美观化:3.按键的重 ...

  2. Thunder团队Alpha周贡献分规则及贡献分分配结果

    小组名称:Thunder 项目名称:爱阅app 组长:王航 成员:李传康.代秋彤.邹双黛.苗威.宋雨.胡佑蓉.杨梓瑞 Alpha周贡献分分配结果

  3. 《剑指offer》第十一题(旋转数组的最小数字)

    // 面试题:旋转数组的最小数字 // 题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. // 输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如数组 // {3, ...

  4. JavaScript权威指南--事件处理

    知识要点 客户端JavaScript程序采用了异步事件驱动变成模型(13.3.2节).这种风格并不只应用于web编程,所有使用图形用户界面的应用程序都采用它,它们静待某些事件发生,然后响应. 事件就是 ...

  5. nginx常用命令汇总

    nginx基础命令: sudo nginx // 开启nginx服务器 sudo nginx -s reload // 重启nginx服务器 sudo nginx -s stop // 关闭nginx ...

  6. elementUI和iview兼容么

    听说iview的作者居然是91年的,我要赶快加油了. https://zhuanlan.zhihu.com/p/25739512

  7. Python 爬虫-股票数据的Scrapy爬虫

    2017-08-06 19:52:21 目标:获取上交所和深交所所有股票的名称和交易信息输出:保存到文件中 技术路线:scrapy 获取股票列表:东方财富网:http://quote.eastmone ...

  8. 问题✅:render json的格式支持。to_json被改成as_json,功能一样

    class StudentsController < ApplicationController def show @student = Student.find(params[:id]) re ...

  9. Android程序员眼中世界上最遥远的距离

    世界上最遥远的距离,是我在if里你在else里,似乎一直相伴又永远分离: 世界上最痴心的等待,是我当case你是switch,或许永远都选不上自己: 世界上最真情的相依,是你在try我在catch. ...

  10. WaitForMultipleObjects用法详解

    本文转载于:http://blog.csdn.net/sac761/article/details/52456385 WaitForMultipleObjects是Windows中的一个功能非常强大的 ...