Qt C++ Can QGraphicsItem's paint() method access underlying pixels? - c++

For visual markers in an imaging application on top of images I would like to enhance the contrast of said markers by using a fill color with high contrast to the local background (e.g. inverted). This requires for the object to read its background in a QGraphicsScene.
Is there an efficient (built-in) way of doing this or does it require something like rendering the scene without the marker, reading pixels in its position and then paint() the marker accordingly?

There is no straight way to get the rendered color of some point in QGraphicsScene. You should actually render the scene and see the color. One workaround is to render the scene to a QImage and pick the color from desired pixel:
QImage image=QImage(width,height,QImage::Format_RGB32);
QPainter painter( &image );
painter.setRenderHint(QPainter::Antialiasing);
myScene->render( &painter, image.rect(),QRectF(0,0,width,height), Qt::KeepAspectRatio );
painter.end();
QColor color = QColor(image.pixel(x,y));

Related

Restrict drawing of qpainter over pixmap

I am using QGraphicsView and Scene over which two QGraphicsPixmap item are set.
One is showing some image, another one is having transparent pixmap which is used to show marking.
I am using qpainter to draw over a transparent qpixmap.
I am using drawline between two points with qpen having rounded point with some pen size.
Problem is:
If i load some png image, with some part of image being transparent, I want to disable marking (on marking pixmap) over transparent region of image.
Is there any way to automatically restrict area of marking of qpainter?
It would be easiest to combine your two pixmaps into a single QGraphicsPixmapItem. Then you could simply use the correct QPainter::CompositionMode, which would need to be
QPainter::CompositionMode_SourceAtop
The source pixel is blended on top of the destination, with the alpha of the source pixel reduced by the alpha of the destination pixel.
e.g.:
QPixmap markingPixmap(sourceImage.size());
markingPixmap.fill(Qt::transparent);
{ // scope for painter1
QPainter painter1(&markingPixmap);
painter1.setPen(...);
painter1.drawLine(...);
}
QPainter painter(&sourceImage);
painter.setCompositionMode(QPainter::CompositionMode_SourceAtop);
painter.drawPixmap(0, 0, markingPixmap);
(Code untested!)
Or you could even use a QBitmap, see QPainter::drawPixmap():
If pixmap is a QBitmap it is drawn with the bits that are "set" using the pens color. If backgroundMode is Qt::OpaqueMode, the "unset" bits are drawn using the color of the background brush; if backgroundMode is Qt::TransparentMode, the "unset" bits are transparent. Drawing bitmaps with gradient or texture colors is not supported.
(You would need to try if this respects the CompositionMode.)

Drawing a Tinted QPixmap using QPainter

I have a single-color transparent PNG loaded with a QPixmap, I want to draw this pixmap multiple times using different colors (e.g. once green, another yellow, etc). These QPixmaps are rendered through QPainter in the paintEvent function of a QWidget.
you can convert the pixmap into qimage and paint your own color .
1- Use QImage::fill(DesiredColor)
2- QPaintDevice supports QImage so use QPainter painter(&qImage); // 8 bit will not support in paint event .
then recreate QPixmap with image using QPixmap::fromImage(qImage);

How can I apply a dark mask layer on a QPixmap?

I am fairly new to Qt and have been doing a lot of reading and practicing exercises.
I have searched for this one quite a lot but I could not find any examples.
I have a QPixmap object to which I load a .png image.
I need to create a copy of this QPixmap with a dark mask applied to it.
Basically I want this QPixmap's image to be covered with a layer of solid black of which the opacity is set to 50%.
I know how to set the opacity of a QPixmap's image but how can I add a layer of solid black with opacity on it?
Thank you!
You can use a QPainter and you a semi-transparent QBrush to paint that dark layer onto your QPixmap.
Assuming pic is a QPixmap loaded with your image:
QPainter p(&pic);
QBrush b(QColor(0,0,0,128)); // adjust color and alpha to taste
p.setBrush(b);
p.drawRect(0, 0, 200, 200);
Effect (before/after):
   vs   
The opaque black border can be removed by setting an semi-transparent pen before painting.
Copy the pixmap before applying the "mask" if you want to preserve the original.

Drawing a scalable QIcon using QPainter

I want to design a new QIcon and want it to look like a fixed text with a rounded rectangle around it
.-----.
| Phy |
`-----´
The icon is supposed to scale without the "pixel-blocks" effect when painting on a QPainter that eventually has a scale transformation applied (for example when I paint into a widget that is part of a QGraphicsView with a scale applied on its scene).
Therefor, I have difficulties knowing how I should paint my QIcon. If I do it in the following way, I will paint a QPixmap that always has a fixed amount of pixels, thus introducing the pixel-blocks effect inevitably when the scale is large enough
void MyWidget::drawIcon(QPainter *painter, QPoint pos) {
QPixmap pixmap = icon.pixmap(QSize(22, 22),
isEnabled() ? QIcon::Normal
: QIcon::Disabled,
isChecked() ? QIcon::On
: QIcon::Off);
painter->drawPixmap(pos, pixmap);
}
What I am looking for is a way similar to how QFont with drawText works. Regardless on how large my scale is, when I draw fonts it always looks sharp and I cannot detect individual pixels.
I imagine that I could tell QPainter to paint my icon into a given pixel rectangle, and QPainter transforms the rectangle itself before letting my QIconEngine::paint render the item into a possibly larger rectangle or pixmap. But I see no way how I could do something like this.
Am I just being stupid and not seeing the obvious solution?
I was indeed completely dump. I can just use QIcon::paint and pass it the rectangle. It will correctly delegate the request to the icon engine.
I do this by creating my icons/images as SVG files, and using QSvgRenderer to paint them onto a QPainter. The required classes are in the SVG module.

How do I draw a semi-transparent rectangle in Qt?

I'm trying to draw a semi-transparent rectangle on top of an image to act as a highlight. Unfortunately, nothing I try seems to be able to perform the transparency effect I want. Instead I just get solid filled rectangles, with no transparency.
Here's what I'm doing right now:
void PageView::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
QImage img=...;
painter.drawImage(0, 0, img);
...
// draw a light blue, transparent rectangle to highlight
QRect rect=...;
painter.fillRect(rect, QColor(128, 128, 255, 128));
...
}
Unfortunately, for me, this draws a solid blue rectangle, instead of the semi-transparent one I expect due to giving the QBrush an alpha value.
I've also tried drawing to an intermediate QImage or QPixMap, playing around with painter.setCompositionMode(...). No luck so far.
Thus my question: How can I convince Qt to draw a semi-transparent rectangle to my PageView?
EDIT: If it's relevant, I'm building this under Qt 4.8.1 on Windows.
The code works for me with a slight modification as it does not compile as you have it:
painter.fillRect(rect, QBrush(QColor(128, 128, 255, 128)));
NOTE:
The OP was painting the semi transparent rectangle in a loop causing the same area to be painted multiple times. This will result in an additive effect which will eventually cause that area to look the same as a solid fill.