vshvetsov 0 Posted February 27, 2023 (edited) Hi, I have this code for drawing an ellipse on a canvas: Canvas->Pen->Color = my_Color; Canvas->Brush->Color = my_Color; Canvas->Ellipse(my_rect); Ellipse is drawn over a background image. How can I draw it semitransparently? Sorry for posting such a question that seems to be explained in the available documentation. Spent several hours reading and trying, didn't succeed. Please help. Edited February 27, 2023 by vshvetsov Share this post Link to post
Remy Lebeau 1436 Posted February 27, 2023 45 minutes ago, vshvetsov said: Ellipse is drawn over a background image. How can I draw it semitransparently? You can't, well not directly anyway. You can draw it opaquely onto an in-memory bitmap first, and then draw that bitmap onto your target Canvas with alpha/transparency applied to it as needed. Share this post Link to post
vshvetsov 0 Posted February 27, 2023 Thank you. I tried to do it, but I didn't succeed. I created a bitmap: bitmap = new Graphics::TBitmap(w, h); and drew a circle in it. Then I drew it in TCanvas: Canvas->Draw(x, y, bitmap, opacity); The problem is that the whole rectangle is drawn as translucent, not just the ellipse. To remove the margins around the ellipse, I set: bitmap->Transparent = true; bitmap->TransparentColor = clWhite; // the color of margins, can also be determined automaticaly // as a color of the left-most pixel Then the ellipse is drawn without margins, as needed, but it is not translucent any more: Canvas->Draw() ignores the opacity value. I don't understand how to get a translucent ellipse without margins... Share this post Link to post
Remy Lebeau 1436 Posted February 28, 2023 (edited) 1 hour ago, vshvetsov said: Then I drew it in TCanvas: Canvas->Draw(x, y, bitmap, opacity); I was thinking more along the lines of creating a 32bit Bitmap with an alpha channel and then using the Win32 AlphaBlend() API to draw the bitmap onto the Canvas (I forgot that TCanvas.Draw() has an opacity parameter). Edited February 28, 2023 by Remy Lebeau Share this post Link to post
angusj 126 Posted February 28, 2023 I've attached a pretty old unit with numerous functions for managing semi-transparent VCL.Graphics.TBitmap controls. However, unless your graphics needs are minimal, I strongly recommend you consider using an open source graphics library. Two graphics libraries for Delphi I can recommend: Graphics32: Multiple developers contributed over the last 20yrs and is widely used. Image32: Recently developed by me. IMHO it's a lot simpler than Graphics32 while almost as fully featured. AlphaBitmaps.pas 2 Share this post Link to post
vshvetsov 0 Posted February 28, 2023 (edited) 7 hours ago, angusj said: ITwo graphics libraries for Delphi I can recommend: Graphics32: Multiple developers contributed over the last 20yrs and is widely used. Image32: Recently developed by me. IMHO it's a lot simpler than Graphics32 while almost as fully featured. Thanks for the tips. 1) I am programming in C++. The VCL provides C++ header files for using classes and functions. How will I use the Image32 (or Graphics32) library? 2) Can I use Image32 in a 64-bit Windows application? Edited February 28, 2023 by vshvetsov Share this post Link to post
angusj 126 Posted March 1, 2023 (edited) 14 hours ago, vshvetsov said: 1) I am programming in C++. The VCL provides C++ header files for using classes and functions. How will I use the Image32 (or Graphics32) library? While I can't guarantee it, this is likely to help: http://www.angusj.com/delphi/image32/Videos/cpp.mkv 14 hours ago, vshvetsov said: 2) Can I use Image32 in a 64-bit Windows application? Absolutely! Edit: The 32 in the library name simply refers to image bits per pixel WRT how images are stored in memory. (And yes the library can read and write images to file using different bpp.) Edited March 1, 2023 by angusj Share this post Link to post
vshvetsov 0 Posted March 4, 2023 On 3/1/2023 at 5:07 AM, angusj said: While I can't guarantee it, this is likely to help: http://www.angusj.com/delphi/image32/Videos/cpp.mkv Absolutely! Edit: The 32 in the library name simply refers to image bits per pixel WRT how images are stored in memory. (And yes the library can read and write images to file using different bpp.) Hi, Angus! Thank you for your answers. Before using libraries I tried to do smth manually. I would be grateful, if you could explain me some things. I draw a rather colorful image on the form. In fact, this is a map of the city, on top of which I draw lines, polygons, etc. I want to highlight the circle on the map, giving it some shade, for example, blue. I created a memory bitmap, set PixelFormat = pf32bit and AlphaFormat = afDefined, filled it with clBlack and drew a circle with clBlue brush. Then I manually (using ScanLine property) set the reserved byte of black pixels to 0, and of blue pixels - to some alpha-value. Then I drew this bitmap on a form using AlphaBlend() API function. The result is close to expected, but there are oddities. The circle does not become completely transparent with alpha=0. The result is also highly dependent on the color of the circle. For example, if we take gray instead of blue, the circle is almost white, opaque, even with alpha=0. I fill the bitmap with black around the circle because that's the only color that becomes fully transparent at alpha=0. Why is this happening? Share this post Link to post
angusj 126 Posted March 4, 2023 (edited) 6 hours ago, vshvetsov said: Why is this happening? I strongly suspect that this is because you haven't pre-multiplied the image before using AlphaBlend. Quote Note that the APIs use premultiplied alpha, which means that the red, green and blue channel values in the bitmap must be premultiplied with the alpha channel value. For example, if the alpha channel value is x, the red, green and blue channels must be multiplied by x and divided by 0xff prior to the call. https://learn.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-blendfunction Here's a (rather poor) example of using AlphaBlend where the image is premultiplied. There's also a PremultiplyAlpha function in my AlphaBitmaps.pas unit. Edited March 4, 2023 by angusj Share this post Link to post
vshvetsov 0 Posted March 5, 2023 13 hours ago, angusj said: I strongly suspect that this is because you haven't pre-multiplied the image before using AlphaBlend. Exactly. After pre-multiplication everything was fixed, thank you very much. A new question has arisen. It turns out that in the structure TRGBQuad the order of colors is reversed in comparison to the VCL type TColor. With a simple reinterpretation of TColor as TRGBQuad, blue becomes red, and vice versa. TColor is widely used in a VCL-application. As I understand it, your TColorEntry type in AlphaBitmaps.pas is compatible with TRGBQuad, that is, the same problem should arise with TColor. I rearrange the bytes manually. Is there any standard conversion function? Share this post Link to post
EugeneK 19 Posted March 13, 2023 You can easily do it with Direct2D // ... uses Winapi.D2D1, Vcl.Direct2D; // ... procedure TForm1.Button3Click(Sender: TObject); begin if (TDirect2DCanvas.Supported) then begin var D2DCanvas := TDirect2DCanvas.Create(Canvas, ClientRect); try D2DCanvas.Font.Assign(Font); D2DCanvas.RenderTarget.BeginDraw; D2DCanvas.RenderTarget.SetAntialiasMode(D2D1_ANTIALIAS_MODE_PER_PRIMITIVE); D2DCanvas.Brush.Color := clRed; D2DCanvas.Brush.Handle.SetOpacity(0.5); D2DCanvas.Ellipse(10, 10, 200, 200); D2DCanvas.RenderTarget.EndDraw; finally D2DCanvas.Free; end; end end; 1 Share this post Link to post
Remy Lebeau 1436 Posted March 13, 2023 (edited) On 3/5/2023 at 5:39 AM, vshvetsov said: A new question has arisen. It turns out that in the structure TRGBQuad the order of colors is reversed in comparison to the VCL type TColor. With a simple reinterpretation of TColor as TRGBQuad, blue becomes red, and vice versa. TColor is an enum representing an integer, and so it is subject to endian. TRGBQuad is not. You should be using the ColorToRGB() function to convert an TColor value into an integer value, and then using the Get(R|G|B)Value() functions to obtain the individual R/G/B values of that integer. The PremultiplyAlpha() function is operating on a bitmap's raw R/G/B pixel bytes directly, it is not going through TColor at all. Edited March 13, 2023 by Remy Lebeau Share this post Link to post