Is there a way to find out what the ContentType of an image is from only the original bytes?
At the moment I have a database column that stores only the byte[], which I use to display an image on a web page.
MemoryStream ms = new MemoryStream(imageBytes);
Image image = Image.FromStream(ms);
image.Save(context.HttpContext.Response.OutputStream, <--ContentType-->);
I could of course just save the ContentType in another column in the table, but just wondered if there was another way e.g. maybe .Net has a way to interrogate the data to get the type.
Check out this file signatures table.
File/magic signatures was the way to go. Below is the working version of the code.
Ref: Stackoverflow - Getting image dimensions without reading the entire file
ImageFormat contentType = ImageHelper.GetContentType(this.imageBytes);
MemoryStream ms = new MemoryStream(this.imageBytes);
Image image = Image.FromStream(ms);
image.Save(context.HttpContext.Response.OutputStream, contentType);
And then the helper class:
public static class ImageHelper
{
public static ImageFormat GetContentType(byte[] imageBytes)
{
MemoryStream ms = new MemoryStream(imageBytes);
using (BinaryReader br = new BinaryReader(ms))
{
int maxMagicBytesLength = imageFormatDecoders.Keys.OrderByDescending(x => x.Length).First().Length;
byte[] magicBytes = new byte[maxMagicBytesLength];
for (int i = 0; i < maxMagicBytesLength; i += 1)
{
magicBytes[i] = br.ReadByte();
foreach (var kvPair in imageFormatDecoders)
{
if (magicBytes.StartsWith(kvPair.Key))
{
return kvPair.Value;
}
}
}
throw new ArgumentException("Could not recognise image format", "binaryReader");
}
}
private static bool StartsWith(this byte[] thisBytes, byte[] thatBytes)
{
for (int i = 0; i < thatBytes.Length; i += 1)
{
if (thisBytes[i] != thatBytes[i])
{
return false;
}
}
return true;
}
private static Dictionary<byte[], ImageFormat> imageFormatDecoders = new Dictionary<byte[], ImageFormat>()
{
{ new byte[]{ 0x42, 0x4D }, ImageFormat.Bmp},
{ new byte[]{ 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 }, ImageFormat.Gif },
{ new byte[]{ 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 }, ImageFormat.Gif },
{ new byte[]{ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }, ImageFormat.Png },
{ new byte[]{ 0xff, 0xd8 }, ImageFormat.Jpeg },
};
This worked for me, ms
being the memorystream. The downside is that it has to load the image.
Dim fmt As System.Drawing.Imaging.ImageFormat
Dim content As String
Using bmp As New Drawing.Bitmap(ms)
fmt = bmp.RawFormat
End Using
Select Case fmt.Guid
Case Drawing.Imaging.ImageFormat.Bmp.Guid
content = "image/x-ms-bmp"
Case Drawing.Imaging.ImageFormat.Jpeg.Guid
content = "image/jpeg"
Case Drawing.Imaging.ImageFormat.Gif.Guid
content = "image/gif"
Case Drawing.Imaging.ImageFormat.Png.Guid
content = "image/png"
Case Else
content = "application/octet-stream"
End Select
Rewrote the method of Nick Clarke a bit using Linq:
public class Program
{
public static void Main(string[] args)
{
byte[] byteArray = File.ReadAllBytes(@"C:/users/Alexander/image.jpg");
ImagePartType type = byteArray.GetImageType();
}
}
public static class ImageHelper
{
public static ImagePartType GetImageType(this byte[] imageBytes)
{
foreach(var imageType in imageFormatDecoders)
{
if (imageType.Key.SequenceEqual(imageBytes.Take(imageType.Key.Length)))
return imageType.Value;
}
throw new ArgumentException("Imagetype is unknown!");
}
private static Dictionary<byte[], ImagePartType> imageFormatDecoders
= new Dictionary<byte[], ImagePartType>()
{
{ new byte[]{ 0x42, 0x4D }, ImagePartType.Bmp},
{ new byte[]{ 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 }, ImagePartType.Gif },
{ new byte[]{ 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 }, ImagePartType.Gif },
{ new byte[]{ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }, ImagePartType.Png },
{ new byte[]{ 0xff, 0xd8 }, ImagePartType.Jpeg }
};
}
I used ImagePartType
because I'm working with Open XML SDK at the moment, but just change the type in the dictionary :)
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