【问题标题】:Determine file type of an image确定图像的文件类型
【发布时间】:2010-09-08 12:35:40
【问题描述】:

我正在从一项服务下载一些图像,该服务并不总是包含内容类型,也没有为我正在下载的文件提供扩展名(呃,别问了)。

在 .NET 中确定图像格式的最佳方法是什么?

正在读取这些下载图像的应用程序需要具有正确的文件扩展名,否则将彻底崩溃。

【问题讨论】:

    标签: .net image content-type mime-types


    【解决方案1】:

    尝试将流加载到 System.IO.BinaryReader。

    然后您需要参考您需要的每种图像格式的规范,并逐字节加载标题以与规范进行比较。例如这里是PNG specifications

    添加:PNG 的实际 file structure

    【讨论】:

      【解决方案2】:

      所有图像格式都将它们的初始字节设置为特定值:

      搜索“jpg 文件格式”,将 jpg 替换为您需要识别的其他文件格式。

      按照 Garth 的建议,database of such 'magic numbers' 显示了许多文件的文件类型。如果您必须检测许多不同的文件类型,则值得通过它来查找您需要的信息。如果您确实需要扩展它以涵盖许多文件类型,请查看关联的file command,它实现了正确使用数据库的引擎(对于许多文件格式而言,这不是微不足道的,而且几乎是一个统计过程)

      -亚当

      【讨论】:

        【解决方案3】:

        亚当指出的方向完全正确。

        如果您想了解如何检测几乎所有文件,请查看 UNIX、Linux 或 Mac OS X 机器上 file 命令背后的数据库。

        file 使用“幻数”数据库——亚当列出的那些初始字节——来感知文件的类型。 man file 会告诉你在你的机器上哪里可以找到数据库,例如/usr/share/file/magicman magic 会告诉你它的format

        您可以根据您在数据库中看到的内容编写自己的检测代码,使用预打包的库(例如 python-magic),或者 - 如果您真的喜欢冒险 - 实现一个.NET 版本的libmagic。没找到,希望有大佬指点一下。

        如果您手边没有 UNIX 机器,数据库如下所示:

        # PNG [便携式网络图形,或“PNG 不是 GIF”] 图像 # (Greg Roelofs, newt@uchicago.edu) #(阿尔伯特·卡哈兰,acahalan@cs.uml.edu) # # 137 P N G \r \n ^Z \n [4字节长度] H E A D [HEAD数据] [HEAD crc] ... # 0 字符串 \x89PNG PNG 图像数据, >4 属于 !0x0d0a1a0a 损坏, >4 属于 0x0d0a1a0a >>16 属于 x %ld x >>20 属于 x %ld, >>24 字节 x %d 位 >>25 字节 0 灰度, >>25 字节 2 \b/颜色 RGB, >>25 字节 3 颜色图, >>25 字节 4 灰度+alpha, >>25 字节 6 \b/颜色 RGBA, #>>26 字节 0 放气/32K, >>28 字节 0 非隔行扫描 >>28 字节 1 隔行扫描 1 字符串 PNG PNG 图像数据,已损坏 # 动图 0 字符串 GIF8 GIF 图像数据 >4 字符串 7a \b,版本 8%s, >4 字符串 9a \b,版本 8%s, >6 leshort >0 %hd x >8 leshort >0 %hd #>10 字节 &0x80 颜色映射, #>10 字节&0x07 =0x00 2 种颜色 #>10 字节&0x07 =0x01 4 色 #>10 字节&0x07 =0x02 8 色 #>10 字节&0x07 =0x03 16 色 #>10字节&0x07 =0x04 32色 #>10 字节&0x07 =0x05 64 色 #>10 字节&0x07 =0x06 128 色 #>10 字节&0x07 =0x07 256 色

        祝你好运!

        【讨论】:

          【解决方案4】:

          一个可能更简单的方法是使用 Image.FromFile() 然后使用 RawFormat 属性,因为它已经知道最常见格式的标头中的魔术位,如下所示:

          Image i = Image.FromFile("c:\\foo");
          if (System.Drawing.Imaging.ImageFormat.Jpeg.Equals(i.RawFormat)) 
              MessageBox.Show("JPEG");
          else if (System.Drawing.Imaging.ImageFormat.Gif.Equals(i.RawFormat))
              MessageBox.Show("GIF");
          //Same for the rest of the formats
          

          【讨论】:

          • 仅供参考,这也适用于使用 System.Drawing.Image.FromStream() 的流
          • 如果您在 Web 应用程序的上下文中,请务必使用完全限定名称或导入程序集以避免与图像控件混淆... System.Drawing.Image
          【解决方案5】:

          有确定图像 MIMETYPE 的编程方式。

          有类System.Drawing.Imaging.ImageCodecInfo

          此类具有属性 MimeTypeFormatID。它还有一个方法GetImageEncoders,它返回所有图像编码器的集合。 创建由格式 id 索引的 mime 类型的字典很容易。

          System.Drawing.Image 具有 System.Drawing.Imaging.ImageFormat 类型的属性 RawFormat 具有属性 Guid 相当于 System.Drawing.Imaging.ImageCodecInfo 类的属性 FormatID,这是从字典中获取 MIMETYPE 的关键。

          例子:

          创建 mime 类型字典的静态方法

          static Dictionary<Guid, string> GetImageFormatMimeTypeIndex()
          {
            Dictionary<Guid, string> ret = new Dictionary<Guid, string>();
          
            var encoders = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders();
          
            foreach(var e in encoders)
            {
              ret.Add(e.FormatID, e.MimeType);
            }
          
            return ret;
          }
          

          用途:

          Dictionary<Guid, string> mimeTypeIndex = GetImageFormatMimeTypeIndex();
          
          FileStream imgStream = File.OpenRead(path);
          var image = System.Drawing.Image.FromStream(imgStream);
          string mimeType = mimeTypeIndex[image.RawFormat.Guid];
          

          【讨论】:

            【解决方案6】:

            您可以使用下面的代码而无需引用 System.Drawing 和不必要地创建对象 Image。即使没有 System.IO 的流和引用,您也可以使用Alex 解决方案。

            public enum ImageFormat
            {
                bmp,
                jpeg,
                gif,
                tiff,
                png,
                unknown
            }
            
            public static ImageFormat GetImageFormat(Stream stream)
            {
                // see http://www.mikekunz.com/image_file_header.html
                var bmp = Encoding.ASCII.GetBytes("BM");     // BMP
                var gif = Encoding.ASCII.GetBytes("GIF");    // GIF
                var png = new byte[] { 137, 80, 78, 71 };    // PNG
                var tiff = new byte[] { 73, 73, 42 };         // TIFF
                var tiff2 = new byte[] { 77, 77, 42 };         // TIFF
                var jpeg = new byte[] { 255, 216, 255, 224 }; // jpeg
                var jpeg2 = new byte[] { 255, 216, 255, 225 }; // jpeg canon
            
                var buffer = new byte[4];
                stream.Read(buffer, 0, buffer.Length);
            
                if (bmp.SequenceEqual(buffer.Take(bmp.Length)))
                    return ImageFormat.bmp;
            
                if (gif.SequenceEqual(buffer.Take(gif.Length)))
                    return ImageFormat.gif;
            
                if (png.SequenceEqual(buffer.Take(png.Length)))
                    return ImageFormat.png;
            
                if (tiff.SequenceEqual(buffer.Take(tiff.Length)))
                    return ImageFormat.tiff;
            
                if (tiff2.SequenceEqual(buffer.Take(tiff2.Length)))
                    return ImageFormat.tiff;
            
                if (jpeg.SequenceEqual(buffer.Take(jpeg.Length)))
                    return ImageFormat.jpeg;
            
                if (jpeg2.SequenceEqual(buffer.Take(jpeg2.Length)))
                    return ImageFormat.jpeg;
            
                return ImageFormat.unknown;
            }
            

            【讨论】:

            • pdf 是否有类似的可预测序列,以便我们可以将其添加到此列表中?谢谢
            • @user95227,是的!请参阅此库:Mime-Detective。 PDF 签名为here
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-12-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-06-24
            • 2011-06-27
            相关资源
            最近更新 更多