如何确定图像是否部分损坏? C#

时间:2012-01-16 06:19:19

标签: image partial corrupt

我有一个图像的原始字节。我使用以下代码来确定图像是否损坏

public bool IsValidGDIPlusImage(byte[] imageData)
{
    try
    {
        using (var ms = new MemoryStream(imageData))
        {
            using (var bmp = new Bitmap(ms))
            {
            }
        }
        return true;
    }
    catch (Exception ex)
    {
        return false;
    }
}

如果图像完全损坏,上面的代码工作正常,但如果我有一个部分损坏的图像呢?像下面的JPEG

enter image description here

如何确定图像部分损坏?

原始图像下方是一个简单的300x300像素图像,中心有一条对角线。

enter image description here 任何指导都非常感谢。 感谢

1 个答案:

答案 0 :(得分:0)

检测部分损坏的图像非常困难。

一种简单的方法是检查起始和结束字节标记是否完整,如下所示:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Net;
using System.IO;
using System.Drawing;

namespace Rextester
{
    public class Program
    {
        public static void Main(string[] args)
        {
            try {

                var imgBytes = Helper.DownloadImageAsBytes("https://i.stack.imgur.com/KQI1j.jpg");
                //valid GDI+? Example true!
                Console.WriteLine(IsValidGDIPlusImage(imgBytes));
                //Complete? Example false
                ImageFile imgFile = new ImageFile(imgBytes);
                Console.WriteLine(imgFile.Complete);

            }
            catch(Exception ex)
            {
                Console.Write(ex.Message);
            }
        }

        public static bool IsValidGDIPlusImage(byte[] imageData)
        {
            try
            {
                using (var ms = new MemoryStream(imageData))
                {
                    using (var bmp = new Bitmap(ms))
                    {
                    }
                }
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }
    }
}

public class Helper {
    public static byte[] DownloadImageAsBytes(String url) {
        using (var webClient = new WebClient()) { 
            return webClient.DownloadData(url);
        }
    }
}

public class ImageFile {

    private Types  _eFileType   = Types.FileNotFound;
    private bool   _blComplete  = false             ;
    public bool Complete
    {
        get { return _blComplete; }
    }
    private int    _iEndingNull = 0                 ;

    private readonly byte[] _abTagPNG  = { 137, 80, 78, 71, 13, 10, 26, 10  };
    private readonly byte[] _abTagJPG  = { 255, 216, 255                    };
    private readonly byte[] _abTagGIFa = { 71, 73, 70, 56, 55, 97           };
    private readonly byte[] _abTagGIFb = { 71, 73, 70, 56, 57, 97           };
    private readonly byte[] _abEndPNG  = { 73, 69, 78, 68, 174, 66, 96, 130 };
    private readonly byte[] _abEndJPGa = { 255, 217, 255, 255               };
    private readonly byte[] _abEndJPGb = { 255, 217                         };
    private readonly byte[] _abEndGIF  = { 0, 59                            };

    public enum Types { FileNotFound, FileEmpty, FileNull, FileTooLarge, FileUnrecognized, PNG, JPG, GIFa, GIFb }

    public ImageFile(byte[] abtTmp) {

        _eFileType = Types.FileUnrecognized; // default if found

        //byte[] abtTmp = File.ReadAllBytes(_sFilename);
        // check the length of actual data
        int iLength = abtTmp.Length;
        if(abtTmp[abtTmp.Length - 1] == 0) {
            for(int i = (abtTmp.Length - 1); i > -1; i--) {
                if(abtTmp[i] != 0) {
                    iLength = i;
                    break;
                }
            }
        }
        // check that there is actual data
        if(iLength == 0) {
            _eFileType = Types.FileNull;
        } else {
            _iEndingNull = (abtTmp.Length - iLength);
            // resize the data so we can work with it
            Array.Resize<byte>(ref abtTmp, iLength);
            // get the file type
            if(_StartsWith(abtTmp, _abTagPNG)) {
                _eFileType = Types.PNG;
            } else if(_StartsWith(abtTmp, _abTagJPG)) {
                _eFileType = Types.JPG;
            } else if(_StartsWith(abtTmp, _abTagGIFa)) {
                _eFileType = Types.GIFa;
            } else if(_StartsWith(abtTmp, _abTagGIFb)) {
                _eFileType = Types.GIFb;
            }
            // check the file is complete
            switch(_eFileType) {
                case Types.PNG:
                    _blComplete = _EndsWidth(abtTmp, _abEndPNG);
                    break;
                case Types.JPG:
                    _blComplete = (_EndsWidth(abtTmp, _abEndJPGa) || _EndsWidth(abtTmp, _abEndJPGb));
                    break;
                case Types.GIFa:
                case Types.GIFb:
                    _blComplete = _EndsWidth(abtTmp, _abEndGIF);
                    break;
            }
            // get rid of ending null bytes at caller's option
            //if(_blComplete && cullEndingNullBytes) File.WriteAllBytes(_sFilename, abtTmp);
        }

    }


    public Types  FileType        { get { return _eFileType  ; } }
    public bool   IsComplete      { get { return _blComplete ; } }
    public int    EndingNullBytes { get { return _iEndingNull; } }

    private bool _StartsWith(byte[] data, byte[] search) {
        bool blRet = false;
        if(search.Length <= data.Length) {
            blRet = true;
            for(int i = 0; i < search.Length; i++) {
                if(data[i] != search[i]) {
                    blRet = false;
                    break;
                }
            }
        }
        return blRet; // RETURN
    }

    private bool _EndsWidth(byte[] data, byte[] search) {
        bool blRet = false;
        if(search.Length <= data.Length) {
            int iStart = (data.Length - search.Length);
            blRet = true;
            for(int i = 0; i < search.Length; i++) {
                if(data[iStart + i] != search[i]) {
                    blRet = false;
                    break;
                }
            }
        }
        return blRet; // RETURN
    }
}

此功能至少适用于某些(更多)图像,但无法检测出开始和结束部分之间数据损坏的图像。

参考:

您可以尝试一些操作,但是要使用某些文件格式(例如:BMP, JPEG(某种程度上),只有人类才能最终决定文件是否 确定或损坏。

有用于此目的的开放软件,建议您看看Bad Peggy(Java)。 如果您愿意使用更大的库,则OpenCV可能会有用。