Search code examples
qtalignmentqimage

QImage data alignment


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?


Solution

  • 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