How to draw with replacement instead of blending - c#

I'm trying to "draw" areas of transparency onto a bitmap -- like cutting holes in the image.
The following code does not draw a line of transparency because drawing a transparent line onto a bitmap of course blends instead of replaces. (Why the default is to do the more complicated of the two drawing operations, makes no sense.)
Bitmap myBitmap = new Bitmap(50, 50);
Graphics g = Graphics.FromImage(myBitmap);
g.FillRectangle(Brushes.Black, 0, 0, 50, 50);
g.FillEllipse(Brushes.Transparent, 25, 0, 25, 25); //Does nothing
g.DrawLine(Pens.Transparent, 0, 0, 50, 50); //Does nothing
How would I modify this so that a transparent circle and line replace what's in the bitmap instead of blending?
(Note that this is the trivial case of "drawing" complete transparency. The end I'm going toward is the ability to "draw" modifying the alpha channel only without creating my own pixel by pixel operation. Being able to do complete transparency will suffice though.)
Following answer in article suggested as a duplicate, I've also tried the following (which does not work)
base.OnPaint(e);
Bitmap myBitmap = new Bitmap(50, 50);
e.Graphics.FillRectangle(Brushes.Black, 0, 0, 50, 50);
Graphics g = Graphics.FromImage(myBitmap);
g.FillEllipse(new SolidBrush(Color.FromArgb(150, 125, 125, 125)), 25, 0, 25, 25);
g.DrawLine(new Pen(Color.FromArgb(150,25,25,25)), 0, 0, 50, 50);
g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
e.Graphics.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
e.Graphics.DrawImage(myBitmap, 0, 0);
also tested this with SourceCopy

This works totally fine for me
Bitmap bmp = new Bitmap(50, 50, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
using (Graphics g = Graphics.FromImage(bmp))
{
g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
g.FillRectangle(Brushes.Black, 0, 0, 50, 50);
g.FillEllipse(Brushes.Transparent, 25, 0, 25, 25);
g.DrawLine(Pens.Transparent, 0, 0, 50, 50);
g.Flush();
}
bmp.Save("Test.bmp");

Related

Change image color with transparent background

I need to load an image with green circle over a transparent background into a bitmap image using c# (System.Drawings).
That's the easy part. However I need to change the color of the circle before adding it to the bigger image, without affecting the transparency of the surrounding. In my case I need to change the circle color to yellow and add it as a sun.
I can't use fixed yellow circle image because the desired color is dynamic.
So in the code below, how can I change the color of the image before adding it to the bitmap?
Image i = Image.FromFile(greenCircleFile);
Bitmap b = new Bitmap(500, 500);
using(Graphics g = Graphics.FromImage(b))
{
//--> Here I need to change the color of the green circle to yellow
//afterwards I can add it to the bitmap image
g.DrawImage(i, 0, 0, 500, 500);
}
Please note that two things need to be into consideration: Keeping the anti-aliasing of the shape (circle), and the color needs to be picked by user and used as is to overlay the original color of the circle.
Fixed:
Thanks to #TaW, he provided the correct answer. However with a glitch, here's the final version that worked for me:
Image i = Image.FromFile(greenCircleFile);
Bitmap b = new Bitmap(500, 500);
using(Graphics g = Graphics.FromImage(b))
{
//Here I need to change the color of the green circle to yellow
i = ChangeToColor(b, Color.Gold)
//afterwards I can add it to the bitmap image
g.DrawImage(i, 0, 0, 500, 500);
}
While ChangeToColor function is as follows:
Bitmap ChangeToColor(Bitmap bmp, Color c)
{
Bitmap bmp2 = new Bitmap(bmp.Width, bmp.Height);
using (Graphics g = Graphics.FromImage(bmp2))
{
float tr = c.R / 255f;
float tg = c.G / 255f;
float tb = c.B / 255f;
ColorMatrix colorMatrix = new ColorMatrix(new float[][]
{
new float[] {0, 0, 0, 0, 0},
new float[] {0, 0, 0, 0, 0},
new float[] {0, 0, 0, 0, 0},
new float[] {0, 0, 0, 1, 0},
new float[] {tr, tg, tb, 0, 1}
});
ImageAttributes attributes = new ImageAttributes();
attributes.SetColorMatrix(colorMatrix);
g.DrawImage(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height),
0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, attributes);
}
return bmp2;
}
This will create a new Bitmap with all non-transparent pixels moved strongly toward a new color:
Bitmap ChangeToColor(Bitmap bmp, Color c)
{
Bitmap bmp2 = new Bitmap(bmp.Width, bmp.Height);
using (Graphics g = Graphics.FromImage(bmp2))
{
float tr = c.R / 255f;
float tg = c.G / 255f;
float tb = c.B / 255f;
ColorMatrix colorMatrix = new ColorMatrix(new float[][]
{
new float[] {0, 0, 0, 0, 0},
new float[] {0, 0, 0, 0, 0},
new float[] {0, 0, 0, 0, 0},
new float[] {0, 0, 0, 1, 0},
new float[] {tr, tg, tb, 0, 1} // kudos to OP!
});
ImageAttributes attributes = new ImageAttributes();
attributes.SetColorMatrix(colorMatrix);
g.DrawImage(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height),
0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, attributes);
}
return bmp2;
}
do make sure not to leak the Bitmaps you create!
Note that there are other methods as well. Here is a link to a method that uses ColorMapping. This allows for a range of colors to be replaced by another range, so it can keep gradients like the ones you get in anti-alised graphics..
Here's my solution you just need to create a new Control
then inherit the Picturebox check this out.
public partial class UICirclePicture : PictureBox
{
[Browsable(false)]
public int Depth { get; set; }
[Browsable(false)]
public SprikiwikiUI Ui
{
get { return SprikiwikiUI.Instance; }
}
[Browsable(false)]
public MouseState MouseState { get; set; }
public UICirclePicture()
{
BackColor = Ui.GetApplicationBackgroundColor();
SizeMode = PictureBoxSizeMode.StretchImage;
}
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
using (var gp = new GraphicsPath())
{
gp.AddEllipse(new Rectangle(0, 0, this.Width - 1, this.Height - 1));
this.Region = new Region(gp);
}
}
}

Draw clockwise filled in circle

I'm trying to make a cooldown visual for my game when actions are used. I want the button that I have that is the action to be filled with a grayish semi-transparent color that "unwinds" clockwise (if that makes sense). Games like World of Warcraft do this where the time it takes for the cooldown is the time the angle of the unwinding takes. You can see an example here. In this picture the cooldown is more than 1/2 way finished.
http://www.vbforums.com/attachment.php?attachmentid=101705&stc=1&d=1372575930
I'm playing around with arc drawing but this doesn't give me what I'm after.
if (globalCD)
{
Pen p = new Pen(Color.FromArgb(125, 255, 0, 0), 10);
//e.Graphics.DrawLine(p, new Point(0, 0), new Point(10, 10));
e.Graphics.DrawArc(p, new Rectangle(0, 0, 64, 64), 270, 270);
}
In general, the Graphics class has a FillX method for each DrawX method. In this case the result is sufficiently different that the names actually change a bit, but you likely want the FillPie method.
if (globalCD)
{
Pen p = new Pen(Color.FromArgb(125, 255, 0, 0), 10);
//e.Graphics.DrawLine(p, new Point(0, 0), new Point(10, 10));
e.Graphics.FillPie(p, new Rectangle(0, 0, 64, 64), 270, 270);
}

how to fill C# Fill rectangle From bottom to top?

I have drawn vertical Rectangle but i want to fill it from bottom to top.
here is the code i used
System.Drawing.Drawing2D.LinearGradientBrush linGrBrush =
new System.Drawing.Drawing2D.LinearGradientBrush(
new Point(0, 12),
new Point(0,2),
Color.FromArgb(0, 0, 0, 0),
Color.FromArgb(255, 190, 0, 0));
Pen pen = new Pen(linGrBrush);
e.Graphics.FillRectangle(linGrBrush,groupBox2.Width -50,10, 25, x);
using (Pen Pen1 = new Pen(Color.BurlyWood, 4))
{
e.Graphics.DrawRectangle(Pen1, groupBox2.Width -50,10, 25, 200);
}
x is color fill offset which fill is used to fill rectangle after every 2 seconds.
I think that you should adjust the starting and the ending points of the gradient:
System.Drawing.Drawing2D.LinearGradientBrush linGrBrush =
new System.Drawing.Drawing2D.LinearGradientBrush(
new Point(0, 1),
new Point(0,0),
Color.FromArgb(0, 0, 0, 0),
Color.FromArgb(255, 190, 0, 0));

How to paint a color with alpha over an image - C#/.NET

What I'm trying to do is paint a solid color and/or pattern with some degree of opacity over an existing image. I believe from what I've read this will involve a bitmap mask. The examples I've seen using bitmap masks as opacity masks only show them used against images to crop them a certain way, and I want to use it for painting. Here is basically what I'm trying to accomplish:
The first image is being loaded and drawn onto a derived Canvas class using DrawImage. I'm trying to accomplish what you see in the 3rd image, the 2nd is an example of a mask I might use. The two key points being that the blue surface in the 3rd image needs to be any arbitrary color, and it needs some opacity so that you can still see the shading on the underlying image. This is kind of a simple example, some of the other objects have much more surface detail and much more complicated masks.
A color matrix can be useful here:
private Image tooth = Image.FromFile(#"c:\...\tooth.png");
private Image maskBMP = Image.FromFile(#"c:\...\toothMask.png");
protected override void OnPaint(PaintEventArgs e) {
base.OnPaint(e);
e.Graphics.DrawImage(tooth, Point.Empty);
using (Bitmap bmp = new Bitmap(maskBMP.Width, maskBMP.Height,
PixelFormat.Format32bppPArgb)) {
// Transfer the mask
using (Graphics g = Graphics.FromImage(bmp)) {
g.DrawImage(maskBMP, Point.Empty);
}
Color color = Color.SteelBlue;
ColorMatrix matrix = new ColorMatrix(
new float[][] {
new float[] { 0, 0, 0, 0, 0},
new float[] { 0, 0, 0, 0, 0},
new float[] { 0, 0, 0, 0, 0},
new float[] { 0, 0, 0, 0.5f, 0},
new float[] { color.R / 255.0f,
color.G / 255.0f,
color.B / 255.0f,
0, 1}
});
ImageAttributes imageAttr = new ImageAttributes();
imageAttr.SetColorMatrix(matrix);
e.Graphics.DrawImage(bmp,
new Rectangle(Point.Empty, bmp.Size),
0,
0,
bmp.Width,
bmp.Height,
GraphicsUnit.Pixel, imageAttr);
}
}
The 0.5f value in the Matrix declaration is the alpha value.

Drawing Text on monochrome Bitmap in C#

My problem is that I need to draw text on a monochrome bitmap. The resulting bitmap has to be printed on a thermal POS printer, so the bitmap has to be 1bpp.
I'm not good in graphics, so I've tried to find some samples.
Here's what I've tried:
Bitmap bmp = new Bitmap(300, 300, PixelFormat.Format1bppIndexed);
using (Graphics g = Graphics.FromImage(bmp))
{
Font font = new Font("Arial", 20, FontStyle.Bold, GraphicsUnit.Point);
g.Clear(Color.White);
g.DrawString(text, font, Brushes.Black, 0, 0);
}
bmp.Save(#"c:\x\x.bmp", ImageFormat.Bmp);
the Save at the end was just to check the result.
With this code, I get the following exception: A Graphics object cannot be created from an image that has an indexed pixel format.
Is there ANY way to draw text to a monochrome memory bitmap?
Just for info: I need this because my stupid POS Printer draws a 0 exactly the same way as a O, so they're impossible to distinguish...
Try this:
Bitmap bmp = new Bitmap(300, 300);
using (Graphics g = Graphics.FromImage(bmp))
{
Font font = new Font("Arial", 20, FontStyle.Bold, GraphicsUnit.Point);
g.Clear(Color.White);
g.DrawString("Hello", font, Brushes.Black, 0, 0);
}
System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format1bppIndexed);
Bitmap newBitmap = new Bitmap(300, 300, bmpData.Stride, System.Drawing.Imaging.PixelFormat.Format1bppIndexed, bmpData.Scan0);
newBitmap.Save(#"c:\x\x.bmp");
Here is a link that could help:
http://msdn.microsoft.com/en-us/library/zy1a2d14.aspx

Categories

Resources