QT : Masking an image - Suggestions? - qt

I dont know if I am using the correct term here. However this is what I am trying to achieve and I would like some suggestions on how I could achieve that. I want to have a circle with border visible. Now here is the hard part and something I dont even know how to start with. I want to manipulate the circle in such a way that the borders of the circle are visible and its center is not (i.e Pretty much that it has a hole in it and would show what ever is placed under it)I would then like to have another image placed under the circle such that only the part of the image that is under the transparent part of the circle is shown the parts outside the transparent boundary of the circle become invisible. Any suggestions on how I could achieve this. It seems that googling isnt helping me.

I would suggest the alternative way for unmasking a circular area of an image. You can specify the clip region - the area where you need to perform painting. For example:
[..]
QPainter painter(this);
// Sample circular area.
QRegion r(QRect(100, 100, 200, 200), QRegion::Ellipse);
painter.setClipRegion(r);
[..]
painter.drawImage(0, 0, image);
[..]
This will draw only those parts of your image that are inside of the circle with radius 200. All the rest pixels will be hidden.
You can handle mouse move event to move this "circle" over the image like a loupe.
UPDATE
Below is the sample code that generates an image with circular mask and insert it into the label:
QPixmap target(500, 500); // the size may vary
QPixmap source("image.png");
QPainter painter(&target);
QRegion r(QRect(100, 100, 200, 200), QRegion::Ellipse);
painter.setClipRegion(r);
painter.drawPixmap(0, 0, source);
QLabel l;
l.setPixmap(target);
l.show();

You might want to have a look at the Composition Example.
In short you could draw the first image and then use one of the Composition Modes to draw the second image on top (or the other way around). Make sure to convert the images to ARGB32 before using them.
To make the inner Part of the Circle transparent you can adjust the Alpha Channel accordingly.
Here is a small Example using Composition mode:
QPainter p(&imageCircle);
p.setCompositionMode(QPainter::CompositionMode_SourceOver);
p.drawImage(image);
p.end()
Here you can find the Qt Documentation of QPainter.

Related

Qt Qpixmap generates a blurry image

As part of a larger project i'm trying to draw basic shapes on a QPixmap but the generated image always appears blurry ie. the circle is not a pure red circle, the edges are blurred and the colour is not true red as expected. This becomes an issue later on with what I need the image for. Here's the relevant code snippet, i've played around with antialiasing options and render hints but i've not had any luck. Any help would be much appreciated!
QPixmap pixmap(QSize(300,300));
QPainter painter( &pixmap);
painter.setRenderHint(QPainter::Antialiasing);
painter.setRenderHint(QPainter::SmoothPixmapTransform);
painter.fillRect( QRectF(0, 0, 300, 300),Qt::white);
painter.setPen(Qt::red);
painter.drawEllipse( QPoint(150,150), 75, 75);
painter.setPen(Qt::green);
QLineF line(30, 30, 30, 270);
painter.drawLine(line);
pixmap.save("test1.jpg", "jpg", 100);
I've been asked to include an image to show the issue, here's a close up of the image which shows the green line not being true green and the red circle not being true red and with blurred edges.
The problem that you have with the red color is that Qt by default uses chroma color subsampling (2x2 blocks) when saving to JPG format.
The only way to avoid this problem is using another format. Saving the same image with PNG format returns a pure red circle (255,0,0).
Regarding to the blurry circle, it occurs because of QPainter::Antialiasing RenderHint. In your case, not using any renderHints shows a sharp image. Below you can see your image with pure red color (PNG format) and sharp edges (not RenderHints). Take into account that the blurriest approach will be using QPainter::Antialiasing so avoid it if you are aiming to image sharpeness. Depending on your needs you could try QPainter::HighQualityAntialiasing RenderHint, but nothing else.

Increase OpenGL display size

I'm just starting to learn OpenGL in Qt, and I've been following a demo clip from youtube, but my display is not same as the display in clip. It looks very small. Is there any way to make it bigger?
I tried to change to the coordinates of the triangle drawing code like:
glColor3f(1,1,0);
glScalef(1, 1, 0.0);
glBegin(GL_TRIANGLES);
glVertex3f(-10,-10,0);
glVertex3f(10,-10,0);
glVertex3f(0.0,10,0);
glEnd();
But, it didn't draw a triangle. My output became a square. See these screen shots for before and after my changes.
You need to set the viewport appropriately (namely the window client region dimensions). At the start of paintGL call glViewport(0, 0, width(), height());.
Also later on you probably want to set appropriate projection and modelview transformations.

Using an alpha transparent mask on a QWidget?

Is it possible to assign an alpha-transparent mask to a QWidget? I know how to set a mask using setMask but it seems it only supports black&white masks. Is it possible to make it support a true alpha channel?
i.e. currently I have a PNG like this:
and a widget like this:
If I load my PNG in a QPixmap and set it as a mask, I get this (notice the edges):
However I would like to get this (smooth edges):
Any idea how to do that?
Note: I'm doing some more complex drawing on the widget, which must be restricted to the mask area, so I cannot simply set my PNG as the widget's background image.
I think your best route is in QPainter's composition modes.
For example:
QPixmap PixmapToBeMasked(Size);
PixmapToBeMasked.fill(QColor(255, 255, 255, 120));
QPixmap Mask = DoSomethingToGetAMask();
QPainter Painter(&PixmapToBeMasked);
Painter.setCompositionMode(QPainter::CompositionMode_DestinationIn);
Painter.drawPixmap(0, 0, Mask.width(), Mask.height(), Mask);
That will handle drawing your widget nicely. If you still need to mask mouse events you might need to do some extra work though.

Qt mouse cursor transparency

I would like to change the stock cursor with a translucent one, a simple filled circle, of various sizes, depending on the level of zoom in the underlying widget (say, RGBA = 200, 200, 200, 128).
Is this at all possible with Qt? If not, is it a limitation in Qt or the underlying libs? Do you have suggestions as to how this could be accomplished by other means, e.g., hiding the cursor and overlaying a transparent pixmap at the cursor position (albeit slower)? TIA
QCursor can take a QPixmap which does support alpha channel. So I don't see why it can't be done.
I just figured this out for a project of my own. I did it with this code in the constructor of the relevant widget:
m_LPixmap = new QPixmap(32,32);
m_LPixmap->fill(Qt::transparent); // Otherwise you get a black background :(
QPainter painter(m_LPixmap);
QColor red(255,0,0,128);
painter.setPen(Qt::NoPen); // Otherwise you get an thin black border
painter.setBrush(red);
painter.drawEllipse(0,0,32,32);
m_Cursor = QCursor(*m_LPixmap);
setCursor(m_Cursor);

Playing with Graphics in Flex

I was just going through one code used to draw one chart. This code is written in the updateDisplayList function of the ItemRenderer of ColumnChart. I am not good at the graphics part of Flex. Can anybody please explain me what this code is doing? I can see the final output, but am not sure how is this achieved.
var rc:Rectangle = new Rectangle(0, 0, width , height);
var g:Graphics = graphics;
g.clear();
g.moveTo(rc.left,rc.top);
g.beginFill(fill);
g.lineTo(rc.right,rc.top);
g.lineTo(rc.right,rc.bottom);
g.lineTo(rc.left,rc.bottom);
g.lineTo(rc.left,rc.top);
g.endFill();
Regards, PK
That code is drawing a rectangle, albeit in a bit of a roundabout way.
The drawing api in flash uses a "draw head". I can't see any reason for using g instead of graphics other than to save some typing. g.clear() erases anything that has been drawn before.
g.moveTo(rc.left, rc.top) moves that into position, in this case the top left corner of the rectangle (0,0). g.beginFill(fill) starts a fill, nothing surprising there.
The g.lineTo(x, y) calls move the draw head around to the the four corners of the rectangle and finally g.endFill() completes the fill.
You can get the same result doing this:
graphics.clear();
graphics.beginFill(fill);
graphics.drawRect(0, 0, width , height);
// this last call is only needed if you're going to draw even more,
// if not you can omit that too
graphics.endFill();
It basically draws a rectangle.
//clear any existing drawings
g.clear();
Set the current drawing position to the top-left corner of the rectangle, which is 0, 0
g.moveTo(rc.left,rc.top);
//start filling with the color specified by `fill`
g.beginFill(fill);
Draw a line to top-right corner of the rectangle from the current location (which is top-left corner). The lineTo method updates the current location so that subsequent drawings start from the new point.
g.lineTo(rc.right,rc.top);
Draw the remaining sides of the rectangle:
g.lineTo(rc.right,rc.bottom);
g.lineTo(rc.left,rc.bottom);
g.lineTo(rc.left,rc.top);
//end the fill.
g.endFill();
Check out the livedocs page for Graphics class for more info.
All the visual components in Flex inherit directly/indirectly from the UIComponent class. The updateDisplayList method of UIComponent draws the object and/or sizes and positions its children. This is an advanced method that you might override when creating a subclass of UIComponent. When you override it in your child class, you should call super.updateDisplayList with the correct parameters to make sure that the base class components are properly updated.
Degrafa makes this kind of thing much easier.

Resources