How to draw a border around a pixmap derived from png
-
Hello everyone. I have a QGraphicsItem. It receives an already processed pixmap with irregular shape and draws it. The pixmap is constructed from a png and the colour of the pixmap is changed via composition source in by the painter of the class, which processes the pixmap. Is there anyway for this class to also draw an outline(a border) around the edges of the pixmap?
I'm aware that QGraphicsPixmapItem has some kind of mask, but I am not sure constructinig it with the pixmap as an argument and then doing some unknown magic will work. Ideally I want to get a QPainterPath which represents the outlines of the shape of the pixmap and then tell the painter to draw it with a pen in any color or size. What is the correct way to do this? Which classes and methods should I use? -
Hi,
Wouldn't using QPainter to draw on your pixmap be enough ?
-
Of course, but how to tell QPainter to outline the pixmap around its borders?
-
This is my progress so far:
QPixmap CustomQGraphicsScene::getPixmap(bool outline) { QPixmap px("test.png"); QPainter painter(&px); painter.setRenderHint(QPainter::Antialiasing, true); painter.setBrush(Qt::green); painter.setCompositionMode(QPainter::CompositionMode_SourceIn); painter.fillRect(0, 0, px.width(), px.height(), Qt::green); if (!outline) return px; //constructing temp object only to get QPainterPath QGraphicsPixmapItem temp_pixmap_item(px); temp_pixmap_item.setShapeMode(QGraphicsPixmapItem::MaskShape); auto path = temp_pixmap_item.shape(); QPen pen(Qt::red, 50, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); painter.setPen(pen); painter.drawPath(path); return px; }I kinda get the result I wanted, but I have to create a QGraphicsPixmapItem, only to calculate the QPainterPath by calling the shape() function. Is there a different and faster way to get the shape without constructing a whole QGraphicsItem object?
-
Why not have custom QGraphicsPixmapItem that does the border drawing ?
-
Unfortunately It's a little more complicated than that :/ I have a custom qgraphicsitem, which recieves an already processed pixmap which is made of a png spritesheet. Depending on the user actions, the different textures are cut, formatted with certain color and outline and then positioned in certain places of the pixmap. Since it's a very complicated process, it is done outside of the scene, and when assembled the pixmap is sent to the QGraphicsItem in the scene and displayed by it in its paint function. Here are some screenshots to get what I mean:
the sprite sheet of the current tooth:

how does it look painted with the current tooth status:

-
Unfortunately It's a little more complicated than that :/ I have a custom qgraphicsitem, which recieves an already processed pixmap which is made of a png spritesheet. Depending on the user actions, the different textures are cut, formatted with certain color and outline and then positioned in certain places of the pixmap. Since it's a very complicated process, it is done outside of the scene, and when assembled the pixmap is sent to the QGraphicsItem in the scene and displayed by it in its paint function. Here are some screenshots to get what I mean:
the sprite sheet of the current tooth:

how does it look painted with the current tooth status:

Is there alpha in that pixmap? What I'd do is to underpaint a dilated version of the image, basically I'd run a filter on it once and save the result. Then underpaint the "shadow"/"outline" in the graphics item. Ideally this could be put in the actual sprite, though, couldn't it?
-
Is there alpha in that pixmap? What I'd do is to underpaint a dilated version of the image, basically I'd run a filter on it once and save the result. Then underpaint the "shadow"/"outline" in the graphics item. Ideally this could be put in the actual sprite, though, couldn't it?
Yes, at the beginning the border was hardpainted in the sprite. But then a problem arised - in some cases the outline should be red, but the inside color should be changed from blue to green so I scrapped that idea. The pixmap has a transparent fill, so probably it has alpha. Can you give me some simple code example of what filter are you talking about?
-
Yes, at the beginning the border was hardpainted in the sprite. But then a problem arised - in some cases the outline should be red, but the inside color should be changed from blue to green so I scrapped that idea. The pixmap has a transparent fill, so probably it has alpha. Can you give me some simple code example of what filter are you talking about?
@Hristo-Konstantinov said in How to draw a border around a pixmap derived from png:
Yes, at the beginning the border was hardpainted in the sprite. But then a problem arised - in some cases the outline should be red, but the inside color should be changed from blue to green so I scrapped that idea.
What inside color? I think I'm missing something.
The pixmap has a transparent fill, so probably it has alpha.
Yes, the transparency is "alpha" (i.e. the alpha channel).
Can you give me some simple code example of what filter are you talking about?
Not off hand, but I can point you to some resources I think.
This is "dilate": https://en.wikipedia.org/wiki/Dilation_(morphology)
and "erode": https://en.wikipedia.org/wiki/Erosion_(morphology)Ignore the math, the basic idea is similar to the median filter (the three are the same class of non-linear filters). Basically it goes like this:
- Take a window of say 3 by 3 pixels that you move over the image, the center pixel of the window is the pixel position in which you're going to write the filtered value in the resulting image.
- So the 9 pixels you have in the window you process in some fashion, for the median filter - take the median, for the dilate filter take the supremum (i.e. the maximum), for the erode - the infimum (i.e. the minimum). Now by value here I mean the alpha channel specifically. While you go you set the RGB to black/red/green w/e and you process the transparency - basically making the (visible) figure larger.
- Write the RGBA to the corresponding pixel in the resulting image.
Here's a toy project I'd made to illustrate color reduction in images. It's not what you want directly, but you can source some ideas on how to process images in Qt.
(And by images I mean
QImage, becauseQPixmapis truly abysmal for pixel-by-pixel operations). -
Thanks for the detailed answer! Definitely will check those out tomorrow.
I meant outline, not border. At first I drew the teeth surfaces in photoshop with red outline and blue inner part, and if I needed an outline, I just painted the sprite untouched. But then it became necessary in some cases for the inner part to be green (blue is filling, green is filling made by the user, red outline means filling with caries underneath), so I had to find a way to do all the painting runtime, while using only the alpha of the png. Anyway, the code I pasted above works for now. Again - many thanks for the guidance! -
Thanks for the detailed answer! Definitely will check those out tomorrow.
I meant outline, not border. At first I drew the teeth surfaces in photoshop with red outline and blue inner part, and if I needed an outline, I just painted the sprite untouched. But then it became necessary in some cases for the inner part to be green (blue is filling, green is filling made by the user, red outline means filling with caries underneath), so I had to find a way to do all the painting runtime, while using only the alpha of the png. Anyway, the code I pasted above works for now. Again - many thanks for the guidance!I was bored while I was chugging my coffee, so I made this micro-demonstration:
https://bitbucket.org/kshegunov/dilate/src/master/
I think this is what you wanted to achieve. Enjoy!
-
I was bored while I was chugging my coffee, so I made this micro-demonstration:
https://bitbucket.org/kshegunov/dilate/src/master/
I think this is what you wanted to achieve. Enjoy!
-
@mrjj said in How to draw a border around a pixmap derived from png:
Good coffee :)
You know the meme ;)

-
I was bored while I was chugging my coffee, so I made this micro-demonstration:
https://bitbucket.org/kshegunov/dilate/src/master/
I think this is what you wanted to achieve. Enjoy!
@kshegunov great work!
Only a small change needed in maxAlpha function:
maxI = std::min(x + window + 1, image.width()) maxJ = std::min(y + window + 1, image.height())Otherwise (without the
+1) there is a missing left pixel -
@kshegunov great work!
Only a small change needed in maxAlpha function:
maxI = std::min(x + window + 1, image.width()) maxJ = std::min(y + window + 1, image.height())Otherwise (without the
+1) there is a missing left pixelYes indeed. I completely missed that rightmost image pixel.
Do you mind opening a pull request so I can merge this in the repo?
