Massive inefficiency using QImage::scanLine()
-
Consider these nested loops operating on a non-const QImage:
for (int j = 0; j < height; j++) { QRgb* pOutPixel = reinterpret_cast<QRgb*>(m_Image->scanLine()); BitmapIteratorConst<std::shared_ptr<CMemoryBitmap>> it{ m_pBitmap }; it.Reset(0, j); for (int i = 0; i < width; i++, ++it, ++pOutPixel) { double fRed, fGreen, fBlue; it.GetPixel(fRed, fGreen, fBlue); *pOutPixel = qRgb(std::clamp(fRed, 0.0, 255.0), std::clamp(fGreen, 0.0, 255.0), std::clamp(fBlue, 0.0, 255.0)); } }
Sounds eminently sane doesn't it - problem is that each call to scanLine() does a deep copy of the QImage! So for an image with 3500 scanlines that's 3500 deep copies made!
Yack!
Yes I know how to get round it:
auto pImageData = m_Image->bits(); auto bytes_per_line = m_Image->bytesPerLine(); for (int j = 0; j < height; j++) { QRgb* pOutPixel = reinterpret_cast<QRgb*>(pImageData + (j * bytes_per_line));
-
@Perdrix QImage::scanLine() works as expected.
QImage::bits() does also a deep copy, but the difference is that in that case you get only once a deep copy.
If you need efficiency then do not modify the image in place, but instead create a new one where you put the modified data. -
I'm not modifying a Qimage (in the normal sense) - though of course I am doing so - I'm filling in a blank QImage I just created using new QImage(width, height).
I entirely accept that scanLine() is "working as designed"
I made my post mainly to alert people that using scanLine on a non-const QImage was not a good idea!
David
-
@Perdrix If you're not modifying then use https://doc.qt.io/qt-5/qimage.html#constScanLine instead...