web-dev-qa-db-ja.com

ファイルが画像かどうかを判別

ディレクトリをループし、すべてのファイルをコピーしています。現在、string.EndsWithまたは".jpg"などの".png"チェックを行っています。 。

上記のようなハッキングチェックなしで、ファイルが画像(任意の画像タイプ)であるかどうかを判断するよりエレガントな方法はありますか?

43
leora

既知のヘッダー のファイルを確認します。 (リンクからの情報は この回答 にも記載されています)

PNGファイルの最初の8バイトには、常に次の(10進数)値が含まれます。13780 78 71 13 10 26 10

33
Mitch Wheat

チェックアウト System.IO.Path.GetExtension

以下に簡単なサンプルを示します。

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
        }
    }
}
28
bendewey

これは、ファイルの最初の数バイトを見て、それがイメージかどうかを判断します。

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

編集

必要に応じて独自の画像を追加できるように上記にいくつかの変更を加え、最初に必要ではなかったコレクションも削除しました。タイプoutstringパラメーターを受け入れるオーバーロードも追加し、ストリームを構成するイメージのタイプに値を設定しました。

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;
    }
}
19
Aydin
System.Web.MimeMapping.GetMimeMapping(filename).StartsWith("image/");

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

file.svgは、ほとんどの場合、イメージ/ MIMEタイプを返さないことが有効です。これは、おそらくスカラーイメージのようにベクトルイメージを処理しないためです。 MIMEタイプを確認するときは、GetMimeMappingが返さない場合でも、SVGにはimage/svg + xmlの標準MIMEタイプがあることに注意してください。

17
Jeremy Cook

System.Drawing名前空間のImageクラスとグラフィッククラスを使用できます。私たちの仕事をするために。コードがエラーなしで機能する場合、それはイメージであり、そうでない場合はそうではありません。それが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;
}
12
yogihosting

ファイル拡張子を比較するだけでなく、ファイルから完全に読み取られる前に画像ファイルを検証する簡単な方法が必要な場合は、ヘッダーをチェックしてファイル署名を探すことができます(次のコード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\0xA\0x1A\0x0A"
        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;
    }

特に複数のファイルを処理する場合、ファイル全体をロードしたり、大きなオブジェクトを作成したりしないため、ヘッダー署名のチェックは高速になります。ただし、残りのデータが整形式かどうかはチェックしません。これを行うには、ファイルをImageオブジェクトにロードしようとする2番目のステップを実行します(これにより、ファイルをプログラムで表示および処理できることを確認できます)。

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;
}
9
Dr Yunke

私は次の方法を使用します。組み込みの画像デコーダを使用して、システムが画像ファイルとして認識する拡張子のリストを取得し、渡されたファイル名の拡張子とそれらの拡張子を比較します。単純な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;
}
6
dylmcc

this が役立つかどうかを確認します。

編集:また、Image.FromFile(....)。RawFormatが役立つ場合があります。ファイルが画像でない場合、例外をスローする可能性があります。

5
shahkalpesh

このソリューションのパフォーマンスの欠点はわかりませんが、イメージではない場合は失敗してcatchブロックに落ちるtryブロックのファイルでいくつかのイメージ機能を実行できませんでしたか?

この戦略はすべての状況で最良の解決策ではないかもしれませんが、私が現在取り組んでいる場合には、1つの大きな利点があります:テスト機能。このようにして、現在のすべての画像タイプをテストできますが、サポートされている画像タイプリストに新しい画像拡張子を追加せずに、将来の画像タイプにも拡張できます。

この戦略の欠点はありますか?

2
James Sumner

必要な答えではありません。ただし、インターネットの場合は、 [〜#〜] mime [〜#〜] type。

2
Cherian

これは私が使用するものです-少し読みやすくするための@dylmccの答えのほんの一部です。

public static bool IsRecognisedImageFile(string fileName)
{
    string targetExtension = System.IO.Path.GetExtension(fileName);
    if (String.IsNullOrEmpty(targetExtension))
    {
        return false;
    }

    var recognisedImageExtensions = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders().SelectMany(codec => codec.FilenameExtension.ToLowerInvariant().Split(';'));

    targetExtension = "*" + targetExtension.ToLowerInvariant();
    return recognisedImageExtensions.Contains(targetExtension);
}
1
meataxe

これはトリッキーなものです。ファイルがイメージではない場合、例外がスローされます。それから、ファイルが画像であるかどうかを確認できます。

        using (Stream stream = File.OpenRead(file))
           {
               try
               {
                   using (Image sourceImage = Image.FromStream(stream, false, false))
                   {

                   }
               }
               catch (Exception x)
               {
                   if (x.Message.Contains("not valid"))
                   {
                     Console.Write("This is not a Image.");
                   }

               }
           }
0
Isuru Dinusha

私の簡単なコード

public static List<string> GetAllPhotosExtensions()
    {
        var list = new List<string>();
        list.Add(".jpg");
        list.Add(".png");
        list.Add(".bmp");
        list.Add(".gif");
        list.Add(".jpeg");
        list.Add(".tiff");
        return list;
    }

画像ファイルかどうかを確認

public static bool IsPhoto(string fileName)
    {
        var list = FileListExtensions.GetAllPhotosExtensions();
        var filename= fileName.ToLower();
        bool isThere = false;
        foreach(var item in list)
        {
            if (filename.EndsWith(item))
            {
                isThere = true;
                break;
            }
        }
        return isThere;     
    }
0
Minute V