Remove a round transparent section of an Image c# - c#

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..

Related

HighQualityBicubic interpolation adds black background during resizing

I'm implementing image scaling function. When I use HighQualityBicubic interpolation mode (which is preferred from quality perspective) I'm getting black background on resized image(only in rectangle of source image. In padding area of destination rectangle it is still transparent).
Input image is bmp with transparent background.
Output is also bmp 32 bpp.
Interesting thing when I change InterpolationMode to NearestNeighbor with some input images background is preserved as transparent after resizing and with another inputs it doesn't help.
What I'm doing wrong?
public Bitmap DrawScaledImage(Image img, int width, int height, int scaledWidth, int scaledHeight)
{
var resultImg = new Bitmap(width, height, PixelFormat.Format32bppArgb);
resultImg.SetResolution(img.HorizontalResolution, img.VerticalResolution);
using (Graphics grPhoto = Graphics.FromImage(resultImg))
{
grPhoto.InterpolationMode = InterpolationMode.HighQualityBicubic;
grPhoto.DrawImage(img,
new Rectangle(0, 0, scaledWidth, scaledHeight), //0;0 - image is drawn in left top corner
new Rectangle(0, 0, img.Width, img.Height),
GraphicsUnit.Pixel);
}
return resultImg;
}
Update
Found funny thing:
I've picked random transparent pixel in source image and took its ARGB in debug: it is ARGB=(255, 0, 0, 0) - pretty clear
Then I've picked same pixel which was intended to be transparent in destination image after scaling and it is still ARGB=(255, 0, 0, 0) but in Paint.Net it is displayed as black.
Then I've picked another random pixel from destination image that is displayed as transparent in Paint.Net and its ARGB schema is ARGB=(0, 0, 0, 0) - what?
So maybe stupid question - why for 1st pic transparent pixel is [255;0;0;0] but for 2nd [255;0;0;0] means black and transparent is [0;0;0;0].
it looks like something went down-under. and Alfa-channel reversed its meaning from 255- transparent to 255-opaque after scaling. Any ideas?
So I found that reason is some buggy behavior saving file in BMP format after resizing with InterpolationMode = InterpolationMode.HighQualityBicubic. Here are cases for reproduction:
1. If I create brand new image with pixel format PixelFormat.Format32bppArgb make some program manipulations with pixels (e.g. paint some line) and save as bmp - no problem at all, transparency is saved and visible in Paint.Net.
2. If I open existing bmp image already with transparency scale it up/down with Graphics.DrawImage method all seems good in debug. Transparent pixels have Alpha = 0. Then I save that image as bmp. Then Open it again in code like Image.FromFile("resized.bmp") and its pixel format is not same as it was before saving: it is now Format32bppRgb however saved image had Format32bppArgb. On opened image transparent pixels now have Alpha = 255. This is the cause why opening in Paint.Net I see black instead of transparent after resizing.
I found 2 workarounds to preserve transparency after resizing:
1. Change InterpolationMode from InterpolationMode.HighQualityBicubic to InterpolationMode.NearestNeighbor. This solves transparency issue but not acceptable due to low quality method.
2. Save resized image as .png. This saves correct Alpha values and reopening image preserves it still. So it is my solution to refuse using BMP file format at all.

How to get an image from a rectangle?

I'm making a program that's cropping images. I have two PictureBoxes and a Button named 'crop'. One picture box contains an image and when I select a rectangle in it and press 'Crop' the selected area appears in the other picture box; so the program is working when I press crop. The problem is: How can I get the image from crop area into picture box Image?
Rectangle rectCropArea;
Image srcImage = null;
TargetPicBox.Refresh();
//Prepare a new Bitmap on which the cropped image will be drawn
Bitmap sourceBitmap = new Bitmap(SrcPicBox.Image, SrcPicBox.Width, SrcPicBox.Height);
Graphics g = TargetPicBox.CreateGraphics();
g.DrawImage(sourceBitmap, new Rectangle(0, 0, TargetPicBox.Width, TargetPicBox.Height),
rectCropArea, GraphicsUnit.Pixel);
//Good practice to dispose the System.Drawing objects when not in use.
sourceBitmap.Dispose();
Image x = TargetPicBox.Image;
The problem is that x = null and the image is showing in the picture box so how can I get the Image from this picture box into the Image variable ?
A couple of issues:
First and most important: You are being confused about the relationship between PictureBox.Image (a Property) and the Graphics you associate with the PictureBox's surface.
The Graphics object you get from Control.CreateGraphics is only able to paint onto the surface of the control; usually not what you want; and even when you do, you usually want to do it in a Paint event using e.Graphics..
So, while your code seems to work, it only paints non-persistent pixels onto the surface. Minimize/maximize and you'll see what non-persistent means..!
To change a Bitmap bmp you need to associate it with a Grahics object like this:
Graphics g = Graphics.FromImage(bmp);
Now you can draw into it:
g.DrawImage(sourceBitmap, targetArea, sourceArea, GraphicsUnit.Pixel);
After that you can assign the Bitmap to the Image Property of the TargetPicBox..
Finally dispose of the Graphics, or better, put it into a using clause..
I am assuming that you have managed to give the rectCropArea meaningful values.
Also note that the way you copy the source bitmap has an error: If you want the full image, do use its Size (*), not the one of the PictureBox!!
And instead of creating a target rectangle, with the same error, simply use the TargetPicBox.ClientRectangle!
Here is an example code for the crop Button:
// a Rectangle for testing
Rectangle rectCropArea = new Rectangle(22,22,55,99);
// see the note below about the aspect ratios of the two rectangles!!
Rectangle targetRect = TargetPicBox.ClientRectangle;
Bitmap targetBitmap = new Bitmap(targetRect.Width, targetRect.Height);
using (Bitmap sourceBitmap = new Bitmap(SrcPicBox.Image,
SrcPicBox.Image.Width, SrcPicBox.Image.Height) )
using (Graphics g = Graphics.FromImage(targetBitmap))
g.DrawImage(sourceBitmap, targetRect, rectCropArea, GraphicsUnit.Pixel);
if (TargetPicBox.Image != null) TargetPicBox.Dispose();
TargetPicBox.Image = targetBitmap;
Of course you should have prepared the Rectangle in the proper mouse events!
Here you would want to decide on the aspect ratio of the result; you probably don't want to distort the result! So you need to decide whether to crop the source cropping rectangle or whether to expand the target rectangle..!
Unless you are sure about the dpi resolution you should use SetResolution to make sure the new image has the same!
Note that since I assign targetBitmap to TargetPicBox.Image I must not dipose of it! Instead, before assigning a new Image, I first Dispose the old one..

Remove image transparency

I'm working on a Machine Learning problem at college and my first job is to convert images into black and white.
The problem is that my image has transparency, and I don't know how to remove it.
What I am trying:
public static Bitmap RemoveTransparency (Bitmap src)
{
Bitmap target = new Bitmap (src.Size.Width, src.Size.Height);
Graphics g = Graphics.FromImage (target);
g.Clear (Color.White);
g.DrawImage (src, 0, 0);
return target;
}
An example of an input image:
An example of output image after "RemoveTransparency" call:
Does anyone know what's going on? Seems like background an the letters have the same color... and my my background is black if I'm coloring to white?
Thank you!
You need to set the CompositingMode of your Graphics object to SourceOver before drawing the other image on top of it.
g.Clear(Color.White);
g.CompositingMode = CompositingMode.SourceOver;
g.DrawImage(src, 0, 0);
The default CompositingMode is SourceCopy, which is taking the transparent black (R=G=B=A=0) pixels in your src image and rendering them as black pixels. SourceOver will do alpha blending, which is what you're looking for.
See here for details: CompositingMode Enumeration

C# drawing in layers

I have an idea and maybe you guys can give me a good start or an idea in which path might be correct.
I have a picturebox right now loading a specific bmp file. What I want to do is load this bmp file into the picturebox and then load another picture on top of it. The kicker to this all is the 2nd picture must be drawn. The 2nd picture is just a fill in black box. This black box must also overlay on the first image exactly right, the black box has cordinates from paint on it (yes we have the # of the cordaints).
Still think the picturebox is the way to go, or is there a way to load paint into this, and then paint on top of the paint image?
1) Need to load an image
2) Need to read a specific file that has cords
3) Need to draw a black rectangle that matches those coords (Those cords were created in paint).
What do you think the best way to approach this is? A Picture box with code to draw in the cords of the redacted image
Here's a code sample that should do what you're after:
//Load in an image
pbTest.Image = Image.FromFile("c:\\Chrysanthemum.jpg");
//Create the graphics surface to draw on
using (Graphics g = Graphics.FromImage(pbTest.Image))
{
using (SolidBrush brush = new SolidBrush(Color.Black))
{
//Draw a black rectangle at some coordinates
g.FillRectangle(brush, new Rectangle(0, 0, 20, 10));
//Or alternatively, given some points
//I'm manually creating the array here to prove the point, you'll want to create your array from your datasource.
Point[] somePoints = new Point[] { new Point(1,1), new Point(20,25), new Point(35, 50), new Point(90, 100) };
g.FillPolygon(brush, somePoints);
}
}
The finished article:
This answer is written to apply to both web and non-web uses of C# (why I did not give specific examples.)
GDI and other graphics libs all have functions that will paint a filled rectangle on top of an image. This is the way to go. If you use two images there is a good chance for a standard user and a great chance for a hacker they will be able to view just the original image, exposing the information you are trying to hide.
If you only send an image with the areas redacted, you will never have to worry about them being seen.

c# Gradients are darker over bitmaps that on a form surface

Could anyone give me a pointer please?
I've almost finished a project I'm working on but have one last issue to resolve.
I have an image on a form that I apply a colour gradient to. However, when I grab this to create a bitmap
(this.DrawToBitmap(BackGroundBmp, BackGroundRect);)
I do not get the gradient. So, I've applied the gradient to the bitmap directly. However, this is noticeably darker than the form image with the gradient over it. Any idea?
Bitmap BackGroundBmp = new Bitmap(this.Width, this.Height);
Rectangle BackGroundRect = new Rectangle(0, 0,this.Width, this.Height);
this.DrawToBitmap(BackGroundBmp, BackGroundRect);
Graphics g = Graphics.FromImage(BackGroundBmp);
g.FillRectangle(RenderBGGradient, RenderBGGradBrush);
Thanks in advance.
I'm not going to pretend that I understand why but even though the image on the form had a gradient on it, but was not visible in the bitmap that was rendered (using -> this.DrawToBitmap), it must have some how applied this gradient (I'm using alpha blend in the gradient). It was doubling up on the gradient that was applied to the form and the bitmap...... which made it darker. I applied the gradient straight to the bitmap......problem solved. The gradient wasn't visible in the rendered bitmap so, therefore, if I'd not been so sloppy and removed the code that applied the gradient to the form, I would have solved this sooner.

Categories

Resources