I am making and photo editor and displaying an image in pictureBox and I resize the image to fit in the pictureBox without effecting its ratio of sides.
Example if the pictureBox is of size (400x400) and the image is of (800x600) i will resize it to (400x300) programatically.
The problem is I want this image to be the size of (400x400) to cover complete pictureBox for this I want to add transparent part in my image to make it from (400x300) to (400x400)
Snapshot of my image on the pictureBox
In the image above my blue is my image and other part is remaining picturebox.
Again I want image'size (blue one) to be equal to picturebox's size and the remaining part of picturebox is covered by transparent part of picture
Note: I don't want to stretch my image but add transparent part
thanks,
The most direct way is to create the larger bitmap and then DrawImage the picture into it.
Bitmap original = (Bitmap) Bitmap.FromFile(someFileName);
Size sz = yourPictureBox.ClientSize;
Bitmap bmp = new Bitmap(sz.Width, sz.Height);
using (Graphics G = Graphics.FromImage(bmp))
G.DrawImage(original, 0, 0);
yourPictureBox.Image = bmp;
Related
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.
I'm drawing shapes on the PictureBox control using Paint event of it.
May I know how to save drawn shapes only on a bitmap without the picture box image(current).
I don't want to save the PictureBox image.
I have created the bitmap from the image(White background image) for saving a drawing on it.
I want to save it on created bitmap image(4).
Image WhiteBackGroundImage=Image.FromFile("path");//fetching white back ground image.
Bitmap pic=new Bitmap(WhiteBackGroundImage);//creating bitmap
pictureBoxImage.DrawToBitmap(pic,pictureBoxImage.ClientRectangle);
pic.Save("path", ImageFormat.Png);
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'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..
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