Reputation: 1282
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.
Upvotes: 9
Views: 20551
Reputation: 14498
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 :)
Upvotes: 4
Reputation: 683
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
Upvotes: 7
Reputation: 1282
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 },
};
Upvotes: 15
Reputation: 1038790
There's no standard way to detect content type from a stream built-in .NET. You could implement your own algorithm that could achieve this for some well-known image formats by reading the first few bytes and trying to match the format.
Upvotes: 1