当前位置:  开发笔记 > 编程语言 > 正文

在C#中验证文件中的图像

如何解决《在C#中验证文件中的图像》经验,为你挑选了6个好方法。

我正在从文件中加载图像,我想知道在从文件中完全读取图像之前如何验证图像.

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

当image.jpg不是真正的jpg时会出现问题.例如,如果我创建一个空文本文件并将其重命名为image.jpg,则在加载image.jpg时将抛出OutOfMemory Exception.

我正在寻找一个功能,它将在给定图像的流或文件路径的情况下验证图像.

示例函数原型

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

Alex.. 68

这是我的图像检查.我不能依赖文件扩展名,必须自己检查格式.我正在从字节数组加载WPF中的BitmapImages,并且不知道预先格式化.WPF检测格式正常,但没有告诉你BitmapImage对象的图像格式(至少我不知道这个属性).我不想再使用System.Drawing加载图像来检测格式.这个解决方案很快,对我来说很好.

public enum ImageFormat
{
    bmp,
    jpeg,
    gif,
    tiff,
    png,
    unknown
}

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

    if (gif.SequenceEqual(bytes.Take(gif.Length)))
        return ImageFormat.gif;

    if (png.SequenceEqual(bytes.Take(png.Length)))
        return ImageFormat.png;

    if (tiff.SequenceEqual(bytes.Take(tiff.Length)))
        return ImageFormat.tiff;

    if (tiff2.SequenceEqual(bytes.Take(tiff2.Length)))
        return ImageFormat.tiff;

    if (jpeg.SequenceEqual(bytes.Take(jpeg.Length)))
        return ImageFormat.jpeg;

    if (jpeg2.SequenceEqual(bytes.Take(jpeg2.Length)))
        return ImageFormat.jpeg;

    return ImageFormat.unknown;
}


MusiGenesis.. 33

使用Windows窗体:

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

否则,如果您使用的是WPF,则可以执行以下操作:

bool IsValidImage(string filename)
{
    try
    {
        using(BitmapImage newImage = new BitmapImage(filename))
        {}
    }
    catch(NotSupportedException)
    {
        // System.NotSupportedException:
        // No imaging component suitable to complete this operation was found.
        return false;
    }
    return true;
}

您必须释放创建的图像.否则,当您多次调用此函数时,这会抛出OutOfMemoryException,因为系统资源不足,而不是因为图像损坏导致结果不正确,并且如果在此步骤之后删除图像,则可能会删除好的.



1> Alex..:

这是我的图像检查.我不能依赖文件扩展名,必须自己检查格式.我正在从字节数组加载WPF中的BitmapImages,并且不知道预先格式化.WPF检测格式正常,但没有告诉你BitmapImage对象的图像格式(至少我不知道这个属性).我不想再使用System.Drawing加载图像来检测格式.这个解决方案很快,对我来说很好.

public enum ImageFormat
{
    bmp,
    jpeg,
    gif,
    tiff,
    png,
    unknown
}

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

    if (gif.SequenceEqual(bytes.Take(gif.Length)))
        return ImageFormat.gif;

    if (png.SequenceEqual(bytes.Take(png.Length)))
        return ImageFormat.png;

    if (tiff.SequenceEqual(bytes.Take(tiff.Length)))
        return ImageFormat.tiff;

    if (tiff2.SequenceEqual(bytes.Take(tiff2.Length)))
        return ImageFormat.tiff;

    if (jpeg.SequenceEqual(bytes.Take(jpeg.Length)))
        return ImageFormat.jpeg;

    if (jpeg2.SequenceEqual(bytes.Take(jpeg2.Length)))
        return ImageFormat.jpeg;

    return ImageFormat.unknown;
}



2> MusiGenesis..:

使用Windows窗体:

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

否则,如果您使用的是WPF,则可以执行以下操作:

bool IsValidImage(string filename)
{
    try
    {
        using(BitmapImage newImage = new BitmapImage(filename))
        {}
    }
    catch(NotSupportedException)
    {
        // System.NotSupportedException:
        // No imaging component suitable to complete this operation was found.
        return false;
    }
    return true;
}

您必须释放创建的图像.否则,当您多次调用此函数时,这会抛出OutOfMemoryException,因为系统资源不足,而不是因为图像损坏导致结果不正确,并且如果在此步骤之后删除图像,则可能会删除好的.


根据MSDN,OutOfMemoryException确实是陷阱的正确异常!!!http://msdn.microsoft.com/zh-cn/library/stf701f5.aspx Microsoft,您永远不会停止惊奇和困惑。

3> FlySwat..:

JPEG没有正式的标头定义,但它们确实有少量可用的元数据.

偏移0(两个字节):JPEG SOI标记(FFD8十六进制)

偏移2(两个字节):图像宽度(以像素为单位)

偏移4(两个字节):图像高度(以像素为单位)

偏移6(字节):组件数量(1 =灰度,3 = RGB)

之后还有其他一些事情,但那些并不重要.

您可以使用二进制流打开文件,并读取此初始数据,并确保OffSet 0为0,OffSet 6为1,2或3.

这至少可以让你更精确.

或者你可以捕获异常并继续前进,但我认为你想挑战:)


不,但我没有声称它会.

4> SemiColon..:

好吧,我继续编写了一组函数来解决问题.它首先检查标头,然后尝试在try/catch块中加载图像.它仅检查GIF,BMP,JPG和PNG文件.您可以通过向imageHeaders添加标题来轻松添加更多类型.

static bool IsValidImage(string filePath)
{
    return File.Exists(filePath) && IsValidImage(new FileStream(filePath, FileMode.Open, FileAccess.Read));
}

static bool IsValidImage(Stream imageStream)
{
    if(imageStream.Length > 0)
    {
        byte[] header = new byte[4]; // Change size if needed.
        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();
                return true;
            }

            catch
            {

            }
        }
    }

    imageStream.Close();
    return false;
}


@Joe我必须不同意.他不应该在这个函数中关闭或处理流.此函数未创建流,因此不应执行意外行为.另外..如果成功,Image.FromStream将使用流(可能只读,并且无法重置),这意味着稍后对流的后续读取将失败,因为流已经被消耗.此外,一旦成功,图像被加载(非常昂贵),然后立即处理.如果此方法返回true,则调用者可能会在下一行加载图像.这是双重工作.

5> Troy Howard..:

你可以通过嗅探标题进行粗略的输入.

这意味着您实现的每种文件格式都需要具有可识别的标头...

JPEG:前4个字节是FF D8 FF E0(实际上只有前两个字节可以用于非jfif jpeg,这里有更多信息).

GIF:前6个字节是"GIF87a"或"GIF89a"(此处有更多信息)

PNG:前8个字​​节是:89 50 4E 47 0D 0A 1A 0A(更多信息在这里)

TIFF:前4个字节是:II42或MM42(此处有更多信息)

等等...您可以找到关于您关心的任何图形格式的标题/格式信息,并根据需要添加到它处理的内容中.这不会做的,是告诉你文件是否是该类型的有效版本,但它会给你一个关于"图像不是图像?"的提示.它仍然可能是一个损坏或不完整的图像,因此在打开时会崩溃,所以仍然需要尝试捕捉.FromFile调用.


嗯..当我打字并收集链接时,有四个人回答.繁忙的地方.

6> David Boike..:

这应该可以解决问题 - 您不必从标头中读取原始字节:

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

当然,您也应该捕获OutOfMemoryException,如果文件根本不是图像,这将节省您的时间.

并且,ImageFormat为GDI +支持的所有其他主要图像类型预先设置了项目.

注意,您必须在ImageFormat对象上使用.Equals()而不是==(它不是枚举),因为operator ==没有重载以调用Equals方法.

推荐阅读
重庆制造漫画社
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有