PDA

View Full Version : QImage from uchar buffer



StarShaper
20th February 2012, 17:51
I'm trying to create a QImage from a buffer, but it doesn't work. If I use setPixel() it works, but if I use a uchar buffer, the Image won't be drawn.

Any idea why?


int imwidth = 4;
int imheight = 16;

uchar BUF[] = {
255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0,
255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0,
255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0,
255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0,
255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0,
255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0,
255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0,
255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0,
255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0,
255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0,
255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0,
255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0,
255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0,
255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0,
255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0,
255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0
};


QImage qi(BUF, imwidth, imheight, QImage::Format_ARGB32); // doesn't work
QRect s(0, 0, imwidth, imheight);
painter->drawImage(s, qi, s, Qt::AutoColor);

http://developer.qt.nokia.com/doc/qt-4.8/qimage.html

mvuori
20th February 2012, 20:21
First, you need to figure out whether the image it is a) not drawn or b) not created properly... I'd suggest the latter, as you have 16 x 16 bytes in your buffer, but you need 16 x 16 x 4 bytes...

StarShaper
20th February 2012, 22:51
I'd suggest the latter, as you have 16 x 16 bytes in your buffer, but you need 16 x 16 x 4 bytes...

The buffer is 256 bytes long, because it is a 4x16 pixel image!

Never mind, I solved the problem.

The image was drawn, but I couldn't see it, because the Alpha channel was at full transparency (0).

It's a little bit weird, because the documentation says QImage::Format_ARGB32 is represented as 0xAARRGGBB.

But in memory the uchar has to be in reverse order. That means, the first 4 bytes are actually BB, GG, RR, AA and not AA, RR, GG, BB as I thought.

ChrisW67
20th February 2012, 23:25
The behaviour is not weird: the documented 0xAARRGGBB describes a 32-bit unsigned int. Ints have a platform-dependent byte order (usually liitle-endian). You can do this:


quint32 BUF[] = {
0xffff0000, 0xffff0000, 0xffff0000, 0xffff0000,
...
// or this
qRgb(255, 0, 0), qRgb(255, 0, 0), qRgb(255, 0, 0), qRgb(255, 0, 0),
...
};

QImage qi(reinterpret_cast<unsigned char*>(BUF), imwidth, imheight, QImage::Format_ARGB32);

and let the compiler or Qt worry about byte ordering.

StarShaper
21st February 2012, 00:32
The behaviour is not weird: the documented 0xAARRGGBB describes a 32-bit unsigned int. Ints have a platform-dependent byte order (usually liitle-endian).

I always thought that ints are stored big-endian on most systems. Now it seems logical...


Although the ubiquitous x86 of today use little-endian storage for all types of data (integer, floating point, BCD), there have been...

http://en.wikipedia.org/wiki/Endianness

Unfortunately I can't allocate the buffer as quint32. It has to be uchar.

ChrisW67
21st February 2012, 05:00
Unfortunately I can't allocate the buffer as quint32. It has to be uchar.
Works fine for me in the example I posted. You have to pass a pointer to uchar, hence the reinterpret_cast, but the buffer can be structured as int (with care). Doing this should also ensure that the data buffer meets the 32-bit aligned requirement.

Edit: As an aside the only big-endian CPUs I have worked with directly are the Motorola 68000 and GEC 4000 series.

StarShaper
21st February 2012, 09:05
Works fine for me in the example I posted. You have to pass a pointer to uchar, hence the reinterpret_cast, but the buffer can be structured as int (with care). Doing this should also ensure that the data buffer meets the 32-bit aligned requirement.

You misunderstood me. I know what you are doing with reinterpret_cast(uchar*). I meant that I can't allocate the buffer as quint32, because I already got the buffer as uchar.

This is the correct buffer.


// Image (ARGB) with 4x16 pixel and with a length of 256 bytes, full red and 0 % (255) transparency.
// Little-endian byte order with Blue, Green, Red, Alpha, ...
//uint8_t BUF[] = {
// 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255,
// 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255,
// 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255,
// 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255,
// 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255,
// 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255,
// 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255,
// 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255,
// 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255,
// 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255,
// 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255,
// 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255,
// 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255,
// 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255,
// 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255
//};