QImage data alignment

1.7k views Asked by At

The documentation of

QImage::QImage(uchar *data, int width, int height, Format format, QImageCleanupFunction cleanupFunction = Q_NULLPTR, void *cleanupInfo = Q_NULLPTR)

describes that the data, refered by parameter 'data', must be 32 bit aligned. http://doc.qt.io/qt-5/qimage.html#QImage-3 But it's at least unclear what is meant exactly. I assume, each pixel takes 32 bits. But that is not the case. Constructing an image like this is working:

uint8_t* rgb = new uint8_t[3 * height * width];
QImage Img(rgb, width, height, QImage::Format_RGB888);

But this is confusing. When I want to get the pixel values from the image, I thought I need to do this (since the data is 32 bit aligned and Qrgb is 32 bit):

QRgb*rawPixelData = (QRgb*) Img.bits();
for(uint32_t i = 0; i < (Img.width * Img.height); ++i)
{
  qDebug() << "Red" << qRed(rawPixelData[i]);
  qDebug() << "Green" << qGreen(rawPixelData[i]);
  qDebug() << "Blue" << qBlue(rawPixelData[i]);
}

But this is not working (leads to a crash). So, I assume, the data is not 32bit aligned. So, isn't the data 32 bit aligned, or I'm understanding something wrong?

2

There are 2 answers

0
dtech On BEST ANSWER

I assume that by the "data" they mean the array of bytes used. And by alignment they mean that the first byte of the array would be 32bit aligned and thus data % 4 would always be 0. It is not the internal alignment of every pixel, just the alignment of the memory block that contains the pixel data.

Furthermore, bits() returns a pointer to an unsigned byte, not a pointer to a QRgb. A QRgb is essentially just an integer:

typedef unsigned int QRgb;   

I suspect you are getting a crash because the raw data is "compacted". Meaning that if your image has only RGB and no alpha, it will use only 24bits or 3 bytes per pixel, because that would eliminate a 25% memory usage overhead. As a result, you are walking off the actual data and getting a crash.

You should try iterating it as w * h * 3 unsigned chars and incrementing by 3 for each next pixel, and your rgb would be respectively the bytes at i, i+1, i+2.

It could probably work if your image format was RGBA.

And indeed if you bother to check the byteCount you'd realize that the amount of bytes used internally are the minimum amount for a given format:

  QImage img(100, 100, QImage::Format_RGB888);
  qDebug() << img.byteCount(); // 30000 or 3 bytes or 24 bits

  QImage img2(100, 100, QImage::Format_RGB555);
  qDebug() << img2.byteCount(); // 20000 or 2 bytes or 15 bits

  QImage img3(100, 100, QImage::Format_RGBA8888);
  qDebug() << img3.byteCount(); // 40000 or 4 bytes or 32 bits
0
Kuba hasn't forgotten Monica On

But it's at least unclear what is meant exactly.

The expression is part of the software engineering vernacular and has nothing to do with the specific situation at hand: it doesn't have anything to do with Qt nor images nor pixels.

On platforms where Qt is supported, it has the following strict meaning:

uchar *data = ...;
Q_ASSERT(reinterpret_cast<uintptr_t>(data) & 3 == 0);

Or, on an arbitrary C++17 platform, it has the following strict meaning:

size_t size = ...;
uchar *data = ...;
Q_ASSERT(std::align(4, size, reinterpret_cast<void*&>(data), size) ==
         reinterpret_cast<void*>(data));