【问题标题】:How do determine if an image is partially corrupt? C#如何确定图像是否部分损坏? C#
【发布时间】:2012-01-16 06:19:19
【问题描述】:

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

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

如何确定图像部分损坏?

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

非常感谢任何指导。 谢谢

【问题讨论】:

    标签: image partial corrupt


    【解决方案1】:

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

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

    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 可能会很有用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-04-13
      • 1970-01-01
      • 1970-01-01
      • 2021-07-28
      • 1970-01-01
      • 2013-04-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多