C# 确定文件是否为图像

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/670546/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 12:40:10  来源:igfitidea点击:

determine if file is an image

c#imagefile

提问by leora

I am looping through a directory and copying all files. Right now I am doing string.EndsWithchecks for ".jpg"or ".png", etc . .

我正在遍历一个目录并复制所有文件。现在我正在string.EndsWith检查".jpg"or".png"等。.

Is there any more elegant way of determining if a file is an image (any image type) without the hacky check like above?

有没有更优雅的方法来确定文件是否是图像(任何图像类型)而无需像上面那样进行 hacky 检查?

采纳答案by Mitch Wheat

Check the file for a known header. (Info from link also mentioned in this answer)

检查文件中的已知标头。(此答案中也提到了来自链接的信息)

The first eight bytes of a PNG file always contain the following (decimal) values: 137 80 78 71 13 10 26 10

PNG 文件的前八个字节始终包含以下(十进制)值:137 80 78 71 13 10 26 10

回答by bendewey

Check out System.IO.Path.GetExtension

查看System.IO.Path.GetExtension

Here is a quick sample.

这是一个快速示例。

public static readonly List<string> ImageExtensions = new List<string> { ".JPG", ".JPE", ".BMP", ".GIF", ".PNG" };

private void button_Click(object sender, RoutedEventArgs e)
{
    var folder = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
    var files = Directory.GetFiles(folder);
    foreach(var f in files)
    {
        if (ImageExtensions.Contains(Path.GetExtension(f).ToUpperInvariant()))
        {
            // process image
        }
    }
}

回答by shahkalpesh

See if thishelps.

看看这是否有帮助。

EDIT: Also, Image.FromFile(....).RawFormat might help. It could throw an exception if the file is not an image.

编辑:此外, Image.FromFile(....).RawFormat 可能会有所帮助。如果文件不是图像,它可能会引发异常。

回答by Cherian

Not exactly the answer you need. But if it's the Internet then MIMEtype.

不完全是您需要的答案。但如果是 Internet,则为MIME类型。

回答by James Sumner

I'm not sure what the performance drawback would be for this solution but couldn't you perform some image function on the file in a try block that would fail and fall to a catch block if it is not an image?

我不确定这个解决方案的性能缺陷是什么,但你不能在 try 块中的文件上执行一些图像函数,如果它不是图像,它会失败并落入 catch 块吗?

This strategy may not be the best solution in all situations but in the case that I am currently working with it has one major advantage: You can use whatever function that you plan to use to process the image (if it is an image) for the test function. In that way you can test all current image types but it would also extend to future image types without adding that new image extension to your supported image type list.

这种策略可能不是所有情况下的最佳解决方案,但在我目前使用它的情况下,它有一个主要优点:您可以使用您计划用于处理图像(如果它是图像)的任何函数测试功能。通过这种方式,您可以测试所有当前的图像类型,但它也可以扩展到未来的图像类型,而无需将新的图像扩展名添加到您支持的图像类型列表中。

Does anyone see any drawbacks to this strategy?

有没有人看到这种策略的任何缺点?

回答by dylmcc

I use the following method. It uses the built in Image decoder to retrieve a list of extensions that the system recognises as image files, then compares those extensions to the extension of the file name you pass in. Returns a simple TRUE/FALSE.

我使用以下方法。它使用内置的图像解码器来检索系统识别为图像文件的扩展名列表,然后将这些扩展名与您传入的文件名的扩展名进行比较。返回一个简单的 TRUE/FALSE。

public static bool IsRecognisedImageFile(string fileName)
{
    string targetExtension = System.IO.Path.GetExtension(fileName);
    if (String.IsNullOrEmpty(targetExtension))
        return false;
    else
        targetExtension = "*" + targetExtension.ToLowerInvariant();

    List<string> recognisedImageExtensions = new List<string>();

    foreach (System.Drawing.Imaging.ImageCodecInfo imageCodec in System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders())
        recognisedImageExtensions.AddRange(imageCodec.FilenameExtension.ToLowerInvariant().Split(";".ToCharArray()));

    foreach (string extension in recognisedImageExtensions)
    {
        if (extension.Equals(targetExtension))
        {
            return true;
        }
    }
    return false;
}

回答by Aydin

This will look at the first few bytes of a file and determine whether it is an image.

这将查看文件的前几个字节并确定它是否是图像。

using System.Collections.Generic;
using System.IO;
using System.Linq;

public static class Extension
{
    public static bool IsImage(this Stream stream)
    {
        stream.Seek(0, SeekOrigin.Begin);

        List<string> jpg = new List<string> { "FF", "D8" };
        List<string> bmp = new List<string> { "42", "4D" };
        List<string> gif = new List<string> { "47", "49", "46" };
        List<string> png = new List<string> { "89", "50", "4E", "47", "0D", "0A", "1A", "0A" };
        List<List<string>> imgTypes = new List<List<string>> { jpg, bmp, gif, png };

        List<string> bytesIterated = new List<string>();

        for (int i = 0; i < 8; i++)
        {
            string bit = stream.ReadByte().ToString("X2");
            bytesIterated.Add(bit);

            bool isImage = imgTypes.Any(img => !img.Except(bytesIterated).Any());
            if (isImage)
            {
                return true;
            }
        }

        return false;
    }
}


Edit

编辑

I've made a few changes to the above to allow you to add your own images if you needed to, also removed collections which weren't necessary to begin with. I also added an overload accepting an outparameter of type string, setting the value to the type of image the stream is composed of.

我对上述内容进行了一些更改,以允许您根据需要添加自己的图像,还删除了不需要的集合。我还添加了一个接受outtype 参数的重载string,将值设置为组成流的图像类型。

public static class Extension
{
    static Extension()
    {
        ImageTypes = new Dictionary<string, string>();
        ImageTypes.Add("FFD8","jpg");
        ImageTypes.Add("424D","bmp");
        ImageTypes.Add("474946","gif");
        ImageTypes.Add("89504E470D0A1A0A","png");
    }

    /// <summary>
    ///     <para> Registers a hexadecimal value used for a given image type </para>
    ///     <param name="imageType"> The type of image, example: "png" </param>
    ///     <param name="uniqueHeaderAsHex"> The type of image, example: "89504E470D0A1A0A" </param>
    /// </summary>
    public static void RegisterImageHeaderSignature(string imageType, string uniqueHeaderAsHex)
    {
        Regex validator = new Regex(@"^[A-F0-9]+$", RegexOptions.CultureInvariant);

        uniqueHeaderAsHex = uniqueHeaderAsHex.Replace(" ", "");

        if (string.IsNullOrWhiteSpace(imageType))         throw new ArgumentNullException("imageType");
        if (string.IsNullOrWhiteSpace(uniqueHeaderAsHex)) throw new ArgumentNullException("uniqueHeaderAsHex");
        if (uniqueHeaderAsHex.Length % 2 != 0)            throw new ArgumentException    ("Hexadecimal value is invalid");
        if (!validator.IsMatch(uniqueHeaderAsHex))        throw new ArgumentException    ("Hexadecimal value is invalid");

        ImageTypes.Add(uniqueHeaderAsHex, imageType);
    }

    private static Dictionary<string, string> ImageTypes;

    public static bool IsImage(this Stream stream)
    {
        string imageType;
        return stream.IsImage(out imageType);
    }

    public static bool IsImage(this Stream stream, out string imageType)
    {
        stream.Seek(0, SeekOrigin.Begin);
        StringBuilder builder = new StringBuilder();
        int largestByteHeader = ImageTypes.Max(img => img.Value.Length);

        for (int i = 0; i < largestByteHeader; i++)
        {
            string bit = stream.ReadByte().ToString("X2");
            builder.Append(bit);

            string builtHex = builder.ToString();
            bool isImage = ImageTypes.Keys.Any(img => img == builtHex);
            if (isImage)
            {
                imageType = ImageTypes[builder.ToString()];
                return true;
            }
        }
        imageType = null;
        return false;
    }
}

回答by yogihosting

We can use Image and graphics classes from namespace System.Drawing; to do our job. If the code works without error it is an image, else it is not. That is let the DotNet framework do the job for us. The code -

我们可以使用命名空间 System.Drawing 中的 Image 和 graphics 类;做我们的工作。如果代码工作没有错误,它是一个图像,否则它不是。这就是让 DotNet 框架为我们完成工作。编码 -

public string CheckFile(file)
{
    string result="";
    try
    {
        System.Drawing.Image imgInput = System.Drawing.Image.FromFile(file);
        System.Drawing.Graphics gInput = System.Drawing.Graphics.fromimage(imgInput);  
        Imaging.ImageFormat thisFormat = imgInput.RawFormat;   
        result="It is image";        
    }
    catch(Exception ex)
    {
        result="It is not image"; 
    }
    return result;
}

回答by Jeremy Cook

System.Web.MimeMapping.GetMimeMapping(filename).StartsWith("image/");

MimeMapping.GetMimeMappingproduces these results:

MimeMapping.GetMimeMapping产生这些结果:

  • file.jpg: image/jpeg
  • file.gif: image/gif
  • file.jpeg: image/jpeg
  • file.png: image/png
  • file.bmp: image/bmp
  • file.tiff: image/tiff
  • file.svg: application/octet-stream
  • 文件.jpg:图像/jpeg
  • 文件.gif:图像/gif
  • file.jpeg:图像/jpeg
  • 文件.png:图像/png
  • 文件.bmp:图像/bmp
  • file.tiff:图像/tiff
  • file.svg:应用程序/八位字节流

file.svg not returning an image/ MIME type works out in most cases because you're probably not going to process a vector image like you would a scalar image. When checking MIME type, do be aware that SVG does have the standard MIME type of image/svg+xml, even if GetMimeMappingdoesn't return it.

file.svg 不返回图像/ MIME 类型在大多数情况下是可行的,因为您可能不会像处理标量图像那样处理矢量图像。检查 MIME 类型时,请注意 SVG 确实具有 image/svg+xml 的标准 MIME 类型,即使GetMimeMapping不返回它。

回答by Dr Yunke

If you want a quick way to validate an image file before it is fully read from the file, besides comparing the file extension, you can just check its header looking for file signature (the following code IsValidImageFile()checks for BMP, GIF87a, GIF89a, PNG, TIFF, JPEG)

如果您想在从文件中完全读取之前快速验证图像文件,除了比较文件扩展名之外,您可以只检查其标头以查找文件签名(以下代码IsValidImageFile()检查BMP、GIF87a、GIF89a、PNG、 TIFF, JPEG)

    /// <summary>
    /// Reads the header of different image formats
    /// </summary>
    /// <param name="file">Image file</param>
    /// <returns>true if valid file signature (magic number/header marker) is found</returns>
    private bool IsValidImageFile(string file)
    {
        byte[] buffer = new byte[8];
        byte[] bufferEnd = new byte[2];

        var bmp = new byte[] { 0x42, 0x4D };               // BMP "BM"
        var gif87a = new byte[] { 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 };     // "GIF87a"
        var gif89a = new byte[] { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 };     // "GIF89a"
        var png = new byte[] { 0x89, 0x50, 0x4e, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };   // PNG "\x89PNG\x0D
bool IsValidImage(string filename)
{
    try
    {
        using(Image newImage = Image.FromFile(filename))
        {}
    }
    catch (OutOfMemoryException ex)
    {
        //The file does not have a valid image format.
        //-or- GDI+ does not support the pixel format of the file

        return false;
    }
    return true;
}
xA##代码##x1A##代码##x0A" var tiffI = new byte[] { 0x49, 0x49, 0x2A, 0x00 }; // TIFF II "II\x2A\x00" var tiffM = new byte[] { 0x4D, 0x4D, 0x00, 0x2A }; // TIFF MM "MM\x00\x2A" var jpeg = new byte[] { 0xFF, 0xD8, 0xFF }; // JPEG JFIF (SOI "\xFF\xD8" and half next marker xFF) var jpegEnd = new byte[] { 0xFF, 0xD9 }; // JPEG EOI "\xFF\xD9" try { using (System.IO.FileStream fs = new System.IO.FileStream(file, System.IO.FileMode.Open, System.IO.FileAccess.Read)) { if (fs.Length > buffer.Length) { fs.Read(buffer, 0, buffer.Length); fs.Position = (int)fs.Length - bufferEnd.Length; fs.Read(bufferEnd, 0, bufferEnd.Length); } fs.Close(); } if (this.ByteArrayStartsWith(buffer, bmp) || this.ByteArrayStartsWith(buffer, gif87a) || this.ByteArrayStartsWith(buffer, gif89a) || this.ByteArrayStartsWith(buffer, png) || this.ByteArrayStartsWith(buffer, tiffI) || this.ByteArrayStartsWith(buffer, tiffM)) { return true; } if (this.ByteArrayStartsWith(buffer, jpeg)) { // Offset 0 (Two Bytes): JPEG SOI marker (FFD8 hex) // Offest 1 (Two Bytes): Application segment (FF?? normally ??=E0) // Trailer (Last Two Bytes): EOI marker FFD9 hex if (this.ByteArrayStartsWith(bufferEnd, jpegEnd)) { return true; } } } catch (Exception ex) { MessageBox.Show(ex.Message, Lang.Lang.ErrorTitle + " IsValidImageFile()", MessageBoxButtons.OK, MessageBoxIcon.Error); } return false; } /// <summary> /// Returns a value indicating whether a specified subarray occurs within array /// </summary> /// <param name="a">Main array</param> /// <param name="b">Subarray to seek within main array</param> /// <returns>true if a array starts with b subarray or if b is empty; otherwise false</returns> private bool ByteArrayStartsWith(byte[] a, byte[] b) { if (a.Length < b.Length) { return false; } for (int i = 0; i < b.Length; i++) { if (a[i] != b[i]) { return false; } } return true; }

Checking the header signature can be fast, since it does not load the whole file or create large objects, specially when processing several files. But it does not check if the rest of the data is well formed. To do so, a second step to try to load the file to an Imageobject can be done (and this way be certain that the file can be displayed and handled by your program).

检查头签名可以很快,因为它不会加载整个文件或创建大对象,特别是在处理多个文件时。但它不会检查其余数据是否格式正确。为此,可以尝试将文件加载到Image对象的第二个步骤可以完成(这样可以确保该文件可以由您的程序显示和处理)。

##代码##