Search code examples
c#image.net-4.8file-conversion

Converted image in memory not the same as when stored and then read again


I've got an Image as Stream coming in and I'm trying to convert the incoming Image from whatever it maybe (even if it already is a PNG) to a PNG.

I'm doing this as part of sanitizing the image as it comes from a source I do not trust. By converting it I'm trying to get rid of any code that might have been injected into the image before I store it and return it to a frontend client at a later date.

I'm trying to do this in memory and to my knowledge it should be done like this:

Image image = Image.FromStream(stream, false, true);
using (MemoryStream ms = new MemoryStream())
{
    image.Save(ms, ImageFormat.Png);
    return ValidateImage(path, ms);
};

What ive noticed however is that doing it in the above way has a different result from storing the image to disk and then reading it again after ive converted it.

Image image = Image.FromStream(stream, false, true);
using (MemoryStream ms = new MemoryStream())
{
    image.Save(ms, ImageFormat.Png);
    File.WriteAllBytes(path, ms.ToArray());
};

using (FileStream fs = new FileStream(path, FileMode.Open))
{    
    return ValidateImage(path, fs);
};

My ValidateImage method at some point does this:


byte[] bytes;
using (MemoryStream ms = new MemoryStream())
{
     contentStream.CopyTo(ms);
     bytes = ms.ToArray();
}

if(Validate(bytes)){
}

public override bool Validate(byte[] data)
{
     ImageFormat _format = new ImageFormat(new Guid("{b96b3caf-0728-11d3-9d7b-0000f81ef32e}"))
    try
    {
        // Try to open the image
        Image img;
        using (Stream ms = new MemoryStream(data))
        {
            img = Image.FromStream(ms);
        }

        // Check if the format matches the expected format
        return img.RawFormat.Equals(_format);
    }
    catch (Exception)
    {
        // Return false on exception
        return false;
    }
}

The above Validate() returns false because the RawFormat does not equal _format when I do the conversion solely in memory. It returns true when I write the file to disk and then read it in again and I'm wondering why and was hoping to find a sage who could enlighten me and help me to do the conversion solely in memory properly.

Thank you in advance


Solution

  • You are disposing Stream ms in Validate() before you are done with img. You must keep ms alive while img is alive.

    You also should reset the current position of MemoryStream ms in the outer code after writing the image to it, so that ValidateImage() sees it.