查看: 859|回复: 0
打印 上一主题 下一主题

位图(BMP)图象格式的学习

[复制链接]
跳转到指定楼层
沙发
发表于 2015-6-3 09:08:01 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
研究了下位图的格式,下面是从网上找到的一个说明文档(中文的,真好~~):
下载地址:
http://space.ednchina.com/Upload/Blog/2007/10/15/894e6ebb-8cf5-4125-96e7-2b2e524a9905.pdf
自己编了个生成位图文件的程序,只看这个文档还不能完全搞透位图,编程中就遇到了一些问题,现在总结一下,希望对大家有用:

1、位图中头的信息是按小字节序存储的,注意编译器如果是大字节序的需要字节顺序调整才可以。

2、位图中图象信息的第一个像素在图象中是左下角的像素,先最下一行从左往右,然后上面一行。

3、文档中有这样的说法:像素数据的长度(按字节计)要是4的倍数,这个4的倍数是怎么体现的呢?
    首先,这个规定并不是可遵守不可遵守的,一旦不遵守,图象水平方向上像素数是4的倍数还好,不然肯定会出错。
    这个4的倍数该怎么理解呢?我的像素怎么排?是不是每个像素占4个字节?
    经过实际用画图板制作各种尺寸的图象得到下面的结论:
    每个像素只占3个字节,水平方向上所有像素连续排列,
统计水平方向像素所占的字节数(像素数*3),如果得到的结果是4的倍数,就继续下一行数据,
    如果不是4的倍数,在最后一个像素数据后面补0,使这一行的总字节数等于4的倍数,然后开始下一行数据

    如:
    3*5的图象:
    水平方向有3个像素,像素占的字节数为9,不是4的倍数,在第三个像素数据后面补3个0,使这一行的总字节数为12,补完0,开始下一行数据。
    5*3的图象:
    水平方向有5个像素,像素占的字节数为15,不是4的倍数,在第五个像素后面补1个0,使此行的总字节数为16,继续下一行数据。



以下是写的程序(使用的编译器是winTC)

#include <stdio.h>

#define PIXEL_X    81          //水平像素数
#define PIXEL_Y    73          //垂直像素数

#define WIDTH_BYTES   ((long)((((long)PIXEL_X*3)&0xfffffffe) + 4) )   // 每行像素的数据总数,必须是4的倍数
#define LENGTH_TAIL   ((long)(4-(long)(PIXEL_X*3)%4))         // 定义水平方向上填充0的个数,小于等于3,填充的0称做"尾巴"

#define BIG   1
#define SMALL 0

enum cmprs_type
{
        BI_RGB,
        BI_RLE8,
        BI_RLE4,
        BI_BITFIELDES
};

struct ST_ImgFileHead                        //total 14(0xE) bytes
{                                                                //offset,size(byte)
        char format[2];                                // 0x00 , 0x2;  固定为"BM"
        long file_size;                      // 0x02 , 0x4;  整个文件大小;注意是大字节序还是小字节序,实际BMP格式中是小字节序
        long reserved;                                // 0x06 , 0x4;  保留,必须为0
        long data_ofst;                                // 0x0A , 0x4;  图象数据的偏移,看后面的图象信息头的多少定,图象信息头大小为0x28则本字段值为0x36,本字段的值实际上为"图象信息头长度+14+调色板信息长度"
};                                       


struct ST_ImgInfHead                        //total 40(0x28) bytes;  图象信息头
{                                       
        long img_inf_size;                        // 0x0E , 0x4;  图象信息头的大小,基本上是0x28,但也不一定,读取位图的时候这个值最好读出来
        long width;                                        // 0x12 , 0x4;  位图宽度,以像素为单位
        long height;                                // 0x16 , 0x4;  位图高度,以像素为单位
        int  planes;                                // 0x1A , 0x2;  位图位平面数,固定为1
        int  pixel_bit_width;                // 0x1C , 0x2;  像素位宽: 1,4,8,16,24,32可选
        long  compression;                        // 0x1E , 0x4;  压缩方式,从枚举的压缩方式中选一种
        long img_size;                                // 0x22 , 0x4;  图象数据大小,以字节为单位,必须是4的倍数
        long h_resolution;                        // 0x26 , 0x4;  水平分辨率,用像素/米表示
        long v_resolution;                        // 0x2A , 0x4;  垂直分辨率,用像素/米表示
        long colors;                                // 0x2E , 0x4;  位图使用的颜色数
        long important;                                // 0x32 , 0x4;  指定重要的颜色数,该域的值为颜色总数或者0时表示所有颜色都一样重要
};

//char palette[];   //压缩方式选择BI_RGB,没有颜色表

struct ST_Pixel
{
        char blue;
        char green;
        char red;
};

struct ST_MatrixPixelX
{
        struct ST_Pixel pixel_data[PIXEL_X];
        char tail_data[LENGTH_TAIL];
};


struct ST_Img
{
        struct ST_ImgFileHead file_head;
        struct ST_ImgInfHead inf_head;
        struct ST_MatrixPixelX matrix[PIXEL_Y];
};

void Endian_Check()
{
        int i = 0x1234;

        if(*((char *)&i) == 0x12)
                return(BIG);  //大字节序
        else
        {
                if(*((char *)&i) == 0x34)
                        return(SMALL);  //小字节序
                else
                {
                        printf("Error");
                }
        }
        getch();
}

void Endian_Regulator(char *data, char data_size)        //调整字节顺序
{
        char temp;
        char i;
        char t,size_temp;
        size_temp = data_size-1;
        for( i=0;i<=(size_temp>>1);i++ )
        {
                //printf("[data+%d]   = %x\n",i,*(data+i));
                //printf("[data+%d-%d] = %x\n",size_temp,i,*(data+size_temp-i));
                temp = *(data+i);
                *(data+i) = *(data + size_temp -i);
                *(data + size_temp -i) = temp;         
                //printf("[data+%d]   = %x\n",i,*(data+i));
                //printf("[data+%d-%d] = %x\n\n",size_temp,i,*(data+size_temp-i));
                //getch();
        }
}


main()
{
        FILE *fp;
        char *pimg;
        long x,y;
        long i;
        struct ST_Img img1;

        img1.file_head.format[0] = 'B';
        img1.file_head.format[1] = 'M';
        img1.file_head.file_size = 0x36+WIDTH_BYTES*PIXEL_Y;
        img1.file_head.reserved = 0;
        img1.file_head.data_ofst = 0x36;

        img1.inf_head.img_inf_size = 0x28;
        img1.inf_head.width = PIXEL_X;
        img1.inf_head.height = PIXEL_Y;
        img1.inf_head.planes = 1;
        img1.inf_head.pixel_bit_width = 24;
        img1.inf_head.compression = BI_RGB;
        img1.inf_head.img_size = WIDTH_BYTES*PIXEL_Y;
        img1.inf_head.colors = 0x1000000;
        img1.inf_head.important = 0;


        for(y=0;y<IXEL_Y;y++)     //图象点从左下角向右,从下到上排列,数组坐标是[y][x]
        {

                for(x=0;x<IXEL_X;x++)
                {
                        //img1.matrix[y].pixel_data[x].red = y*3;
                        //img1.matrix[y].pixel_data[x].green = 0;
                        //img1.matrix[y].pixel_data[x].blue = 0;

                        if(x<=PIXEL_X/3)
                        {
                                img1.matrix[y].pixel_data[x].red = y*3;
                                img1.matrix[y].pixel_data[x].green = 0;
                                img1.matrix[y].pixel_data[x].blue = 0;
                        }
                        else
                        {
                                if((x>IXEL_X/3) && (x<=(PIXEL_X*2)/3))
                                {
                                        img1.matrix[y].pixel_data[x].red = 0;
                                        img1.matrix[y].pixel_data[x].green = y*3;
                                        img1.matrix[y].pixel_data[x].blue = 0;
                                }
                                else
                                {
                                        if(x>(PIXEL_X*2)/3)
                                        {
                                                img1.matrix[y].pixel_data[x].red = 0;
                                                img1.matrix[y].pixel_data[x].green = 0;
                                                img1.matrix[y].pixel_data[x].blue = y*3;
                                        }
                                }
                        }
                }
                for(x=0;x<LENGTH_TAIL;x++)
                {
                        img1.matrix[y].tail_data[x] = 0;        //填充尾巴"0"
                }

        }

        pimg = &img1;
        fp = fopen("test.bmp","wb+");
        for(i=0;i<img1.file_head.file_size;i++)
        {
                fputc(*(pimg++),fp);        //把图象结构体写入文件
        }
        fclose(fp);
}
转载

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 加入因仑

本版积分规则

快速回复 返回顶部 返回列表