let's assume I let the user choose an image from the computer. I load the file to a picture box. here is the conversion method:
public static Image LoadImageFromFile(string fileName)
{
Image result = null;
if (!File.Exists(fileName))
return result;
FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
try
{
using (Image image = Image.FromStream(fs))
{
ImageManipulation.RotateImageByExifOrientationData(image);
result =(Image) image.Clone();
image.Dispose();
}
}
finally
{
fs.Close();
}
return result;
}
then, when the user clicks on the Save button, I convert the image into a byte array and save it into the database. here is the conversion code:
public static byte[] ImageToByteArray(Image image)
{
if (image == null)
return null;
using (var ms = new MemoryStream())
{
ImageFormat imageFormat = image.RawFormat;
ImageCodecInfo codec = ImageCodecInfo.GetImageDecoders().FirstOrDefault(c => c.FormatID == imageFormat.Guid);
var encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 100L);
if (codec != null)
image.Save(ms, codec, encoderParameters);
else
image.Save(ms, ImageFormat.Jpeg);
return ms.ToArray();
}
}
but the problem:
I have a jpg file on the disk. I can load it into my picture box without any problem. the picture is perfectly visible in it. but when I save it, the code gives me "A generic error occurred in GDI+." Error at 'image.Save(ms, codec,encoderParameters)' line.
more odd incident: I don't get this error all the time. it is happening with specific images. for example, I downloaded an image from the internet and crop it in "Paint" and saved it as jpg. error happened. open it in Paint again and save it as png. no error!!!! that is why I am really confused . and Yes I already have tried to don't dispose the image. not helping
I know it might be a stupid question but I am desperately stuck here :)
Thank you in Advanced
I didn't find out why my code is not working but I just substitute my loading method with the code below. it is releasing the file and at the same time works as it should.
public static Image LoadImageFromFile(string fileName)
{
using (Bitmap bmb = new Bitmap(fileName))
{
MemoryStream m = new MemoryStream();
bmb.Save(m, ImageFormat.Bmp);
return Image.FromStream(m);
}
}
I have an Image I am retrieving from the database as a byte array. I want to save it outside the Project i.e on the Clients System. I would appreciate if the code aspect can be assisted with. Here is a sample method I have so far:
public Image byteArrayToImage2()
{
var filePath = "C:\\cat.jpg";
byte[] fileBytes = System.IO.File.ReadAllBytes(filePath);
Image returnImage = null;
using (MemoryStream ms = new MemoryStream(fileBytes))
{
returnImage = Image.FromStream(ms);
returnImage.Save("cat2.jpg", ImageFormat.Jpeg);
}
return returnImage;
}
Try the below approach
PS: make sure your fileBytes is of type byte Array.
MemoryStream imageStream = new MemoryStream();
imageStream.Write(fileBytes, 0, fileBytes.Length);
// Include the file name along with extension (Eg: 'C:\TestImage.JPEG')
FileStream fs = File.Create("Give the path where you want to save the image");
imageStream.WriteTo(fs);
fs.Close();
imageStream.Close();
I got some problem here, so in case after I show the image, I don't want to change the image that shown but It get me some exception but when I choose the same images again, it works
System.ArgumentNullException: 'Path cannot be null.
Parameter name: path'
and when I change the image and saves the changes its fine properly. line 2 exception
byte[] imagebt = null;
FileStream fst = new FileStream(picUploadAdmin.ImageLocation, FileMode.Open, FileAccess.Read);
BinaryReader br = new BinaryReader(fst);
imagebt = br.ReadBytes((int)fst.Length);
upcs.updateimageonclubs(txtEditClubNameAdmin.Text, imagebt);
This is how I show my image
if (dr.HasRows)
{
byte[] images = ((byte[])dr1["image"]);
if (images != null)
{
MemoryStream ms = new MemoryStream(images);
picUploadAdmin.Image = Image.FromStream(ms);
}
else
{
images = null;
}
I am trying to add some text on top of a photo take by the camera, and here is the method I am using, but unfortunately I either get a closedStream error, or that there is cross-thread access when I try use the dispatcher. Could someone please explain me what is going wrong?
void cam_CaptureImageAvailable(object sender, Microsoft.Devices.ContentReadyEventArgs e)
{
DateTime dt = DateTime.Now;
string fileName = dt.Year.ToString() + dt.Month.ToString() + dt.Day.ToString() + dt.Hour.ToString() + dt.Minute.ToString() + dt.Second.ToString() + ".jpg";
try
{
// Save picture to the library camera roll.
library.SavePictureToCameraRoll(fileName, e.ImageStream);
// Set the position of the stream back to start
e.ImageStream.Seek(0, SeekOrigin.Begin);
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
// load photo to writable bitmap
WriteableBitmap writeableBitmap = PictureDecoder.DecodeJpeg(e.ImageStream);
writeableBitmap.Invalidate();
var renderText = new TextBlock
{
Text = "Hello World",
FontSize = 72,
Foreground = new SolidColorBrush(Colors.White),
FontWeight = FontWeights.Black,
Width = 500,
Height = 100
};
writeableBitmap.Render(renderText, new TranslateTransform() { X = 100, Y = 300 });
writeableBitmap.Invalidate();
using (var ms = new MemoryStream())
{
writeableBitmap.SaveJpeg(ms, 1024, 768, 0, 100);
ms.Seek(0, SeekOrigin.Begin);
library.SavePicture("x" + fileName, ms);
}
// e.ImageStream.Close();
});
// Save picture as JPEG to isolated storage.
using (IsolatedStorageFile isStore = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream targetStream = isStore.OpenFile(fileName, FileMode.Create, FileAccess.Write))
{
// Initialize the buffer for 4KB disk pages.
byte[] readBuffer = new byte[4096];
int bytesRead = -1;
// Copy the image to isolated storage.
while ((bytesRead = e.ImageStream.Read(readBuffer, 0, readBuffer.Length)) > 0)
{
targetStream.Write(readBuffer, 0, bytesRead);
}
}
}
}
finally
{
// Close image stream
e.ImageStream.Close();
}
}
With the code above I get the following error: Cannot access a closed Stream.
If i remove the Dispatcher, I get this error: Invalid cross-thread access.
Thanks.
place ui less code outside dispatcher scope.
or save your e.ImageStream to other stream can be gotted in dispatcher scope.
First, what is occurring?
Dispatcher.BeginInvoke postpones your code and tells the UI thread to execute it whenever it's available. Therefore, your e.ImageStream.Close(); line is executed before the code inside of the BeginInvoke. So when you're trying to read the contents of the stream, it's already closed.
Two ways to solve that:
Remove the e.ImageStream.Close(); from the finally block. But I don't know if the stream will remain open anyway.
If 1. doesn't work, copy the contents of the stream to a MemoryStream, then use this stream to create the WriteableBitmap:
var stream = new MemoryStream();
e.ImageStream.CopyTo(stream);
In both case, don't forget to close the stream when you're done creating the WriteableBitmap.
I loaded an image into a Picture Box using:
picturebox1.Image = Image.FromFile()
and I save it by using:
Bitmap bm = new Bitmap(pictureBox1.Image);
bm.Save(FileName, ImageFormat.Bmp);
It works perfectly fine when creating a new file, but when I try to replace the existing image, I get thrown the following runtime error:
A generic error occurred in GDI+
So what can I do to solve this problem??
That because the image file is used by your picturebox1.Image, try to save it to different file path instead:
picturebox1.Image = Image.FromFile(FileName);
Bitmap bm = new Bitmap(pictureBox1.Image);
bm.Save(#"New File Name", ImageFormat.Bmp);
Edit: You could also add a copy from the image at the first place like:
picturebox1.Image = new Bitmap(Image.FromFile(FileName));
Bitmap bm = new Bitmap(pictureBox1.Image);
bm.Save(FileName, ImageFormat.Bmp);//no error will occurs here.
The FromFile method locks the file, so use the Image.FromStream() method for reading the image:
byte[] bytes = System.IO.File.ReadAllBytes(filename);
System.IO.MemoryStream ms = new System.IO.MemoryStream(bytes);
pictureBox1.Image = Image.FromStream(ms);
Then save like you were before.
This can also happen if the path does not exist.
You could create the dir with:
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(FileName));
When either a Bitmap object or an Image object is constructed from a file, the file remains locked for the lifetime of the object. As a result, you cannot change an image and save it back to the same file where it originated. http://support.microsoft.com/?id=814675
A generic error occurred in GDI+, JPEG Image to MemoryStream:
Image.Save(..) // throws a GDI+ exception because the memory stream is closed
http://alperguc.blogspot.in/2008/11/c-generic-error-occurred-in-gdi.html
EDIT: Just writing from memory. Saving to an 'intermediary' MemoryStream should work:
For example, replace this:
Bitmap newBitmap = new Bitmap(thumbBMP);
thumbBMP.Dispose();
thumbBMP = null;
newBitmap.Save("~/image/thumbs/" + "t" + objPropBannerImage.ImageId, ImageFormat.Jpeg);
with something like:
string outputFileName = "...";
using (MemoryStream memory = new MemoryStream())
{
using (FileStream fs = new FileStream(outputFileName, FileMode.Create, FileAccess.ReadWrite))
{
thumbBMP.Save(memory, ImageFormat.Jpeg);
byte[] bytes = memory.ToArray();
fs.Write(bytes, 0, bytes.Length);
}
}
try this.
picturebox1.Image = Image.FromFile(FileName);
Bitmap bm = new Bitmat(pictureBox1.Image);
Image img = (Image)b;
img.Save(FileName, ImageFormat.Bmp);
Just like #Jalal Aldeen Saa'd said, the picture box is using the file and locked from file replacement.
//unlock file by clearing it from picture box
if (picturebox1.Image != null)
{
picturebox1.Image.Dispose();
picturebox1.Image = null;
}
//put back the picture inside the pictureBox?
try this it will work
public void SavePicture()
{
Bitmap bm = new Bitmap(this.myBitmap)
bm.Save("Output\\out.bmp" ,System.Drawing.Imaging.ImageFormat.Bmp );
}
This can also happen if you forget to add the filename:
bm.Save(#"C:\Temp\Download", System.Drawing.Imaging.ImageFormat.Png);
And can be fixed by adding the file name:
bm.Save(#"C:\Temp\Download\Image.png", System.Drawing.Imaging.ImageFormat.Png);
Note: You don't actually have to add the extension for it to work.
Try this:
private void LoadPictureBoxWithImage( string ImagePath)
{
Stream objInputImageStream = null;
BitmapData bmdImageData = null;
Bitmap bmpSrcImage = null, bmTemp = null;
byte[] arrImageBytes = null;
int bppModifier = 3;
try
{
objInputImageStream = new MemoryStream();
using (FileStream objFile = new FileStream(ImagePath, FileMode.Open, FileAccess.Read))
{
objFile.CopyTo(objInputImageStream);
}
bmpSrcImage = new Bitmap(objInputImageStream);
bppModifier = bmpSrcImage.PixelFormat == PixelFormat.Format24bppRgb ? 3 : 4;
//reda from byte[] to bitmap
bmdImageData = bmpSrcImage.LockBits(new Rectangle(0, 0, bmpSrcImage.Width, bmpSrcImage.Height), ImageLockMode.ReadOnly, bmpSrcImage.PixelFormat);
arrImageBytes = new byte[Math.Abs(bmdImageData.Stride) * bmpSrcImage.Height];
System.Runtime.InteropServices.Marshal.Copy(bmdImageData.Scan0, arrImageBytes, 0, arrImageBytes.Length);
bmpSrcImage.UnlockBits(bmdImageData);
pbSetup.Image = (Bitmap)bmpSrcImage.Clone();
pbSetup.Refresh();
}
catch (Exception ex)
{
throw new Exception("Error in Function " + System.Reflection.MethodInfo.GetCurrentMethod().Name + "; " + ex.Message);
}
finally
{
if (objInputImageStream != null)
{
objInputImageStream.Dispose();
objInputImageStream = null;
}
if (bmdImageData != null)
{
bmdImageData = null;
}
if (bmpSrcImage != null)
{
bmpSrcImage.Dispose();
bmpSrcImage = null;
}
if (bmTemp != null)
{
bmTemp.Dispose();
bmTemp = null;
}
if (arrImageBytes != null)
{
arrImageBytes = null;
}
}
}
A generic error occurred in GDI+
I also faced the same issue. I tried so many ways to fix this issue. Finally, I found a place where I have gone wrong. The problem is that I used space in the file path, which is not acceptable. Now it is working fine after removing the space in front of C after the apostrophe:
"SupplyItems":"C:\\inetpub\\HIBMS_Ver1\\BarcodeImages\\Supply\\"
instead... I used below one.
"SupplyItems":" C:\\inetpub\\HIBMS_Ver1\\BarcodeImages\\Supply\\"
Minor mistake but took a long time to find and to fix it.
Note that images created by Image.Clone() will still cause GDI+ errors as shown by the BAD code below, you must use the Image.FromStream() method for reading the image as shown in the solution on this page.
//BAD CODE: the image we will try to save AFTER the original image has been cloned and disposed
Image clonedImage;
//load image from file, clone it then dispose
using (var loadedFromDiskImage = Image.FromFile(filePath))
{
clonedImage = (Image) loadedFromDiskImage.Clone();
}
//you might think the new image can be saved given the original is disposed
//but this doesn't seem to be the way Clone() works
//expect GDI+ error in line below:
clonedImage.Save(filePath);