zoukankan      html  css  js  c++  java
  • Bitmap 格式

    源:Bitmap 格式

    参考:bitmap文件格式            

    Bitmap是Windows操作系统中的标准图像文件格式,可以分成两类:设备相关位图(DDB)和设备无关位图(DIB),DDB已经基本停用。

    Bitmap格式有4部分组成: 文件头、图像描述、颜色表(在真彩色(24或32位)模式无颜色表)和图像数据区

    1. 文件头  14B

    2B    0000-0001:文件标识,为字母ASCII码“BM”,即0x4d42

    4B    0002-0005:文件大小,字节数,最大为4G

    4B    0006-0009:保留,每字节以“00”填写。

    4B    000A-000D:记录图像数据区的起始位置。各字节的信息依次含义为:文件头信息块大小,图像描述信息块的大小,图像颜色表的大小,保留(为01)。

    数据类型定义:(32位系统下的定义;64位系统下在编译时需要加入-m32)

    typedef unsigned char BYTE;               // 1B
    typedef unsigned short WORD;           // 2B
    typedef unsigned long DWORD;          // 4B
    typedef long LONG;                            // 4B

    文件头结构定义

    typedef struct tagBITMAPFILEHEADER {
        WORD magic; // "BM",即0x4d42
        DWORD bfSize; //文件大小 
        WORD bfReserved1; //保留字,不考虑 
        WORD bfReserved2; //保留字,同上 
        DWORD bfOffBits; //实际位图数据的偏移字节数,即前三个部分长度之和
    } BITMAPFILEHEADER;

    2. 图像描述      40B

    4B    000E-0011:图像描述信息块的大小,常为40。 

    4B    0012-0015:图像宽度。

    4B    0016-0019:图像高度。

    2B    001A-001B:图像的plane(平面?)总数(恒为1)。

    2B    001C-001D:记录像素的位数,很重要的数值,图像的颜色数由该值决定。

    4B    001E-0021:数据压缩方式(数值位0:不压缩;1:8位压缩;2:4位压缩)。

    4B    0022-0025:图像区数据的大小。 

    4B    0026-0029:水平每米有多少像素,在设备无关位图(.DIB)中,每字节以00H填写。 

    4B    002A-002D:垂直每米有多少像素,在设备无关位图(.DIB)中,每字节以00H填写。

    4B    002E-0031:此图像所用的颜色数,如值为0,表示所有颜色一样重要。

    4B    0032-0035:重要的颜色数

    图像信息描述结构

    typedef struct tagBITMAPINFOHEADER{
        DWORD biSize; //指定此结构体的长度,为40
        LONG biWidth; //位图宽
        LONG biHeight; //位图高
        WORD biPlanes; //平面数,为1
        WORD biBitCount; //采用颜色位数,可以是1,2,4,8,16,24,新的可以是32
        DWORD biCompression; //压缩方式,可以是0,1,2,其中0表示不压缩
        DWORD biSizeImage; //实际位图数据占用的字节数
        LONG biXPelsPerMeter; //X方向分辨率
        LONG biYPelsPerMeter; //Y方向分辨率
        DWORD biClrUsed; //使用的颜色数,如果为0,则表示默认值(2^颜色位数)
        DWORD biClrImportant; //重要颜色数,如果为0,则表示所有颜色都是重要的
    } BITMAPINFOHEADER;

    不包含颜色表的数据头大小为54B

    3. 颜色表

        在真彩色(24或32位)模式无颜色表

        其他色彩图像的颜色表的大小根据所使用的颜色模式而定:

                  2色图像的颜色表大小是8字节;16色图像的颜色表大小是64字节;256色图像颜色表大小是1024字节。

                 其中,每4字节表示一种颜色,并以B(蓝色)、G(绿色)、R(红色)、alpha(像素的透明度值,一般不需要)。即首先4字节表示颜色号0的颜色,接下来表示颜色号1的颜色,依此类推。

                 以16色图像为例:每一种颜色是4B,所以颜色表大小就是16*4=64B。

    4 图像数据区

        注意情况: 每种颜色模式的行字节数要用数据“00”补齐为4的整数倍

        16色图像,图像宽为19,存储时每行则要补充4-(19/2+1)%4=2个字节(加1是因为里面有一个像素点要独占了一字节)。

        256色图像,图像宽为19,每行也要补充4-19%4=1个字节。

        24位色彩图,图像宽为19,每行也要补充4-(19*3)%4=3个字节。

        32位色彩图,图像宽为19,每行也要补充4-(19*4)%4=0个字节,即无需补字节,本身已经是4B对齐了

    参考程序

    #include <stdio.h>
    #include <stdlib.h>
    
    #define WIDTHBYTES(bits) (((bits)+31)/32*4)
    
    typedef unsigned char BYTE;
    typedef unsigned short WORD;
    typedef unsigned long DWORD;
    typedef long LONG;
    
    
    //位图文件头信息结构定义
    //其中不包含文件类型信息(由于结构体的内存结构决定,要是加了的话将不能正确读取文件信息)
    typedef struct tagBITMAPFILEHEADER {
        DWORD bfSize; //文件大小
        WORD bfReserved1; //保留字,不考虑
        WORD bfReserved2; //保留字,同上
        DWORD bfOffBits; //实际位图数据的偏移字节数,即前三个部分长度之和
    } BITMAPFILEHEADER;
    
    
    //信息头BITMAPINFOHEADER,也是一个结构,其定义如下:
    typedef struct tagBITMAPINFOHEADER{
        //public:
        DWORD biSize; //指定此结构体的长度,为40
        LONG biWidth; //位图宽
        LONG biHeight; //位图高
        WORD biPlanes; //平面数,为1
        WORD biBitCount; //采用颜色位数,可以是1,2,4,8,16,24,新的可以是32
        DWORD biCompression; //压缩方式,可以是0,1,2,其中0表示不压缩
        DWORD biSizeImage; //实际位图数据占用的字节数
        LONG biXPelsPerMeter; //X方向分辨率
        LONG biYPelsPerMeter; //Y方向分辨率
        DWORD biClrUsed; //使用的颜色数,如果为0,则表示默认值(2^颜色位数)
        DWORD biClrImportant; //重要颜色数,如果为0,则表示所有颜色都是重要的
    } BITMAPINFOHEADER;
    
    
    //调色板Palette,当然,这里是对那些需要调色板的位图文件而言的。24位和32位是不需要调色板的。
    //(似乎是调色板结构体个数等于使用的颜色数。)
    typedef struct tagRGBQUAD {
        //public:
        BYTE rgbBlue; //该颜色的蓝色分量
        BYTE rgbGreen; //该颜色的绿色分量
        BYTE rgbRed; //该颜色的红色分量
        BYTE rgbReserved; //保留值
    } RGBQUAD;
    
    void showBmpHead(BITMAPFILEHEADER* pBmpHead)
    {
        printf("位图文件头:
    ");
        printf("文件大小:%d
    ",pBmpHead->bfSize);
        printf("保留字:%d
    ",pBmpHead->bfReserved1);
        printf("保留字:%d
    ",pBmpHead->bfReserved2);
        printf("实际位图数据的偏移字节数:%d
    ",pBmpHead->bfOffBits);
    }
    
    void showBmpInforHead(BITMAPINFOHEADER* pBmpInforHead)
    {
        printf("位图信息头:
    ");
        printf("结构体的长度:%d
    ",pBmpInforHead->biSize);
        printf("位图宽:%d
    ",pBmpInforHead->biWidth);
        printf("位图高:%d
    ",pBmpInforHead->biHeight);
        printf("biPlanes平面数:%d
    ",pBmpInforHead->biPlanes);
        printf("biBitCount采用颜色位数:%d
    ",pBmpInforHead->biBitCount);
        printf("压缩方式:%d
    ",pBmpInforHead->biCompression);
        printf("biSizeImage实际位图数据占用的字节数:%d
    ",pBmpInforHead->biSizeImage);
        printf("X方向分辨率:%d
    ",pBmpInforHead->biXPelsPerMeter);
        printf("Y方向分辨率:%d
    ",pBmpInforHead->biYPelsPerMeter);
        printf("使用的颜色数:%d
    ",pBmpInforHead->biClrUsed);
        printf("重要颜色数:%d
    ",pBmpInforHead->biClrImportant);
    }
    
    void showRgbQuan(RGBQUAD* pRGB)
    {
        printf("(%-3d,%-3d,%-3d) ",pRGB->rgbRed,pRGB->rgbGreen,pRGB->rgbBlue);
    }
    
    void main()
    {
    #ifdef __x86_64__
        printf("__x86_64__
    ");
    #elif __i386__
        printf("__i386__
    ");
    #endif
    
        BITMAPFILEHEADER bitHead;
        BITMAPINFOHEADER bitInfoHead;
        FILE* pfile;
    
        char strFile[50];
        printf("please input the .bmp file name:
    ");
        scanf("%s",strFile);
    
        pfile = fopen(strFile,"rb");//打开文件
    
        if(pfile!=NULL) {
            printf("file bkwood.bmp open success.
    ");
            //读取位图文件头信息
            WORD fileType;
            fread(&fileType,1,sizeof(WORD),pfile);
            if(fileType != 0x4d42) {<span style="color:#ff0000;">   // 将magic单独出来,没有放到头信息里处理,来判断该文件是否时bitmap文件</span>
                printf("file is not .bmp file!");
                return;
            }
            fread(&bitHead,1,sizeof(BITMAPFILEHEADER),pfile);
    
            showBmpHead(&bitHead);
            printf("
    
    ");
    
            //读取位图信息头信息
            fread(&bitInfoHead,1,sizeof(BITMAPINFOHEADER),pfile);
            showBmpInforHead(&bitInfoHead);
            printf("
    ");
        } else {
            printf("file open fail!
    ");
            return;
        }
    
        RGBQUAD *pRgb ;
    
        int width = bitInfoHead.biWidth;
        int height = bitInfoHead.biHeight;
        //分配内存空间把源图存入内存
        int l_width = WIDTHBYTES(width* bitInfoHead.biBitCount);//计算位图的实际宽度并确保它为32的倍数
        BYTE *pColorData=(BYTE *)malloc(height*l_width);
        memset(pColorData,0,height*l_width);
        long nData = height*l_width;
    
        //把位图数据信息读到数组里
        fread(pColorData,1,nData,pfile);
    
        //将位图数据转化为RGB数据
        RGBQUAD* dataOfBmp;
        dataOfBmp = (RGBQUAD *)malloc(width*height*sizeof(RGBQUAD));//用于保存各像素对应的RGB数据
        memset(dataOfBmp,0,width*height*sizeof(RGBQUAD));
    
        int k = 0;
        int i = 0, j = 0, index = 0;
        for(;i<height;i++) {
            for(j=0;j<width;j++) {
                k = i*l_width + j*3;
                dataOfBmp[index].rgbRed = pColorData[k+2];
                dataOfBmp[index].rgbGreen = pColorData[k+1];
                dataOfBmp[index].rgbBlue = pColorData[k];
                index++;
            }
        }
    
    
        printf("像素数据信息:
    ");
        for (i=0; i<width*height; i++) {
            if (i%5==0) {
                printf("
    ");
            }
            showRgbQuan(&dataOfBmp[i]);
        }
    
        fclose(pfile);
        if (bitInfoHead.biBitCount<24) {
            free(pRgb);
        }
        free(dataOfBmp);
        free(pColorData);
        printf("
    ");
    }

    编译时需要注意:

             如果是64位,需要使用-m32参数。例如gcc main.c -m32

             这是因为某些数据类型如long,在32和64是不同的

    参考文章: http://blog.sina.com.cn/s/blog_523491650100fk1z.html

    这里有详细的带有颜色表的bitmap的处理

  • 相关阅读:
    List内存分配
    《深入理解JAVA虚拟机》笔记1
    oracle(三)
    常见排序算法
    C++在单继承、多继承、虚继承时,构造函数、复制构造函数、赋值操作符、析构函数的执行顺序和执行内容
    C++ Primer 有感(异常处理)(四)
    C++ Primer 有感(异常处理)(三)
    C++ Primer 有感(异常处理)(二)
    C++ Primer 有感(异常处理)
    C++ Primer 有感(多重继承与虚继承)
  • 原文地址:https://www.cnblogs.com/LittleTiger/p/4723988.html
Copyright © 2011-2022 走看看