I need to stretch various sized bitmaps to fill a PictureBox.
PictureBoxSizeMode.StretchImage sort of does what I need but can't think of a way to properly add text or lines to the image using this method. The image below is a 5x5 pixel Bitmap stretched to a 380x150 PictureBox.
pictureBox.SizeMode = PictureBoxSizeMode.StretchImage;
pictureBox.Image = bmp;
I tried adapting this example and this example this way
using (var bmp2 = new Bitmap(pictureBox.Width, pictureBox.Height))
using (var g = Graphics.FromImage(bmp2))
{
g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.DrawImage(bmp, new Rectangle(Point.Empty, bmp2.Size));
pictureBox.Image = bmp2;
}
but get this
What am I missing?
It appears you're throwing away the bitmap (bmp2) you'd like to see in your picture box! The using block from the example you posted is used because the code no longer needs the Bitmap object after the code returns. In your example you need the Bitmap to hang around, hence no using-block on the bmp2 variable.
The following should work:
using (bmp)
{
var bmp2 = new Bitmap(pictureBox.Width, pictureBox.Height);
using (var g = Graphics.FromImage(bmp2))
{
g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.DrawImage(bmp, new Rectangle(Point.Empty, bmp2.Size));
pictureBox.Image = bmp2;
}
}
The red X on white background happens when you have an exception in a paint method.
Your error is that you are trying to assign a disposed bitmap as the image source of your picturebox. The use of "using" keyword will dispose the bitmap you are using in the picturebox!
So your exception, i know, will be ObjectDisposedException :)
You should create the bitmap once and keep it until it is not needed anymore.
void ReplaceResizedPictureBoxImage(Bitmap bmp)
{
var oldBitmap = pictureBox.Image;
var bmp2 = new Bitmap(pictureBox.Width, pictureBox.Height);
using (var g = Graphics.FromImage(bmp2))
{
g.InterpolationMode = InterpolationMode.NearestNeighbor;
g.DrawImage(bmp, new Rectangle(Point.Empty, bmp2.Size));
pictureBox.Image = bmp2;
}
if (oldBitmap != null)
oldBitmap.Dispose();
}
This function will allow you to replace the old bitmap disposing the previous one, if you need to do that to release resources.
Related
recently I started working on my project and unfortunately I have a problem. I want to get sqaures 5x5 from one image, count average color of them and then draw a circle to another Bitmap so I can get a result like this http://imageshack.com/a/img924/9093/ldgQAd.jpg
I have it done, but I can't save to file the Graphics object. I've tried many solutions from Stack, but none of them worked for me.
My code:
//GET IMAGE OBJECT
Image img = Image.FromFile(path);
Image newbmp = new Bitmap(img.Width, img.Height);
Size size = img.Size;
//CREATE NEW BITMAP WITH THIS IMAGE
Bitmap bmp = new Bitmap(img);
//CREATE EMPTY BITMAP TO DRAW ON IT
Graphics g = Graphics.FromImage(newbmp);
//DRAWING...
//SAVING TO FILE
Bitmap save = new Bitmap(size.Width, size.Height, g);
g.Dispose();
save.Save("file.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
The file 'file.bmp' is just a blank image. What am I doing wrong?
First, your Graphics object should be created from the target bitmap.
Bitmap save = new Bitmap(size.Width, size.Height) ;
Graphics g = Graphics.FromImage(save );
Second, flush your graphics before Save()
g.Flush() ;
And last, Dispose() after Save() (or use a using block)
save.Save("file.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
g.Dispose();
It should give you something like this :
Image img = Image.FromFile(path);
Size size = img.Size;
//CREATE EMPTY BITMAP TO DRAW ON IT
using (Bitmap save = new Bitmap(size.Width, size.Height))
{
using (Graphics g = Graphics.FromImage(save))
{
//DRAWING...
//SAVING TO FILE
g.Flush();
save.Save("file.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
}
}
I am trying to save my drawing from picturebox into bitmap and draw that bitmap into image. So far, nothing has appeared in the final image, but while debugging I can only say, that the original bitmap is not null and with/height are correct. However nothing appears after I draw it into image.
I save my drawing into bitmap like this:
GraphicsPath path = RoundedRectangle.Create(x, y, width, height, corners, RoundedRectangle.RectangleCorners.All);
g.FillPath(Brushes.LightGray, path);
g.SetClip(path);
using (Font f = new Font("Tahoma", 9, FontStyle.Bold))
g.DrawString(mtb_hotspotData.Text, f, Brushes.Black, textX, textY);
g.ResetClip();
bitmap = new Bitmap(width, height, g);
Then save it:
hs.bitmap = new Bitmap(bitmap);
And finally use it:
for (int i = 0; i < imageSequence.Count; i++) {
Graphics g = Graphics.FromImage(imageSequence[i]);
//g.CompositingMode = CompositingMode.SourceOver;
//hotspot.bitmap.MakeTransparent();
int x = hotspot.coordinates[i].X;
int y = hotspot.coordinates[i].Y;
g.DrawImage(hotspot.bitmap, new Point(x, y));
}
return imageSequence;
So far I was not able to find any problem in this solution, therefore I have no idea, where the malfunction is.
You seem to misunderstand the relation of a Bitmap and a Graphics object.
A Graphics object does not contain any graphics; it is a tool used to draw into a bitmap of some sort.
The Bitmap constructor you are using (public Bitmap(int width, int height, Graphics g)) does not really connect the Bitmap and the Graphics object. It only uses the dpi resolution from the Graphics.
You don't show how your Graphics is created. If you want to draw into a Bitmap (as opposed to a control's surface) the most direct way is this:
Bitmap bitmap = new Bitmap(width, height);
bitmap.SetResolution(dpiX, dpiY); // optional
using (Graphics G = Graphics.FromImage(bitmap ))
{
// do the drawing..
// insert all your drawing code here!
}
// now the Bitmap can be saved or cloned..
bitmap.Save(..);
hs.bitmap = new Bitmap(bitmap); // one way..
hs.bitmap = bitmap.Clone(); // ..or the other
// and finally disposed of (!!)
bitmap.Dispose();
I'm using C# and I would like to draw some polygons on a Form, then to save the graphics in a Bitmap.
Following this question answers I wrote a method in my Form class:
private void draw_pol()
{
Graphics d = this.CreateGraphics();
// drawing stuff
Bitmap bmp = new Bitmap(this.Width, this.Height, d);
bmp.Save("image.bmp");
}
In this way the Form displays correctly the graphics and the Bitmap file named "image.bmp" is created, but that file is a white image.
Why isn't the bmp file showing any image? What I'm doing wrong?
Thank you very much.
The graphics parameter you are passing to your bitmap is only used to specify the resolution of the bitmap. It does not in any way paint to the bitmap.
from MSDN:
The new Bitmap that this method creates takes its horizontal and vertical resolution from the DpiX and DpiY properties of g, respectively.
Instead, use Graphics.FromImage() to get a Graphics object you can use. Moreover, you should Dispose the Graphics object after painting. This is an ideal usage for the using statement.
Bitmap bmp = new Bitmap(this.Width, this.Height);
using (Graphics g = Graphics.FromImage(bmp))
{
//paint stuff
}
bmp.Save(yourFile);
If you also need to paint this to the form, you can easily just draw the bitmap you created:
Graphics g = this.CreateGraphics();
g.DrawImage(bmp, 0, 0);
A Graphics instance only operates on one Bitmap. It's either the one you want to save, or the one on your form.
You can for example do this to render the drawn bitmap on your form and save it afterwards:
private void DrawOnBitmap()
{
using (var bitmap = new Bitmap(this.Width, this.Height))
{
using (var bitmapGraphics = Graphics.FromImage(bitmap))
{
// Draw on the bitmap
var pen = new Pen(Color.Red);
var rect = new Rectangle(20, 20, 100, 100);
bitmapGraphics.DrawRectangle(pen, rect);
// Display the bitmap on the form
using (var formGraphics = this.CreateGraphics())
{
formGraphics.DrawImage(bitmap, new Point(0, 0));
}
// Save the bitmap
bitmap.Save("image.bmp");
}
}
}
you need a graphics object that represents the bitmap,so that you can draw on image.do lke this:
create the bitmap object
create the graphics object using Graphics.FromImage method
pass bitmap object as argument to graphics object
Bitmap bmp = new Bitmap(this.Width, this.Height, d);
bmp.Save("image.bmp");//for your need
Graphics d=Graphics.FromImage(bmp);
I'm really trying to nail out a little more performance out of this tidbit of code. It's not a heavly used bit of code but is used every time a new image is uploaded, and 4 times for each image (100px, 200px, 500px, 700px). So when there are any more than 2 or 3 images processing, it gets a little busy on the server. Also I'm trying to figure out how to make it correctly process images with a low resolution. Currently it just chops it off half way through, not plesent.
Examples: Original, large, xLarge
public static byte[] ResizeImageFile(byte[] imageFile, int targetSize)
{
using (System.Drawing.Image oldImage = System.Drawing.Image.FromStream(new MemoryStream(imageFile)))
{
Size newSize = CalculateDimensions(oldImage.Size, targetSize);
using (Bitmap newImage = new Bitmap(newSize.Width, newSize.Height, PixelFormat.Format32bppRgb))
{
newImage.SetResolution(oldImage.HorizontalResolution, oldImage.VerticalResolution);
using (Graphics canvas = Graphics.FromImage(newImage))
{
canvas.SmoothingMode = SmoothingMode.AntiAlias;
canvas.InterpolationMode = InterpolationMode.HighQualityBicubic;
canvas.PixelOffsetMode = PixelOffsetMode.HighQuality;
canvas.DrawImage(oldImage, new Rectangle(new Point(0, 0), newSize));
MemoryStream m = new MemoryStream();
newImage.Save(m, ImageFormat.Jpeg);
return m.GetBuffer();
}
}
}
}
private static Size CalculateDimensions(Size oldSize, int targetSize)
{
Size newSize = new Size();
if (oldSize.Width > oldSize.Height)
{
newSize.Width = targetSize;
newSize.Height = (int)(oldSize.Height * (float)targetSize / (float)oldSize.Width);
}
else
{
newSize.Width = (int)(oldSize.Width * (float)targetSize / (float)oldSize.Height);
newSize.Height = targetSize;
}
return newSize;
}
Thanks for and help!
The first thought that comes to mind is, have you thought about Multithreading it? i.e. calling this method for each image (or batch of images) in a separate thread? That way, if your server has a few cores you can get things done quicker. Just a thought...
(Threading is a great tip.)
Try to call your method with the smallest possible image as input each time, instead of the original image. If the original image is, say 2000px, then create the 700px image from it and then use your newly created 700px image to create the 500px, etc...
With the HighQualityBicubic setting I doubt that you'll notice any difference in the 100px image. (But it of course it needs to be verified.)
For completeness, here is the solution to the second part of the question which was never answered. When processing a low resolution image the image was being cut off. The solution now, seems obvious. The problem lies in this bit of code from above:
using (Bitmap newImage = new Bitmap(newSize.Width, newSize.Height,
PixelFormat.Format32bppRgb))
The problem being that I'm selecting the PixelFormat, not letting it be the format of the original image. The correct code is here:
public static byte[] ResizeImageFile(byte[] imageFile, int targetSize)
{
using (System.Drawing.Image oldImage = System.Drawing.Image.FromStream(new MemoryStream(imageFile)))
{
Size newSize = CalculateDimensions(oldImage.Size, targetSize);
using (Bitmap newImage = new Bitmap(newSize.Width, newSize.Height,
oldImage.PixelFormat))
{
newImage.SetResolution(oldImage.HorizontalResolution,
oldImage.VerticalResolution);
using (Graphics canvas = Graphics.FromImage(newImage))
{
canvas.SmoothingMode = SmoothingMode.AntiAlias;
canvas.InterpolationMode = InterpolationMode.HighQualityBicubic;
canvas.PixelOffsetMode = PixelOffsetMode.HighQuality;
canvas.DrawImage(oldImage, new Rectangle(new Point(0, 0), newSize));
MemoryStream m = new MemoryStream();
newImage.Save(m, ImageFormat.Jpeg);
return m.GetBuffer();
}
}
}
}
What I have is a .tif file being loaded into a picture box. When I try to draw a rectangle on top of that tif it throws the following error:
A Graphics object cannot be created from an image that has an indexed pixel format.
here is the code i'm using, it throws the error at using (Graphics g = Graphics.FromImage(img)). img is the file being loaded into the picture box.
using (Graphics g = Graphics.FromImage(img))
{
int x1value = Convert.ToInt32(x1);
int y1value = Convert.ToInt32(y1);
int x3value = Convert.ToInt32(x3);
int y3value = Convert.ToInt32(y3);
SolidBrush blackBrush = new SolidBrush(Color.Black);
g.FillRectangle(blackBrush, x1value, y1value, x3value, y3value);
Image img = Image.FromFile(string2image);
Bitmap source = (Bitmap)img;
source = new Bitmap(320, 240, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
pictureBox1.Image = source;
pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage;
using (Graphics g = Graphics.FromImage(pictureBox1.Image))
This method actually only draws a gaint black box. not causes a blackbox to be written over the original file.
You're trying to get a graphics context from an image. You need to get one from a Bitmap buffer i believe.