将两张bmp图片进行叠加

#include <iostream>
#include <fstream>
#include <cstdint>
#include <cstring>

#pragma pack(2) // 结构体按字节对齐,每个元素的大小必须是2的整数倍
// bmp文件头
struct BMPHeader
{
    uint16_t bfType;
    uint32_t bfSize;
    uint16_t bfReserved1;
    uint16_t bfReserved2;
    uint32_t bfOffBits;
};
// bmp信息头
struct BMPInfoHeader
{
    uint32_t biSize;
    int32_t biWidth;
    int32_t biHeight;
    uint16_t biPlanes;
    uint16_t biBitCount;
    uint32_t biCompression;
    uint32_t biSizeImage;
    int32_t biXPelsPerMeter;
    int32_t biYPelsPerMeter;
    uint32_t biClrUsed;
    uint32_t biClrImportant;
};
#pragma pack()

// 读取bmp图片并返回像素数据
unsigned char *readBMP(const char *filePath, BMPHeader &header, BMPInfoHeader &infoHeader)
{
    std::ifstream file(filePath, std::ios::binary); // 以二进制方式打开文件
    if (!file.is_open())
    {
        std::cerr << "Can't open " << filePath << std::endl;
        return nullptr;
    }
    // 读取文件头
    file.read(reinterpret_cast<char *>(&header), sizeof(header));
    if (header.bfType != 0x4D42)
    {
        std::cerr << filePath << " is not a BMP file" << std::endl;
        return nullptr;
    }
    // 读取信息头
    file.read(reinterpret_cast<char *>(&infoHeader), sizeof(infoHeader));
    if (infoHeader.biBitCount != 24)
    { // 只处理24位真彩色图片
        std::cerr << filePath << " is not a 24-bit BMP file" << std::endl;
        return nullptr;
    }
    // 读取像素数据
    unsigned char *pixels = new unsigned char[infoHeader.biSizeImage];
    file.seekg(header.bfOffBits, std::ios::beg);
    file.read(reinterpret_cast<char *>(pixels), infoHeader.biSizeImage);
    file.close();
    return pixels;
}

// 写入bmp图片
bool writeBMP(const char *filePath, BMPHeader &header, BMPInfoHeader &infoHeader, unsigned char *pixels)
{
    std::ofstream file(filePath, std::ios::binary); // 以二进制方式打开文件
    if (!file.is_open())
    {
        std::cerr << "Can't create " << filePath << std::endl;
        return false;
    }
    // 写入文件头
    file.write(reinterpret_cast<char *>(&header), sizeof(header));
    // 写入信息头
    file.write(reinterpret_cast<char *>(&infoHeader), sizeof(infoHeader));
    // 写入像素数据
    file.write(reinterpret_cast<char *>(pixels), infoHeader.biSizeImage);
    file.close();
    return true;
}

// 在bmp图片的指定位置叠加另一张bmp图片
bool addBMP(const char *bottomFilePath, const char *topFilePath, const char *outputFilePath,
            int32_t posX, int32_t posY)
{
    // 分别读取两张图片
    BMPHeader bottomHeader, topHeader, outputHeader;
    BMPInfoHeader bottomInfoHeader, topInfoHeader, outputInfoHeader;
    unsigned char *bottomPixels = readBMP(bottomFilePath, bottomHeader, bottomInfoHeader);
    unsigned char *topPixels = readBMP(topFilePath, topHeader, topInfoHeader);
    if (!bottomPixels || !topPixels)
    {
        std::cerr << "Read BMP failed" << std::endl;
        return false;
    }
    // 处理图片
    int32_t width = bottomInfoHeader.biWidth;
    int32_t height = bottomInfoHeader.biHeight;
    int32_t bytesPerRow = width * 3;
    while (bytesPerRow % 4 != 0)
    { // 每一行的字节数必须是4的整数倍
        ++bytesPerRow;
    }
    if (posX + topInfoHeader.biWidth > width || posY + topInfoHeader.biHeight > height)
    {
        std::cerr << "The position is out of range" << std::endl;
        return false;
    }
    for (int32_t i = 0; i < topInfoHeader.biHeight; ++i)
    {
        for (int32_t j = 0; j < topInfoHeader.biWidth; ++j)
        {
            // 计算索引值
            int32_t topIndex = (topInfoHeader.biHeight - 1 - i) * topInfoHeader.biWidth * 3 + j * 3;
            int32_t bottomIndex = (height - 1 - (posY + i)) * bytesPerRow + (posX + j) * 3;
            // 取两张图片中像素值中较大的一个作为输出的像素值
            bottomPixels[bottomIndex] = std::max(bottomPixels[bottomIndex], topPixels[topIndex]);
            bottomPixels[bottomIndex + 1] = std::max(bottomPixels[bottomIndex + 1], topPixels[topIndex + 1]);
            bottomPixels[bottomIndex + 2] = std::max(bottomPixels[bottomIndex + 2], topPixels[topIndex + 2]);
        }
    }
    // 写入输出文件
    outputInfoHeader = bottomInfoHeader;
    outputHeader = bottomHeader;
    bool result = writeBMP(outputFilePath, outputHeader, outputInfoHeader, bottomPixels);
    delete[] bottomPixels;
    delete[] topPixels;
    return result;
}

int main()
{
    const char *bottomFilePath = "image.bmp";
    const char *topFilePath = "image1.bmp";
    const char *outputFilePath = "output.bmp";
    int32_t posX = 0.5 * (4096 - 640);
    int32_t posY = 2730 - 400;
    if (!addBMP(bottomFilePath, topFilePath, outputFilePath, posX, posY))
    {
        std::cerr << "Add BMP failed" << std::endl;
        return -1;
    }
    std::cout << "Add BMP success" << std::endl;
    return 0;
}

实现效果如下:

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
要在C++中使用GDI+先组合两张BMP图片进行绘制,你可以按照以下步骤进行操作: 1. 首先,确保你已经在项目中添加了所需的GDI+头文件和库文件,并初始化GDI+库。在程序的入口函数中添加以下代码: ```cpp #include <gdiplus.h> #pragma comment(lib, "gdiplus.lib") ULONG_PTR gdiplusToken; Gdiplus::GdiplusStartupInput gdiplusStartupInput; Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); ``` 2. 在窗口类中添加以下成员变量: ```cpp Gdiplus::Bitmap* bitmap1; Gdiplus::Bitmap* bitmap2; ``` 3. 在窗口的创建函数中,加载两张BMP图片文件并创建对应的位图对象: ```cpp bitmap1 = new Gdiplus::Bitmap(L"image1.bmp"); bitmap2 = new Gdiplus::Bitmap(L"image2.bmp"); ``` 这里,"image1.bmp"和"image2.bmp"是你要加载的两张BMP图片文件名。 4. 在窗口的绘制函数中,组合两张图片并绘制到窗口: ```cpp PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); Gdiplus::Graphics graphics(hdc); graphics.DrawImage(bitmap1, 0, 0); // 绘制第一张图片 int width = bitmap1->GetWidth(); int height = bitmap1->GetHeight(); graphics.DrawImage(bitmap2, width, 0); // 绘制第二张图片 EndPaint(hWnd, &ps); ``` 这里,我们假设第一张图片位于窗口的左上角,第二张图片位于第一张图片的右边。你可以根据需要调整这些坐标。 5. 在窗口销毁时,释放相关资源: ```cpp delete bitmap1; delete bitmap2; Gdiplus::GdiplusShutdown(gdiplusToken); ``` 通过这些步骤,你可以在C++中使用GDI+先组合两张BMP图片进行绘制。希望对你有帮助!如果你有其他问题,请随时提问。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值