Save Image from Memorystream using C# and ASP.NET - c#

I am using a memory stream to resize an image through a FileUpload control. After it resizes it I want it to save to my filesystem at "~/images/2012/" + filename.
How do I save the image from a memorystream?
System.Drawing.Image imageLarge = System.Drawing.Image.FromStream(stream);
System.Drawing.Image imageLarge1 = ResizeImage(imageLarge, 200, 300);
MemoryStream memolarge = new MemoryStream();
imageLarge1.Save(memolarge, System.Drawing.Imaging.ImageFormat.Jpeg);
System.Drawing.Image returnImage = System.Drawing.Image.FromStream(memolarge);
Encoder myEncoder;
EncoderParameter myEncoderParameter;
EncoderParameters myEncoderParameters;
myEncoder = Encoder.Quality;
myEncoderParameter = new EncoderParameter(myEncoder, 100L);
myEncoderParameters.Param[0] = myEncoderParameter;
string convertedImage = returnImage.ToString();
returnImage.Save("~/images/2012/" + filename,
ImageFormat.Jpeg, myEncoderParameters);
This is the error I am getting along with an overloaded method error:
cannot convert from 'System.Drawing.Imaging.ImageFormat' to System.Drawing.Imaging.ImageCodecInfo

Look at the overloads of Image.Save.
Only the final two accept EncoderParameters, and neither of them accept an ImageFormat - both accept an ImageCodecInfo.
It's very important to be able to diagnose this kind of problem yourself:
Look at the compiler error carefully
Read the documentation
Check whether the call you're making makes sense
This has nothing to do with saving to a MemoryStream in particular - in fact, it's not clear why you're saving an Image and then immediately loading an Image from the same stream. (I'd advise setting the Position to 0 before you do so anyway, if you really want to keep doing this.)

Try this line instead:
returnImage.Save(
"~/images/2012/" + filename,
ImageCodecInfo.GetImageEncoders()
.Where(i => i.MimeType == "image/jpeg")
.First(),
myEncoderParameters);

See post Saving as jpeg from memorystream in c# it does something very similar to what you are looking for.
Also to change the codec properly
http://msdn.microsoft.com/en-us/library/ytz20d80.aspx

Related

C# saving bitmap to jpeg with colour space information

I've been trying to find a ways to write in information about jpeg colour space information, since regular saving does not do that, and barely anyone talks about it. Part of the code I use to save into jpeg:
using (Bitmap bmp = new Bitmap(bitmapPicture))
{
ImageCodecInfo jpgEncoder = GetEncoder(ImageFormat.Jpeg);
System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality;
EncoderParameters myEncoderParameters = new EncoderParameters(1);
EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, 100L);
myEncoderParameters.Param[0] = myEncoderParameter;
bmp.Save(textBox1.Text + "\\" + textBox2.Text + ".jpg", jpgEncoder, myEncoderParameters);
}
It does the trick, but it doesn't add colour space information which I think is one of the problems when opening that picture with different applications. The colours appears to be incorrect. Also for some reason bitmap brush only uses argb colour space (notice code below). If I'd type in '.FromSrgb' or '.FromRgb' it errors it out (apparently no such thing exists). This is example how I create bitmap which later on is being saved:
using (Graphics gfx = Graphics.FromImage(bitmapPicture))
using (SolidBrush brush = new SolidBrush(System.Drawing.Color.FromArgb(255, 255, 255)))
{
gfx.FillRectangle(brush, 0, 0, with, height);
gfx.DrawImage(addOtherImageOnSameBitmap, xCoordinate, yCoordinate, with2, height2);
}
Also tried doing that with Save File Dialog (code below), but the result is the same - jpeg colours is way off and has no information about colour space.
SaveFileDialog save = new SaveFileDialog();
save.Filter = "Images|*.jpg";
ImageFormat format = ImageFormat.Png;
if (save.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
string ext = System.IO.Path.GetExtension(save.FileName);
switch (ext)
{
case ".jpg":
format = ImageFormat.Jpeg;
break;
}
pictureBox1.Image.Save(save.FileName, format);
}
The problem is fixed when opening that image in photoshop and saving it with sRGB colour space. Is it possible to do that in C#? To save jpeg in sRGB and adding this information to jpeg file itself? Because going into photoshop to fix this problem seems to be a bit too much of a hassle (especially when dealing with a lot of pictures).
P.S. sorry if posted codes seems somewhat off, I just started learning C# couple days ago.

Saving encoded image returns GDI+ error

Here's the deal. I'm trying to use a function to compress an image from my notebook camera while using a standard code to do that:
public static byte[] EncodeImage(this Image image)
{
using (MemoryStream ms = new MemoryStream())
{
ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg");
EncoderParameter qualityParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 80);
EncoderParameters encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = qualityParam;
image.Save(ms, jpegCodec, encoderParams);
return ms.ToArray();
}
}
After the compression is done, I save it to the database. Works good, providing me with a good amount of compression (500 000 bytes vs 32 000). Some time later, I need to show the image to the user in a winforms application.
using (MemoryStream ms = new MemoryStream(entity.Photo))
fotoPictureBox.Image = Image.FromStream(ms);
Again, this displays a nice image. However, then I want the user to be able to download the image and save where he sees suitable. And this is when all the problems arise.
If I use this code:
fotoPictureBox.Image.Save(imageSaveFileDialog.FileName);
I receieve a typical generic GDI+ error.
If I try to save the image by using the code I've encoded it
public static void SaveEncodedImage(this Image image, string targetPath)
{
ImageCodecInfo jpegCodec = Pomocne.GetEncoderInfo("image/jpeg");
EncoderParameter qualityParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 80);
EncoderParameters encoderParams = new EncoderParameters(1);
encoderParams.Param[0] = qualityParam;
image.Save(targetPath, jpegCodec, encoderParams);
}
I get this error (pointing to the line image.Save(targetPath, jpegCodec, encoderParams);):
An unhandled exception of type System.ArgumentException occurred in System.Drawing.dll
Additional information: Parameter is not valid.
Can please anyone help? It's rather urgent, thank you.
To address some questions/answers you will probably start with - if I don't compress the image with this code, I can save the image to the chosen path without any problems. So there's clearly some problem with decoding or something like that. Don't ask me if I have sufficient permissions, because I have.
For some reason this code works great:
File.WriteAllBytes(targetPath, byteArray);
I guess sometimes the easiest solution is the right one. Not sure about the exact explanation (you can provide one, I'll surely vote up), but this is resolved.
Thanks anyway.

A generic error occured in GDI+

I'm attempting to resize and image using the following function and receiving this error:
Exception Details: System.Runtime.InteropServices.ExternalException: A generic error occurred in GDI+.
on this line:
imageConvertedToBitmap.Save(cachedFileName, info[1], encoderParameters);
Any ideas why this might be happening?
private byte[] GetCachedImage(string cachedFileName, string pathToImage, int width, int height)
{
if (!System.IO.File.Exists(cachedFileName) || (System.IO.File.GetLastWriteTime(pathToImage) > System.IO.File.GetLastWriteTime(cachedFileName)))
{
Image imageToResize = Image.FromFile(pathToImage);
Image imageConvertedToBitmap = new Bitmap(width, height);
Graphics graphicsController = Graphics.FromImage(imageConvertedToBitmap);
graphicsController.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphicsController.SmoothingMode = SmoothingMode.HighQuality;
graphicsController.PixelOffsetMode = PixelOffsetMode.HighQuality;
graphicsController.CompositingQuality = CompositingQuality.HighQuality;
graphicsController.DrawImage(imageToResize, 0, 0, width, height);
EncoderParameters parameters = new EncoderParameters(1);
parameters.Param[0] = new EncoderParameter(Encoder.Quality, 80L);
ImageCodecInfo[] info = ImageCodecInfo.GetImageEncoders();
EncoderParameters encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 80L);
MemoryStream memoryStream = new MemoryStream();
imageConvertedToBitmap.Save(cachedFileName, info[1], encoderParameters);
imageConvertedToBitmap.Save(memoryStream, info[1], encoderParameters);
imageToResize.Dispose();
imageConvertedToBitmap.Dispose();
graphicsController.Dispose();
parameters.Dispose();
encoderParameters.Dispose();
return memoryStream.GetBuffer();
}
byte[] buffer = null;
try
{
FileStream fileStream = new FileStream(cachedFileName, FileMode.Open, FileAccess.Read);
BinaryReader binaryReader = new BinaryReader(fileStream);
long totalBytes = new FileInfo(cachedFileName).Length;
buffer = binaryReader.ReadBytes((Int32)totalBytes);
fileStream.Close();
fileStream.Dispose();
binaryReader.Close();
}
catch { }
return buffer;
}
It was a permissions error. Had to give appropriate Write permission to the directory I was saving to. Sometimes it's the simple things. :)
From what I read, when getting this GDI+ error, the first thing to check should be permissions as it's almost always an indicator of a security problem.
Try an overload of Save that doesn't take EncoderParameters as a parameter. It should work fine and produce the resized image that you're looking for.
I had this error one time, it was because I tried to save under a locked file by a Bitmap object.
We just see your method but not how you use it.
I think there are several syntax problems in your code : you must use "using() { }" for all the disable objects in your code.
using(Image imageToResize = Image.FromFile(pathToImage))
using(Image imageConvertedToBitmap = new Bitmap(width, height))
etc.
{
}
Your got this error on another instance.
Firstly understand what this error means the other way:
When you get the error, go to task manager and navigate to Details tab.
Right click on the table headers and click select columns.
Tick the GDI objects checkbox.
Now find the name of your program in the table and check the no. of GDI objects.
It would have exceeded 10000 or must be at 10000.
The error pops up whenever the no. of GDI objects by a program exceeds
10000 as 10000 is the limit.
Check how many times the System.Drawing.... runs in your code.
Prevent objects like Fonts or Images from being created again and again.
Instead set a reference point.

How to convert PNG to BMP at runtime?

I need to convert PNG file to BMP file on runtime.
I can't do it like
Image dummy = Image.FromFile("image.png");
dummy.Save("image.bmp", ImageFormat.Bmp);
because i can't save the bmp image on the local disk as a file.
Thanks for any help.
You can save to stream
using(MemoryStream stream = new MemoryStream())
{
Dummy.Save(stream, ImageFormat.Bmp);
}
Precise answer given here.
Image Dummy = Image.FromFile("image.png");
Dummy.Save("image.bmp", ImageFormat.Bmp);
Since you don't want to follow this method, you can do it the way Stecya answered.
Just do it this way.
Stream stream;
Dummy.save(stream, ImageFormat.Bmp)

Strange GDI+ behaviour

I have made a method to CompressImageSize according to Image quality. The code for it is
public static Image CompressImage(string imagePath, long quality)
{
Image srcImg = LoadImage(imagePath);
//Image srcImg = Image.FromFile(imagePath);
EncoderParameters parameters = new EncoderParameters(1);
parameters.Param[0] = new EncoderParameter(Encoder.Quality, quality);
ImageCodecInfo encoder = GetCodecInfo("image/jpeg");
srcImg.Save("d:\\creatives\\abcd123.jpg", encoder, parameters);
}
public static Image LoadImage(string filename)
{
using (FileStream fs = new FileStream(filename, FileMode.Open))
{
return(Image.FromStream(fs));
}
}
Now, when i run this code as is it gives me a 'Generic GDI+ exception' while saving the srcImg(last line in func #1), BUT when i uncomment the 2nd line and load the image using Image.FromFile everything works fine.
Why ??
According to MSDN:
Remarks:
You must keep the stream open for the lifetime of the Image.
Here your stream is in a using block and thus closed before the end of the lifetime of the image.
You should rewrite your code:
public static Image LoadImage(string filename)
{
FileStream fs = new FileStream(filename, FileMode.Open);
return Image.FromStream(fs);
}
Construction using is wrong in this case because FileStream needs to be alive for using your Image.
A wild guess... Image is IDisposable. Are you calling this in a loop or something? Try putting your Image itself in a using() block?
In the end of LoadImage, the FileStream containing the Image is disposed. This is too soon; the file stream needs to be alive for use by the method calling LoadImage.
See using on MSDN.
There are various issues with Image.FromFile()...
Image srcImg = Image.FromFile(imagePath);
The above statement will not close the file stream and that will create problems if you want to access file again or delete it. I would write your function this way.
public static Image CompressImage(string imagePath, long quality)
{
using(FileStream fs = File.OpenRead(imagePath)){
Image srcImg = Image.FromStream(fs);
EncoderParameters parameters = new EncoderParameters(1);
parameters.Param[0] = new EncoderParameter(Encoder.Quality, quality);
ImageCodecInfo encoder = GetCodecInfo("image/jpeg");
srcImg.Save("d:\\creatives\\abcd123.jpg", encoder, parameters);
}
}
This will guarentee that my file will be closed at the end of using scope.
Fix , but for me the Dispose call is a bug in .net framework...
public static Image CompressImage(string imagePath, long quality)
{
Image srcImg = LoadImage(imagePath);
//Image srcImg = Image.FromFile(imagePath);
EncoderParameters parameters = new EncoderParameters(1);
parameters.Param[0] = new EncoderParameter(Encoder.Quality, quality);
ImageCodecInfo encoder = GetCodecInfo("image/jpeg");
srcImg.Save("d:\\creatives\\abcd123.jpg", encoder, parameters);
srcImg.Dispose();
}

Categories

Resources