我是靠谱客的博主 碧蓝雨,最近开发中收集的这篇文章主要介绍【C/C++】BITMAP格式分析,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

BITMAP文件大体上分成四个部分,如下表所示。

文件部分长度(字节)
位图文件头 Bitmap File Header14
位图信息数据头 Bitmap Info Header40
调色板 Palette4*n (n≥0)
位图数据 Image Data不定长

 

BITMAP文件格式

1、位图文件头 Bitmap File Header

typedef struct tagBITMAPFILEHEADER {
        WORD    bfType;
        DWORD   bfSize;
        WORD    bfReserved1;
        WORD    bfReserved2;
        DWORD   bfOffBits;
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;
字段说明

bfType

文件类型,必须是0x4D42,即字符串“BM”

bfSize

指定文件大小,以字节为单位,包括本结构体长度

bfReserved1

保留字,必须设置为0

bfReserved2

保留字,必须设置为0

bfOffBits

从文件头开始到实际的图象数据的偏移字节数。

 

2、位图信息数据头 Bitmap Info Header 

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;
字段说明

biSize

该结构体长度。

biWidth

说明图象的宽度,单位为象素。

biHeight

说明图象的高度,单位为象素。

biPlanes

位平面数,必须为1。

biBitCount

指定颜色位数,1为二值,4为16色,8为256色,16、24、32为真彩色。

biCompression

指定是否压缩,有效的值为BI_RGB,BI_RLE8,BI_RLE4、BI_BITFIELDS。

biSizeImage

实际的位图数据占用的字节数。

biXPelsPerMeter

目标设备水平分辨率,单位是每米的像素数。

biYPelsPerMeter

目标设备垂直分辨率,单位是每米的像素数。

biClrUsed

实际使用的颜色数。

biClrImportant

图像中重要的颜色数,若该值为0,则所有的颜色都是重要的。

 

3、调色板 Palette

第三部分为调色板(Palette),当然,这里是对那些需要调色板的位图文件而言的。有些位图,如真彩色图,前面已经讲过,是不需要调色板的,BITMAPINFOHEADER后直接是位图数据。 
调色板实际上是一个数组,共有biClrUsed个元素(如果该值为零,则有2的biBitCount次方个元素)。数组中每个元素的类型是一个RGBQUAD结构,占4个字节,其定义如下:

typedef struct tagRGBQUAD {
        BYTE    rgbBlue;             //该颜色蓝色分量
        BYTE    rgbGreen;            //该绿色蓝色分量
        BYTE    rgbRed;              //该红色蓝色分量    
        BYTE    rgbReserved;         //保留
} RGBQUAD;

 

4、位图数据 ImageData

第四部分就是实际的图象数据了。对于用到调色板的位图,图象数据就是该像素颜在调色板中的索引值,对于真彩色图,图象数据就是实际的R,G,B值。下面就2色,16色,256色位图和真彩色位图分别介绍。

  • 2色位图:用1位就可以表示该像素的颜色(一般0表示黑,1表示白),所以一个字节可以表示8个像素。
  • 16色位图:用4位可以表示一个像素的颜色,所以一个字节可以表示2个像素。
  • 256色位图:一个字节刚好可以表示1个像素。 
  • 真彩色图:三个字节才能表示1个像素。

 

例子

以一幅24位真彩色图像为例,读取并顺时针旋转并保存。该BITMAP图片尺寸为450 * 227。

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

#pragma pack(push)
#pragma pack(1)

//24位真彩色
struct RGB
{
    BYTE			b;
    BYTE			g;
    BYTE			r;
};

#pragma pack(pop)

void imgOpr(RGB &a, RGB &b)
{
    b.b = a.b;
    b.g = a.g;
    b.r = a.r;
}

//二维数组申请img[m][n]
RGB ** RGB_new(int m, int n)
{
	int					i;
	RGB					**img;

	img = new RGB * [m];

	for (i = 0; i < m; i ++)
	{
		img[i] = new RGB [n];
	}

	return img;
}

//释放img[m][n]
void RGB_delete(RGB **img, int m, int n)
{
	int					i;

	for (i = 0; i < m; i ++)
	{
		delete [] img[i];
	}
 
	delete [] img;
}

int main()
{
    BITMAPFILEHEADER	bfh;
    BITMAPINFOHEADER	bih;

	RGB					**img1;
    RGB					**img2;
	BYTE				*tmp;

	int					i, j;
    int					height, width;
	int					m, n;

    FILE				*fp, *fq; 
	errno_t				err;
	
	err = fopen_s(&fp, "D:\Work\Debug\7.bmp", "rb");

	if (err == 0)
	{
		printf("The input file was opened!n");
	}
	else
	{
		printf("The input file was not opened!n");
		return 1;
	}

	err = fopen_s(&fq, "D:\Work\Debug\2.bmp", "wb");

	if (err == 0)
	{
		printf("The output file was opened!n");
	}
	else
	{
		printf("The output file was not opened!n");
		return 1;
	}

    fread(&bfh, sizeof(BITMAPFILEHEADER), 1, fp);
    fread(&bih, sizeof(BITMAPINFOHEADER), 1, fp);
    
	height = bih.biHeight;
    width = bih.biWidth;
	
	img1 = RGB_new(height, width);
	img2 = RGB_new(width, height);
	
	//计算每行图像字节数,必须是4的整倍数,不够需要填充
	m = (bih.biWidth * bih.biBitCount + 31) / 32 * 4; 
	n = (bih.biHeight * bih.biBitCount + 31) / 32 * 4;
	
	tmp = new BYTE [n];
	memset(tmp, 0x0, n);

    //对图片进行操作
	for (i = 0; i < height; i ++)
	{
		//跳过调色板数据段,并寻址
		fseek(fp, bfh.bfOffBits + i * m, SEEK_SET);
		fread(img1[i], sizeof(RGB), width, fp);

		for (j = 0; j < width; j ++)
		{
			//将数组 img 赋值给 img2
			imgOpr(img1[i][j], img2[j][i]);
		}
	}

	//更新BITMAPINFOHEADER结构体
	bih.biHeight = width;
	bih.biWidth = height;
	bih.biSizeImage = n * width;

	//将修改后的图片保存到文件
	fwrite(&bfh, sizeof(BITMAPFILEHEADER), 1, fq);
	fwrite(&bih, sizeof(BITMAPINFOHEADER), 1, fq);

	for (i = 0; i < width; i ++)
	{
		memcpy(tmp, img2[i], sizeof(RGB) * height);
		fwrite(tmp, 1, n, fq);
	}

    fclose(fp);
    fclose(fq);

	//释放
	RGB_delete(img1, height, width);
	RGB_delete(img2, width, height);
	
	delete [] tmp;
 
	system("pause");

    return 0;
}

原图

 

顺时针旋转90度

 

下载地址:https://download.csdn.net/download/sunriver2000/12152422

最后

以上就是碧蓝雨为你收集整理的【C/C++】BITMAP格式分析的全部内容,希望文章能够帮你解决【C/C++】BITMAP格式分析所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(59)

评论列表共有 0 条评论

立即
投稿
返回
顶部