我不想依赖文件扩展名。我不在乎知道它是什么类型的图像(.jpg,.png等),我只是想知道文件是否是图像。如果可能的话,我宁愿不使用任何非.NET dll。
我知道如何执行此操作的最佳方式如下:
bool isImageFile;
try
{
Image.FromFile(imageFile).Dispose();
isImageFile = true;
}
catch (OutOfMemoryException)
{
isImageFile = false;
}
如上所述:http://msdn.microsoft.com/en-us/library/stf701f5.aspx,Image.FromFile()
如果文件不是有效的图片格式,则会引发OutOfMemoryException
。使用上面的内容为我提供了我想要的结果,但是由于以下原因我不想使用它:
Image.FromFile()
将整个图像文件(如果是图像文件)加载到内存中。这是浪费我假设,因为我只需要文件类型,并且不需要在我的代码中进行任何进一步的图像处理。OutOfMemoryException
,因为如果存在真正的内存不足问题并且我的程序吞下它并继续进行该怎么办?有没有更好的方法可以做到这一点?或者,上面列出的任何/所有问题都是无根据的?
修改:自从收到答案后,这些是三个解决方案我现在知道了:
Image.FromFile()
和try-catch将整个图像加载到内存中。
(我没有看到明确的"胜利者"因为我可以想象每个人都适合的情况。对于我的应用程序的目的,文件类型检查很少发生,以至于方法1的性能问题不是问题。)
答案 0 :(得分:10)
如果您只支持少数流行的图像格式,那么您只需读取文件的前几个字节即可根据Magic Number
确定类型提供的链接示例:
答案 1 :(得分:8)
答案 2 :(得分:2)
我可以理解你的顾虑,但是如果你看一下Image.FromFile方法的来源,它只是GDI +调用的包装器,所以很遗憾你什么都不能做,因为我可以看到bizzare选择的异常(OutOfMemoryException) )是在GDI +中完成的
因此,您似乎无法使用当前代码或检查文件头,但这并不能保证该文件确实是一个有效的图像。
也许您应该首先考虑是否真的需要isImageFile方法?在扩展上检测图像文件,它会快得多,如果从文件加载失败,它将引发异常,这样你就可以在真正需要加载图像时处理它。
答案 3 :(得分:2)
采取检查文件头的路线,我写了这个实现:
public static ImageType GetFileImageTypeFromHeader(string file)
{
byte[] headerBytes;
using (FileStream fileStream = new FileStream(file, FileMode.Open))
{
const int mostBytesNeeded = 11;//For JPEG
if (fileStream.Length < mostBytesNeeded)
return ImageType.Unknown;
headerBytes = new byte[mostBytesNeeded];
fileStream.Read(headerBytes, 0, mostBytesNeeded);
}
//Sources:
//http://stackoverflow.com/questions/9354747
//http://en.wikipedia.org/wiki/Magic_number_%28programming%29#Magic_numbers_in_files
//http://www.mikekunz.com/image_file_header.html
//JPEG:
if (headerBytes[0] == 0xFF &&//FF D8
headerBytes[1] == 0xD8 &&
(
(headerBytes[6] == 0x4A &&//'JFIF'
headerBytes[7] == 0x46 &&
headerBytes[8] == 0x49 &&
headerBytes[9] == 0x46)
||
(headerBytes[6] == 0x45 &&//'EXIF'
headerBytes[7] == 0x78 &&
headerBytes[8] == 0x69 &&
headerBytes[9] == 0x66)
) &&
headerBytes[10] == 00)
{
return ImageType.JPEG;
}
//PNG
if (headerBytes[0] == 0x89 && //89 50 4E 47 0D 0A 1A 0A
headerBytes[1] == 0x50 &&
headerBytes[2] == 0x4E &&
headerBytes[3] == 0x47 &&
headerBytes[4] == 0x0D &&
headerBytes[5] == 0x0A &&
headerBytes[6] == 0x1A &&
headerBytes[7] == 0x0A)
{
return ImageType.PNG;
}
//GIF
if (headerBytes[0] == 0x47 &&//'GIF'
headerBytes[1] == 0x49 &&
headerBytes[2] == 0x46)
{
return ImageType.GIF;
}
//BMP
if (headerBytes[0] == 0x42 &&//42 4D
headerBytes[1] == 0x4D)
{
return ImageType.BMP;
}
//TIFF
if ((headerBytes[0] == 0x49 &&//49 49 2A 00
headerBytes[1] == 0x49 &&
headerBytes[2] == 0x2A &&
headerBytes[3] == 0x00)
||
(headerBytes[0] == 0x4D &&//4D 4D 00 2A
headerBytes[1] == 0x4D &&
headerBytes[2] == 0x00 &&
headerBytes[3] == 0x2A))
{
return ImageType.TIFF;
}
return ImageType.Unknown;
}
public enum ImageType
{
Unknown,
JPEG,
PNG,
GIF,
BMP,
TIFF,
}
我将它与方法一起放入实用程序/辅助类中:GetFileImageTypeFromFullLoad()
和GetFileImageTypeFromExtension()
。前者使用我上面提到的Image.FromFile
方法,后者只是检查文件扩展名。我打算根据情况的要求使用这三种情况。
答案 4 :(得分:1)
首先使用System.IO.Path.GetExtension()方法检查Extension是否为图像类型。然后,如果你想通过,你可以检查文件中的标题。
答案 5 :(得分:1)
这是使用Gdi +中签名的那个:
public static ImageCodecInfo DetectCodec(Stream stream)
{
var ib = 0;
var rgCodecs = ImageCodecInfo.GetImageDecoders();
for (var cCodecs = rgCodecs.Length; cCodecs > 0; )
{
var b = stream.ReadByte();
if (b == -1)
return null; // EOF
for (int iCodec = cCodecs - 1; iCodec >= 0; iCodec--)
{
var codec = rgCodecs[iCodec];
for (int iSig = 0; iSig < codec.SignaturePatterns.Length; iSig++)
{
var mask = codec.SignatureMasks[iSig];
var patt = codec.SignaturePatterns[iSig];
if (ib >= patt.Length)
return codec;
if ((b & mask[ib]) != patt[ib])
{
rgCodecs[iCodec] = rgCodecs[--cCodecs];
break;
}
}
}
ib++;
}
return null;
}