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);
}
}
Related
am having a problem when i attempt to update a Record image in the DB.
the workflow am using goes as follows :
the user loads the image to a picture box using FilaDialog.
DialogResult path = openFileDialog1.ShowDialog();
if (path == DialogResult.OK)
{
pictureBox.Image = new Bitmap(openFileDialog1.FileName);
pictureBox.Refresh();
}
after the user finishes inserting the remaining fields and attempts to save the Image is loaded from the PictureBox and saved to the db.
Image img = PictureBox.Image;
byte[] photo_aray = null;
using (MemoryStream ms = new MemoryStream())
{
img.Save(ms, ImageFormat.Jpeg);
photo_aray = new byte[ms.Length];
ms.Position = 0;
ms.Read(photo_aray, 0, photo_aray.Length);
}
so far so good, but the problem occurs when i attempt to update the Image which follows as such :
the user selects the Record from a list, an event loads Record information, image is loaded to a PictureBox.
after the user finishes updating the remaining fields and attempts to save the Image is loaded from the PictureBox and saved to the db using the same logic written above with some changes to the SQL query.
Image img = PictureBox.Image;
byte[] photo_aray = null;
using (MemoryStream ms = new MemoryStream())
{
img.Save(ms, ImageFormat.Jpeg); // BREAKING POINT
photo_aray = new byte[ms.Length];
ms.Position = 0;
ms.Read(photo_aray, 0, photo_aray.Length);
}
Every time the user attempts to update, the following error message is shown :
A generic error occurred in GDI+.:: at System.Drawing.Image.Save(Stream stream, ImageCodecInfo encoder, EncoderParameters encoderParams)
at System.Drawing.Image.Save(Stream stream, ImageFormat format)
note that if the user changes the image or simply choose the same image using the Filedialog no error occurs.
any help is appreciated.
****** EDIT #1 *********
just to clarify,
records are first loaded from the database into RecordsList object which is bound to a List.
when a user selects a certain record, the Image is loaded from the Selected Record to the PictureBox.
if no changes are made to the picture , the image is loaded from picturebox to the logic explained above.
Thanks to Mr. #Jimi , I've managed to solve the issue.
as he so kindly pointed out, i need to dispose of the Memory stream after saving the object.
so my code was edited like this :
Image img = PictureBox.Image;
byte[] photo_aray = null;
MemoryStream ms = new MemoryStream();
img.Save(ms, ImageFormat.Jpeg);
photo_aray = new byte[ms.Length];
ms.Position = 0;
ms.Read(photo_aray, 0, photo_aray.Length);
//
//
//SQL UPDATE HERE
//
//
ms.Close();
ms.Dispose();
Thanks!
I am trying to save a bitmap to a MemoryStream and then convert it to string. But the problem is, I am having an error that says the line img.Save(m, img.RawFormat); cannot be null. The error is this
The bitmap is from a fingerprint scan, that I converted to image. Now I want to convert its data to a string, by using MemoryStream. This is for the fingerprint data to be saved in the database. I don't know where I went wrong. You can find my code below:
Bitmap bitmap;
bitmap = ConvertSampleToBitmap(Sample);
Bitmap img = new Bitmap(bitmap, fingerprint.Size);
this.Invoke(new Function(delegate () {
fingerprint.Image = img; // fit the image into the picture box
}));
string ping;
using (MemoryStream m = new MemoryStream())
{
img.Save(m, img.RawFormat);
ping = m.ToString();
}
I hope for an accurate answer that can pin point the major error and what parts of the code should I change.
Though any help would be much appreciated.
Interesting; what happens here is:
public void Save(Stream stream, ImageFormat format)
{
if (format == null)
{
throw new ArgumentNullException("format");
}
ImageCodecInfo encoder = format.FindEncoder();
this.Save(stream, encoder, null);
}
with the inner Save doing this check:
public void Save(Stream stream, ImageCodecInfo encoder, EncoderParameters encoderParams)
{
if (stream == null)
{
throw new ArgumentNullException("stream");
}
if (encoder == null)
{
throw new ArgumentNullException("encoder");
}
so; we can assume that format.FindEncoder(); is returning null here. As it happens, this is indeed the default if there is no matching codec:
internal ImageCodecInfo FindEncoder()
{
foreach (ImageCodecInfo info in ImageCodecInfo.GetImageEncoders())
{
if (info.FormatID.Equals(this.guid))
{
return info;
}
}
return null;
}
So basically, it isn't clear, but the problem is: there is no encoder found for the image format that you're using. Try saving as a well-known format, not necessarily the one that it loaded from. Maybe use ImageFormat.Png and save it as a png?
img.Save(m, ImageFormat.Png);
and as already mentioned in the comments, to get base-64 of that, you'll need:
ping = Convert.ToBase64String(m.GetBuffer(), 0, (int)m.Length);
My aim is to convert a base64 string into an image and save it to the disk. I have the following code (mostly from this SO answer) -
namespace ImageSaver
{
using System;
static class Program
{
public static void LoadImage()
{
//get a temp image from bytes, instead of loading from disk
//data:image/gif;base64,
//this image is a single pixel (black)
byte[] bytes = Convert.FromBase64String("R0lGODlhAQABAIAAAAAAAAAAACH5BAAAAAAALAAAAAABAAEAAAICTAEAOw==");
Image image;
Bitmap bimage;
using (MemoryStream ms = new MemoryStream(bytes))
{
image = Image.FromStream(ms);
}
bimage = new Bitmap(image);
bimage.Save("c:\\img.gif", System.Drawing.Imaging.ImageFormat.Gif);
}
static void Main(string[] args)
{
ImageSaver.Program.LoadImage();
}
}
}
I ran it on MS Visual Studio 2010 Ultimate (Windows 8.1 Pro x64), without errors, but I could not find the image file in C drive. Where did I go wrong?
Try to save your file in this way:
File.WriteAllBytes(#"c:\img.gif", bytes);
EDIT
Anyway put your code under try'n'catch to better understand why you file is not being saved.
Try updating LoadImage to this to find out what the error is, and set a debug point on the MessageBox to examine the full details of what's happening;
public static void LoadImage()
{
try
{
//get a temp image from bytes, instead of loading from disk
//data:image/gif;base64,
//this image is a single pixel (black)
byte[] bytes = Convert.FromBase64String("R0lGODlhAQABAIAAAAAAAAAAACH5BAAAAAAALAAAAAABAAEAAAICTAEAOw==");
Image image;
Bitmap bimage;
using (MemoryStream ms = new MemoryStream(bytes))
{
image = Image.FromStream(ms);
}
bimage = new Bitmap(image);
bimage.Save("c:\\img.gif", System.Drawing.Imaging.ImageFormat.Gif);
}
catch (Exception ex) {
MessageBox.Show(ex.Message);
}
}
When i save an image to an memoriestream in Exif Format i get an ArgumentNullException, Der Wert darf nicht NULL sein.Parametername: encoder
Here is my code:
Image image = Image.FromFile(#"C:\Users\tkaemmerling\Pictures\alpha-test-photo.jpg");
image.Save(#"C:\Users\tkaemmerling\Pictures\alpha-test-photo.Exif", ImageFormat.Exif);
using (MemoryStream memstream = new MemoryStream())
{
image.Save(memstream, ImageFormat.Exif);
}
How can i save the image in exif format to an memory stream?
Actually I don't think it works even for saving file on disk. If you open the saved file it has PNG in the header. If you check the internals, the save method looks like this:
public void Save(string filename, ImageFormat format)
{
if (format == null)
{
throw new ArgumentNullException("format");
}
ImageCodecInfo imageCodecInfo = format.FindEncoder();
if (imageCodecInfo == null)
{
imageCodecInfo = ImageFormat.Png.FindEncoder();
}
this.Save(filename, imageCodecInfo, null);
}
Problem is there is no encoder associated with the EXIF format - try debugging
var imageEncoders = ImageCodecInfo.GetImageEncoders();
So you may as well use
Image image = Image.FromFile(#"C:\Users\tkaemmerling\Pictures\alpha-test-photo.jpg");
image.Save(#"C:\Users\tkaemmerling\Pictures\alpha-test-photo.Exif", ImageFormat.Png);
using (MemoryStream memstream = new MemoryStream())
{
image.Save(memstream, ImageFormat.Png);
}
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);