Drawing opacity on a transparent Form C# - c#

I have a form that is transparent. (done simply by matching the background color, and transparency key.
When attempting to draw things that are transparent, it simply does not work. As the alpha variable gets closer to 0, the color drawn simply gets closer to the original background color of the form.
SolidBrush opaqueBrush = new SolidBrush(Color.FromArgb(255, 0, 0, 255));
SolidBrush semiTransBrush = new SolidBrush(Color.FromArgb(128, 0, 0, 255));
SolidBrush superTransBrush = new SolidBrush(Color.FromArgb(10, 0, 0, 255));
using these 3 brushes to draw on a regular form would result in the desired effect. But using it on my transparent form simply matches superTransBrush with my transparencyKey/ Background color, and the semiTransBrush is somewhere between my desired color and the background. Anyway around this?

There does not seem to be a way around this from .NET Forms itself.
The definition of alpha blending in .NET states:
The alpha value indicates the transparency of the color — the extent
to which the color is blended with the background color. Alpha values
range from 0 through 255, where 0 represents a fully transparent
color, and 255 represents a fully opaque color.
Alpha blending is a
pixel-by-pixel blending of source and background color data. Each of
the three components (red, green, blue) of a given source color is
blended with the corresponding component of the background color
according to the following formula:
displayColor = sourceColor × alpha / 255 + backgroundColor × (255 – alpha) / 255
Notice there's no consideration given to the transparency of the background itself when calculating alpha blending.
The closest workaround would be to set the CompositingMode to source copy:
e.Graphics.CompositingMode = CompositingMode.SourceCopy;
This prevents blending the transparent colour with the background colour, so your brush will be blue, instead of a blend of blue + background colour. Your brush will still be opaque, however.

Background
Windows Forms is build on top of GDI and GDI+.
GDI is a very old technology dating back a long way in Windows history, and wasn't designed to be alpha aware.
GDI+ Which was shipped with WindowsXP and successors was designed to complement GDI with alpga blending, anti-aliasing, and other such features you'd expect from a modern 2D graphics library.
Unfortunately, GDI+ does not make GDI alpha aware, it only fakes alpha in some cases.
Your Scenario
In your case, it's faking the alpha channel, and drawing the SolidBrush color onto your form, before performing the transparency operation to the form, thus, the renderer sees a different color to the one you specified for transparency and ignores it.
My Scenario
In my case, I was trying to draw a drop shadow to a borderless form. It worked. but it was buggy as hell.
I have achieved what you're trying to do, but you won't do it purely with Managed C#/.NET; you're going to have to call into GDI/GDI+ directly using P/Invoke.

Related

Change InkDrawingAttributes Opacity for Pen brush

I using a color picker to draw with a pen, but using this code I can't change de opacity of the pen color:
InkDrawingAttributes inkDrawingAttributes = InkCanvas.InkPresenter.CopyDefaultDrawingAttributes();
inkDrawingAttributes.Color = ColorPenSelected;
InkCanvas.InkPresenter.UpdateDefaultDrawingAttributes(inkDrawingAttributes);
This way works well with a pen:
But, using the InkCanvas.InkPresenter.CopyDefaultDrawingAttributes() the inkDrawingAttributes.PencilProperties is null and I can't change the Opacity. It is not allowed to change the opacity.
I could change the opacity with this code:
InkDrawingAttributes inkDrawingAttributes = InkDrawingAttributes.CreateForPencil();
inkDrawingAttributes.Color = ColorPenSelected;
inkDrawingAttributes.PencilProperties.Opacity = (double)ColorPenSelected.A * 5 / 255;
InkCanvas.InkPresenter.UpdateDefaultDrawingAttributes(inkDrawingAttributes);
Using as a pencil in CreateForPencil().
Now, I could change the Opacity. However, the brush texture is different, even using Opacity 100%, compared to the first image. There are many dots in the line, instead an unique line:
So, How can I change the opacity for the Pen brush and keep the same texture as the first image? With a continuous line, without dots as in the second image.
I initially thought that you could set the inkDrawingAttributes.Color as an ARGB value, but this isn't possible for the below reason.
Taken from learn.microsoft.com
The value of Color is an ARGB value. However, the value of the
transparency component (A, or alpha channel) is ignored and the
InkStroke is rendered at full opacity.
I'm afraid it would seem that this isn't possible. You could perhaps render the stroke as semi transparent afterwards - But doesn't seem like you can set the opacity of the pen.

Set MaterialPropertyBlock color alpha in Unity with C#

I am changing the color of a mesh by setting a MaterialPropertyBlock like so
mpb = new MaterialPropertyBlock();
Color color = Color.red
mpb.SetColor("_Main", color);
_meshRenderer.SetPropertyBlock(mpb);
The issue is the color is applied at its 100% intensity. There is no alpha property on the color or the MaterialPropertyBlock.
Can you suggest how I can make this color change more gradual via an alpha? I would like to tween in and out the red effect instead of it just being 100% on or off (note: I know I am not using a tween here as I would tween the alpha once I know how to set it above).
Update
As per a suggestion from #TEEBQNE I tried setting the alpha in the constructor but even at 0 it showed up at full intensity
mpb = new MaterialPropertyBlock();
Color color = new Color(0, 255, 0, 0f); // Still shows 100% color change
mpb.SetColor("_Main", color);
_meshRenderer.SetPropertyBlock(mpb);
Update
This issue was shader specific and I had to set another property (specifically the "_Color" alpha property). So my general answer is that to add color + alpha will depend on your specific shader and a specific named property.
I am unfamiliar with your current shader, but you can change the RenderMode of your Material to Transparent or one of the other alternates to transparency.
Once you do that, when you change the Albedo alpha channel of your texture, the alpha will change your object.
From the docs, changing the alpha of the albedo
...has an effect if the Rendering Mode for the material is set to one
of the transparent mode, and not Opaque

Advanced color blending with GDI+

Using GDI+ with Windows Forms, I want to be able to draw with a pen and blend color based on the destination pixel color.
For example, if I draw a line and it passes over black pixels, I want it to be a lighter color (like white for example) so that it's visible. When that same line passes over white pixels, it should be a darker color (black for example) so that it's still clearly visible.
Is there any way to do this with GDI+?
As Hans Passant proposed, you could paint using what's currently in the canvas as the image for a texture brush (you might need double buffering for that to work correctly) and use a ColorMatrix to modify the colors being painted on the canvas.
There is a color matrix that inverts the colors similar to a XOR, the problem is it won't work with the middle gray. A color matrix that inverts RGB and leaves alpha intact would be:
-1, 0, 0, 0, 0
0,-1, 0, 0, 0
0, 0,-1, 0, 0
0, 0, 0, 1, 0
1, 1, 1, 0, 1
Something similar, albeit slower would be to copy the canvas to an image and process that image pixel per pixel with rules such as if the color is brighter than 0.5, make it slightly darker else, make it slightly brighter. Then, you paint with that processed image as a texture brush. This would give a better result but it would be significantly slower than using a ColorMatrix.
You could try XORing the pen color. Paint.NET does this with the selection border to make it visible on any color.
Oh, I don't think this is too difficult. You could create a pen that automatically changes colors based on wherever it is. Simply read the pixel at where the location of the pen is (See example), Get the Alpha component and set the pen color to black or white if it's greater than or less than 255/2 respectively :)

GDI+ text has a black edge

I'm clearing an image with a transparent color (120 alpha) and then drawing a string onto it with a gradient, and then drawing that image onto a larger image but the text has blackish edge to it instead of being nice and smooth like it should be. The text looks fine if the background is drawn with 255 alpha.
120 Alpha: Image
255 Alpha: Image
As you can see, the text is much easier to read with the background fully opaque
Note: the green dot is my cursor
Edit: gfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias; removes the black edges but it's blurry, I'll try some other combinations of graphics settings and see how this goes.
Edit: gfx.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit; Looks much better, although the A's in the Arial font look a little funky
This is normal behaviour. You must change your drawing order to get it right.
Since you draw the text onto a semi-transparent surface its anti-aliasing pixels will be semi-transparent, too, but somwehre in-between the text color and the background of the first image.
Now, if you draw the result onto another image you will have uniform transparent pixels where no text is, no transparency where text is and varying tranparencies and colors for the antialiasing pixels.
Note that those will have various colors as the antialiasing tries to spread color diferences as well as differences in brightness.
Either write on a non-transparent surface or delay the writing to the end. (Or turn off all anti-aliasing. But that's not nice.)

Is there a way to paint semi transparently on a PictureBox?

I use a transparent background for the PictureBox control.
But I also want to be able to paint with a %50 opacity blue FillRectangle.
How to do this?
.NET WinForm controls themselves do not support transparency, but GDI+ does as far as general rendering goes. If you are rendering onto a PictureBox (or onto anything else) and want to render something with partial opacity, then create a color with an alpha value less then 255 (opaque) and use it to create a brush or pen.
For example:
Color c = Color.FromArgb(128, Color.Blue);
using (Brush b = new SolidBrush(c))
{
e.Graphics.FillRectangle(b, 0, 0, 50, 50);
}

Categories

Resources