如何用C++代码实现BMP图片叠加
时间: 2023-07-28 13:06:57 浏览: 184
BMP 图片叠加的 C++ 实现可以参考以下代码:
```c++
#include <iostream>
#include <fstream>
#include <vector>
#include <cstring>
using namespace std;
#pragma pack(push, 1)
// BMP 文件头结构体
typedef struct tagBITMAPFILEHEADER {
unsigned short bfType; // 文件类型,必须为 "BM"
unsigned int bfSize; // 文件大小,单位为字节
unsigned short bfReserved1; // 保留字段
unsigned short bfReserved2; // 保留字段
unsigned int bfOffBits; // 从文件头到像素数据的偏移量,单位为字节
} BITMAPFILEHEADER;
// BMP 信息头结构体
typedef struct tagBITMAPINFOHEADER {
unsigned int biSize; // 信息头大小,单位为字节
int biWidth; // 图像宽度,单位为像素
int biHeight; // 图像高度,单位为像素
unsigned short biPlanes; // 位平面数,必须为 1
unsigned short biBitCount; // 每像素位数,常用的为 1、4、8、24
unsigned int biCompression; // 压缩方式,常用的为 0(不压缩)
unsigned int biSizeImage; // 像素数据大小,单位为字节
int biXPelsPerMeter; // 水平分辨率,单位为像素/米
int biYPelsPerMeter; // 垂直分辨率,单位为像素/米
unsigned int biClrUsed; // 使用的颜色数,如果为 0,则使用所有颜色
unsigned int biClrImportant; // 重要的颜色数,如果为 0,则都重要
} BITMAPINFOHEADER;
// BMP 调色板结构体
typedef struct tagRGBQUAD {
unsigned char rgbBlue; // 蓝色分量
unsigned char rgbGreen; // 绿色分量
unsigned char rgbRed; // 红色分量
unsigned char rgbReserved; // 保留字段
} RGBQUAD;
#pragma pack(pop)
// 读取 BMP 文件
bool loadBmp(const char *filename, vector<unsigned char> &imageData,
BITMAPFILEHEADER &bmpFileHeader, BITMAPINFOHEADER &bmpInfoHeader, vector<RGBQUAD> &bmpPalette) {
// 打开 BMP 文件
ifstream file(filename, ios::binary);
if (!file) {
cerr << "Error: BMP file not found." << endl;
return false;
}
// 读取 BMP 文件头
file.read(reinterpret_cast<char *>(&bmpFileHeader), sizeof(BITMAPFILEHEADER));
if (bmpFileHeader.bfType != 0x4D42) {
cerr << "Error: Invalid BMP file format." << endl;
return false;
}
// 读取 BMP 信息头
file.read(reinterpret_cast<char *>(&bmpInfoHeader), sizeof(BITMAPINFOHEADER));
if (bmpInfoHeader.biBitCount != 24 && bmpInfoHeader.biBitCount != 32) {
cerr << "Error: Unsupported BMP bit count." << endl;
return false;
}
// 读取 BMP 调色板(如果有)
if (bmpInfoHeader.biClrUsed != 0) {
bmpPalette.resize(bmpInfoHeader.biClrUsed);
file.read(reinterpret_cast<char *>(bmpPalette.data()), bmpInfoHeader.biClrUsed * sizeof(RGBQUAD));
}
// 读取 BMP 图像数据
imageData.resize(bmpInfoHeader.biSizeImage);
file.read(reinterpret_cast<char *>(imageData.data()), bmpInfoHeader.biSizeImage);
// 关闭 BMP 文件
file.close();
return true;
}
// 保存 BMP 文件
bool saveBmp(const char *filename, const vector<unsigned char> &imageData,
const BITMAPFILEHEADER &bmpFileHeader, const BITMAPINFOHEADER &bmpInfoHeader, const vector<RGBQUAD> &bmpPalette) {
// 创建 BMP 文件
ofstream file(filename, ios::binary);
if (!file) {
cerr << "Error: Failed to create BMP file." << endl;
return false;
}
// 写入 BMP 文件头
file.write(reinterpret_cast<const char *>(&bmpFileHeader), sizeof(BITMAPFILEHEADER));
// 写入 BMP 信息头
file.write(reinterpret_cast<const char *>(&bmpInfoHeader), sizeof(BITMAPINFOHEADER));
// 写入 BMP 调色板(如果有)
if (bmpInfoHeader.biClrUsed != 0) {
file.write(reinterpret_cast<const char *>(bmpPalette.data()), bmpInfoHeader.biClrUsed * sizeof(RGBQUAD));
}
// 写入 BMP 图像数据
file.write(reinterpret_cast<const char *>(imageData.data()), bmpInfoHeader.biSizeImage);
// 关闭 BMP 文件
file.close();
return true;
}
// 将两张 BMP 图片叠加
bool blendBmp(const vector<unsigned char> &imageData1, const BITMAPINFOHEADER &bmpInfoHeader1,
const vector<unsigned char> &imageData2, const BITMAPINFOHEADER &bmpInfoHeader2,
vector<unsigned char> &imageData3, BITMAPINFOHEADER &bmpInfoHeader3) {
// 检查两张 BMP 图片是否具有相同的尺寸和位深度
if (bmpInfoHeader1.biWidth != bmpInfoHeader2.biWidth ||
bmpInfoHeader1.biHeight != bmpInfoHeader2.biHeight ||
bmpInfoHeader1.biBitCount != bmpInfoHeader2.biBitCount) {
cerr << "Error: BMP images have different sizes or bit depths." << endl;
return false;
}
// 拷贝 BMP 信息头
memcpy(&bmpInfoHeader3, &bmpInfoHeader1, sizeof(BITMAPINFOHEADER));
// 计算 BMP 图像数据大小(注意,必须按 4 字节对齐)
int rowSize = (bmpInfoHeader1.biWidth * bmpInfoHeader1.biBitCount + 31) / 32 * 4;
bmpInfoHeader3.biSizeImage = rowSize * bmpInfoHeader1.biHeight;
// 分配 BMP 图像数据内存
imageData3.resize(bmpInfoHeader3.biSizeImage);
// 循环遍历 BMP 图像数据,并将两张 BMP 图片叠加
int imageSize = bmpInfoHeader1.biWidth * bmpInfoHeader1.biHeight * (bmpInfoHeader1.biBitCount / 8);
for (int i = 0; i < imageSize; i += (bmpInfoHeader1.biBitCount / 8)) {
int r1 = imageData1[i + 2];
int g1 = imageData1[i + 1];
int b1 = imageData1[i];
int r2 = imageData2[i + 2];
int g2 = imageData2[i + 1];
int b2 = imageData2[i];
int r3 = min(r1 + r2, 255);
int g3 = min(g1 + g2, 255);
int b3 = min(b1 + b2, 255);
imageData3[i] = static_cast<unsigned char>(b3);
imageData3[i + 1] = static_cast<unsigned char>(g3);
imageData3[i + 2] = static_cast<unsigned char>(r3);
}
return true;
}
int main() {
// 读取第一张 BMP 图片
BITMAPFILEHEADER bmpFileHeader1;
BITMAPINFOHEADER bmpInfoHeader1;
vector<unsigned char> imageData1;
vector<RGBQUAD> bmpPalette1;
if (!loadBmp("image1.bmp", imageData1, bmpFileHeader1, bmpInfoHeader1, bmpPalette1)) {
return 1;
}
// 读取第二张 BMP 图片
BITMAPFILEHEADER bmpFileHeader2;
BITMAPINFOHEADER bmpInfoHeader2;
vector<unsigned char> imageData2;
vector<RGBQUAD> bmpPalette2;
if (!loadBmp("image2.bmp", imageData2, bmpFileHeader2, bmpInfoHeader2, bmpPalette2)) {
return 1;
}
// 将两张 BMP 图片叠加
vector<unsigned char> imageData3;
BITMAPINFOHEADER bmpInfoHeader3;
if (!blendBmp(imageData1, bmpInfoHeader1, imageData2, bmpInfoHeader2, imageData3, bmpInfoHeader3)) {
return 1;
}
// 保存叠加后的 BMP 图片
BITMAPFILEHEADER bmpFileHeader3;
bmpFileHeader3.bfType = 0x4D42;
bmpFileHeader3.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + bmpInfoHeader3.biSizeImage;
bmpFileHeader3.bfReserved1 = 0;
bmpFileHeader3.bfReserved2 = 0;
bmpFileHeader3.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
if (!saveBmp("image3.bmp", imageData3, bmpFileHeader3, bmpInfoHeader3, bmpPalette1)) {
return 1;
}
return 0;
}
```
这段代码中,loadBmp() 函数用于读取 BMP 文件,saveBmp() 函数用于保存 BMP 文件,blendBmp() 函数用于将两张 BMP 图片叠加。在主函数中,首先读取两张 BMP 图片,然后将它们叠加,并保存为新的 BMP 文件。需要注意的是,这段代码中只支持 24 位和 32 位的 BMP 图片。如果需要支持其他位深度的 BMP 图片,需要进行相应的修改。
阅读全文