Today someone asked how to copy one image into another image in Qt. I thought it was a nice idea to write an example about how to do that, plus a few extra things. We will create a resizable photo frame from just one simple image of a photo frame! It works like this:
- Reimplement QWidget::paintEvent() and construct a QPainter(this) in the reimplementation so we can draw on the widget
- Load the image of the photo frame and define 4 QRect objects to define the position of the frame borders – these borders are not allowed to scale
- Draw something which will be contained inside of the frame – for example another image using QPainter::drawPixmap() or QPainter::drawImage()
- Generate and draw the frame bars (the pieces between the borders)
- Make use of the QImage::mirrored() function and another QPainter to create a new pixmap which contains the frame bar plus the mirrored frame bar.
- This will make the bar look great when the frame bar is enlarged by tiling. This method is actually a very popular one in basic photo manipulation.
- Draw the four borders
The result looks like this:
Photo frame in native size – versus – Enlarged photo frame
The code looks like this:
photowidget.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #ifndef PHOTOWIDGET_H #define PHOTOWIDGET_H #include <QtGui/QWidget> class PhotoWidget : public QWidget { Q_OBJECT public: PhotoWidget(QWidget *parent = 0); protected: void paintEvent(QPaintEvent *event); private: QPixmap createBar(Qt::Orientation orientation, const QPixmap &pixmap, const QRect &rect); }; #endif // PHOTOWIDGET_H |
photowidget.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | #include "photowidget.h" #include <QPainter> #include <QPaintEvent> #define SIZE 108 PhotoWidget::PhotoWidget(QWidget *parent) : QWidget(parent) { resize(400, 329); setWindowTitle("Photo Frame Example"); } // This function generates a pixmap that can be used as a tiled bar. // Note: We use a QPainter and the mirrored() function to make sure that the bar looks good when tiled. // This technique is often applied in basic photo manipulation. QPixmap PhotoWidget::createBar(Qt::Orientation orientation, const QPixmap &pixmap, const QRect &rect) { QImage barA = pixmap.copy(rect).toImage(); QImage barB = barA.mirrored(orientation == Qt::Horizontal ? true : false, orientation == Qt::Vertical ? true : false); QSize size; size.setWidth(orientation == Qt::Horizontal ? barA.width() << 1 : barA.width()); size.setHeight(orientation == Qt::Vertical ? barA.height() << 1 : barA.height()); QPixmap bar(size); bar.fill(Qt::transparent); QPainter merger(&bar); merger.drawImage(0, 0, barA); if (orientation == Qt::Horizontal) merger.drawImage(barA.width(), 0, barB); else merger.drawImage(0, barA.height(), barB); return bar; } void PhotoWidget::paintEvent(QPaintEvent *event) { QPainter p(this); // Our frame as one full image, and an image to put in the frame QPixmap frame(":/img/frame.png"); QPixmap sky(":/img/palmtree.jpg"); // These four rectangles define the four borders of the frame QRect topLeft(0, 0, SIZE, SIZE); QRect topRight(frame.width() - SIZE, 0, SIZE, SIZE); QRect bottomLeft(0, frame.height() - SIZE, SIZE, SIZE); QRect bottomRight(frame.width() - SIZE, frame.height() - SIZE, SIZE, SIZE); // Draw the image first p.drawPixmap(QRect(40, 40, event->rect().width() - 80, event->rect().height() - 80), sky); // Draw the bars p.drawTiledPixmap(QRect(QPoint(SIZE, 0), event->rect().topRight() + QPoint(-SIZE, SIZE - 1)), createBar(Qt::Horizontal, frame, QRect(QPoint(SIZE, 0), frame.rect().topRight() + QPoint(-SIZE, SIZE)))); p.drawTiledPixmap(QRect(event->rect().bottomLeft() + QPoint(SIZE, -SIZE - 1), event->rect().bottomRight() - QPoint(SIZE, 0)), createBar(Qt::Horizontal, frame, QRect(frame.rect().bottomLeft() + QPoint(SIZE, -SIZE), frame.rect().bottomRight() - QPoint(SIZE, 0)))); p.drawTiledPixmap(QRect(QPoint(0, SIZE), event->rect().bottomLeft() + QPoint(SIZE, -SIZE)), createBar(Qt::Vertical, frame, QRect(QPoint(0, SIZE), frame.rect().bottomLeft() + QPoint(SIZE, -SIZE)))); p.drawTiledPixmap(QRect(event->rect().topRight() - QPoint(SIZE + 1, -SIZE), event->rect().bottomRight() - QPoint(0, SIZE)), createBar(Qt::Vertical, frame, QRect(frame.rect().topRight() - QPoint(SIZE, -SIZE), frame.rect().bottomRight() - QPoint(0, SIZE)))); // Draw the borders p.drawPixmap(QPoint(0, 0), frame, topLeft); p.drawPixmap(event->rect().topRight() - QPoint(SIZE, 0), frame, topRight); p.drawPixmap(event->rect().bottomLeft() - QPoint(0, SIZE), frame, bottomLeft); p.drawPixmap(event->rect().bottomRight() - QPoint(SIZE, SIZE), frame, bottomRight); } |