47


41

ファイルからイメージをロードしていますが、ファイルから完全に読み取られる前にイメージを検証する方法を知りたいです。

string filePath = "image.jpg"; Image newImage = Image.FromFile(filePath);

image.jpgが本当にjpgではない場合、問題が発生します。 たとえば、空のテキストファイルを作成してimage.jpgに名前を変更すると、image.jpgが読み込まれたときにOutOfMemory例外がスローされます。

私はストリームまたは画像のファイルパスを与えられた画像を検証する機能を探しています。

関数プロトタイプの例

bool IsValidImage(string fileName); bool IsValidImage(Stream imageStream);

12 Answer


59


これが私のイメージチェックです。 ファイル拡張子に頼ることはできず、自分でフォーマットをチェックする必要があります。 私はバイト配列からWPFでBitmapImagesをロードしています、そしてフォーマットが前もってわかりません。 WPFはフォーマットを問題なく検出しますが、BitmapImageオブジェクトのイメージフォーマットを教えてくれません(少なくともこのためのプロパティを知りません)。 また、フォーマットを検出するためだけにSystem.Drawingを使用してイメージを再度読み込むことはしたくありません。 この解決策は速く、私にはうまくいきます。

パブリック列挙体ImageFormat {bmp、jpeg、gif、tiff、png、不明}

public static ImageFormat GetImageFormat(byte [] bytes){// 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

if(bmp.SequenceEqual(bytes.Take(bmp.Length)))はImageFormat.bmpを返します。

if(gif.SequenceEqual(bytes.Take(gif.Length)))はImageFormat.gifを返します。

if(png.SequenceEqual(bytes.Take(png.Length)))はImageFormat.pngを返します。

if(tiff.SequenceEqual(bytes.Take(tiff.Length)))はImageFormat.tiffを返します。

if(tiff2.SequenceEqual(bytes.Take(tiff2.Length)))はImageFormat.tiffを返します。

if(jpeg.SequenceEqual(bytes.Take(jpeg.Length)))はImageFormat.jpegを返します。

if(jpeg2.SequenceEqual(bytes.Take(jpeg2.Length)))はImageFormat.jpegを返します。

ImageFormat.unknownを返します。 }


32


  • Windowsフォームを使う:*

bool IsValidImage(string filename){try {using(Image newImage = Image.FromFile(filename)){}} catch(OutOfMemoryException ex){//ファイルに有効な画像形式がありません。 //  - または -  GDIはファイルのピクセルフォーマットをサポートしていません

falseを返します。 trueを返します。 }

そうでなければ*あなたが* WPF *を使用しているならば、あなたは以下をすることができます:

bool IsValidImage(string filename){try {using(BitmapImage newImage = new BitmapImage(filename)){}} catch(NotSupportedException){// System.NotSupportedException://この操作を完了するのに適したイメージングコンポーネントが見つかりませんでした。 falseを返します。 trueを返します。 }

作成した画像を解放する必要があります。 そうでなければ、この関数を何度も呼び出すとき、これは* OutOfMemoryException *をスローします。システムがリソースを使い果たしたためで、画像が壊れていて間違った結果が得られたためではありません。良いものを削除する。


23


JPEGには正式なヘッダ定義はありませんが、使用できる少量のメタデータがあります。

  • オフセット0(2バイト):JPEG SOIマーカー(FFD8 16進数)

  • オフセット2(2バイト):画像の幅(ピクセル)

  • オフセット4(2バイト):画像の高さ(ピクセル)

  • オフセット6(バイト):コンポーネント数(1 =グレースケール、3 = RGB)

その後他にもいくつかありますが、それらは重要ではありません。

バイナリストリームを使用してファイルを開き、この初期データを読み取り、OffSet 0が0で、OffSet 6が1、2、または3であることを確認します。

それは少なくともあなたにもう少し正確さを与えるでしょう。

あるいは、例外をトラップして先に進むこともできますが、私はあなたが挑戦を望んでいると思いました:)


18


さて、私は先に進み、問題を解決するために一連の関数をコーディングしました。 最初にヘッダーをチェックしてから、try / catchブロックにイメージをロードしようとします。 GIF、BMP、JPG、およびPNGファイルのみがチェックされます。 imageHeadersにヘッダーを追加することで、さらに多くの種類を簡単に追加できます。

static bool IsValidImage(string filePath){return File.Exists(filePath)

static bool IsValidImage(Stream imageStream){if(imageStream.Length> 0){byte [] header = new byte [4]; //必要に応じてサイズを変更する string [] imageHeaders = new [] {"\ xFF \ xD8"、// JPEG "BM"、// BMP "GIF"、// GIF Encoding.ASCII.GetString(new byte [] {137、80、78、 71})}; // PNG

imageStream.Read(header、0、header.Length);

bool isImageHeader = imageHeaders.Count(str => Encoding.ASCII.GetString(header).StartsWith(str))> 0; if(isImageHeader == true){try {Image.FromStream(imageStream).Dispose();} imageStream.Close(); trueを返します。 }

キャッチ{

}}}

imageStream.Close(); falseを返します。 }


12


あなたはヘッダをスニッフィングすることによって大まかな型付けをすることができます。

これはあなたが実装するそれぞれのファイルフォーマットが識別可能なヘッダを持つ必要があることを意味します…​

JPEG:最初の4バイトはFF D8 FF E0です(実際には最初の2バイトだけが非jfif jpegのためにそれをするでしょう、より多くの情報 here)。

GIF:最初の6バイトは "GIF87a"または "GIF89a"のいずれかです(詳細は ここを参照)

PNG:最初の8バイトは次のとおりです。89 50 4E 47 0D 0A 1A 0A(詳細情報 ここ

TIFF:最初の4バイトは次のとおりです。II42またはMM42(詳細情報 ここ

等…​ あなたが気にしているグラフィックスフォーマットについてのヘッダ/フォーマット情報を見つけて、必要に応じてそれに追加することができます。 これがしないことは、ファイルがそのタイプの有効なバージョンであるかどうかをあなたに言うことですが、それはあなたに「image not image」についてのヒントを与えるでしょう。 まだ破損しているか不完全な画像である可能性があるため、開くときにクラッシュするため、.FromFile呼び出しを回避するためのtry catchが依然として必要です。


6


これはうまくいくはずです - あなたはヘッダから生のバイトを読む必要はありません:

using(Image test = Image.FromFile(filePath)){bool isJpeg =(test.RawFormat.Equals(ImageFormat.Jpeg)); }

もちろん、OutOfMemoryExceptionもトラップする必要があります。これは、ファイルがまったくイメージではない場合に役立ちます。

また、ImageFormatには、GDIがサポートする他のすべての主要な画像タイプ用のプリセット項目があります。

演算子==がEqualsメソッドを呼び出すためにオーバーロードされていないため、ImageFormatオブジェクトでは==ではなく.Equals()を使用する必要があります。


3


TiffとJpegもサポートするメソッド

プライベートbool IsValidImage(string filename){Stream imageStream = null;試してください{imageStream = new FileStream(filename、FileMode.Open);

if(imageStream.Length> 0){byte [] header = new byte [30]; //必要に応じてサイズを変更する string [] imageHeaders = new [] {"BM"、// BMP "GIF"、// GIF Encoding.ASCII.GetString(new byte [] {137、80、78、71})、// PNG "MM \ x00 \ x2a "、// TIFF" II \ x2a \ x00 "// TIFF};

imageStream.Read(header、0、header.Length);

bool isImageHeader = imageHeaders.Count(str => Encoding.ASCII.GetString(header).StartsWith(str))> 0; if(imageStream!= null){imageStream.Close(); imageStream.Dispose(); imageStream = null; }

if(isImageHeader == false){//(BinaryReader br = new BinaryReader(File.Open(filename、FileMode.Open))を使用してjpegかどうかを確認します){UInt16 soi = br.ReadUInt16(); //画像の開始(SOI)マーカー(FFD8)UInt16 jfif = br.ReadUInt16(); // JFIFマーカー

soi == 0xd8ffを返す

isImageHeaderを返します。 }

falseを返します。 } catch {falseを返します。 }最後に{if(imageStream!= null){imageStream.Close();} imageStream.Dispose(); }}}


1


以下のようなメソッドを作成します。

画像openImage(string filename);

私は例外を処理します。 戻り値がNullの場合、無効なファイル名/タイプがあります。


1


私はセミコロンの答えを取り、VBに変換しました:

ブール値としてのプライベート関数IsValidImage(imageStream As System.IO.Stream)

If(imageStream.Length = 0)isvalidimage = Falseの場合終了関数終了If

Dim pngByte()Byte = New Byte(){137、80、78、71} Dim pngHeader as String = System.Text.Encoding.ASCII.GetString(pngByte)

Dim jpgByte()As Byte = New Byte(){255、216} Dim jpgHeader As String = System.Text.Encoding.ASCII.GetString(jpgByte)

Dim bmpHeader As String = "BM" Dim gifHeader As String = "GIF"

薄暗いヘッダー(3)としてByte

imageHeaders As String()= New String(){jpgHeader、bmpHeader、gifHeader、pngHeader} imageStream.Read(header、0、header.Length)

薄暗いisImageHeader As Boolean = imageHeaders.Count(関数(str)System.Text.Encoding.ASCII.GetString(header).StartsWith(str))> 0

If(isImageHeader)次に試してみてくださいSystem.Drawing.Image.FromStream(imageStream).Dispose()imageStream.Close()IsValidImage = True終了関数例外としてのキャッチSystem.Diagnostics.Debug.WriteLine( "Not an image")終了お試しくださいその他System.Diagnostics.Debug.WriteLine( "画像ではありません")End If

imageStream.Close()IsValidImage = False終了関数


0


あなたはストリームの最初の数バイトを読み、JPEGのためのマジックヘッダバイトとそれらを比較することができます。