How to flip a QImage - c++

What is the right way to flip/mirror a QImage? The following snippet does not work.
//allocate buffer
BYTE* pRgb32Buffer = new BYTE[width*height* 4];
//create paint device
QImage img = QImage(pRgb32Buffer , width, height, getStride(width, pixelFormat), QImage::Format_RGB32);
//do some drawing on image (works!)
QPainter painter(&img);
painter.drawText(10, 50, QString("some text"));
//mirrore image (doesn't mirror the orignal buffer!!!)
img = img.mirrored(false,true);
//doesn't work either
//QImage mirrored = img.mirrored();
//img = mirrored;
//mirrored.detach();

A solution using QImage::mirrored():
memmove(pRgb32Buffer, img.mirrored().bits(),img.byteCount());

I have this working code to mirror a QPixmap onto an QImage.
QPixmap* source = //... Getting my pixmap form somewhere...
QImage target(QSize(source->width(), source->height()), QImage::Format_ARGB32);
QPainter painter(&target);
QTransform transf = painter.transform();
transf.scale(-1, 1);
painter.setTransform(transf);
painter.drawPixmap(-source->width(), 0, *source);
The source contains the mirrored pixmap after that code. You should be able to do the same with QImageand the QPainter::drawImage function as alternative.
Optionally you can save the file if you want (make sure you have the imageformats dll's or it won't write):
QImageWriter writer("c:\\theimage.tiff", "tiff");
writer.setCompression(1);
writer.write(target);

Related

QPainter composition mode example does not work as expected

I'm stuck with the difference from the book example and my version of it.
Qt version 5.12.0
As it's shown in the example:
As I see from my output:
First, destination and source In/Atop modes have not the same pictures. And, another noticed thing is, that we can see the rectangle as an additional layer between two.
Code to create the label:
QLabel* lblCreate(const QPainter::CompositionMode& mode){
QLabel* lbl = new QLabel;
lbl->setFixedSize(100, 100);
QRect rect(lbl->contentsRect());
QPainter painter;
// create first image
QImage sourceImage(rect.size(), QImage::Format_ARGB32_Premultiplied);
painter.begin(&sourceImage);
painter.setRenderHint(QPainter::Antialiasing, true);
painter.setBrush(QColor(0, 255, 0));
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
// draw triangle
painter.drawPolygon(QPolygon() << rect.bottomLeft()
<< QPoint(rect.center().x(), 0)
<< rect.bottomRight());
painter.end();
// create second image
QImage resultImage(rect.size(), QImage::Format_ARGB32_Premultiplied);
painter.begin(&resultImage);
painter.setRenderHint(QPainter::Antialiasing, true);
painter.setPen(QPen(QColor(0, 255, 0), 4));
painter.setBrush(QColor(255, 0, 0));
// draw circle
painter.drawEllipse(rect);
painter.setCompositionMode(mode);
painter.drawImage(rect, sourceImage);
painter.end();
lbl->setPixmap(QPixmap::fromImage(resultImage));
return lbl;}
How it creates in main.cpp:
innerLayout_2->addWidget(lblCreate(QPainter::CompositionMode_Source), 0, 0);
innerLayout_2->addWidget(new QLabel("<CENTER>Source</CENTER>"), 1, 0);
My own suspicion is it may be depend on QImage::Format_ARGB32_Premultiplied.
Or it's mine handmade bug.
Anyway, I would be grateful for any ideas.
Thnx in advance!
The composition mode works on transparent backgrounds, in your case it is not, so you must set it before painting, for this you could use the fill() method:
QImage sourceImage(rect.size(), QImage::Format_ARGB32_Premultiplied);
sourceImage.fill(Qt::transparent);
QImage resultImage(rect.size(), QImage::Format_ARGB32_Premultiplied);
resultImage.fill(Qt::transparent);

Cannot draw rect on QPixmap with QPainter

I have a problem with drawing a rect on QPixmap, which I loaded from file. And I also want to use this pixmap as a icon in listView.
Code:
QPixmap pixmap(100, 100);//(temp);// = QPixmap(temp);
pixmap.load(temp);
QPainter* painter = new QPainter(&pixmap);
painter->setPen(QPen(Qt::blue, 4, Qt::SolidLine));
painter->drawRect(4, 4, 50, 50);
painter->end();
QIcon icon = QIcon();
icon.addPixmap(pixmap);
temp is a QString path to the file. It shows only a resized photo without rect. When I commented a line with load, then rect is shown with random background.
or maybe someone know how to do this with QIcon::paint function.
Thanks in advance!

QT5: Drawing rect on top of another rect using drawPixMap()

am I using drawPixmap() correctly?
Essentially my goal is to take an tileset image, and replace an individual tile with a custom tile image.
I'm able to get both images to load on the screen, but when I call drawPixmap(), then original image doesn't change at all.
Thanks in advance.
void replaceCustomTile(QPixmap custom, QPixmap target, int whichTile) {
QRect rect(0, 0 + (squareTileSize * whichTile), squareTileSize, squareTileSize);
QRect customRect = custom.rect();
QPainter painter(this);
painter.drawPixmap(rect, target, customRect);
painter.end();
}
EDIT:
This is how replaceCustomTile is called:
QPixmap terrainTiles(":/static/Terrain.png");
QPixmap customTile(":/static/Smiles.png");
replaceCustomTile(customTile, terrainTiles, 0);
To intialize QPainter by this it must be called from the widget paintEvent(QPaintEvent *) if you want to draw it on some widget. So, replaceCustomTile() should be called from the event handler in that case.
To draw some pixmap on top of another pixmap QPainter should be initialized by the target pixmap using QPainter::begin():
QPainter painter;
painter.begin(&target);
painter.drawPixmap(rect, custom);
painter.end();
The above code draws QPixmap custom into given QRect rect over QPixmap target. The target is modified.

Qt- fill circle with images

I've tried to fill circle with four images. Firstly , each photo brush in the same size ,hereafter scale final image with that size. But result is not what I want.
At the moment circle in foreground and photos on background, like here:
How to fill circle with photos and remove rectangle?
Here is my code:
QPixmap *CGlobalZone::profPicFromFourPics(QList<QPixmap> pixmapList)
{
QPixmap *avatar = NULL;
QImage roundedImage(CGlobalZone::AVATAR_WIDTH_M*2, CGlobalZone::AVATAR_HEIGHT_M*2, QImage::Format_ARGB32);
roundedImage.fill(Qt::transparent);
QBrush brush0(pixmapList[0]);
QBrush brush1(pixmapList[1]);
QBrush brush2(pixmapList[2]);
QBrush brush3(pixmapList[3]);
QPainter painter(&roundedImage);
QPen pen(QColor(176, 216, 242), 1);
painter.setRenderHint(QPainter::Antialiasing);
painter.setBrush(brush0);
painter.drawRect(0 , 0 , CGlobalZone::AVATAR_WIDTH_M , CGlobalZone::AVATAR_HEIGHT_M );
painter.setBrush(brush1);
painter.drawRect(CGlobalZone::AVATAR_WIDTH_M , 0 , CGlobalZone::AVATAR_WIDTH_M*2 , CGlobalZone::AVATAR_HEIGHT_M );
painter.setBrush(brush2);
painter.drawRect(CGlobalZone::AVATAR_WIDTH_M , CGlobalZone::AVATAR_HEIGHT_M , CGlobalZone::AVATAR_WIDTH_M*2 , CGlobalZone::AVATAR_HEIGHT_M*2 );
painter.setBrush(brush3);
painter.drawRect(0 , CGlobalZone::AVATAR_HEIGHT_M , CGlobalZone::AVATAR_WIDTH_M*2 , CGlobalZone::AVATAR_HEIGHT_M*2 );
painter.drawEllipse(0, 0, CGlobalZone::AVATAR_WIDTH_M*2-3 , CGlobalZone::AVATAR_HEIGHT_M*2-3 );
avatar = new QPixmap(QPixmap::fromImage(roundedImage).scaled(QSize(CGlobalZone::AVATAR_WIDTH_M, CGlobalZone::AVATAR_HEIGHT_M),
Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation));
return avatar;
}
I would do this in the following way (details in source comments):
// The avatar image. Should be four, but use one for demonstration.
QPixmap source("avatar.png");
// Initialize the avatar and bring it to a standard size.
// This step may be skipped if avatars have the same sizes.
const int width = CGlobalZone::AVATAR_WIDTH_M;
const int height = CGlobalZone::AVATAR_HEIGHT_M;
source = source.scaled(width, height);
// Set up the final image that contains four avatar images.
QPixmap target(2 * width, 2 * height);
target.fill(Qt::transparent);
QPainter painter(&target);
// Set clipped region (circle) in the center of the target image
QRegion r(QRect(width / 2, height / 2, width, height), QRegion::Ellipse);
painter.setClipRegion(r);
painter.drawPixmap(0, 0, source); // First avatar
painter.drawPixmap(width, 0, source); // Second avatar
painter.drawPixmap(0, height, source); // Third avatar
painter.drawPixmap(width, height, source); // Fourth avatar
target.save("test.png");
Use painter paths for the task. Rather than drawEllipse you should do
int dim = CGlobalZone::AVATAR_WIDTH_M*2;
QPainterPath entirePath;
QPainterPath ellipsePath;
entirePath.addRect(0, 0, dim, dim);
ellipsePath.addEllipse(0, 0, dim-3, dim-3);
QPainterPath outOfEllipse = entirePath.subtracted(ellipsePath);
painter.fillPath(outOfEllipse, QBrush(Qt::transparent));
edit: Because QPainterPath is for complex cases, you should use QRegion. After testing I found out there might small pixel errors when filling inside and outside the same path (in your case it is going to be fine).

scale a QImage in Qt

What the easiest way to draw an image as a background for a QGraphicsRectItem?
I can set the background as follows but I can't scale the image:
QGraphicsRectItem *enemyItem;
QImage *image = new QImage(":/PaperMario.png");
QBrush *brush = new QBrush(*image);
enemyItem = new QGraphicsRectItem();
enemyItem->setBrush(*brush);
enemyItem->setRect(enemy->getXPos()*30,enemy->getYPos()*30,30,30);
scene->addItem(enemyItem);
inside QGraphicsRectItem
void MySquare::setBrush(QColor _color){
color = _color;
color_pressed = _color;
update(); //repaint
}
I have tried it using:
QBrush *brush = new QBrush(*image->scaled(10));
But I'm stuck: doesn't want to compile.
Is this the way to do it?
Edit:
QImage *image = new QImage(":/PaperMario.png");
QImage *scaled_image = new QImage(image->scaled(35,35,Qt::KeepAspectRatio));
QBrush *brush = new QBrush(*scaled_image);
Does does draw it but it still shows the image multiple times in the drawing
when you display your image in a scene (what i would guess) why dont you use QGraphicsScene::addPixmap(QPixmap) and use the QPixmap::fromImage ( const QImage & image, Qt::ImageConversionFlags flags = Qt::AutoColor ) to get your image into the right format.
*image->scaled(10) does not work on a QImage*. Either you write *image.scaled or (better) image->scaled.