翻转并裁剪位图

Flip and crop a bitmap

本文关键字:位图 裁剪 翻转      更新时间:2023-10-16

我正在从源代码中获取一个字节数组(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部分。位图所需的唯一分配是像素。标头和其他信息根本不需要分配。

请参阅下面的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;
}