我有一个图像的原始字节。我使用以下代码来确定图像是否损坏
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像素图像,中心有一条对角线。
任何指导都非常感谢。 感谢
答案 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可能会有用。