QImage \ QPixmal loses alpha color when drawing



  • Qt 5.7, Clang, OSX

    I have png image with QImage::Format_ARGB32 filled with color ARGB(0, 255, 255, 255).

    When I draw the image to another image with same format, color of alpha pixels loses. All ARGB(0, 255, 255, 255) pixels converts to ARGB(0, 0, 0, 0).

    Following code loses color of alpha-pixels:

    QImage sourceImage("image.png");
    QImage destImage(sourceImage.width(), sourceImage.height(), sourceImage.format());
    QPainter painter(&destImage);
    
    painter.setCompositionMode(QPainter::CompositionMode_Source);
    painter.drawImage(0, 0, sourceImage);
    painter.end();
    

    Scaling image loses color of alpha-pixels too:

    QImage destImage = sourceImage:scaled(sourceImage.width() / 2, sourceImage.height() / 2);
    

    But following code save pixels color:

    QImage sourceImage("image.png");
    QImage destImage(sourceImage.width(), sourceImage.height(), sourceImage.format());
    for(int x = 0; x < sourceImage.width(); x++)
    {
    	for(int y = 0; y < sourceImage.height(); y++)
    	{
    		destImage.setPixelColor(x, y, sourceImage.pixelColor(x, y));
    	}
    }
    

    So, it's synthetic example. In real task I have image with white text rendering in OpenGL application. In that case I get black pixels artifacts around my white text because GL can mix color of pixel with neighbor pixels.

    Summary:
    I need two things: smooth scale image and draw it to another image without losing rgb color of transparent pixels.



  • This post is deleted!

  • Qt Champions 2016

    Works normally on my machine (Debian). Here's the code I used:

    #include <QApplication>
    #include <QPainter>
    #include <QImage>
    #include <QTimer>
    #include <QLabel>
    
    int main(int argc, char ** argv)
    {
        QApplication app(argc, argv);
    
        QLabel view;
        QTimer::singleShot(0, [&view] () -> void  {
            QImage sourceImage("butterfly2.png");
            QImage destImage(sourceImage.width(), sourceImage.height(), sourceImage.format());
    
            QPainter painter(&destImage);
            painter.fillRect(destImage.rect(), Qt::magenta);
    
            painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
            painter.drawImage(0, 0, sourceImage);
    
            view.setPixmap(QPixmap::fromImage(destImage));
            view.show();
        });
    
        return QApplication::exec();
    }
    

    I also fetched this image for my test run. (QPainter::CompositionMode_Source also works as expected for me)



  • Thank your for answer, but I means different case.

    Please try this image. Just load it to QImage and draw to another QImage with same format(ARGB32). Next, render it without blending. (Best way is render it using OpenGL with glDisable(GL_BLEND) ).

    This is correct result
    White butterfly on white background. Pixels of transparent area of source image were white but with zero alpha and after splitting alpha channel pixels become opaque white. It's correct.

    This is incorrect result
    White butterfly on black background. Pixels of transparent area of source image were white with zero alpha channel. But after QPainter::drawImage pixels become black with zero alpha channel. So, after splitting alpha channel pixels become opaque black. It's incorrect.



  • Hi,
    Image-drawing and also scaling is always done by some kind of alpha-blending, so if you use full transparent pixels in drawing they will always end in qRgba(0,0,0,0).

    What you can do:
    If you need a copy of the source.image, use image.copy() instead of drawing the src-image into a new one of the same size and format,

    If you need to scale such an image you have to invert the pixels before and after the scaling. The scaled Image will be in QImage::Format_ARGB32_Premultiplied, so it has to be converted to QImage::Format_ARGB32.
    If you want to draw such an Image into an exsiting image both, the src and the destination image, needs to be in QImage::Format_ARGB32 and both needs to be inverted.
    Example for scaling:

    QImage sourceImage("butterfly3.png");
    QImage destImage;
    sourceImage.invertPixels(QImage::InvertRgba);
    destImage = sourceImage.scaled(sourceImage.width()/2, sourceImage.height()/2, Qt::IgnoreAspectRatio, Qt::SmoothTransformation).convertToFormat(QImage::Format_ARGB32);
    
    sourceImage.invertPixels(QImage::InvertRgba);
    destImage.invertPixels(QImage::InvertRgba);
    destImage.save("out.png", "PNG");
    
    

    Hope that helps
    Regards
    Gerd



  • Hi, thank you for answer, but it work only for white images. Now drawing loses color of full opaque pixels instead of transparent pixels (I.e. all image areas with opaque pixels become white)


  • Qt Champions 2016

    @Pisyandry said in QImage \ QPixmal loses alpha color when drawing:

    Please try this image. Just load it to QImage and draw to another QImage with same format(ARGB32). Next, render it without blending. (Best way is render it using OpenGL with glDisable(GL_BLEND) ).

    This is what I do in my example. One image is drawn to another and is then rendered to the screen. With the suggested image I still get correct behavior.

    Best way is render it using OpenGL with glDisable(GL_BLEND)

    I don't understand what raw GL calls are doing here, or how they relate to the issue at all.

    White butterfly on black background. Pixels of transparent area of source image were white with zero alpha channel. But after QPainter::drawImage pixels become black with zero alpha channel.

    ???!?

    So, after splitting alpha channel pixels become opaque black. It's incorrect.

    What is this splitting you're talking about, I don't get what you're trying to accomplish and I don't understand how are you obtaining these images.



  • Hi,
    according to your description and your example i thought you where talking about black/white images.
    However, even if i think it's not a good idea to deal with "the color of transparent pixels" you can try this:

    QImage sourceImage("butterfly3.png");
    QImage destImage;
    destImage = sourceImage.scaled(sourceImage.width()/2, sourceImage.height()/2, Qt::IgnoreAspectRatio, Qt::SmoothTransformation).convertToFormat(QImage::Format_ARGB32);
    quint32 *dst = (quint32*)destImage.bits();
    for (int i = 0; i < destImage.byteCount() / 4; i++, dst++)
       if (*dst == 0x00000000)
          *dst = 0x00ffffff;
    destImage.save("out.png", "PNG");
    
    

    Regards
    Gerd


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.