在进行本文章的阅读前, 应确保已有BMP文件结构的基础知识。
BMP图像结构基本知识链接:C++:关于BMP图像文件的基础知识
BMP类的建立
在对BMP图像文件进行操作前,应对**BMP文件**的属性及接口进行**封装**
class BMP
{
private:
int lineByte;
unsigned char* bmpBuffer;
RGBQUAD* colorTable;
BITMAPFILEHEADER fhead;
BITMAPINFOHEADER ihead;
public:
//初始化
BMP()
{
lineByte = 0;
bmpBuffer = new unsigned char;
colorTable = new RGBQUAD[256];
}
//记得要写析构函数
~BMP(){ delete[]bmpBuffer, colorTable; }
//两个接口:读写操作
void readBmp(string filename);
void saveBmp(string filename);
};
一、BMP的读操作
- 创建ifstream对象, 并以二进制模式打开;
ifstream ifile(filename, ios::binary);
- 读取并存取 BITMAPFILEHEADER 和 BITMAPINFOHEADER
此处用到了std::istream &std::istream::read(char *_Str, std::streamsize _Count);
1)第一个参数是一个char类型的指针,是用于存储所读的信息;
2)第二个参数是一个streamsize类型,可理解为有符号的整型,是用于判断一次读操作所读取的大小;
//此处用到了强制类型转换
ifile.read((char*)&fhead, sizeof(BITMAPFILEHEADER));
ifile.read((char*)&ihead, sizeof(BITMAPINFOHEADER));
- 由于真彩色图像(24位或更高位图像)无调色板,而在有调色板的图像中,8位图像又更为常见,因此在有调色板的情况中,我们仅考虑8位图像的情况,1位和4位图像的情况只要以此类推。
注:8位图像可以表示256色位图
if (ihead.biBitCount == 8)
for (int i = 0; i < 256; i++) //256色位图
ifile.read((char*)&colorTable[i], sizeof(RGBQUAD));
- 计算每行像素所占的字节数,并存储位图数据。
//lineByte必须是4的倍数,且只能进位
lineByte = (ihead.biWidth * ihead.biBitCount / 8 + 3) / 4 * 4;
bmpBuffer = new unsigned char[lineByte * ihead.biHeight];
for (int i = 0; i < lineByte * ihead.biHeight; i++)
ifile.read((char*)&bmpBuffer[i], 1);
二、BMP图像的写操作
BMP图像的写操作较为简单,只需将BITMAPFILEHEADER、BITMAPINFOHEADER 、RGBQUAD 、和位图数据
依次写进文件中即可。
void BMP::saveBmp(string filename)
{
if (!bmpBuffer) return;
ofstream ofile(filename, ios::binary);
ofile.write((char*)&fhead, sizeof(BITMAPFILEHEADER));
ofile.write((char*)&ihead, sizeof(BITMAPINFOHEADER));
if (ihead.biBitCount == 8)for (int i = 0; i < 256; i++)
ofile.write((char*)&colorTable[i], sizeof(RGBQUAD));
ofile.write((char*)bmpBuffer, lineByte * ihead.biHeight);
ofile.close();
}
三、完整代码如下
#include<Windows.h>
#include<stdio.h>
#include<fstream>
using namespace std;
class BMP
{
private:
int lineByte;
unsigned char* bmpBuffer;
RGBQUAD* colorTable;
BITMAPFILEHEADER fhead;
BITMAPINFOHEADER ihead;
public:
//初始化
BMP()
{
lineByte = 0;
bmpBuffer = new unsigned char;
colorTable = new RGBQUAD[256];
}
//记得要写析构函数
~BMP(){ delete[]bmpBuffer, colorTable; }
//两个接口:读写操作
void readBmp(string filename);
void saveBmp(string filename);
};
void BMP::readBmp(string filename)
{
ifstream ifile(filename, ios::binary);
ifile.read((char*)&fhead, sizeof(BITMAPFILEHEADER));
ifile.read((char*)&ihead, sizeof(BITMAPINFOHEADER));
if (ihead.biBitCount == 8)
for (int i = 0; i < 256; i++)
ifile.read((char*)&colorTable[i], sizeof(RGBQUAD));
lineByte = (ihead.biWidth * ihead.biBitCount / 8 + 3) / 4 * 4;
bmpBuffer = new unsigned char[lineByte * ihead.biHeight];
for (int i = 0; i < lineByte * ihead.biHeight; i++)
ifile.read((char*)&bmpBuffer[i], 1);
ifile.close();
}
void BMP::saveBmp(string filename)
{
if (!bmpBuffer) return;
ofstream ofile(filename, ios::binary);
ofile.write((char*)&fhead, sizeof(BITMAPFILEHEADER));
ofile.write((char*)&ihead, sizeof(BITMAPINFOHEADER));
if (ihead.biBitCount == 8)for (int i = 0; i < 256; i++)
ofile.write((char*)&colorTable[i], sizeof(RGBQUAD));
ofile.write((char*)bmpBuffer, lineByte * ihead.biHeight);
ofile.close();
}
int main()
{
BMP bmp;
bmp.readBmp("1.bmp");
bmp.saveBmp("2.bmp");
bmp.showBmp();
return 0;
}