Dave
Dave

Reputation: 3017

Create a bitmap from a stored byte array and save to disk throws GDI+ exception when source of byte array was a jpg

I hope someone can help with an issue I am having saving an image that has been given to me as a byte array.

Versions:

The story is

  1. User uploads image
  2. We serialise into a byte array and store this
  3. At a later point we get that byte array and create a memory steam and with that stream create a bitmap object.
  4. use that bitmap object to save to disk

That all works when the original file is in PNG format. However it fails when it is in Jpg format.

Below is some sample code that you can stick in a basic console app and as long as you reference System.Drawing it will run.

static void Main(string[] args)
{
    Console.WriteLine("Enter image file location");
    var filePath = Console.ReadLine();
    while (!File.Exists(filePath))
    {
        Console.WriteLine("Cannot find file. Try Again");
        filePath = Console.ReadLine();
    }

    byte[] bytes = File.ReadAllBytes(filePath);

    Bitmap image;
    using (var stream = new MemoryStream(bytes))
    {
        image = new Bitmap(stream);
    }

    WriteToFile(image);
    image.Dispose();
    Console.ReadKey();
}

private static void WriteToFile(Bitmap image)
{
    Console.WriteLine("Enter write location filename");
    var fileName = Console.ReadLine();
    image.Save(fileName);
    Console.WriteLine($"File saved to {fileName}");
}

If the original image is a PNG is works fine, if it is a JPG it fails. Why is that? I see that the Save method on the bitmap class has an overload that takes an ImageFormat instance. However only I have is the original byte array so I don't know what my image format is.

Any help would be really appreciated, thanks!

EDIT: I've tried specifying the Image Format as JPG both when creating the byte array from the original file and when saving it back to disk (see code below) and with jpgs it still continues to fail. Pngs however are still working fine

static void Main(string[] args)
{
    Console.WriteLine("Enter jpg file location");
    var filePath = Console.ReadLine();
    while (!File.Exists(filePath))
    {
        Console.WriteLine("Cannot find file. Try Again");
        filePath = Console.ReadLine();
    }

    byte[] bytes = CreateSerializedImage(filePath);

    Image image;
    using (var steram = new MemoryStream(bytes))
    {
        image = Image.FromStream(steram);
    }

    WriteToFile(image);
    image.Dispose();
    Console.ReadKey();
}

private static byte[] CreateSerializedImage(string filePath)
{
    var image = Image.FromFile(filePath);
    using (var stream = new MemoryStream())
    {
        image.Save(stream,ImageFormat.Jpeg);
        return stream.ToArray();
    }
}

private static void WriteToFile(Image image)
{
    Console.WriteLine("Enter write location filename");
    var fileName = Console.ReadLine();
    image.Save(fileName, ImageFormat.Jpeg);
    Console.WriteLine($"File saved to {fileName}");
}

Upvotes: 0

Views: 1626

Answers (1)

Michael
Michael

Reputation: 2113

You're disposing the MemoryStream before the image is written, try disposing the stream after the file has been saved. That worked for me :)

If you want to get the image format, try detecting it from the first few bytes of the stream:

Wikipedia: file-signature-list

Upvotes: 1

Related Questions