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);
}
Related
I am creating an Circle on a bitmap but want to have a hole in it. After serching for half an hour I only found ways to crop an image to a circle. The hard thing is, that the hole in the middle should be transparent as the rest of the Image.
This is the base image and the yellow circle represents the transparent area that should be added.
Thanks for any kind of help.
The start is simple: Create a transparent bitmap by doing a g.Clear(Color.Transparent) and then draw/fill a circle in a color.
The next step is a bit trickier: You next want to paint the hole with transparency.
To do so you need to switch the Graphics object to the right CompositingMode; default is SourceOver but you want SourceCopy. The former overlays the alpha values creating mixed colors. The latter will do what we want: Draw the hole by copying the drawn colors including alpha right over the old ones..
Here is an example:
Bitmap bmp = new Bitmap(500, 500);
using (Graphics g = Graphics.FromImage(bmp))
{
g.Clear(Color.Transparent);
//g.SmoothingMode = SmoothingMode.AntiAlias;
g.CompositingMode = CompositingMode.SourceCopy;
g.FillEllipse(Brushes.DarkGreen, 100, 100, 300, 300);
g.FillEllipse(Brushes.Transparent, 200, 200, 100, 100);
}
pictureBox1.Image = bmp;
This is what is looks like in a PictureBox with a BackgroundImage:
A few notes:
You can also use a semi-transparent brush to create a 'tinted' hole; do not use anti-aliasing for this though, as it would introduce colored fringes.
We used simple circles here but with a GraphicsPath you can create and fill shapes of almost any shape and complexity..
And using a GraphicsPath would also have been an alternative to filling with transparency: By first adding the large and then the smaller, inner ellipse the path would have been created with a hole and filling it would have had the very same result! But I found the solution above more instructive..
Final note: As clarkitect noted, to save, do use a format that supports transparency. Png is always recommended..
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.
This might sound like a weird question but I have C# Winform that I set the FormBorderStyle to None. So far everything is good but I was wondering if there was a way to add like a 1px border on around my form ? I know I could do it by creating my own image but I was wondering if there was a more natural way of doing it.
Thanks
I consider using an image, or creating unnecessary controls for something that is easily paintable using GDI+ a waste of resources.
I think the simplest solution is overriding the OnPaint method of your form and drawing the border yourself:
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.DrawRectangle(Pens.Black, this.Bounds);
}
Of course, you may also use your own Pen with your own color and width.
Use padding 1;1;1;1 to your form and set a background color to your form, and put a panel to your form. Set white or other normal background color to the panel. And set dock in parent controller. The background color of the form will act as a border.
How about just adding a Panel (and setting it's border) to the Form?
Thanks for the suggestions, I've decided to create 4 1px label and just toss on the edge on each side. That way:
1. They are minding their own business on the side rather than taking up the whole middle if you use use a groupbox or panel.
2. You are able to choose change your border color.
There is no more natural or non natural ways to do it. It depends on what you want.
If you put a background image on the form, you have to consider a fact that in order to be able to support resizable for you have to have resizable background images.
If you simply draw on the background with a Pen or Brush, you can support also resizable form, but you have to work more if you want to do something cool, instead with image it's easier.
You can embed some control inside the form and with color's of them make a feeling of the border. Like control, you can use Panel, as suggested in comment, can use GroupBox that creates thin broder arround, or something else.
I created this method, so you could easily set the borderposition, color and thickness.
private void customBackgroundPainter(PaintEventArgs e, int linethickness = 2, Color linecolor = new Color(), int offsetborder = 6)
{
Rectangle rect = new Rectangle(offsetborder, offsetborder, this.ClientSize.Width - (offsetborder * 2), this.ClientSize.Height - (offsetborder * 2));
Pen pen = new Pen(new Color());
pen.Width = linethickness;
if (linecolor != new Color())
{
pen.Color = linecolor;
}
else
{
pen.Color = Color.Black;
}
e.Graphics.DrawRectangle(pen, rect);
}
You could use it in the OnPaintBackground likes this:
protected override void OnPaintBackground(PaintEventArgs e)
{
base.OnPaintBackground(e);
customBackgroundPainter(
e,
linethickness: 3,
linecolor: Color.DarkOrange,
offsetborder: 5
);
}
We have a winforms app (Framework v4) that shows an image (via PictureBox) on the screen and allows selection of a rectangular region on that image. During and after the image selection, we show the boundary of the selected area. This is currently done via a DrawRectangle call.
The problem is how to choose the color of this rectangle. Regardless of the chosen color, it is always possible that it will blend into the background (the image). Microsoft paint handles this very well by reversing the colors dynamically on the "selection rectangle". This suits very well to our application, but I have no idea how to do it in winforms.
I also looked around to see if there's a dash-style that would allow two colors to be used (so that I could specify black and white as these colors, making it visible no matter what the background colors are), but I could not find anything of this sort.
Thanks in advance for all the help.
you can use ControlPaint methods to paint a reversible rectangle/frame
ControlPaint.FillReversibleRectangle MSDN
and
ControlPaint.DrawReversibleFrame MSDN
here is a little pseudo code method example
private void DrawReversibleRectangle(int x, int y) {
// Hide the previous rectangle by calling the methods with the same parameters.
var rect = GetSelectionRectangle(this.PointToScreen(this.reversibleRectStartPoint), this.PointToScreen(this.reversibleRectEndPoint));
ControlPaint.FillReversibleRectangle(rect, Color.Black);
ControlPaint.DrawReversibleFrame(rect, Color.Black, FrameStyle.Dashed);
this.reversibleRectEndPoint = new Point(x, y);
// Draw the new rectangle by calling
rect = GetSelectionRectangle(this.PointToScreen(this.reversibleRectStartPoint), this.PointToScreen(this.reversibleRectEndPoint));
ControlPaint.FillReversibleRectangle(rect, Color.Black);
ControlPaint.DrawReversibleFrame(rect, Color.Black, FrameStyle.Dashed);
}
You mention an alternative solution would be to draw a dashed line in two colors, black and white, so that it would be visible on any background.
Fake this by drawing solid line in one color (e.g. black), then draw a dashed line in the other color (e.g. white).
Idea and code from: http://csharphelper.com/blog/2012/09/draw-two-colored-dashed-lines-that-are-visible-on-any-background-in-c/
using (Pen pen1 = new Pen(Color.Black, 2))
{
e.Graphics.DrawRectangle(pen1, rect);
}
using (Pen pen2 = new Pen(Color.White, 2))
{
pen2.DashPattern = new float[] { 5, 5 };
e.Graphics.DrawRectangle(pen2, rect);
}
I want to know how to change the background color when I generate the image dynamically.
Just use the Graphics object .Clear() method, passing the color you wish to use for the background.
For example:
g.Clear(Color.Blue);
It's simple:
Graphics graph = Graphics.FromImage(bitmap);
graph.Clear(Color.Yellow); // set color for background
If you're talking about a specific file format's "background color" field, I'm not sure if GDI+ supports that, but usually to set the background color of an image you'd fill a rectangle the size of the image with one color.
Example, assuming g is your Graphics object, image is your Image object, and color is your Color object:
g.FillRectangle(new SolidBrush(color), new Rectangle(Point.Empty, image.Size));
Also, as FlipScript suggested, you can use the Clear method. (I had no idea it existed!)
g.Clear(color);