When I try to create a ARGB32 QImage from a reinterpret_cast<uchar*>(quint32*)
using the QImage constructor the Image looses its color and alpha channel and the resulting QImage is grayscale!
The grayscale image is displayed as expected, if I was trying to display it in grayscale. So I know the scaling and indexing of ushort data to the quint32 array went well, but what is going wrong?
A Qt forum post suggested to do it the way I am doing it (as far as I can see), but maybe behavior has changed since that version of Qt? (I am Using Qt 5.9)
I realise that the documentation says:
data must be 32-bit aligned, and each scanline of data in the image must also be 32-bit aligned.
But I would expect quint32 to be 32-bit aligned even after reinterpret_cast<uchar*>()
?
Now the details: I am converting the results of a calculation (an array with unsigned short values) to a semi-transparent blue-to-green-to-red image like this:
inline uchar val_to_blue(const double val) {
if (val > 0.5)
return 0;
else if (val < 0.25)
return 255;
else // x={.5,...,.25}:a=255/(.25-.5)=-4*255 & b=-255*0.5/(0.25-0.5)=4/2*255=2*255
return (uchar)(val * -4.0 * 255.0) + 2 * 255;
}
inline uchar val_to_green(const double val) {
if (val > 0.25 && val < 0.75)
return 255;
else if (val < 0.25)// x={0,...,.25}:a=255/(.25-0)=4*255 & b=-255*0/(0.25-0)=0
return (uchar)(val * 4.0 * 255.0);
else // if (val > .75) // x={.75,...,1}:a=255/(.75-.5)=4*255 & b=-255*0.5/(0.75-0.5)=-4/2*255=-2*255
return (uchar)(val * -4.0 * 255.0) - 2 * 255;
}
inline uchar val_to_red(const double val) {
if (val < 0.5)
return 0;
if (val > 0.75)
return 255;
else // x={0.5,...,0.75}:a=255/(0.75-0.5)=4*255 & b=-255*0.5/(0.75-0.5)=-4/2*255=-2*255
return (uchar)(val * 4.0 * 255.0) - 2 * 255;
}
inline QRgb val_to_rgba_scale(const double val) {
return qRgba( // ax+b={0,...,255} for x={i,...,j}, a=255/(j-i), b= -255i/(j-i)
val_to_blue(val),
val_to_green(val),
val_to_red(val),
(uchar)(val * 81)
);
}
Where val
is a double between 0 and 1 scaled from the ushort data.
Each QRgb
value is stored at the corresponding index of a quint32
array, like this:
if (m_pData[i*m_iWidth + j] >= uppVal)
tmpData[tmpIdx] = 0x45ff0000;
else if (m_pData[i*m_iWidth + j] <= lowVal)
tmpData[tmpIdx] = 0x00000000;
else
tmpData[tmpIdx] = val_to_rgba_scale((m_pData[i*m_iWidth + j] - lowVal) / (double)winWidth);
Where (m_pData[i*m_iWidth + j] - lowVal) / (double)winWidth
is the ushort-to-double scaling method.
This is done in a for loop.
Finally I attempt to construct the image with:
QImage tmpQImage = QImage(reinterpret_cast<unsigned char*>(tmpData), m_iWidth, m_iHeight, QImage::Format_ARGB32);
But this doesn't work as I expect, because tmpQImage.allGray()
returns true when called immediately after!
What am I doing wrong, and what should I do instead to create a ARGB image and keep both the colors and alpha channel?