Drawing text with shadow on pixmap with QPainter - c++

I am working on a project in C++ with Qt, and I am trying to find a way to apply a text shadow when drawing text on a QPixmap using QPainter.
I understand that QGraphicsDropShadowEffect is a thing, and I am using in other parts of my project, but I can't for the life of me find a way to apply a QGraphicsEffect when drawing with QPainter on a pixmap. Drawing the same text multiple times with different offsets and opacities doesn't quite cut it.
Are there any ways to do this?
If not, how could I go about making a function that does it, given a QGraphicsEffect to get the radius and color from?
Thanks in advance!

I don't think it is directly possible to "draw text with shadow", it is only possible to apply a shadow to something already drawn that would take in an element and use say its alpha channel to calculate the shadow.
You should use composition, either of the final products or during drawing. It should work if you use it on a text element. The other option would be to draw your text in black, apply Gaussian blur and then again draw the text on top of it with the desired offset.

Thanks for your answer ddriver, it made me search with some new keywords, which lead me to find a suiting solution for my project.
What I figured out is that you can simply create a QLabel with the text and effects you want (QGraphicsDropShadowEffect, in my case), and render it into a QPixmap using QWidget::grab(). You can then draw this new pixmap with QPainter as you would any other image, by converting your pixmap to a QImage and using QPainter's drawImage().

Related

Draw semi transparent shadow around Window

I'm trying to do something like what Auslogics Disk Defrag does with its custom window:
As can be seen, the blurred semi transparent shadow surrounding the window is much darker than the standard one, so the program must be drawing it by itself. The problem is, I can't find a way to paint anything transparent around a window.
In an answer to a similiar question, someone suggested creating a slightly bigger transparent window (using WS_EX_LAYERED + SetLayeredWindowAttributes()) behind the actual application window, and then do the translucent drawing on the transparent one. Not only does it sound like an ugly hack, it doesn't actually work. If, for example, one tries to draw a semi transparent black rectangle on a transparent window via GDI+, alpha blending is applied to the shape's color over the window background color (which would also be the transparency color) and then the shape is drawn with the calculated color, which obviously is not the window transparency, resulting in an opaque rectangle.
The semi transparent shadow is actually done by Gaussian Blur of the black square.
You can use this effect to create glows and drop shadows and use the
composite effect to apply the result to the original image. It is
useful in photo processing for filters like highlights and shadows.
You can use the output of this effect for input into lighting effects,
like the Specular Lighting or Diffuse Lighting effects, because the
alpha channel is blurred, too and lighting effects use the alpha
channel to determine surface geometry as a height map.
This effect is used by the built-in Shadow effect.
Refer: Gaussian blur effect
Then remove the standard frame, the entire window is your client area, so you can draw shadow in the extended frame.
Refer: Drawing in the Extended Frame Window
I think I've found a solution that works for me. I was hoping I wouldn't have to create an extra window just for the shadow, but every method I could find or think of would require me to draw all the controls by myself and/or somehow correct their alpha values.
So, I'm using a layered window with per pixel alpha. I paint over it with Direct2D, or, alternatively, I use some PNGs with transparency for the edges and corners of the shadow and copy them on a memory DC. Either way I simply recreate the shadow with the right dimensions when the window is resized, and call UpdateLayeredWindowIndirect. Both methods seem to be working well on Windows 7 and 10, and so far I haven't found any glitches.
Preventing it from showing on the taskbar was a bit tricky. All the ways I know have drawbacks. What worked best for me was making the layered window owned by the main one. At least that way it will only be visible on the desktop where the program is actually running, unlike other alternatives which would force it to show on every virtual desktop. Finally, because I disable that window, I interact with it by processing WM_SETCURSOR.

Add a border to a QPixmap

I load a QPixmap from a file. I want to add a border around the QPixmap, say 4px white on each side.
What is the fastest way to do this? Do I have to create a second larger QPixmap and draw the first into the second or is there some way to extend the existing one without scaling (I've noticed that there is a QPixmap::transformed() but don't know if this is suitable in my case.
Do I have to create a second larger QPixmap and draw the first into the second
Yes.
is there some way to extend the existing one without scaling
Yes. The larger pixmap will take an unscaled copy of the original one.
The foregoing assumes that you care about the resulting pixmap. If you don't care about it, but only care to display the pixmap on a window/widget with some border, then simply draw the border and pixmap separately using QPainter, OpenGL geometry, etc.

Stroke and Fill Shapes in Cocos2dx

I am looking for a feature in Cocos2dx that is readily available in a couple presentation frameworks I have used.
Stroke and Fill Brushes
Rich shape rendering allows one to specify a shape (ellipse, rectangle, custom polygon, custom shape with curves, etc.), a location, a size, a stroke brush and a fill brush then render.
Below is an example of the feature. In this case the shape is a star with a variety of brushes.
Brush Varieties for Shape
I have searched for such functionality in Cocos2dx but the closest I could find is polygon rendering with a solid color stroke and fill. I used it and it worked well but is not the "smart brush" I am looking for.
Brush Animation
Second feature I am looking for is the ability to animate the brushes. In this example, the fill brush starts off green then either instantly changes to or animates to yellow. This is done by altering properties of the shape, not recreating.
Brush Animation Example
Is this possible in Cocos2dx? If not, could you provide suggestions about how I might code this?
I think CCSprite/CCLayerColor/CCLayerGradient with CCClippingNode can simulate the "smart brush", and tintTo/tintBy action of CCSprite/CCLayerColor can change color without destroying the object

(Qt C++) Resize pixmap and KEEP pixelation?

In my project I have a QLabel that I change the pixmap frequently like this:
ui->frameLabel->setPixmap(slot_pic[blockId[currentSlot]][damageId[currentSlot]]);
slot_pic is simply a 2d map. So you can look at it clearer like this:
ui->frameLabel->setPixmap(pixmap);
The image is 16x16 in size and my label is 32x32. I have scaledContents checked so when the pixmap changes, the image is double in size. However, the image is now blurry. I understand why, but I was wondering if there is a way to make it stay pixelated. I want to just have a bigger pixelated image. (The image is from Minecraft if that helps you understand what I mean)
Thanks for your time :)
Don't let the QLabel do the scaling. Instead, do the scaling by yourself using QPixmap::scaled(). Something like this:
ui->frameLabel->setPixmap(
pixmap.scaled(32, 32, Qt::IgnoreAspectRatio, Qt::FastTransformation));
The important parameter is the last one, transformMode, which tells whether bilinear filtering is used or not.

Coordinate confusion

I subclassed QGraphicsItem and reimplemented paint.
In paint I wrote something like this for labeling the item:
painter->drawText("Test",10,40);
After some time I think It may be useful to handle labeling with seperate item. So I wrote something like this.
QGraphicsTextItem *label = new QGraphicsTextItem("TEST",this);
setPos(10,40);
But two "TEST" drawing do not appear in the same place on screen. I guess difference may be related with item coordinates - scene coordinates. I tried all mapFrom... and mapTo... combinations inside QGraphicsItem interface but no progress. I want to drawings to appear in the same place on screen.
What I miss?
I assume that you are using the same font size and type in both cases. If the difference in position is very small the reason can be the QGraphicTextItem is using some padding for the text it contains. I would try to use QGraphicsSimpleTextItem that is not going to add fancy stuff internally and see if you still have the same problem. The coordinates system is the same one if you use painter or setPost so that is not the problem. If this doesn't help I will suggest to specify the same rect for both to avoid Qt adding it owns separation spaces.