BMP文件解析_图片分析

BMP文件解析_图片分析BMP文件简介BMP(全称Bitmap)是Window操作系统中的标准图像文件格式,可以分成两类:设备相关位图(DDB)和设备无关位图(DIB),使用非常广。它采用位映射存储格式,除了图像深度可选以外,不采用其他任何压缩,因此,BMP文件所占用的空间很大。BMP文件的图像深度可选lbit、4bit、8bit及24bit。BMP文件存储数据时,图像的扫描方式是按从左到右、从下到上的顺序。由于BMP文

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

BMP文件简介

BMP(全称Bitmap)是Window操作系统中的标准图像文件格式,可以分成两类:设备相关位图(DDB)和设备无关位图(DIB),使用非常广。它采用位映射存储格式,除了图像深度可选以外,不采用其他任何压缩,因此,BMP文件所占用的空间很大。BMP文件的图像深度可选lbit、4bit、8bit、16bit、24bit或者32bit。BMP文件存储数据时,图像的扫描方式是按从左到右、从下到上的顺序。 由于BMP文件格式是Windows环境中交换与图有关的数据的一种标准,因此在Windows环境中运行的图形图像软件都支持BMP图像格式。

BMP文件结构

BMP文件一般由四部分组成:
1、文件头
2、文件信息头
3、调色板(不一定有)
4、位图数据
调色板不是必须的,只有在单色位图、16色位图、256色位图中才有,也是位图深度为1bit、4bit、8bit的位图才有调色板。关于BMP文件的定义,在windows.h这个头文件中都有描述,一般来说,一个BMP文件用C语言代码可以这样表示:

struct BMP
{
    BITMAPFILEHEADER fileHeader;    //文件头
    BITMAPINFOHEADER infoHeader;    //文件信息头
    PALETTEENTRY     palette[n];    //调色板信息,n为颜色数目
    byte *pixels;                   //像素数据指针
};

Jetbrains全家桶1年46,售后保障稳定

下面将对BMP文件给出详细的解析

1、BMP文件头

BMP文件头在Windows.h中被声明为:BITMAPFILEHEADER。该结构完整的声明如下:

typedef struct tagBITMAPFILEHEADER {
        WORD    bfType;
        DWORD   bfSize;
        WORD    bfReserved1;
        WORD    bfReserved2;
        DWORD   bfOffBits;
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;
  1. bfType:两个字节,表示文件的类型,该值一般是0x4D42,也就是‘BM’。
  2. bfSize : 四个字节,说明文件的大小,以字节为单位。文件总的大小=文件头字节数+信息头的字节数+调色板字节数+像素数据字节数。
  3. bfReserved1:保留数据,一般为0。
  4. bfReserved2:保留数据,一般为0。
  5. bfOffBits:文件头到像素数据之间的字节偏移量,用来定位像素数据。这个参数非常有用,因为位图信息头和调色板的长度会根据不同的情况而有所变化,利用这个偏移量可以迅速读取到像素数据。其大小一般是:偏移量=文件头字节数+文件信息头字节数+调色板字节数。

2、位图信息头

BMP信息头在windows.h中被声明为:BITMAPINFOHEADER 。该结构完整的声明如下:

    typedef struct tagBITMAPINFOHEADER{
        DWORD      biSize;
        LONG       biWidth;
        LONG       biHeight;
        WORD       biPlanes;
        WORD       biBitCount;
        DWORD      biCompression;
        DWORD      biSizeImage;
        LONG       biXPelsPerMeter;
        LONG       biYPelsPerMeter;
        DWORD      biClrUsed;
        DWORD      biClrImportant;
    } BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;
  1. biSize:4字节,说明BITMAPINFOHEADER结构所需的字节数,数值为sizeof(BITMAPINFOHEADER),一般是40字节,但也可能不是,具体要看系统。
  2. biWidth:4个字节,说明图像的宽度,以像素为单位。
  3. biHeight:4个字节,说明图像的高度,以像素为单位。该值除了指示位图的高度之外,还可指示图像的方向:当该值为正数时,位图是倒向的,当该值为负数时,位图是正向的。一般位图都是倒向的,也就是该值一般是正数。
  4. biPlanes:2个字节,说明图像的位面数,一般就是1;
  5. biBitCount:2个字节,说明每个像素所具有的比特数。该值可以是1、4、8、16、24、32,一般来说,使用24色的位图,该值就是24。
  6. biCompression:4个字节,说明图像数据的压缩类型,其中:BI_RGB表示无压缩;BI_RLE8表示每个像素8比特的RLE压缩编码,压缩格式由2字节组成(重复像素计数和颜色索引);BI_RLE4表示每个像素4比特的RLE压缩编码,压缩格式由2字节组成;BI_BITFIELDS:每个像素的比特由指定的掩码决定;BI_JPEG:JPEG格式。
  7. biSizeImage:4个字节,说明图像的大小,以字节为单位,必须是4的倍数,当使用BI_RGB格式时,该值可以为0。
  8. biXPelsPerMeter:4个字节,水平分辨率,用像素/米表示,不知道就设为0。
  9. biYPelsPerMeter:4个字节,垂直分辨率,用像素/米表示,不知道就设为0。
  10. biClrUsed:4字节,说明位图实际使用的彩色表中颜色索引数,采用索引色时会用到,如果采用无压缩的RGB格式,这个值可以是0。
  11. biClrImportant:4个字节,说明对图像显示有重要影响的颜色索引数目,为0则表示都很重要。

3、调色板

调色板的目的是建立一个颜色索引,从而节省存储空间。在调色板中,保存着位图用到的所有颜色,而位图数据部分储存的是颜色的索引,读取bmp文件的像素数据时,通过索引找到相对应的颜色。调色板不一定会有,像16位色、24位色和32位色的位图就没有调色板。调色板是一个RGBQUAD类型的的数组,数组的大小跟颜色数目有关。RGBQUAD结构体在windows.h中的定义如下:

typedef struct tagRGBQUAD {
        BYTE    rgbBlue;
        BYTE    rgbGreen;
        BYTE    rgbRed;
        BYTE    rgbReserved;
} RGBQUAD

该结构体占用四个字节,前三个表示颜色的三个分量,取值范围是0到255,分别是蓝、绿、红(不是红、绿、蓝),第四个是保留项,一般都是0。调色板一般可这样定义:

RGBQUAD palette[n]

其中n表示颜色的数目,对于单色位图,颜色数目只有两个,n=2;对于4bit的位图,颜色数是16,n=16;对于8bit的位图,颜色数是256,n=256;而对于16bit、24bit和32bit的位图,由于颜色过多,不适宜使用调色板,因此没有调色板,n=0。由于色彩的需要,现在大多数位图都是24位的真彩色,甚至有32位的。

4、位图数据

位图数据一般可以保存在一个二维的数组里,值得注意的是:
(1)window系统扫描BMP图像时是逐行按每四个字节进行扫描的,也就是说,位图每行的字节长度应该是4的倍数,如果不是4的倍数,要补全,没有像素的地方,用0填充。例如一个16*16的单色位图,它的宽度为16像素,每像素用1bit表示,则每行的字节长度为2字节,但是2字节不是4的倍数,所以要将行的字节数扩充为4字节,这样的话,相当于位图变为32*16大小了。多出的部分只是占个位置,方便系统扫描罢了,不会影响原来的位图显示。
(2)window系统显示位图时,扫描像素数据时时按照B、G、R的顺序来的,而不是R、G、B,因此在填充位图数据时,要注意颜色分量的存储顺序。

C语言代码生成BMP文件

下面用C语言创建BMP文件,该文件可以是单色位图、16色位图、256色位图、16bit位图、24bit位图或者是32bit位图。的位图数据没有经过压缩,调色板的有无根据颜色深度而定。

/*********************************************************************************************************************/
//函数名:SaveBmp
//功能: 将像素数据保存文BMP文件
//参数: 分别为文件名、图片宽度、图片高度、每像素比特数、调色板指针、像素数据指针
//返回值:如果保存成功,返回true,否则为false
//说明: bCount参数可以是1、4、8、16、24、32,crPalette参数是一个指向调色板数组的指针,如果没有调色板,该项可以写NULL。
// bPixels是指向像素数据的指针,该项应该与bCount项相匹配。
/**********************************************************************************************************************/
#include<windows.h>
#include<stdio.h>

bool SaveBmp(const char *fileName, int bWidth, int bHeight, int bCount, RGBQUAD *crPalette, byte *bPixels)
{
    //调色板字节数
    int paletteSize;

    switch (bCount)
    {
    case 1:
        paletteSize = 8;
        break;
    case 4:
        paletteSize = 64;
        break;
    case 8:
        paletteSize = 1024;
        break;
    default:
        paletteSize = 0;
        break;
    }

    //需要写进文件的像素字节数
    int pixelsSize;
    pixelsSize = 4 * ((bCount*bWidth+31) / 32 )*bHeight;

    //文件头
    BITMAPFILEHEADER bmpFileHeader;

    bmpFileHeader.bfType = 'MB';
    bmpFileHeader.bfSize = 54+paletteSize+pixelsSize;
    bmpFileHeader.bfReserved1 = 0;
    bmpFileHeader.bfReserved2 = 0;
    bmpFileHeader.bfOffBits =54+paletteSize ;

    //信息头
    BITMAPINFOHEADER bmpInfoHeader;

    bmpInfoHeader.biBitCount = bCount;
    bmpInfoHeader.biClrImportant = 0;
    bmpInfoHeader.biClrUsed = 0;
    bmpInfoHeader.biCompression = BI_RGB;
    bmpInfoHeader.biHeight = bHeight;
    bmpInfoHeader.biPlanes = 1;
    bmpInfoHeader.biSize =40;
    bmpInfoHeader.biSizeImage =pixelsSize;
    bmpInfoHeader.biWidth = bWidth;
    bmpInfoHeader.biXPelsPerMeter = 0;
    bmpInfoHeader.biYPelsPerMeter = 0;

    //分配新的像素缓冲
    byte *pPixels;

    if ( (bCount*bWidth)%32==0)
    {
        //如果行的字节数刚好是4的倍数,则直接利用原来的像素缓冲
        pPixels = bPixels;
    }
    else
    {
        //否则,新创建一个缓冲区,使得每行的字节数刚好是4的倍数
        pPixels = (byte*)malloc(pixelsSize);

        //像素缓冲初始化为0
        memset(pPixels, 0, pixelsSize);

        int oldRow, newRow;

        //原来的像素缓冲每行所占的字节数
        oldRow = (bCount*bWidth+7)/ 8;

        //新的像素缓冲每行所占的字节数
        newRow = pixelsSize / bHeight;

        //将旧的像素缓冲的数据复制到新的像素缓冲
        for (int i = 0;i <bHeight;i++)
        {
            memcpy(pPixels+i*newRow, bPixels+i*oldRow, oldRow);
        }
    }

    FILE *fp;

    fp=fopen(fileName, "wb");
    if (!fp)
    {
        return false;
    }

    //写入文件头
    fwrite(&bmpFileHeader, 14, 1, fp);

    //写入信息头
    fwrite(&bmpInfoHeader, 40, 1, fp);

    //写入调色板
    fwrite(crPalette,paletteSize, 1, fp);

    //写入像素数据
    fwrite(pPixels,pixelsSize, 1, fp);
    fclose(fp);

    //如果像素缓冲区是动态创建的,则释放缓冲
    if(pPixels!=bPixels)free(pPixels);

    return true;

}

C语言代码读取BMP文件

以下代码是读取BMP文件,返回的是位图信息、调色板和像素数据。

/***************************************************************************************************************/
//函数名:LoadBmp
//功能: 载入bmp文件
//参数: 分别为文件名、位图信息头结构、调色板二重指针、像素数据二重指针
//返回值:如果读取文件成功,则返回true,否则返回false
//说明: 文件的相关信息都会被填充到bmpInfoHeader指向的结构中,crPalette、bPixels参数分别传回调色板和像素数据的指针
/***************************************************************************************************************/
#include<windows.h>
#include<stdio.h>

bool LoadBmp(const char *fileName, BITMAPINFOHEADER *bmpInfoHeader, RGBQUAD **crPalette, byte **bPixels)
{
    BITMAPFILEHEADER fileHeader;
    FILE *fp;

    fp = fopen(fileName, "rb");
    if (!fp)
    {
        return false;
    }
    //读取文件头
    fread(&fileHeader, 14, 1, fp);

    //读取信息头
    fread(bmpInfoHeader, 40, 1, fp);

    //调色板字节数
    int paletteSize;
    switch ((*bmpInfoHeader).biBitCount)
    {
    case 1:
        paletteSize = 8;
        break;
    case 4:
        paletteSize = 64;
        break;
    case 8:
        paletteSize = 1024;
        break;
    default:
        paletteSize = 0;
        break;
    }

    //动态创建调色板缓冲区
    *crPalette = (RGBQUAD*)malloc(paletteSize);

    //读入调色板数据
    fread(*crPalette, paletteSize, 1, fp);

    int pixelsSize;
    pixelsSize = fileHeader.bfSize - fileHeader.bfOffBits;

    //动态创建像素缓冲区
    *bPixels = (byte*)malloc(pixelsSize);

    //读入像素数据
    fread(*bPixels,pixelsSize, 1, fp);

    fclose(fp);

    return false;
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/230842.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 小鹤双拼尝试

    小鹤双拼尝试26个英文字母除了a,o,e,i,u,v(代表ü,下同)之外都被用作声母,而除了这20个声母之外还有3个声母分别为双字母的zh,ch,sh,汉字中绝大部分字的读音都是声母加韵母组成的。而韵母中,除了上述提到的六个字母,其余韵母都是由两个或三个字母组成。小鹤双拼编码方案:第一个字母表示声母,第二字母表示韵母,没有声母时用零声母代替单字母声母韵母键位不变,就意味着26个字母都是和它本来的音相同,比较特殊的就是v,i,u三个(它们也可以拼成yu,yi,wu),当他们被第一个按下时,会代表声母zh,ch,sh

  • 如何区分共射极放大电路与共基极放大电路?「建议收藏」

    如何区分共射极放大电路与共基极放大电路?「建议收藏」如何区分共射极放大电路与共基极放大电路?_百度知道如何区分共射极放大电路与共基极放大电路?_百度知道答有简单的方法:观察信号的输入端和输出端,就看信号正极。共射电路:信号从基极进入,从集电极

  • 三天撸完了MyBatis,各位随便问!!(冰河吐血整理,建议收藏)

    三天撸完了MyBatis,各位随便问!!(冰河吐血整理,建议收藏)很多大厂在面试的时候喜欢问MyBatis底层的原理和源码实现。总之,MyBatis几乎成为了Java开发人员必须深入掌握的框架技术,冰河吐血整理,建议收藏!!

    2022年10月14日
  • 腾讯股票数据接口

     0:未知 1:名字:name 2:代码:code 3:现价:trade 4:昨收:yestclose 5:今开:open 6:成交量(手):volume 7:外盘 8:内盘 9:买一10:买一量(手)11-18:买二买五19:卖一20:卖一量21-28:卖二卖五29:最近逐笔成交30:时间31:涨跌:change32:涨跌幅:changepercent33:最高:high34:最低:low3…

  • navicat mac激活码【2021.7最新】

    (navicat mac激活码)2021最新分享一个能用的的激活码出来,希望能帮到需要激活的朋友。目前这个是能用的,但是用的人多了之后也会失效,会不定时更新的,大家持续关注此网站~IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.cn/100143.html…

  • 不管怎么选择,都会有遗憾「建议收藏」

    到底什么样的选择才是最好的,每一种选择都会有遗憾!最近有点想家,虽然在这个城市安了新家。那个小的城市–延安,和这个大的城市—长沙,两种感觉,不同的生活体验。现在都十一月了,要是在延安,那么现在已经是深秋,开始变得萧条,不想夏天那么生机盎然,而现在这个城市秋天和夏天在外观上看不出什么变化,只是现在的温度比夏天舒服了很多,不冷 不热。城市的车水马龙,霓虹灯,夜晚还是有很多的喧嚣,也看不到漫天的繁星。

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号