How to make a QImage or QPixmap semi-transparent -

2019-04-28 04:36发布

问题:

4.7 and like to overlay two images on a qgraphicsview. The image on top shall be semi-transparent to allow to see through it. Initially both images are fully opaque. I expected some function for setting a global alpha-value for each pixel to exist, but it seems like there is no such function. The closest thing to it is QPixmap::setAlphaChannel(const QPixmap & alphaChannel), which, however, is marked as obsolete since Qt-4.6. Instead the manual refers to the CompositionModes of QPainter, but I don't succeed to add transparency to an opaque image like I want. Could anyone point me to a working example or share some code?

Edit: I'm almost sorry for having an own answer, now just a few hours after asking the question. From this article I figured out that the following code does the job. I just wonder if this is considered "better" (which often translates to faster) than modifying the alpha values pixelwise.

QPainter p; 
p.begin(image);
p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
p.fillRect(image->rect(), QColor(0, 0, 0, 120));
p.end();            
mpGraphicsView->scene()->addPixmap(QPixmap::fromImage(image->mirrored(false,true),0));  

回答1:

The Qt's composition demo can be a bit intimidating, because they try to show everything off. Hopefully the demo plus the QPainter documentation is helpful for you. You want to use CompositionMode::SourceOver and make sure that the images are converted to ARGB32 (premultiplied). From the documentation:

When the paint device is a QImage, the image format must be set to Format_ARGB32Premultiplied or Format_ARGB32 for the composition modes to have any effect. For performance the premultiplied version is the preferred format.



回答2:

Use your painter object and set the opacity.

void ClassName::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setOpacity(1.00);  //0.00 = 0%, 1.00 = 100% opacity.
    painter.drawPixmap(QPixmap(path));
}


回答3:

First of all, for internal operations on images, often you need to use QImage instead of QPixmap, as the direct access functionality to QPixmap is restricted. Reason is that QPixmaps are stored on the rendering device, e.g. pixmap on the X server or GL texture. On the other hand, going from QPixmap to QImage and back is expensive as it often results in copying from the graphics card memory to main memory and back.

As I see it you need an operation that changes only the alpha value of the pixels, leaving their original values intact, for blitting. One solution that is not elegant, but works, is the following:

for (int y = 0; y < image.height() ++y) {
  QRgb *row = (QRgb*)image.scanLine(y);
  for (int x = 0; x < image.width(); ++x) {
    ((unsigned char*)&row[x])[3] = alpha;
  }
}

Note: it is much faster to alter each pixel of the QImage, and then do painter.drawImage() than drawing each pixel with corresponding alpha by hand.