12

Here's my attempt (ugly GDI+ and GDI mix...)

// ...
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);
// ...

Someone told me to use LockBits but I really didn't understand how. I tried it, but I failed so I'm not going to post that attempt, too.

4 Answers 4

7

You could use Bitmap::LockBits to get access to a raw array of data. Here you could read about how to use Bitmap::LockBits.

Sign up to request clarification or add additional context in comments.

Comments

7

Here's something I wrote that returns a vector of vectors (with the contained vectors representing columns of pixels in the image) when passed a file path:

#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;
}

Comments

4

Here is how I would do it using GDIPlus Bitmap.LockBits method defined in the header GdiPlusBitmap.h:

Notice that since bitmaps are usually DWORD aligned you may want to discard this unused data that was needed for the alignment, as malat correctly commented..

    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;
    }

2 Comments

No this will not work, bitmapData.Stride is different from bitmapData.Width * sizeof( bitmapData.PixelFormat), since it contains also unused data. This requires a for loop to discard unused data.
code crashes at memcpy(...)
3

Have you tried supplying the bytes when you create the bitmap:

int width = BMP_WIDTH;
int height = BMP_HEIGHT;
int stride = 4 * width;
BYTE bytes[stride * height];

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

2 Comments

This is an easy case, one should pay attention that stride % 4 == 0 in the general case (not all 3 components RGB works).
how do that, when BITMAP is created using BITMAP::FromHBITMAP(...) ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.