I am painting in a custom widget to match the "Google-Styled" cards. I have most of the dimensions and font correct however upon painting an image it is always stretched. Here is a reference image and the relevant code. I would like to keep the image at it's default aspect ratio.
Image:
QRect topPortion = QRect(QPoint(0, 0), QSize(width(), (height()/4)*3));
QPainterPath backgroundPath;
backgroundPath.addRect(topPortion);
QPainterPath bottom = getCornerPath().subtracted(backgroundPath);
QRect bottomRect = QRegion(rect()).subtracted(QRegion(topPortion)).boundingRect();
painter.fillPath(getCornerPath(), m_bColor);
painter.fillPath(bottom, m_fColor);
painter.drawPixmap(topPortion, m_image.scaled(topPortion.size(), Qt::KeepAspectRatio, Qt::FastTransformation));//Issue
painter.setPen(QPen(QColor(50, 50, 50)));
painter.setFont(titleFont);
painter.drawText(QPointF(12, topPortion.height()+((bottomRect.height()-fontHeight)/2)+QFontMetrics(titleFont).ascent()), "Add Record");
painter.setFont(subtitleText);
painter.drawText(QPointF(12, topPortion.height()+((bottomRect.height()-fontHeight)/2)+fontHeight), "Add Record");
You're scaling your image with m_image.scaled function, however passing also to painter.drawPixmap function, the topPortion variable, and according to docs:
The pixmap is scaled to fit the rectangle, if both the pixmap and
rectangle size disagree.
So my solution is:
//Your's calculation area
QRect topPortion = QRect(QPoint(0, 0), QSize(width(), (height() / 4) * 3));
QPixmap pixmap = QPixmap(1024, 768); //Random image
pixmap.fill(Qt::red); //Random color
//Scaled size that will be used to set draw aera to QPainter, with aspect ratio preserved
QSize size = pixmap.size().scaled(topPortion.size(), Qt::KeepAspectRatio);
//Draw the pixmap inside the scaled area, with aspect ratio preserved
painter.drawPixmap(topPortion.x(), topPortion.y(), size.width(), size.height(), pixmap);
Related
I had tried to fill the color outside of the actual image but fails to do so. I get the pixmap as the input.
QRect target = AlignRect(aRect, iPixmap.size(), Alignment());
aPainter.drawPixmap(target, iPixmap);
QPainter painter(&iPixmap);
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
painter.setBrush(QColor::fromRgb(43, 174, 255));
painter.setPen(QColor::fromRgb(43, 174, 255));
painter.drawRect(target);
I get the below image as the pixmap.
I want to fill the color outside the white icon like
Can someone give the pointer for the same?
This can be done easily because your iPixmap has a transparent background...
You can draw a rect at 0,0 with a WIDTH and HEIGH of the widgets size and then after that place the X on top of that.
example:
painter.drawRect(0,0,w,h);
I have an issue with pixmaps created for drag events. For drag events of my derived QGraphicsRectItem I create a semi-transparent pixmap from that item.
In the debug build everything looks fine.
But in the release build the drag pixmap has some periodic and random artefacts
here is the code:
QPixmap MyGraphicsRectItem::toPixmap() const
{
QRect r = boundingRect().toRect();
QPixmap pixmap(r.width(), r.height());
QColor dragColor(color);
dragColor.setAlphaF(0.5);
QPainter painter;
painter.begin(&pixmap);
painter.fillRect(pixmap.rect(), dragColor);
painter.setPen(Qt::white);
QFont font("SegoeUI");
font.setBold(true);
painter.setFont(font);
painter.drawText(pixmap.rect(), QString(" ") + textItem->toPlainText());
if (pixItem != nullptr) {
painter.setOpacity(0.5);
painter.drawPixmap(pixItem->pos(), pixItem->pixmap());
}
painter.end();
return pixmap;
}
Could that be a kind of memory issue?
The QPixmap is initialized with uninitialized data. In Debug, this is often set to a fixed pattern, but in Release it is garbage.
You should fill the pixmap with transparent color before using it.
QPixmap::QPixmap(int width, int height)
Constructs a pixmap with the given width and height. If either width or height is zero, a null pixmap is constructed.
Warning: This will create a QPixmap with uninitialized data. Call fill() to fill the pixmap with an appropriate color before drawing onto it with QPainter.
(From Qt Docs)
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!
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.
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).