How to fill the void with transparent background when rotating a QImage? - qt

When I rotate an image in Qt, It automatically enlarge the image to encapsulate the bigger dimensions which is great and intelligent. However, it fills the newly created void with white color which is not what I want. How can I make it fill with a totally transparent color?
Here is may code.
QImage lSource("/path/to/an/image/file");
QTransform lRotation;
lRotation.rotate(30.0);
QImage lRotated(lSource.transformed(lRotation, Qt::SmoothTransformation));
ui.labelImage->setPixmap(QPixmap::fromImage(lRotated));
Thanks a lot!

Based on my comment above...
I suspect, that the void areas of the rotated image are transparent, and the white color is the background color of your label. If you want to set a specific background to your rotated image, you can do the following:
// Create rotated image.
QImage lSource("source.png");
QTransform lRotation;
lRotation.rotate(30.0);
QImage lRotated(lSource.transformed(lRotation, Qt::SmoothTransformation));
// Create resulting image with specific background.
QImage img(lRotated.size(), QImage::Format_ARGB32);
img.fill(Qt::red); // Set the red background
QPainter p(&img);
p.drawImage(0, 0, lRotated);
QLabel l;
l.setPixmap(QPixmap::fromImage(img));
l.show();

Related

How to print a grayscale image as a monochrome colored image?

I have a grayscale PNG image 'myImage' that I want to show as a monochrome image in color 'myColor' (blue in my case).
grayscale image:
QPainter p;
QImage mask(myImage);
p.begin(&mask);
p.setCompositionMode(QPainter::CompositionMode_SourceIn);
p.fillRect(QRect(0.0,0.0,image.width(),image.height()), myColor);
p.end();
p.begin(&myImage);
p.setCompositionMode(QPainter::CompositionMode_Overlay);
p.drawImage(0, 0, mask);
p.end();
The result look like this:
monochrome image:
Which is 'almost' what I want:
the black on the right should be fully blue
the gradient should have a color starting from blue, going to white.
You can draw semitransparent (alphaBlue) image over white image to achieve that effect.
QImage mask("path/to/mask.png");
mask.invertPixels();
QImage alphaBlue(mask.width(), mask.height(), QImage::Format_ARGB32);
alphaBlue.fill(Qt::blue);
alphaBlue.setAlphaChannel(mask);
QImage result(mask.width(), mask.height(), QImage::Format_ARGB32);
result.fill(Qt::white);
QPainter painter(&result);
painter.drawImage(0, 0, alphaBlue);
result.save("path/to/result.png");

How do I add a border to a rounded QPixmap?

I'm trying to show a rounded avatar QPixMap with a white border around it. However, I have no clue as to how I could add the border... Is it even possible?
This is the function I have to draw the avatar image.
void AccountDropDownMenu::setAvatar(
const QByteArray& bytes)
{
QPixmap new_avatar;
new_avatar.loadFromData(bytes);
new_avatar = new_avatar.scaledToHeight(40, Qt::SmoothTransformation);
QBitmap map(new_avatar.size());
map.fill(Qt::color0);
QPainter painter(&map);
painter.setRenderHint(QPainter::Antialiasing);
painter.setBrush(Qt::color1);
painter.setPen(QPen(Qt::white, 10));
painter.drawRoundedRect(
m_avatar_label->x(),
m_avatar_label->y(),
new_avatar.width(),
new_avatar.height(),
45,
45);
new_avatar.setMask(map);
avatar_label->setPixmap(new_avatar);
}
Update
Thanks to dtech I was able to get the desired output using the following updated function.... Although it's a bit pixly (the border).
void AccountDropDownMenu::setAvatar(
const QByteArray& bytes)
{
QPixmap new_avatar;
new_avatar.loadFromData(bytes);
new_avatar = new_avatar.scaledToHeight(40, Qt::SmoothTransformation);
QBitmap map(new_avatar.size());
map.fill(Qt::color0);
QPainter painter(&map);
painter.setRenderHint(QPainter::Antialiasing);
painter.setBrush(Qt::color1);
painter.drawRoundedRect(
QRectF(
avatar_label->x(),
avatar_label->y(),
new_avatar.width(),
new_avatar.height()),
40,
40);
new_avatar.setMask(map);
QPainter painter2(&new_avatar);
painter2.setRenderHint(QPainter::Antialiasing);
painter2.setPen(QPen(Qt::white, 1));
painter2.drawRoundedRect(
QRectF(
avatar_label->x(),
avatar_label->y(),
new_avatar.width(),
new_avatar.height()),
40,
40);
avatar_label->setPixmap(new_avatar);
}
In Qt you draw fills with a brush, but outlines are drawn with a QPen.
I haven't used QPainter in a long time, but IIRC, the default pen is zero width, which would explain why you aren't getting anything - you are not setting a pen.
Also, you don't need "another" rounded rectangle, you can apply fill and outline to the same geometry, as demonstrated in this answer.
Update:
Your updated code sets a mask, which sets an alpha channel. That cuts away from what you already have, it could not possibly add anything. You have to paint on the pixmap. Simply use new_avatar as the paint device - QPainter painter(&new_avatar); and get rid of the rest.

QImage overlay with mouse selection

How to highlight the pixels in a QImage to highlight or draw a overlay on the pixels which user selected using mouse. I just want to know how i can specify the particular area.
Ex: With a 400x400 QImage data how i can increase or decrease the pixel intensity or overlap an image on top of it where the user selected.
You can involve QPainter (please refer to the documentation) to draw over your QImage. It allows drawing another images, rectangles, lines etc.
void View::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
// Draws your original image.
painter.drawImage(0, 0, myImage);
// Draws a blue rectangle over the image.
QPen rectPen(Qt::blue);
rectPen.setStyle(Qt::DashLine);
painter.setPen(rectPen);
painter.drawRect(0, 0, 100, 100);
[..]
}
You can maintain your mouse clicks and movement and draw corresponding stuff in paint event handler.

Qt : draw triangle image

I need to do something similar to QPainter::drawImage, but drawing a triangle part of the given picture (into a triangular region of my widget) instead of working with rectangles.
Any idea how I could do that, besides painfully trying to redraw every pixel?
Thanks for your insights!
If it is feasible for you to use a QPixmap instead of a QImage, you can set a bitmap mask for the QPixmap which defines which of the pixels are shown and which are transparent:
myPixmap->setMask(myTriangleMask);
painter->drawPixmap(myPixmap);
Here is another solution based on QImage:
MaskWidget::MaskWidget(QWidget* parent) : QWidget(parent) {
img = QImage("Sample.jpg"); // The image to paint
mask = QImage("Mask.png"); // An indexed 2-bit colormap image
QPainter imgPainter(&img);
imgPainter.drawImage(0, 0, mask); // Paint the mask onto the image
}
void MaskWidget::paintEvent ( QPaintEvent * event ) {
QPainter painter(this);
painter.drawImage(10, 10, img);
}
Mask.png is an image file with the same size as Sample.jpg. It contains an alpha channel to support transparency. You can create this file easily with The GIMP, for example. I added an alpha channel, changed all areas I want to have painted to transparent and all other areas to white. To reduce the size, I finally converted it to an indexed 2-bit image.
You could even create the mask image programmatically with Qt, if you need your triangle be computed based on various parameters.

How to add an image on the top of another image?

I want to show difference between a trimed clip and non trimed clip in my video editor application, i.e. I want to add a small film image on my thumbnail for a trimed clip. How can I do this?
It would be just to show the difference between an image and a video in our gallery application.
How to add an image on the top of another one in Qt?
Open the QPainter on the bottom image and draw the top image using its drawPixmap()/drawImage() methods.
QPixmap base, overlay; // come from your code
{
QPainter painter(base);
painter.drawPixmap(100, 100, overlay);
}
If your overlay contains an alpha channel (e.g. fancy PNG icon) and your base image does not, you should create a new QPixmap with an alpha channel and draw both images into it:
QPixmap base, overlay; // come from your code
QPixmap result(base.width(), base.height());
result.fill(Qt::transparent); // force alpha channel
{
QPainter painter(&result);
painter.drawPixmap(0, 0, base);
painter.drawPixmap(100, 100, overlay);
}
QPixmaps and QImages can be used interchangeably, although not all combinations give good performance).
If it's just about showing an image above another, then you could also go with this answer.
QGridLayout *layout = new QGridLayout(widget);
Pixmap base, overlay;
QLabel *background = new Label();
background->setPixmap(&base);
QLabel *lOverlay = new QLabel();
lOverlay->setPixmap(&overlay);
//label gets positioned above textBrowser and is an overlay
layout->addWidget(background, 0, 0, Qt::AlignLeft | Qt::AlignTop);
layout->addWidget(lOverlay, 0, 0, Qt::AlignRight | Qt::AlignBottom);
Of course then the QPixbuf of the background doesn't contain the QPixbuf of the overlay-image, but it only appears to do.

Resources