Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Tinting a QPixmap using QPainter (CompositionMode_Overlay)
Forum Updated to NodeBB v4.3 + New Features

Tinting a QPixmap using QPainter (CompositionMode_Overlay)

Scheduled Pinned Locked Moved Unsolved General and Desktop
qt5qtcreatorqpainterqpixmapqcolor
7 Posts 5 Posters 8.6k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • V Offline
    V Offline
    Votato
    wrote on last edited by Votato
    #1

    I'm having some issues tinting a QPixmap.

    My code is:

          image.load(imagePath); // load the image
          QPainter *paint = new QPainter(&image);
          paint->setCompositionMode(QPainter::CompositionMode_Overlay); // I want the box to blend into the image
          QRectF rectangle(0.0, 0.0, 45, 45); // the rectangle
          color.setAlpha(brightness); // I am setting the alpha so that the colour is actually visible
          paint->fillRect(rectangle, color); // this is the issue - it changes the alpha on the image, I want the alpha 255 pixels to be coloured in, not alpha 0.
          delete paint;
          color = colors;
          brightness = brightnessSlider;
          return image;
    

    This is my source image: http://i.imgur.com/ZkcYJfg.png
    This is the result: http://i.imgur.com/gPKbY9l.png (please ignore the size difference)

    The problem is that the source image has a transparent background (alpha 0), and my sprite, has pixels which are opaque (alpha 255). However, the overlay mode ignores this, and decides to tint all of my source image.
    The mode 'CompositionMode_Atop' sort of works, however it does not have the same desired effect as the Overlay mode.

    Ideally, I would like the result to have a transparent background, and also to be tinted using the Overlay mode.

    Thanks, VOT.

    1 Reply Last reply
    0
    • mrjjM Offline
      mrjjM Offline
      mrjj
      Lifetime Qt Champion
      wrote on last edited by
      #2

      @Votato said:
      Hi
      Maybe you have tried it, but i wonder if you could use the
      http://doc.qt.io/qt-4.8/qimage.html#createAlphaMask
      with painter setClipRegion
      so you only affect the area you want.
      Like here:
      http://stackoverflow.com/questions/7539257/how-to-use-a-mask-with-qpainter

      1 Reply Last reply
      0
      • Chris KawaC Offline
        Chris KawaC Offline
        Chris Kawa
        Lifetime Qt Champion
        wrote on last edited by
        #3

        You can do this in two steps:

        QPainter p;
        
        QImage img(imagePath);
        QImage mask(img);
        
        p.begin(&mask);
        p.setCompositionMode(QPainter::CompositionMode_SourceIn);
        p.fillRect(rect, color);
        p.end();
        
        p.begin(&img);
        p.setCompositionMode(QPainter::CompositionMode_Overlay);
        p.drawImage(0, 0, mask);
        p.end();
        
        return img;
        

        Btw. Don't create painters on the heap. Dynamic allocation is slower than stack values. It also requires lifetime management (delete) which makes your code unnecessary complex.

        1 Reply Last reply
        2
        • D Offline
          D Offline
          dethtoll
          wrote on last edited by
          #4

          This is an old thread, but still comes up in related Google searches.

          Chris Kawa's answer is fine for most cases, but doesn't work if the tint color itself has alpha (eg. if you want to make the original image more transparent). It's bananas to me that Qt doesn't have a composition mode that multiplies the alpha channels together.

          Given that, the simplest and most efficient approach is probably to multiply the pixel colors manually using a QImage (QPixmap can be converted to/from a QImage).

          Here's the code for my approach:

          ////////////////////////////////////////////////////////////////////////////////
          // Multiplies all pixels in the given image by the specified color
          //	- Alpha channel is also multiplied
          //	- The images format is converted if it is not Format_ARGB32 or Format_ARGB32_Premultiplied
          //		- FUTURE: Support additional format types without conversion if needed
          void TintImage(QImage& inoutImage, const QColor& tintColor)
          {
          	if (tintColor == Qt::white)
          		return;
          
          	// Convert to 4-channel 32-bit format if needed
          	auto format = inoutImage.format();
          	if (format != QImage::Format_ARGB32 && format != QImage::Format_ARGB32_Premultiplied)
          	{
          		format = QImage::Format_ARGB32_Premultiplied;
          		inoutImage = inoutImage.convertToFormat(format);
          	}
          
          	const bool isPremultiplied = (format == QImage::Format_ARGB32_Premultiplied);
          	const auto tint = tintColor.rgba();
          
          	// Convert scanline by scanline (a bit tricker than using setPixelColor, but much more efficient)
          	const int sizeX = inoutImage.width();
          	const int sizeY = inoutImage.height();
          	for (int y = 0; y < sizeY; ++y)
          	{
          		// Note: Qt documentation explicitly recommends this cast for 32-bit images
          		auto* scanline = (QRgb*)inoutImage.scanLine(y);
          		for (int x = 0; x < sizeX; ++x)
          		{
          			auto color = scanline[x];
          			if (isPremultiplied)
          				color = qUnpremultiply(color);
          
          			color = qRgba(
          				(qRed(color) * qRed(tint)) / 255
          				, (qGreen(color) * qGreen(tint)) / 255
          				, (qBlue(color) * qBlue(tint)) / 255
          				, (qAlpha(color) * qAlpha(tint)) / 255
          			);
          
          			if (isPremultiplied)
          				color = qPremultiply(color);
          
          			scanline[x] = color;
          		}
          	}
          }
          
          1 Reply Last reply
          1
          • Chris KawaC Offline
            Chris KawaC Offline
            Chris Kawa
            Lifetime Qt Champion
            wrote on last edited by Chris Kawa
            #5

            It's bananas to me that Qt doesn't have a composition mode that multiplies the alpha channels together.

            Of course it does. At least couple of modes do that. But they do it in a more sensible way.

            Multiplying values channel wise is a very weird operation when you talk about colors and I haven't seen it in any graphics API. You could argue that multiplying alphas has some sense in some situations, but color channels? To put it simply: what does "red times red" mean? That's the bananas. You might be getting something that you like by accident but it has little sense computationally. In most common composition modes you mix color channels with alpha values in one form or another.

            eg. if you want to make the original image more transparent)

            If you want to apply source alpha to the destination you would multiply the source alpha channel with the destination color channels, not its alpha channel alone. That's what for example QPainter::CompositionMode_DestinationIn mode does.

            1 Reply Last reply
            2
            • M Offline
              M Offline
              Matt Chaput
              wrote on last edited by
              #6

              It seems odd for a moderator to be so belligerent, and act so condescending when they don't even seem to understand the issue.

              Overlay mode would be useful for tinting e.g. icons with color, except it writes over transparent areas. To be useful, it should multiply the alpha of the source and destination. There's nothing sensible about Qt is doing.

              Geez.

              Chris KawaC 1 Reply Last reply
              0
              • M Matt Chaput

                It seems odd for a moderator to be so belligerent, and act so condescending when they don't even seem to understand the issue.

                Overlay mode would be useful for tinting e.g. icons with color, except it writes over transparent areas. To be useful, it should multiply the alpha of the source and destination. There's nothing sensible about Qt is doing.

                Geez.

                Chris KawaC Offline
                Chris KawaC Offline
                Chris Kawa
                Lifetime Qt Champion
                wrote on last edited by
                #7

                @Matt-Chaput said:

                It seems odd for a moderator to be so belligerent, and act so condescending

                I'm sorry you feel that way but there's nothing I can do about it. I did try to provide a solution and explain why the other one was incorrect mathematically.

                Overlay mode would be useful for tinting e.g. icons with color, except it writes over transparent areas.

                That shortcoming of overlay mode is exactly the reason I suggested a two step approach instead. It breaks the problem into an alpha step and a color step.

                To be useful, it should multiply the alpha of the source and destination.

                If you wanted to do it in one step, yes. But, since there's no such mode in Qt, you can use the two step approach I suggested.

                composition mode

                First is the original.
                Second is the mask created using the alpha of the source (CompositionMode_SourceIn).
                Third is the final result using overlay with the mask (CompositionMode_Overlay).

                As far as I can tell this is the result OP wanted, so can you explain what I got wrong?

                There's nothing sensible about Qt is doing.

                Qt is providing a pretty common set of composition modes implemented by various APIs, described e.g. here, here and here. If you know of a graphics API that does SourceIn+Overlay in one step could you point us to it?

                1 Reply Last reply
                5

                • Login

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • Users
                • Groups
                • Search
                • Get Qt Extensions
                • Unsolved