翻转和裁剪位图

Flip and crop a bitmap

我正在从源获取字节数组(32 位或 16 位)。

如果尺寸宽度为奇数,每行的最后一个像素需要被删除。
如果高度为奇数,则需要删除最后一行。
如果高度为负,位图需要垂直翻转。

到目前为止,这是我的代码:

m_pbmiLast = new BITMAPINFO(*m_pbmi);
m_pbmiLast->bmiHeader.biWidth = abs(m_pbmiLast->bmiHeader.biWidth) - (abs(m_pbmiLast->bmiHeader.biWidth) % 2);
m_pbmiLast->bmiHeader.biHeight = abs(m_pbmiLast->bmiHeader.biHeight) - (abs(m_pbmiLast->bmiHeader.biHeight) % 2);

int biWidth = m_pbmiLast->bmiHeader.biWidth;
int biHeight = m_pbmiLast->bmiHeader.biHeight;
int iAdjustedStride = ((((biWidth * m_pbmiLast->bmiHeader.biBitCount) + 31) & ~31) >> 3);
int iRealStride = ((((m_pbmi->bmiHeader.biWidth * m_pbmi->bmiHeader.biBitCount) + 31) & ~31) >> 3);


if (m_pbmi->bmiHeader.biHeight < 0) {
    /* Copy the actual data */
    int iLineOffsetSource = 0;
    int iLineOffsetDest = (biHeight - 1) * iRealStride;
    for (int i = 0; i < biHeight; ++i) {
        memcpy(&pData[iLineOffsetDest], &m_inputBuffer[iLineOffsetSource], iAdjustedStride);
        iLineOffsetSource += iRealStride;
        iLineOffsetDest -= iRealStride;
    }
} else {
    int iLineOffset = 0;
    for (int i = 0; i < biHeight; ++i) {
        memcpy(&pData[iLineOffset], &m_inputBuffer[iLineOffset], iAdjustedStride);
        iLineOffset += iRealStride;
    }
}

不翻转位图,当位图为奇数宽度时,倾斜位图。

可以这样..我包括阅读和写作只是为了让它成为SSCCE。它几乎没有错误。

至于我对 new BITMAPINFO 的评论。我是说你不必在 HEAP 上分配这么小的结构。放弃 new 部分。位图所需的唯一分配是像素。 header 和其他信息根本不需要分配。

请参阅下面的 Flip 函数。

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

#include <windows.h>

typedef struct
{
    BITMAPFILEHEADER Header;
    BITMAPINFO Info;
    unsigned char* Pixels;
} BITMAPDATA;

void LoadBmp(const char* path, BITMAPDATA* Data)
{
    std::ifstream hFile(path, std::ios::in | std::ios::binary);

    if(hFile.is_open())
    {
        hFile.read((char*)&Data->Header, sizeof(Data->Header));
        hFile.read((char*)&Data->Info, sizeof(Data->Info));
        hFile.seekg(Data->Header.bfOffBits, std::ios::beg);

        Data->Pixels = new unsigned char[Data->Info.bmiHeader.biSizeImage];
        hFile.read((char*)Data->Pixels, Data->Info.bmiHeader.biSizeImage);
        hFile.close();
    }
}

void SaveBmp(const char* path, BITMAPDATA* Data)
{
    std::ofstream hFile(path, std::ios::out | std::ios::binary);

    if (hFile.is_open())
    {
        hFile.write((char*)&Data->Header, sizeof(Data->Header));
        hFile.write((char*)&Data->Info, sizeof(Data->Info));
        hFile.seekp(Data->Header.bfOffBits, std::ios::beg);

        hFile.write((char*)Data->Pixels, Data->Info.bmiHeader.biSizeImage);
        hFile.close();
    }
}

void Flip(BITMAPDATA* Data)
{
    unsigned short bpp = Data->Info.bmiHeader.biBitCount;
    unsigned int width = std::abs(Data->Info.bmiHeader.biWidth);
    unsigned int height = std::abs(Data->Info.bmiHeader.biHeight);

    unsigned char* out = new unsigned char[Data->Info.bmiHeader.biSizeImage];
    unsigned long chunk = (bpp > 24 ? width * 4 : width * 3 + width % 4);

    unsigned char* dst = out;
    unsigned char* src = Data->Pixels + chunk * (height - 1);

    while(src != Data->Pixels)
    {
        std::memcpy(dst, src, chunk);
        dst += chunk;
        src -= chunk;
    }

    std::memcpy(dst, src, chunk); //for 24-bit.
    std::swap(Data->Pixels, out);
    delete[] out;
}


int main()
{
    BITMAPDATA Data;
    LoadBmp("C:/Users/Brandon/Desktop/Bar.bmp", &Data);
    Flip(&Data);
    SaveBmp("C:/Users/Brandon/Desktop/Foo.bmp", &Data);
    delete[] Data.Pixels;
    return 0;
}