Convert an image to base64 and vice versa - c#

I want to convert an image to base64 and back to image again.
Here is the code which i tried so far and the error also. Any suggestions please?
public void Base64ToImage(string coded)
{
System.Drawing.Image finalImage;
MemoryStream ms = new MemoryStream();
byte[] imageBytes = Convert.FromBase64String(coded);
ms.Read(imageBytes, 0, imageBytes.Length);
ms.Seek(0, SeekOrigin.Begin);
finalImage = System.Drawing.Image.FromStream(ms);
Response.ContentType = "image/jpeg";
Response.AppendHeader("Content-Disposition", "attachment; filename=LeftCorner.jpg");
finalImage.Save(Response.OutputStream, ImageFormat.Jpeg);
}
The error is :
Parameter is not valid.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.ArgumentException: Parameter is not valid.
Source Error:
Line 34: ms.Read(imageBytes, 0, imageBytes.Length);
Line 35: ms.Seek(0, SeekOrigin.Begin);
Line 36: finalImage = System.Drawing.Image.FromStream(ms);
Line 37:
Line 38: Response.ContentType = "image/jpeg";
Source File: e:\Practice Projects\FaceDetection\Default.aspx.cs Line: 36

You are reading from an empty stream, rather than loading the existing data (imageBytes) into the stream. Try:
byte[] imageBytes = Convert.FromBase64String(coded);
using(var ms = new MemoryStream(imageBytes)) {
finalImage = System.Drawing.Image.FromStream(ms);
}
Also, you should endeavour to ensure that finalImage is disposed; I would propose:
System.Drawing.Image finalImage = null;
try {
// the existing code that may (or may not) successfully create an image
// and assign to finalImage
} finally {
if(finalImage != null) finalImage.Dispose();
}
And finally, note that System.Drawing is not supported on ASP.NET; YMMV.
Caution
Classes within the System.Drawing namespace are not supported for use within a Windows or ASP.NET service. Attempting to use these classes from within one of these application types may produce unexpected problems, such as diminished service performance and run-time exceptions. For a supported alternative, see Windows Imaging Components.

The MemoryStream.Read Method reads bytes from the MemoryStream into the specified byte array.
If you want to write the byte array to the MemoryStream, use the MemoryStream.Write Method:
ms.Write(imageBytes, 0, imageBytes.Length);
ms.Seek(0, SeekOrigin.Begin);
Alternatively, you can simply wrap the byte array in a MemoryStream:
MemoryStream ms = new MemoryStream(imageBytes);

Related

C# byte[] to bitmap System.InvalidOperationException

I'm doing a C# web service soap receiving an image.
I send a string contain the byte characters.
I transform the string in byte[] and next I world like to create the Bitmap.
The line Bitmap img = new Bitmap(ms); generate an exception : invalid argument.
I have a in the ms object this error : System.InvalidOperationException
value contain the correct string, imgBytes contain the good number of sell.
public string GetImage(string value)
{
byte[] imgBytes = Encoding.ASCII.GetBytes(value);
MemoryStream ms = new MemoryStream(imgBytes, true);
Bitmap img = new Bitmap(ms);
Code with debug mode
Exception
Thank you for your help.
It looks like your string holds base64 encoded data. Try to decode it to a byte array via Convert.FromBase64String
I had a similar problem. Basically you write into your memory stream (in the constructor) and the position pointer is at the end. So before reuse the memory stream you can try setting its position pointer to the beginning. Like this:
MemoryStream ms = new MemoryStream(imgBytes, true);
ms.Position = 0;
Bitmap img = new Bitmap(ms);
or the more general approach:
MemoryStream ms = new MemoryStream(imgBytes, true);
ms.Seek(0, SeekOrigin.Begin);
Bitmap img = new Bitmap(ms);
Hope this will solve your Problem.
Update
I think #heinbeinz answer is also important: First decode your string from the right encoding (normally base64), then set the position.

C# Convert BitmapImage object to ByteArray

How do I convert an object of BitmapImage type to a byte array?
There's plenty of examples out on the web but all of them are using methods that no longer exist for windows Store app.
best solution I've found is this, however I get an exception on the first code line when trying to run it
public static byte[] ConvertBitmapToByteArrayAsync(WriteableBitmap bitmap)
{
using (var stream = bitmap.PixelBuffer.AsStream())
{
MemoryStream memoryStream = new MemoryStream();
stream.CopyTo(memoryStream);
return memoryStream.ToArray();
}
}
exception:
A first chance exception of type 'System.AccessViolationException'
occurred in System.Runtime.WindowsRuntime.dll
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
from what I can gather it may have to do with the size of the stream but I haven't been able to figure out how to fix it.
I hope this can help you:
// Converting Bitmap to byte array
private byte[] ConvertBitmapToByteArray(Bitmap imageToConvert)
{
MemoryStream ms = new System.IO.MemoryStream();
imageToConvert.Save(ms, ImageFormat.Png);
return ms.ToArray();
}
// Converting byte array to bitmap
private Bitmap ConvertBytesToBitmap(byte[] BytesToConvert)
{
MemoryStream ms = new MemoryStream(BytesToConvert);
try { return new Bitmap(ms); }
catch { return null; }
}

Generic GDI+ error (error number -2147467259)

My friends,
I am trying convert a image to a Base64 String in a c# console app (.net 4.0).
The method:
public static String ConvertBitmapToBase64String(Bitmap bitmap,
ImageFormat imageFormat)
{
String generatedString = string.Empty;
MemoryStream memoryStream = new MemoryStream();
bitmap.Save(memoryStream, imageFormat);
memoryStream.Position = 0;
byte[] byteBuffer = memoryStream.ToArray();
memoryStream.Close();
generatedString = Convert.ToBase64String(byteBuffer);
byteBuffer = null;
return generatedString;
}
But when I invoke this method it is throwing an exception saying: "generic gdi+ error" and the error number is -2147467259.
Invoker code:
StreamReader streamReader = new StreamReader(#"C:\Anita.jpg");
Bitmap bitmap = new Bitmap(streamReader.BaseStream);
streamReader.Close();
String base64String = ImageUtil.ConvertBitmapToBase64String(bitmap, ImageFormat.Jpeg);
Anybody can give me a help?
Thanks.
The only likely problem I see is that the image is too large or big. Perhaps, instead of using a MemoryStream, you can use File.ReadAllBytes directly instead of passing around the Bitmap object, saving directly to a MemoryStream, and saving.
Also, you're reading the data in with a StreamReader, which is meant for text! Moving to just reading the bytes into an array and calling Convert.ToBase64String() should handle what you want to do.

Parameter is not valid when getting image from stream

I have this code:
MemoryStream ms = new MemoryStream(newbytes, 0,
newbytes.Length);
ms.Position = 0;
ms.Write(newbytes, 0, newbytes.Length);
Image img = Image.FromStream(ms);
img.Save(#"C:\Users\gsira\Pictures\Blue hills5.jpg");
I get this error at the Image.FromStream(ms) call:
System.ArgumentException: Parameter is not valid.
at System.Drawing.Image.FromStream(Stream stream, Boolean useEmbeddedColorManagement, Boolean validateIma
How can I resolve this? A couple of links which solve this problem (one on an MSDN thread) are broken so I am lost.
If you initialise a MemoryStream with a byte array (which is what I am assuming newbytes to be), you should not need to write to it.
The call to Write(newbytes, 0, newbytes.Length) in your sample is completely redundant.
var s = new MemoryStream(newbytes, 0, newbytes.Length);
var i = Image.FromStream(s);
i.Save(#"C:\Users\gsira\Pictures\Blue hills5.jpg");
The above works for me where newbytes is a byte array of the contents of an image file on my hard drive.
Try to rewind memory stream to the very beginning after you wrote bytes into it.
ms.Seek(0, SeekOrigin.Begin);
Than it's possible to create Image.FromStream

Cannot render image to HttpContext.Response.OutputStream

Basically I am trying to render a simple image in an ASP.NET handler:
public void ProcessRequest (HttpContext context)
{
Bitmap image = new Bitmap(16, 16);
Graphics graph = Graphics.FromImage(image);
graph.FillEllipse(Brushes.Green, 0, 0, 16, 16);
context.Response.ContentType = "image/png";
image.Save(context.Response.OutputStream, ImageFormat.Png);
}
But I get the following exception:
System.Runtime.InteropServices.ExternalException: A generic error
occurred in GDI+.
at System.Drawing.Image.Save(Stream stream, ImageCodecInfo encoder,
EncoderParameters encoderParams)
The solution is to use this instead of having image write to OutputStream:
MemoryStream temp = new MemoryStream();
image.Save(temp, ImageFormat.Png);
byte[] buffer = temp.GetBuffer();
context.Response.OutputStream.Write(buffer, 0, buffer.Length);
So I'm just curious as to why the first variant is problematic?
Edit: The HRESULT is 80004005 which is just "generic".
The writer indeed needs to seek to write in the stream properly.
But in your last source code, make sure that you do use either MemoryStream.ToArray() to get the proper data or, if you do not want to copy the data, use MemoryStream.GetBuffer() with MemoryStream.Length and not the length of the returned array.
GetBuffer will return the internal buffer used by the MemoryStream, and its length generally greater than the length of the data that has been written to the stream.
This will avoid you to send garbage at the end of the stream, and not mess up some strict image decoder that would not tolerate trailing garbage. (And transfer less data...)
Image.Save(MemoryStream stream) does require a MemoryStream object that can be seeked upon. The context.Response.OutputStream is forward-only and doesn't support seeking, so you need an intermediate stream. However, you don't need the byte array buffer. You can write directly from the temporary memory stream into the context.Response.OutputStream:
/// <summary>
/// Sends a given image to the client browser as a PNG encoded image.
/// </summary>
/// <param name="image">The image object to send.</param>
private void SendImage(Image image)
{
// Get the PNG image codec
ImageCodecInfo codec = GetCodec("image/png");
// Configure to encode at high quality
using (EncoderParameters ep = new EncoderParameters())
{
ep.Param[0] = new EncoderParameter(Encoder.Quality, 100L);
// Encode the image
using (MemoryStream ms = new MemoryStream())
{
image.Save(ms, codec, ep);
// Send the encoded image to the browser
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.ContentType = "image/png";
ms.WriteTo(HttpContext.Current.Response.OutputStream);
}
}
}
A fully functional code sample is available here:
Auto-Generate Anti-Aliased Text Images with ASP.NET
I believe the problem is that the Response.OutputStream does not support seeking. In order to save a PNG (or JPEG), the image object needs to be able to write the output non-sequentially. If I remember correctly, it would have worked if you saved the image as a BMP since that image format can be written without seeking the stream.
Ok I used a wrapper for Stream (implements Stream and passes calls to an underlying stream) to determine that Image.Save() calls Position and Length properties without checking CanSeek which returns false. It also tries to set Position to 0.
So it seems an intermediate buffer is required.

Categories