Alex Wade
Alex Wade

Reputation: 737

Drawing in-memory 8-bit greyscale image buffer to screen using wxWidgets

I would like to draw 8-bit grayscale image data to a wxPaintDC, but I have been having trouble. The data is made available to me in a uint8_t array. See the non-working code below (this is one of several attempts). I am able to draw using other wxPaintDC::Draw* functions, so I believe that everything else is set up fine.

uint8_t testBuffer[] = 
{   
    250, 220, 222, 223, 210,
    186, 22, 29, 89, 110,
    250, 220, 222, 203, 210,
    240, 120, 220, 123, 210,
    230, 210, 252, 223, 210
};
wxBitmap cameraImage(5, 5, 8);
wxNativePixelData cameraImageData(cameraImage);
wxNativePixelData::Iterator p(cameraImageData);
for(unsigned y = 0; y < 5; ++y)
{
    wxNativePixelData::Iterator rowStart = p;
    for(unsigned x = 0; x < 5; ++x, ++p)
    {
        uint8_t value = testBuffer[5 * y + x];
        p.Red() = value;
        p.Green() = value;
        p.Blue() = value;
    }
    p = rowStart;
    p.OffsetY(cameraImageData, 1);
}

 // _dialogDrawingCanvas is a wxPaintDC*
_dialogDrawingCanvas->DrawBitmap(cameraImage, 50, 50);

EDIT I looked at wxImage based on the suggestion made by Thomas Matthews. Using wxImage works when I use testBuffer, but not when I use the actual buffer.

This works:

uint8_t testBuffer[] = 
{   
    250, 220, 222, 223, 210,
    186, 22, 29, 89, 110,
    250, 220, 222, 203, 210,
    240, 120, 220, 123, 210,
    230, 210, 252, 223, 210
};
wxImage image(5, 5, testBuffer, true);
wxBitmap bmp(image);
_dialogDrawingCanvas->DrawBitmap(bmp, 50, 50);

However, the code below does not. I get a crash in the wxBitmap ctor.

// Returns instance of a class that provides access to camera image.
CameraImage camImage = grabCameraImage(); 
uint8_t* buf = camImage.getBuffer();
wxImage image(camImage.getWidth(), camImage.getHeight(), buf, true);
wxBitmap bmp(image); // Crashes here.
_dialogDrawingCanvas->DrawBitmap(bmp, 50, 50);

The crash I get is:

First-chance exception at 0x000007fdcf824b5b in [redacted].exe: 0xC0000005: Access violation reading location 0x000000000304d27a. Unhandled exception at 0x000007fdcf824b5b in [redacted].exe: 0xC000041D: An unhandled exception was encountered during a user callback.

EDIT 2 I linked the wxWidgets DLL to its source code and traced into the call to the wxBitmap ctor. It looks like it's expecting at least 24BPP and starts reading at the end of the wxImage buffer and goes backwards so it's crashing as soon as it tries to access what it thinks is the last 3 bytes of the buffer. It looks like the depth argument to the wxBitmap constructor is ignored. I think maybe this wasn't an issue with testBuffer because it was a fixed size array.

Upvotes: 2

Views: 1470

Answers (1)

Alex Wade
Alex Wade

Reputation: 737

This is basically answered in my edits, but the problem was caused by using 8 BPP data in the buffer. I was able to accomplish what I wanted to do as follows:

CameraImage camImage = grabCameraImage(); 
wxImage image(camImage.getWidth(), camImage.getHeight());
const uint8_t* cameraBuffer = camImage.getBuffer();
for(uint16_t y = 0; y < camImage.getHeight(); ++y)
{
    for(uint16_t x = 0; x < camImage.getWidth(); ++x)
    {
        uint8_t intensity = cameraBuffer[y * camImage.getWidth() + x];
        image.SetRGB(x, y, intensity, intensity, intensity);
    }
}
wxBitmap bmp(image, 8);
_dialogDrawingCanvas->DrawBitmap(bmp, 50, 50);

Upvotes: 1

Related Questions