【问题标题】:Qt drawing icons using color and alpha-mapQt 使用颜色和 alpha-map 绘制图标
【发布时间】:2014-09-16 14:22:14
【问题描述】:

我想用不同的颜色绘制图标(只有一种颜色)。为此,我想导入单个 alpha 纹理,然后将其与应用程序中的给定颜色组合。

结果应该是,当 alpha 贴图的不透明度为 0 并且应绘制使用的颜色时,当不透明度为 1 时,不会在背景上绘制任何内容。

一个解决方案应该隐藏在QPainter 的某个地方,因为您可以手动设置合成模式 (QPainter::setCompositionMode)。但我没有让它像我想要的那样工作。

有人有想法吗?

提前致谢。

编辑:这是一个解释我想做的小图形。我想使用如图所示的 Alpha-Map,然后使用颜色层来创建我的图标。重要的是,背景保持透明。

【问题讨论】:

  • “我没有让它像我想要的那样工作。”如果您声称您的代码不起作用,您应该发布代码 - 事实上,您应该发布一个自包含的示例,让我们编译它。

标签: qt icons alpha qpainter


【解决方案1】:

你可以像这样使用 QPainter 来做这些:

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);

这是我使用上面的代码得到的灰度图像和两个彩色图标(QPixmap.save() 方法): icons

【讨论】:

  • 出于某种原因,我不得不用painter.fillRect(pixmap.rect(), color)(在python中)替换设置的画笔、钢笔和drawRect线。更少的代码和工作,这很好。我也有painter.end(),但不确定是否需要。
【解决方案2】:

DestinationIn 组合模式可以解决问题。

  1. 使用默认的合成模式SourceOver绘制颜色层。

  2. 使用DestinationIn合成模式绘制alpha层。

例如:

// 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();
}

【讨论】:

    【解决方案3】:

    我找到了解决方案。但是,我没有像我在第一篇文章中使用的那样为 alpha 贴图使用透明图形,而是必须使用黑色/白色图形,其中黑色像素是透明的,白色像素不透明(=渲染)。

    // ++++ 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
    

    【讨论】:

    • 由于 QWidget::rect() 总是从 0,0 开始,您可以简单地使用 painter.drawImage(0, 0, renderedIcon)。您也不一定需要自定义小部件 - 您可以将 QPixmap::fromQImage 传递给标签。当然,如果您需要渲染许多这样的图标,那么让自定义小部件完成这项工作肯定会节省内存。
    • 嗨,我还用图标做一些其他的事情,比如在悬停时改变颜色等。这就是为什么我认为自定义小部件在这里很有用。 ;) 感谢rect() 的提示。我并没有真正查看文档并认为它也决定了大小。 ;D
    【解决方案4】:

    我不太明白这个问题,但可能你可以使用 QGraphicsColorizeEffect 类? QGraphicsColorizeEffect

    【讨论】:

    • 嗨,我已经认为我没有很好地解释我的问题。我将添加一个应该有助于理解我的图形。 :) 我会试试 QGraphicsColorizeEffect。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-03
    相关资源
    最近更新 更多