2

I'm new to Qt and Qt Graphics API.

I have a larger QPixMap and a smaller QPixMap. I need to replace a portion (a QRect) of the larger one with the smaller one.

How am I supposed to achieve this?

Thanks.

UPDATE

QPainter::drawPixmap() does not update the image represented by pImage->p_PixMap.

Code

class GraphicImage : public QObject,
    public QGraphicsPixmapItem
{
    Q_OBJECT

public:
    GraphicImage(QPixmap* oImage,GraphiItemCtrl* pParent);
    virtual ~GraphicImage(void);
    QPixmap* p_PixMap;
};
- - - - 
GraphicImage::GraphicImage(QPixmap* oImage,GraphiItemCtrl* pParent)
    :QGraphicsPixmapItem(*oImage), p_Parent(pParent)
{
    p_PixMap = oImage;
}
- - - - 
void GraphiItemCtrl::SetImagePortion( QString sFileName, QRect rect, QPixmap pChildPixMap )
{
    GraphicImage* pImage = map_CurrentImages[sFileName];

    if ( !pImage )
        return;

    pChildPixMap.save("test.jpg");
    QPixmap* pMap = pImage->p_PixMap;
    QPainter pPainter(pMap);

    pPainter.drawPixmap(rect, pChildPixMap);
    qDebug() << rect.topLeft();
}

pChildPixMap.save("test.jpg"); saves the required portion of the image without an issue.

NOTE : pImage is inherited from QObject and QGraphicsPixmapItem. pMap is not NULL

Praneeth Peiris
  • 2,008
  • 20
  • 40
  • You should look at the answers to this question http://stackoverflow.com/questions/17888795/how-to-use-qpainter-on-qpixmap – zeFrenchy Nov 21 '16 at 15:30

3 Answers3

3

The function you are looking for is:

void QPainter::drawPixmap(const QRect &rectangle, const QPixmap &pixmap)

It will draw the pixmap into a rectangle portion of the painter's target.

You may also want to use this one:

void QPainter::drawPixmap(const QRect &target, const QPixmap &pixmap, const QRect &source)

Which will draw a portion of the source into a portion of the target.

In both cases if the sizes mismatch the image will be scaled, so if you are getting poor results, you will additionally need to tweak the scaling method.

As established in this answer, setting setRenderHint(QPainter::SmoothPixmapTransform); by itself does not seem to produce optimal results. If you want the best quality you will need to manually scale() the pixmap and then draw it, which produces much better results than scaling it on the fly while painting.

Community
  • 1
  • 1
dtech
  • 47,916
  • 17
  • 112
  • 190
2

Quick pseudocode:

QPainter painter(pixmap1);
painter.drawPixmap(QRect, pixmap2);

Take a look at the documentation here

Marco A.
  • 43,032
  • 26
  • 132
  • 246
  • Thanks, I will try this and get back. – Praneeth Peiris Nov 21 '16 at 15:38
  • Then how am I supposed to extract the output `QPixMap` ? – Praneeth Peiris Nov 21 '16 at 16:52
  • @PraneethNilangaPeiris The pixmap where you'll invoke `drawPixmap` will be drawn onto – Marco A. Nov 21 '16 at 17:33
  • This is some dangerous pseudocode. You should hold the painter by value. – Kuba hasn't forgotten Monica Nov 21 '16 at 19:51
  • @KubaOber I stand corrected, most Qt memory management is done under the hood with a parent-child hierarchy (so naked allocations - that I usually detest - aren't a problem).. but in this case there was a leak. Thanks. – Marco A. Nov 21 '16 at 19:55
  • 1
    @MarcoA. That's too broad of a generalization: You have the **option** to *leverage* a parent-child relationship between `QObject`s for memory management purposes. It's **truly and purely optional**. An object can hold child objects by value and then the C++ semantics ensure that the children get destroyed when needed. E.g. `class Foo : public QWidget { QLabel child1{"Hello", this}; QLabel child2{"World", this}; ... };` - the labels will be gone before the parent, and Qt has no involvement in it at all. If the lifetime of children is that of a parent, you should just hold them by value! – Kuba hasn't forgotten Monica Nov 21 '16 at 20:01
  • 1
    @MarcoA. Note the difference between the broad "most Qt memory managment" and "parent-child relationship between `QObject`s": not everything is a `QObject`. Also note that leveraging it is optional: you can, but you don't have to, and you shouldn't if the parent and child lifetimes are identical and you're the author of the parent class. – Kuba hasn't forgotten Monica Nov 21 '16 at 20:04
  • @KubaOber Thanks, I was mostly referring to [this](http://stackoverflow.com/a/1651647/1938163) kind of common widget paradigm (got me wondering what was the catch the first time I saw it) – Marco A. Nov 21 '16 at 20:09
0

You need to use a painter on the destination pixmap to draw the source pixmap in a given destination rectangle:

void draw(QPixmap &dst, const QRect &dstRect, const QPixmap &src) {
  QPainter(dst).drawPixmap(dstRect, src); 
}

If you're drawing multiple such pixmaps on one destination, you should hold on to the painter - it'd be wasteful to construct new painter over and over in a loop:

struct Replacement {
  QRect dstRect;
  QPixmap source;
};

void draw(QPixmap &dst, const QList<Replacement> &replacements) {
  QPainter painter{dst};
  for (auto & r : replacements)
    painter.drawPixmap(r.dstRect, r.source);
}
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313