探测部分损坏的图像非常困难。
简单化的方法是检查起步和末端 marks是否像这样完整:
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
}
}
这至少对一些(更多)图像有用,但无法在开端和端段之间用损坏的数据探测图像。
References:
You can try some things, but with certain file formats (example: BMP,
JPEG to some extent) only a human can ultimately decide if the file is
OK or corrupted.
There is open software out for this purpose, recommend to take a look at Bad Peggy (Java).
If you are willing to use a bigger library, OpenCV could be useful.