Im trying to save a file that i am using im getting a GDI+ error because im trying to save over the source file im using. Any solutions?
Example:
private void Form1_Load(object sender, EventArgs e)
{
Bitmap sourceImage = new Bitmap("images/sourceImage.jpg");
sourceImage = CropBitmap(sourceImage, 0, 0, sourceImage.Width, 50);
sourceImage.Save("images/sourceImage.jpg", ImageFormat.Jpeg);
}
public Bitmap CropBitmap(Bitmap bitmap, int cropX, int cropY, int cropWidth, int cropHeight)
{
Rectangle rect = new Rectangle(cropX, cropY, cropWidth, cropHeight);
Bitmap cropped = bitmap.Clone(rect, bitmap.PixelFormat);
return cropped;
}
See the documentation for this constructor. Specifically the section that reads:
The file remains locked until the Bitmap is disposed.
You must dispose the sourceImage before saving a new one. So, use different variables:
var sourceImage = new Bitmap("images/sourceImage.jpg");
var croppedImage = CropBitmap(sourceImage, 0, 0, sourceImage.Width, 50);
sourceImage.Dispose();
croppedImage.Save("images/sourceImage.jpg", ImageFormat.Jpeg);
croppedImage.Dispose();
When you replace sourceImage with the reference from CropBitmap, the original file is still open. You will have to Dispose of it after reading it from the file, open a new Bitmap and save it overwriting the existing one.
private void Form1_Load(object sender, EventArgs e)
{
Bitmap sourceImage = new Bitmap("images/sourceImage.jpg");
Bitmap targetImage = CropBitmap(sourceImage, 0, 0, sourceImage.Width, 50);
sourceImage.Dispose();
targetImage.Save("images/sourceImage.jpg", ImageFormat.Jpeg);
}
MSDN Bitmap documentation
The file remains locked until the Bitmap is disposed.
Related
In c# and Visual Studio Windows forms I have loaded an image into a picture box (pictureBox2) and then cropped it and show in another picture box (pictureBox3).
Now I want to save what is inside pictureBox3 as an image file.
How can I do this?
private void crop_bttn_Click(object sender, EventArgs e)
{
Image crop = GetCopyImage("grayScale.jpg");
pictureBox2.Image = crop;
Bitmap sourceBitmap = new Bitmap(pictureBox2.Image,
pictureBox2.Width, pictureBox2.Height);
Graphics g = pictureBox3.CreateGraphics();
g.DrawImage(sourceBitmap, new Rectangle(0, 0,
pictureBox3.Width, pictureBox3.Height), rectCropArea, GraphicsUnit.Pixel);
sourceBitmap.Dispose();
}
Never use control.CreateGraphics! Either draw into a Bitmap bmp using a Graphics g = Graphics.FromImage(bmp) or in the Paint event of a control, using the e.Graphics parameter..
Here is a cropping code that draws into a new Bitmap and that makes use of your controls etc but changes a few things:
It uses a Graphics object that is created from a new Bitmap
It make use of using clauses to make sure it won't leak
It takes the size of the pictureBox3.ClientSize so it won't include any borders..
private void crop_bttn_Click(object sender, EventArgs e)
{
Image crop = GetCopyImage("grayScale.jpg");
pictureBox2.Image = crop;
Bitmap targetBitmap = new Bitmap(pictureBox3.ClientSize.Width,
pictureBox3.ClientSize.Height);
using (Bitmap sourceBitmap = new Bitmap(pictureBox2.Image,
pictureBox2.ClientSize.Width, pictureBox2.ClientSize.Height))
{
using (Graphics g = Graphics.FromImage(targetBitmap))
{
g.DrawImage(sourceBitmap, new Rectangle(0, 0,
pictureBox3.ClientSize.Width, pictureBox3.ClientSize.Height),
rectCropArea, GraphicsUnit.Pixel);
}
}
if (pictureBox3.Image != null) pictureBox3.Image.Dispose();
pictureBox3.Image = targetBitmap;
targetBitmap.Save(somename, someFormat);
}
The alternative would be to..:
move all your code to the Paint event
replace the Graphics g = pictureBox3.CreateGraphics(); be Graphics g = e.Graphics;
insert these two lines to the click event:
Bitmap targetBitmap = new Bitmap(pictureBox3.ClientSize.Width,
pictureBox3.ClientSize.Height);
pictureBox3.DrawToBitmap(targetBitmap, pictureBox3.ClientRectangle);
The method PictureBox.CreateGraphics() should not be used unless you know what you are doing because it can cause some not-so-obvious problems. For example, in you scenario, the image in pictureBox3 will disappear when you minimize or resize the window.
A better way is to draw to a bitmap, which you also can save:
var croppedImage = new Bitmap(pictureBox3.Width, pictureBox3.Height);
var g = Graphics.FromImage(croppedImage);
g.DrawImage(crop, new Point(0, 0), rectCropArea, GraphicsUnit.Pixel);
g.Dispose();
//Now you can save the bitmap
croppedImage.Save(...);
pictureBox3.Image = croppedImage;
Btw, please use more reasonable variable names, especially for pictureBox1..3.
I am try Try capture an image of an particular area in my webpage. Below code works fine but issue is it gives me only a blank image with a size of 1.64kb every time.
Function call
protected void btn_Click(object sender, EventArgs e)
{
System.Drawing.Image image = CaptureScreen(50, 99, 930, 450);
image.Save(Server.MapPath("/img/screen.jpg"));
}
Function Definition
public System.Drawing.Image CaptureScreen(int sourceX, int sourceY, int destX, int destY)
{
Bitmap bmp = new Bitmap(930, 430);
Graphics g = Graphics.FromImage(bmp);
Size xx=new Size();
xx.Width=930;
xx.Height=450;
g.CopyFromScreen(sourceX, sourceY, destX, destY, xx);
return bmp;
}
When I run the code below to take screenshot, I get an error like A generic error occurred in GDI+. How can I resolve this issue or any other way to take screenshot of current window?
protected void Page_Load(object sender, EventArgs e) {
Bitmap bitmap = new Bitmap(100, 200);
Graphics graphics = Graphics.FromImage(bitmap as System.Drawing.Image);
graphics.CopyFromScreen(0, 0, 0, 0, bitmap.Size);
bitmap.Save("c:\\screenshot.jpeg", ImageFormat.Jpeg);
}
You should use
bitmap.Save(#"c:\\screenshot.jpeg", ImageFormat.Jpeg);
Also why you define bitmap again, it's not needed:
Graphics graphics = Graphics.FromImage(bitmap);
I have made an application, and i need the function drawbitmap to print my panel. When i push the button (btnUpdate) 12 times or more I get a parameter exception(invalid parameter)on this rule: panel1.DrawToBitmap(bmp1, new Rectangle(0, 0, 2480, 3508));
private void preview()
{
Bitmap bmp1 = new Bitmap(2480, 3508);
panel1.DrawToBitmap(bmp1, new Rectangle(0, 0, 2480, 3508));
pictureBox2.Image = bmp1;
}
private void btnUpdate_Click(object sender, EventArgs e)
{
preview();
}
Can someone help me please?
I can't use the bmp1.Dispose(); function... I get an exeption in the Program.cs file in this line: Application.Run(new Form1());
This could be a case of not disposing the bitmaps when you're done with them. Try this:
panel1.DrawToBitmap(...);
// get old image
Bitmap oldBitmap = pictureBox2.Image as Bitmap;
// set the new image
pictureBox2.Image = bmp1;
// now dispose the old image
if (oldBitmap != null)
{
oldBitmap.Dispose();
}
You have a great big Memory leak there, watch your memory as you click the button 12 clicks and your up to 1GB,
try declaring you Bitmap as a varable and Dispose it before re assigning.
private Bitmap bmp1;
private void preview()
{
if (bmp1 != null)
{
bmp1.Dispose();
}
bmp1 = new Bitmap(2480, 3508);
panel1.DrawToBitmap(bmp1, new Rectangle(0, 0, 2480, 3508));
pictureBox2.Image = bmp1;
}
Or just clear the PictureBox befor assigning a new Bitmap
private void preview()
{
if (pictureBox2.Image != null)
{
pictureBox2.Image.Dispose();
}
Bitmap bmp1 = new Bitmap(2480, 3508);
panel1.DrawToBitmap(bmp1, new Rectangle(0, 0, 2480, 3508));
pictureBox2.Image = bmp1;
}
The problem is fixed by doing this:
private void preview()
{
Bitmap bmp1 = new Bitmap(2480, 3508);
panel1.DrawToBitmap(bmp1, new Rectangle(0, 0, 2480, 3508));
Image img = pictureBox2.Image;
pictureBox2.Image = bmp1;
if (img != null) img.Dispose(); // the first time it'll be null
}
private void btnUpdate_Click(object sender, EventArgs e)
{
preview();
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
}
The XAML:
<ImageBrush x:Key="Symbol1Brush" ImageSource="Resources\Symbol1.png" Stretch="Uniform" />
The code:
// In some class
_imageProcessor = new ImageProcessor(Resources["Symbol1Image"] as BitmapImage)
and
public class ImageProcessor
{
private readonly Bitmap _primaryMarkerSymbol;
public ImageProcessor(BitmapImage primaryMarkerSymbol)
{
if (primaryMarkerSymbol == null)
throw new ArgumentNullException("primaryMarkerSymbol");
_primaryMarkerSymbol = new Bitmap(primaryMarkerSymbol.StreamSource);
}
public Bitmap ProcessImage()
{
Graphics g = Graphics.FromImage(img);
g.DrawImage(_primaryMarkerSymbol);
g.Flush();
return img;
}
}
_primaryMarkerSymbol = new Bitmap(primaryMarkerSymbol.StreamSource)
throws Exception: Value of 'null' is not valid for 'stream'.
I assume the StreamSource is not populated if BitmapImage is created from Resource.
What alternatives there are?
Thanks.
EDIT:
The point is to use the source object (ex. ImageBrush, BitmapImage) defined in the XAML ResourceDictionary.
You might need to copy the bitmap's pixels somehow like this:
// test image
BitmapImage image = new BitmapImage(new Uri(#"C:\Users\Public\Pictures\Sample Pictures\Desert.jpg"));
// copy to byte array
int stride = image.PixelWidth * 4;
byte[] buffer = new byte[stride * image.PixelHeight];
image.CopyPixels(buffer, stride, 0);
// create bitmap
System.Drawing.Bitmap bitmap =
new System.Drawing.Bitmap(
image.PixelWidth,
image.PixelHeight,
System.Drawing.Imaging.PixelFormat.Format32bppArgb);
// lock bitmap data
System.Drawing.Imaging.BitmapData bitmapData =
bitmap.LockBits(
new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height),
System.Drawing.Imaging.ImageLockMode.WriteOnly,
bitmap.PixelFormat);
// copy byte array to bitmap data
System.Runtime.InteropServices.Marshal.Copy(
buffer, 0, bitmapData.Scan0, buffer.Length);
// unlock
bitmap.UnlockBits(bitmapData);
This worked for me to set an image source using resource files
var bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(MyProject.Properties.Resources.myImage.GetHbitmap(),
IntPtr.Zero,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions());
MyButton.Background = new ImageBrush(bitmapSource);
In the constructor, I would rather use this:
System.Windows.Resources.StreamResourceInfo imageInfo = System.Windows.Application.GetResourceStream(primaryMarkerSymbol.UriSource);
_primaryMarkerSymbol = Image.FromStream(imageInfo.Stream);
On a clear moment I have come up with a solution that I could saddle with.
I used the BitmapImage.UriSource to get the relative image path and load the Image:
public class ImageProcessor
{
private readonly Image _primaryMarkerSymbol;
public ImageProcessor(BitmapImage primaryMarkerSymbol)
{
_primaryMarkerSymbol = Image.FromFile(primaryMarkerSymbol.UriSource.ToString());
}
public Bitmap ProcessImage(string fileName)
{
var img = new Bitmap(fileName);
Graphics g = Graphics.FromImage(img);
g.DrawImage(_primaryMarkerSymbol);
g.Flush();
return img;
}
}
It would be good if I could use the object itself to draw the image on the graphics not to load by path. So you are welcome to come up with a better idea.