前些天看到一幅gif图片,大致是一个程序员通过绘图工具绘出一幅bmp图片,然后用文本文件打开,可以看出其实他是写的C++版的helloworld程序。当真正了解了bmp图片的编码规则时,就可以很清楚知道这是如何实现的。
bmp(bitmap)一种没有进行压缩的图片格式,它是一种二进制的格式。可以通过如下的数据结构struct bmp_data来了解该格式中的各个数据位表示的具体含义。首先是两个字节bmp_type,bmp格式这两个字节固定为0x4248,它其实也是"BM"这两个字符的ASII码;其次是bmp_head,表示bmp的头部,其中有整个bmp文件的大小、保留位以偏移量;接着是bmp_info,表示该bmp图片相关的一些信息,如宽度和高度、bpp等信息;最后是data,即具体的图像完整的编码数据,对于常用的24位bmp格式,就是通过RGB格式表示每个像素点的颜色。
/*
** 这里的long型表示32位整数即4字节,short和char表示8位整数即1字节
*/
struct bmp_head {
unsigned long size;
unsigned long reserved;
unsigned long offset;
};
struct bmp_info {
unsigned long size;
long width;
long height;
unsigned short planes;
unsigned short bpp;
unsigned long compression;
unsigned long image_size;
long x_ppm;
long y_ppm;
unsigned long used;
unsigned long important;
};
struct bmp_type {
char type[2];
};
struct bmp_data {
struct bmp_type type;
struct bmp_head head;
struct bmp_info info;
void *data;
};
当明白以上的数据结构,就不难理解gif图片中是如何实现的:首先写出helloworld,然后将其按照对应ASII码转化为相应的RGB绘制出来,之后只要通过文本方式打开就可以得到gif中的效果。如下图,是我自己实现的gif中的效果。当然逆向制作会非常简单,首先用绘图软件任意绘制一幅大小为4X10像素的bmp图片(可任意选择大小)并保存;然后使用二进制查看工具UE打开,并通过UE将helloworld程序复制到该图片的bmp_data中的data域,除了helloworld程序代码外,其它用0x0D0A代替(即回车符与换行符);最后保存好数据,用绘图工具重新打开该文件,就可以看到helloworld版本的图像(注意:要保证该图经过修改后数据长度一致,即bmp_size中的size大小与整个文件大小一致)。