Gdiplus::Bitmap如何转换为BYTE数组?

12

这是我的尝试(丑陋的 GDI+ 和 GDI 混合使用...)

// ...
BYTE               pixels[BMP_WIDTH * BMP_HEIGHT * BMP_BPP];
HBITMAP            hBitmap;
Gdiplus::Bitmap    cBitmap(BMP_WIDTH, BMP_HEIGHT, PixelFormat32bppRGB);
Gdiplus::Graphics  cGraphics(&cBitmap);
Gdiplus::Pen       cPen(Gdiplus::Color(255, 255, 0, 0));

cGraphics.DrawRectangle(&cPen, 0, 0, cBitmap.GetWidth() - 1, cBitmap.GetHeight() - 1);

// and here it get's real ugly, I'd like to change that...
cBitmap.GetHBITMAP(Gdiplus::Color(255, 255, 255), &hBitmap);
GetBitmapBits(hBitmap, sizeof(pixels), pixels);
// ...

有人告诉我要使用LockBits,但我真的不太懂。我尝试了一下,但失败了,所以我不会发布那个尝试的版本。

4个回答

7

这是我写的一个函数,当传入文件路径时,它会返回一个二维向量(其中包含的向量表示图像中的列像素):

#include <vector>
std::vector<std::vector<unsigned>> getPixels(const wchar_t *filename, int &width, int &height) {
    Gdiplus::Bitmap bitmap(filename);

    //Pass up the width and height, as these are useful for accessing pixels in the vector o' vectors.
    width = bitmap.GetWidth();
    height = bitmap.GetHeight();

    auto *bitmapData = new Gdiplus::BitmapData;

    //Lock the whole bitmap so we can read pixel data easily.
    Gdiplus::Rect rect(0, 0, width, height);
    bitmap.LockBits(&rect, Gdiplus::ImageLockModeRead, PixelFormat32bppARGB, bitmapData);

    //Get the individual pixels from the locked area.
    auto *pixels = static_cast<unsigned *>(bitmapData->Scan0);

    //Vector of vectors; each vector is a column.
    std::vector<std::vector<unsigned>> resultPixels(width, std::vector<unsigned>(height));

    const int stride = abs(bitmapData->Stride);
    for(int x = 0; x < width; x++) {
        for(int y = 0; y < height; y++) {
            //Get the pixel colour from the pixels array which we got earlier.
            const unsigned pxColor = pixels[y * stride / 4 + x];

            //Get each individual colour component. Bitmap colours are in reverse order.
            const unsigned red = (pxColor & 0xFF0000) >> 16;
            const unsigned green = (pxColor & 0xFF00) >> 8;
            const unsigned blue = pxColor & 0xFF;

            //Combine the values in a more typical RGB format (as opposed to the bitmap way).
            const int rgbValue = RGB(red, green, blue);

            //Assign this RGB value to the pixel location in the vector o' vectors.
            resultPixels[x][y] = rgbValue;
        }
    }

    //Unlock the bits that we locked before.
    bitmap.UnlockBits(bitmapData);
    return resultPixels;
}

7

您可以使用 Bitmap::LockBits 方法来获取原始数据数组的访问权限。您可以在这里了解如何使用 Bitmap::LockBits


4

以下是我使用GDIPlus Bitmap.LockBits方法来完成的:

请注意,由于位图通常是DWORD对齐的,因此您可能希望丢弃为对齐而需要的未使用数据,就像malat正确地评论的那样。

    Gdiplus::BitmapData bitmapData;
    Gdiplus::Rect rect(0, 0, bitmap.GetWidth(), bitmap.GetHeight());

    //get the bitmap data
    if(Gdiplus::Ok == bitmap.LockBits(
                        &rect, //A rectangle structure that specifies the portion of the Bitmap to lock.
                        Gdiplus::ImageLockModeRead | Gdiplus::ImageLockModeWrite, //ImageLockMode values that specifies the access level (read/write) for the Bitmap.
                        bitmap.GetPixelFormat(),// PixelFormat values that specifies the data format of the Bitmap.
                        &bitmapData //BitmapData that will contain the information about the lock operation.
                        ))
    {
         //get the lenght of the bitmap data in bytes
         int len = bitmapData.Height * std::abs(bitmapData.Stride);

         BYTE* buffer = new BYTE[len];
         memcpy(bitmapData.Scan0, buffer, len);//copy it to an array of BYTEs

         //... 

         //cleanup
         bitmap.UnlockBits(&bitmapData);        
         delete []buffer;
    }

不行,bitmapData.StridebitmapData.Width * sizeof(bitmapData.PixelFormat)不同,因为它还包含未使用的数据。这需要使用for循环来丢弃未使用的数据。 - malat
代码在 memcpy(...) 处崩溃。 - Gray Programmerz

3
你尝试在创建位图时提供字节吗:
int width = BMP_WIDTH;
int height = BMP_HEIGHT;
int stride = 4 * width;
BYTE bytes[stride * height];

Gdiplus::Bitmap  cBitmap(width, height, stride, PixelFormat32bppRGB, bytes);

这是一个简单的情况,需要注意在一般情况下(不是所有3个组件RGB都适用),stride%4 == 0 - malat
当使用BITMAP::FromHBITMAP(...)创建BITMAP时,怎么做? - Gray Programmerz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接