13

I would like to draw icons (only one color) in different colors. To do so, I would like to import a single alpha-texture and then combine this with a given color in the application.

The result should be, that nothing is drawn on to the background, when the alpha-map has an opacity of 0 and the used color should be drawn, when the opacity is 1.

One soulution should be hidden somewhere in QPainter, since you can manually set the Composition-Mode (QPainter::setCompositionMode). But I don't get it to work like I want.

Does somebody have an idea?

Thanks in advance.

EDIT: Here is a little graphic explaining what I would like to do. I want to use a Alpha-Map like shown in the graphic and then use a color layer to create my icon. Important is, that the background stays transparent.

enter image description here

ruhig brauner
  • 943
  • 1
  • 13
  • 35
  • "I don't get it to work like I want." If you claim that you have code that doesn't work, you should post the code - in fact, you should post a self contained example that lets us compile it. – Kuba hasn't forgotten Monica Jul 25 '14 at 10:34

4 Answers4

14

You can do thos using QPainter like this:

QColor color;
// set color value

// load gray-scale image (an alpha map)
QPixmap pixmap = QPixmap(":/images/earth.png");

// initialize painter to draw on a pixmap and set composition mode
QPainter painter(&pixmap);
painter.setCompositionMode(QPainter::CompositionMode_SourceIn);

painter.setBrush(color);
painter.setPen(color);

painter.drawRect(pixmap.rect());

// Here is our new colored icon!
QIcon icon = QIcon(pixmap);

Here is gray-scale image and two colored icons which i get using the code above (QPixmap.save() method): icons

Arkady Dyakonov
  • 156
  • 1
  • 3
  • 2
    For some reason I had to replace the set brush, pen and drawRect lines with `painter.fillRect(pixmap.rect(), color)` (in python). Less code and works, so that is nice. I also have `painter.end()` but not sure if that is needed. – Rafe Jan 30 '18 at 23:07
2

The DestinationIn composition mode will do the trick.

  1. Draw the color layer using the default composition mode of SourceOver.

  2. Draw the alpha layer using the DestinationIn composition mode.

For example:

screenshot

// https://github.com/KubaO/stackoverflown/tree/master/questions/alpha-mask-24943711
#include <QtWidgets>

QImage icon(int size) {
   QImage image{size, size, QImage::Format_ARGB32_Premultiplied};
   image.fill(Qt::transparent);
   QPainter p(&image);
   p.setRenderHint(QPainter::Antialiasing);
   p.setPen(Qt::NoPen);
   p.translate(image.rect().center());
   p.scale(image.width()/2.2, image.height()/2.2);
   p.setBrush(Qt::white);
   p.drawEllipse(QRectF{-.5, -.5, 1., 1.});
   p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
   p.setBrush(Qt::transparent);
   p.drawEllipse(QRectF{-.3, -.3, .6, .6});
   for (auto angle : {0., 100., 150.}) {
      p.save();
      p.rotate(angle);
      p.drawRect(QRectF{-.1, 0, .2, -1.});
      p.restore();
   }
   return image;
}

QImage checkers(int size) {
   QImage img{size*2, size*2, QImage::Format_ARGB32_Premultiplied};
   QPainter p(&img);
   p.fillRect(0, 0, size, size, Qt::darkGray);
   p.fillRect(size, size, size, 2*size, Qt::darkGray);
   p.fillRect(size, 0, size, size, Qt::lightGray);
   p.fillRect(0, size, size, size, Qt::lightGray);
   return img;
}

void drawColorIcon(QPainter & p, QColor color, const QImage & alpha)
{
  p.save();
  p.setCompositionMode(QPainter::CompositionMode_SourceOver);
  p.fillRect(QRect{0, 0, alpha.width(), alpha.height()}, color);
  p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
  p.drawImage(0, 0, alpha);
  p.restore();
}

QImage drawColorIconProof(QColor color, const QImage & alpha) {
   QImage result{alpha.size(), alpha.format()};
   QPainter p(&result);
   drawColorIcon(p, color, alpha);
   p.setCompositionMode(QPainter::CompositionMode_DestinationAtop);
   p.fillRect(alpha.rect(), {checkers(10)});
   return result;
}

int main(int argc, char *argv[])
{
   QApplication app{argc, argv};
   QLabel label;
   label.setPixmap(QPixmap::fromImage(drawColorIconProof("orangered", icon(200))));
   label.show();
   return app.exec();
}
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
0

I found a solution. However, instead of using a transparent graphic for the alpha map like I've used in the first post, I had to use a black/white-graphic where black pixels are transparent and white pixels are not (=rendered).

// ++++ in constructor ++++ 
QImage alphaMap = QImage(fileName);

QColor color;

// ++++ in paint Event ++++

QPainter painter(this);
painter.setRenderHints(QPainter::RenderHint::Antialiasing);
painter.setRenderHints(QPainter::RenderHint::HighQualityAntialiasing);

// draw icon
QImage renderedIcon(alphaMap);  
// fill with color
renderedIcon.fill(color);                   
// set alpha-map, black pixels -> opacity of 0, white pixels -> opacity 1
renderedIcon.setAlphaChannel(alphaMap);     

painter.drawImage(this->rect(), renderedIcon);  // draw image to QWidget
ruhig brauner
  • 943
  • 1
  • 13
  • 35
  • Since `QWidget::rect()` always starts at 0,0, you can simply have `painter.drawImage(0, 0, renderedIcon)`. You also don't necessarily need a custom widget for this - you could pass a `QPixmap::fromQImage` to a label. Of course if you need to render many such icons, it certainly saves memory to have a custom widget do the job. – Kuba hasn't forgotten Monica Jul 25 '14 at 10:43
  • Hi, I also do some other stuff with the Icon like changing the color when hovering etc. Thats why I think a custom widget is usefule here. ;) Thanks for the hint with `rect()`. I didn't realy looked into the documentation and thought it also determins the size. ;D – ruhig brauner Jul 25 '14 at 10:54
-1

I do not quite understand the problem, but may be you can use QGraphicsColorizeEffect class? QGraphicsColorizeEffect

Krionix
  • 37
  • 3
  • Hi, I already thought that I didn't made a good job in explaining my problem. I will add a graphic which should help understanding me. :) I will try the QGraphicsColorizeEffect. – ruhig brauner Jul 25 '14 at 09:30