I have a WebAPI endpoint (hosted in IIS) that reads images from a database (byte array) and returns them in the PNG format. This code is simple:
Image img = ImageHelper.ReadFromDatabase(…);
using (MemoryStream ms = new MemoryStream())
{
img.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new ByteArrayContent(ms.ToArray());
response.Content.Headers.ContentType = new MediaTypeHeaderValue("image/png");
response.ConfigureResponseCachability(parseConceptVersion, TimeSpan.FromHours(1));
return response;
}
I have three web servers and on one of the them the above code causes this error: A generic error occurred in GDI+.
at at System.Drawing.Image.Save()
.
The servers are running different OS versions:
I have changed the above code to return a JPEG instead of a PNG and that fixes the problem.
img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
I have to send PNG images so I need to find the root cause.
I converted the code to use WPF classes (System.Windows.Media) instead of Windows Form classes. The result is interesting: I get an error creating PNGs as well. This time the error is The component registration is invalid. (Exception from HRESULT: 0x88982F8A)
at System.Windows.Media.Imaging.BitmapEncoder.SaveFrame()
Could it be that my server is missing a low level component that is necessary to save PNGs?
Thanks
@Chris Pratt asked to see the code that creates the images from the byte array. There are several layers between the WebAPI code and the SqlDataReader invocation but here is the code that converts the byte array read from the database.
/// <summary>
/// Creates a bitmap from a byte array
/// </summary>
public static Bitmap CreateBitmapFromBytes(byte[] bytes, int width, int height)
{
// Make sure bytes were specified.
if (bytes == null ||
bytes.Length == 0)
{
return null;
}
using (MemoryStream imageStream = new MemoryStream(bytes))
{
Bitmap bitmap;
try
{
bitmap = (Bitmap)Bitmap.FromStream(imageStream);
}
catch(ArgumentException)
{
return GetEmptyBitmap(width, height);
}
using (bitmap)
{
return new Bitmap(bitmap, width, height);
}
}
}
The System.Drawing namespace has a lot of known downsides for processing images. Please refer to this article with a nice and thorough explanation.
When dealing with this namespace, you have to be very careful where you dispose memory streams, bitmaps etc. etc. Your issue sounds like it has something to do with these disposable objects.
That said, a good alternative is to use the ImageSharp library, which among else, nicely handles reading an image from a byte array and saving it as png.
You could use the Image.Load method:
var img = Image.Load(ImageHelper.ReadFromDatabaseAsByteArray());
and save it as png to a MemoryStream for further use:
using (var memStream = new MemoryStream())
{
image.SaveAsPng(memStream);
// Do something with the memStream, for example prepare http response
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With