使用C#,我该如何测试一个文件是否为JPEG格式?我需要检查文件的扩展名为.jpg吗?
谢谢。
有几个选项:
你可以检查文件扩展名:
static bool HasJpegExtension(string filename)
{
// add other possible extensions here
return Path.GetExtension(filename).Equals(".jpg", StringComparison.InvariantCultureIgnoreCase)
|| Path.GetExtension(filename).Equals(".jpeg", StringComparison.InvariantCultureIgnoreCase);
}
或者检查文件头部的正确魔数:
static bool HasJpegHeader(string filename)
{
using (BinaryReader br = new BinaryReader(File.Open(filename, FileMode.Open, FileAccess.Read)))
{
UInt16 soi = br.ReadUInt16(); // Start of Image (SOI) marker (FFD8)
UInt16 marker = br.ReadUInt16(); // JFIF marker (FFE0) or EXIF marker(FFE1)
return soi == 0xd8ff && (marker & 0xe0ff) == 0xe0ff;
}
}
另一个选项是加载图像并检查正确的类型。然而,这种方法不太高效(除非您无论如何都要加载图像),但可能会给您最可靠的结果(请注意加载和解压缩的额外成本以及可能的异常处理):
static bool IsJpegImage(string filename)
{
try
{
using (System.Drawing.Image img = System.Drawing.Image.FromFile(filename))
{
// Two image formats can be compared using the Equals method
// See http://msdn.microsoft.com/en-us/library/system.drawing.imaging.imageformat.aspx
//
return img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
catch (OutOfMemoryException)
{
// Image.FromFile throws an OutOfMemoryException
// if the file does not have a valid image format or
// GDI+ does not support the pixel format of the file.
//
return false;
}
}
哎呀,这么多代码示例都是错的,错的,错的。
EXIF 文件有一个 0xff*e1* 的标记,JFIF 文件有一个 0xff*e0* 的标记。因此,所有依赖于 0xffe0 来检测 JPEG 文件的代码都将忽略所有 EXIF 文件。
这里有一个版本,可以同时检测两种类型,并且可以轻松地修改为仅返回 JFIF 或仅返回 EXIF(例如,在尝试恢复您的 iPhone 照片时非常有用)。
public static bool HasJpegHeader(string filename)
{
try
{
// 0000000: ffd8 ffe0 0010 4a46 4946 0001 0101 0048 ......JFIF.....H
// 0000000: ffd8 ffe1 14f8 4578 6966 0000 4d4d 002a ......Exif..MM.*
using (BinaryReader br = new BinaryReader(File.Open(filename, FileMode.Open, FileAccess.ReadWrite)))
{
UInt16 soi = br.ReadUInt16(); // Start of Image (SOI) marker (FFD8)
UInt16 marker = br.ReadUInt16(); // JFIF marker (FFE0) EXIF marker (FFE1)
UInt16 markerSize = br.ReadUInt16(); // size of marker data (incl. marker)
UInt32 four = br.ReadUInt32(); // JFIF 0x4649464a or Exif 0x66697845
Boolean isJpeg = soi == 0xd8ff && (marker & 0xe0ff) == 0xe0ff;
Boolean isExif = isJpeg && four == 0x66697845;
Boolean isJfif = isJpeg && four == 0x4649464a;
if (isJpeg)
{
if (isExif)
Console.WriteLine("EXIF: {0}", filename);
else if (isJfif)
Console.WriteLine("JFIF: {0}", filename);
else
Console.WriteLine("JPEG: {0}", filename);
}
return isJpeg;
return isJfif;
return isExif;
}
}
catch
{
return false;
}
}
4A 46 49 46
,但您正在检查0x4649464a
。EXIF是45 78 69 66
,但您正在检查0x66697845
。我假设您的代码是正确的,但为什么它们是反过来的呢? - vaindil以流的方式打开文件,并查找JPEG文件的魔数。
JPEG图像文件的开头是FF D8,结尾是FF D9。JPEG/JFIF文件包含ASCII码为'JFIF'(4A 46 49 46)的以空字符结尾的字符串。JPEG/Exif文件包含ASCII码为'Exif'(45 78 69 66)也是以空字符结尾的字符串。
你可以尝试将文件加载到图像中,然后检查格式。
Image img = Image.FromFile(filePath);
bool isBitmap = img.RawFormat.Equals(ImageFormat.Jpeg);
或者你可以打开文件并检查头部以获取类型
ImageFormat.Equals
而不是使用 ==
运算符。 - Dirk Vollmar您可以找到关于jpeg文件格式的文档,特别是头部信息。然后尝试从文件中读取此信息,并将其与预期的jpeg头字节进行比较。
这将循环遍历当前目录中的每个文件,并输出任何找到的具有JPG或JPEG扩展名的Jpeg图像。
foreach (FileInfo f in new DirectoryInfo(".").GetFiles())
{
if (f.Extension.ToUpperInvariant() == ".JPG"
|| f.Extension.ToUpperInvariant() == ".JPEG")
{
Image image = Image.FromFile(f.FullName);
if (image.RawFormat == ImageFormat.Jpeg)
{
Console.WriteLine(f.FullName + " is a Jpeg image");
}
}
}
只需获取文件的媒体类型并进行验证:
private bool isJpeg()
{
string p = currFile.Headers.ContentType.MediaType;
return p.ToLower().Equals("image/jpeg") || p.ToLower().Equals("image/pjpeg") || p.ToLower().Equals("image/png");
}
这里的代码:
http://mark.michaelis.net/Blog/RetrievingMetaDataFromJPEGFilesUsingC.aspx
展示如何获取元数据。我猜如果你的图像不是有效的JPEG格式,那么会抛出异常。
IsJpeg
或您的一些建议。由于这是一个简单的例子,我不想用异常处理来过度负荷它,但通常我会在堆栈的更高层处理与文件IO和访问权限相关的异常。 - Dirk Vollmar