合并两个 QPixmap 的问题

Issues with combining two QPixmaps

我正在开发类似画家的应用程序。这个想法是有两个像素图。第一个包含用户上传的原始图像,第二个包含所有绘图并具有透明背景。要显示结果 pixmaps 将被组合并显示在 QLabel 中。 是这样完成的:

  1. 正在上传图像并创建相同大小的透明像素图

        void ImageViewer::on_openAct_triggered()
        {
                QString fileName = QFileDialog::getOpenFileName(this,
                                                 tr("Open File"), QDir::currentPath());
                if (!fileName.isEmpty()) {
                     QImage image(fileName);
                     if (image.isNull()) {
                         QMessageBox::information(this, tr("Image Viewer"),
                                                  tr("Cannot load %1.").arg(fileName));
                         return;
                     }
                     imageLabel->setPixmap(QPixmap::fromImage(image));
                     scaleFactor = 1.0;
    
                     objectpix.scaled(QSize(imageLabel->size()), Qt::KeepAspectRatio, Qt::FastTransformation);
                     objectpix.fill(Qt::transparent);
    
                    /.../
                }
    
        }
    
  2. 获取鼠标坐标,在第二个像素图上绘制并合并第一个和第二个

           mFirstX =  e->x()/scaleFactor+ scrollArea->horizontalScrollBar()->value()/scaleFactor;
           mFirstY = (e->y() - 31)/scaleFactor+ scrollArea->verticalScrollBar()->value()/scaleFactor;
    
       /.../
    
    
        QPainter paint(&objectpix);
    
        QPen PointPen (Qt::red);
        PointPen.setWidth(5);
        QBrush PointBrush (Qt::red,Qt::SolidPattern);
    
        QPoint p1 = QPoint(mFirstX,mFirstY);
    
        paint.setPen(PointPen);
        paint.setBrush(PointBrush);
        paint.drawEllipse(p1,2,2);
    
        QPixmap p(*imageLabel->pixmap());
        QPainter painter(&p);
        painter.drawPixmap(imageLabel->rect(),objectpix,objectpix.rect());\
        painter.end();
        imageLabel->setPixmap(p);
    

但是没有那样显示。如果我只显示第二个像素图(包含所有绘图并具有透明背景),它只显示透明像素图,即我看到我的应用程序的背景。我究竟做错了什么?感谢任何帮助。

您必须先在 objectpix 上完成绘图,然后才能与其他画家一起使用。绘制椭圆后调用paint.end()。在您销毁画家或使用 end().

明确完成绘画之前,不会修改像素图

不知何故,我感觉 OP 描述的实际上应该是可能的...

...并自行尝试。

这是我得到的 (testQPixmapCombine.cc):

#include <QtWidgets>

class Label: public QLabel {

  private:
    QPixmap _qPixmap;

  public:
    Label(QWidget *pQParent = nullptr):
      QLabel(pQParent)
    { }

    virtual ~Label() = default;

    Label(const Label&) = delete;
    Label& operator=(const Label&) = delete;

    void setPixmap(const QPixmap &qPixmap)
    {
      _qPixmap = qPixmap;
      QLabel::setPixmap(_qPixmap = qPixmap);
    }

  protected:

    virtual void mousePressEvent(QMouseEvent *pQEvent) override;
};

void Label::mousePressEvent(QMouseEvent *pQEvent)
{
  // clear overlay
  QPixmap qPixmapDraw(_qPixmap.size());
  qPixmapDraw.fill(QColor(0, 0, 0, 0));
  // draw red circle at mouse coordinates
  { QPainter qPainter(&qPixmapDraw);
    qPainter.setPen(QPen(Qt::red, 2));
    qPainter.drawEllipse(pQEvent->pos(), 20, 20);
  }
  // combine pixmaps
  QPixmap qPixmapComp = _qPixmap;
  { QPainter qPainter(&qPixmapComp);
    qPainter.drawPixmap(0, 0, qPixmapDraw);
  }
  QLabel::setPixmap(qPixmapComp);
  pQEvent->accept();
}

int main(int argc, char **argv)
{
  qDebug() << "Qt Version:" << QT_VERSION_STR;
  QApplication app(argc, argv);
  // load image file
  const QImage qImg("cat.png");
  QPixmap qPixmap;
  qPixmap.convertFromImage(qImg);
  // setup UI
  Label qWin;
  qWin.setWindowTitle(QString::fromUtf8("Combine Pixmaps"));
  qWin.setPixmap(qPixmap);
  qWin.show();
  // runtime loop
  return app.exec();
}

以及对应的Qt项目(testQPixmapCombine.pro):

SOURCES = testQPixmapCombine.cc

QT += widgets

我在cygwin64编译测试:

$ qmake-qt5 testQPixmapCombine.pro

$ make && ./testQPixmapCombine
g++ -c -fno-keep-inline-dllexport -D_GNU_SOURCE -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I. -isystem /usr/include/qt5 -isystem /usr/include/qt5/QtWidgets -isystem /usr/include/qt5/QtGui -isystem /usr/include/qt5/QtCore -I. -I/usr/lib/qt5/mkspecs/cygwin-g++ -o testQPixmapCombine.o testQPixmapCombine.cc
g++  -o testQPixmapCombine.exe testQPixmapCombine.o   -lQt5Widgets -lQt5Gui -lQt5Core -lGL -lpthread 
Qt Version: 5.9.4

图片底部有一个小红圈,是我点击螺栓后出现的。

我必须承认,关于我的代码,我什至不需要额外的 QPixmap。 (根据 OP 的问题,我想证明使用透明像素图绘图可以正常工作。)

Label::mousePressEvent() 的替代实现会产生相同的效果:

void Label::mousePressEvent(QMouseEvent *pQEvent)
{
  QPixmap qPixmapDraw(_qPixmap);
  // draw red circle at mouse coordinates
  { QPainter qPainter(&qPixmapDraw);
    qPainter.setPen(QPen(Qt::red, 2));
    qPainter.drawEllipse(pQEvent->pos(), 20, 20);
  }
  QLabel::setPixmap(qPixmapDraw);
  pQEvent->accept();
}

请注意,我考虑了 : Scoping the QPainter qPainter with an extra pair of curly braces, I achieved the same effect as noted in the doc. of QPainter::end() 中提出的潜在问题:

Ends painting. Any resources used while painting are released. You don't normally need to call this since it is called by the destructor.

(强调 - 我的。)