FatalCatharsis
FatalCatharsis

Reputation: 3577

QImage::pixel() not returning transparency properly

Here is what i'm trying to do. I have an .svg image that I made to have a transparent background and is otherwise completely white. I wish to render the image to a QImage and then I want to adjust the hue of the image so that I can change the color to match the interface at any time, and then I will adjust the saturation and value whenever it is moused over or clicked on. I have successfully rendered the image to a QImage like so:

QSvgRenderer renderer(TAG_DELETE_ICON_PATH);
m_TagDeleteImage = QImage(m_Metric.height(), m_Metric.height(), QImage::Format_ARGB32);
m_TagDeleteImage.fill(0x00000000);

QPainter painter(&m_TagDeleteImage);
painter.setRenderHint(QPainter::Antialiasing);
renderer.render(&painter);

where m_TagDeleteImage is a QImage, TAG_DELETE_ICON_PATH is a valid path to the icon, and m_Metric is a font metric to a valid font. Yes the height and width are both supposed to be the height of the font. This all happens in the constructor, and is then drawn to the widget in the paint function. If I leave it at this, the white image with proper transparency is drawn without issue. Now I just need to change the hue, value, and saturation of the image. The documentation seemed pretty thorough, (although apparently missing some key details), and so I try to adjust each pixel in the image like so:

QSvgRenderer renderer(TAG_DELETE_ICON_PATH);
m_TagDeleteImage = QImage(m_Metric.height(), m_Metric.height(), QImage::Format_ARGB32);
m_TagDeleteImage.fill(0x00000000);

QPainter painter(&m_TagDeleteImage);
painter.setRenderHint(QPainter::Antialiasing);
renderer.render(&painter);

for(int x = 0; x < m_TagDeleteImage.width(); x++)
{
    for(int y = 0; y < m_TagDeleteImage.height(); y++)
    {
        QColor current(m_TagDeleteImage.pixel(x, y));
        QRgb newPixel = qRgba(TAG_DELETE_ICON_COLOR.red(), TAG_DELETE_ICON_COLOR.green(),
                              TAG_DELETE_ICON_COLOR.blue(), current.alpha());

        m_TagDeleteImage.setPixel(x, y, newPixel);
    }
}

where TAG_DELETE_ICON_COLOR is a valid QColor already set to the hsv I want. Right now it's white against the blue background of another widget so it's very visible. When I did these, even though you see that I tried to retain the current alpha value and only change the value, all I get is a completely white square where my image originally was, alpha apparently being completely ignored. Since it is a fairly small QImage, like 16 x 16, I decided to print the value of each pixel like this:

for(int x = 0; x < m_TagDeleteImage.width(); x++)
{
    for(int y = 0; y < m_TagDeleteImage.height(); y++)
    {
        QColor current(m_TagDeleteImage.pixel(x, y));
        qDebug() << "pixel: " << (m_TagDeleteImage.width() * x) + y << " "
                 << current.red() << " " << current.green() << " "
                 << current.blue() << " " << current.alpha();
    }
}

and it definately showed that all pixels in the image were completely white and completely opaque , (255, 255, 255, 255). Just to make sure that I was getting the current pixel correctly, I performed the same print statement, but immediately after I cleared the image like so:

QSvgRenderer renderer(TAG_DELETE_ICON_PATH);
m_TagDeleteImage = QImage(m_Metric.height(), m_Metric.height(), QImage::Format_ARGB32);
m_TagDeleteImage.fill(0x00000000);

for(int x = 0; x < m_TagDeleteImage.width(); x++)
{
    for(int y = 0; y < m_TagDeleteImage.height(); y++)
    {
        QColor current(m_TagDeleteImage.pixel(x, y));
        qDebug() << "pixel: " << (m_TagDeleteImage.width() * x) + y << " "
                 << current.red() << " " << current.green() << " "
                 << current.blue() << " " << current.alpha();
    }
}

and then I discovered the issue. Even though all the pixels are supposed to be completely transparent at this point (rgba 0, 0, 0, 0), every pixel is reporting back (rgba 0, 0, 0, 255). The image format is set to QImage::Format_ARGB32 so it should definitely respect the alpha channel. I've verified that m_TagDeleteImage.hasAlphaChannel() does return true. So can anyone tell what is going on?

I will pastebin if you need more code.

EDIT: Changed the line:

m_TagDeleteImage.fill(0x0000000);

to

m_TagDeleteImage.fill(QColor(0, 0, 0, 0));

No change.

Upvotes: 0

Views: 722

Answers (1)

FatalCatharsis
FatalCatharsis

Reputation: 3577

Alright, I fiddled with some more random functions across Qt and reading through piles of documentation, I found a little relevant tidbit in the QColor documentation page for the QColor::QColor( QRgb color) constructor:

'Constructs a color with the value color. The alpha component is ignored and set to solid.'

Why it does this, I don't know. Revised the code to just stick to QRgb and its helper function and it works fine.

QSvgRenderer renderer(TAG_DELETE_ICON_PATH);
m_TagDeleteImage = QImage(m_Metric.height(), m_Metric.height(), QImage::Format_ARGB32);
m_TagDeleteImage.fill(QColor(0, 0, 0, 0));

QPainter painter(&m_TagDeleteImage);
painter.setRenderHint(QPainter::Antialiasing);
renderer.render(&painter);

for(int x = 0; x < m_TagDeleteImage.width(); x++)
{
    for(int y = 0; y < m_TagDeleteImage.height(); y++)
    {
        QRgb current = m_TagDeleteImage.pixel(x, y);
        QRgb newPixel = qRgba(TAG_DELETE_ICON_COLOR.red(), TAG_DELETE_ICON_COLOR.green(),
                              TAG_DELETE_ICON_COLOR.blue(), qAlpha(current));

        m_TagDeleteImage.setPixel(x, y, newPixel);
    }
}

Upvotes: 3

Related Questions