2009-08-07 19 views
8

有没有办法找出图像的ContentType只来自原始字节?从字节中查找图像的ContentType []

目前我有一个数据库列只存储字节[],我用它来在网页上显示图像。

MemoryStream ms = new MemoryStream(imageBytes); 
Image image = Image.FromStream(ms); 
image.Save(context.HttpContext.Response.OutputStream, <--ContentType-->); 

我当然可以将ContentType保存在表中的另一列,但只是想知道是否有另一种方式,例如,也许.Net有一种方法来查询数据来获取类型。

回答

15

看看这个file signatures table

+0

+1好的答案。 – 2009-08-07 15:58:48

+0

欢呼的链接。我做了一些搜索,现在我知道要寻找什么,这似乎是一条路。 – 2009-08-07 16:32:44

+0

根据你的想法,我已经把下面的代码的工作版本。 – 2009-08-07 17:32:09

0

RawFormat属性是否适合您?

MemoryStream ms = new MemoryStream(imageBytes); 
Image image = Image.FromStream(ms); 
image.Save(context.HttpContext.Response.OutputStream, image.RawFormat); 
+0

RawFormat似乎适用于jpeg和gif,但不适用于png。对于一个测试,我也尝试将它硬编码为jpeg,并且它的工作方式相同(对于所有人而不是png),我想.Net会将更多逻辑应用于png。 – 2009-08-07 16:11:43

+0

从其他例子中我看到RawFormat似乎只在图像从文件系统加载而不是通过字节(db列)创建时才起作用。 – 2009-08-07 17:40:17

1

有没有标准的方法来检测内置.NET流的内容类型。您可以通过读取前几个字节并尝试匹配格式来实现自己的算法,该算法可以实现一些well-known图像格式。

14

文件/魔法签名是要走的路。以下是代码的工作版本。

编号: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); 

然后是辅助类:

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 }, 
    }; 
+0

出于好奇,是否有你的循环增加“i + = 1”而不是“i ++”的原因? – Portman 2009-08-11 20:20:19

+0

我改编了另一个Stackoverflow问题/答案(上面提到)的代码。代码已经改变,因为我也理解i ++比i + = 1更多。 – 2009-08-12 09:16:18

+0

@Portman,个人风格和偏好。有人认为'i ++'更清晰,其他人认为它不太“最佳实践”。看到这个:http://stackoverflow.com/questions/971312/why-avoid-increment-and-decrement-operators-in-javascript – ANeves 2012-10-25 12:06:35

6

这为我工作,ms是将MemoryStream。缺点是它必须加载图像。

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 
2

重写了尼克·克拉克的一点使用LINQ的方法:我用ImagePartType,因为我与此刻的Open XML SDK的工作,但只是改变了字典中的类型

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 } 
    }; 
} 

: )