How not to lose the alpha channel when converting between QRgb/QColor/QString
Working on color imagery for QiTissue recently, I realized we were accidentally losing the alpha channel in multiple places. For efficiency reasons, we keep colors in memory using the QRgb
type, and convert that to/from QString
for serialization purposes via QColor
as needed. Here’s what I discovered about why that doesn’t work, and some ways I fixed it.
Firstly, be aware there is no QRgba
in the Qt API . There is only QRgb
, for 8bit color channels. It can hold an alpha value too, despite the lack of a trailing a
in the type name. Then there is QRgba64
which uses 16bit per color channel. For our purposes, 8bit per channel is sufficient. So where do we lose the alpha channel, when QRgb
can store it in principle?
The first pitfall is QColor(QRgb)
, which calls QColor::fromRgb
internally. Both of these functions silently ignore the alpha channel of the passed QRgb
value and assume the color is fully opaque. To get around this, you have to use QColor::fromRgba
instead.
QColor toColor(QRgb colorWithAlpha)
{
// all bad: input alpha ignored, set to fully opaque
return QColor(colorWithAlpha);
return colorWithAlpha;
return QColor::fromRgb(colorWithAlpha);
// good:
return QColor::fromRgba(colorWithAlpha);
}
Then you’ll find that QColor::name()
also ignores the alpha channel. Here, you have to use QColor::name(QColor::HexArgb)
instead.
QString toString(const QColor &colorWithAlpha)
{
// bad: input alpha ignored, output is e.g. #112233
return colorWithAlpha.name();
// good: output is e.g. #00112233
return colorWithAlpha.name(QColor::HexArgb);
}
Thankfully, the QColor
constructors and QColor::setName
function, which parse a string color name, won’t ignore the alpha channel when you pass an ‘#AARRGGBB’ string.
However, there is one more pitfall: When you have a QColorDialog
with QColorDialog::ShowAlphaChannel
, and listen to its currentColorChanged
signal and set a color with an alpha channel on it, a stray change signal notification will be emitted with a fully opaque color. The reason is that, internally, the color dialog will first set the RGB color components, and then in a second step will set the alpha component. But both will trigger a change notification, where the first step holds a fully opaque color. This should be fixed upstream, but thankfully for now it is easy to workaround by ignoring the signal while setting a color from the outside.
If you like this article and want to read similar material, consider subscribing via our RSS feed.
Subscribe to KDAB TV for similar informative short video content.
KDAB provides market leading software consulting and development services and training in Qt, C++ and 3D/OpenGL. Contact us.