Validate Image from File in C#

Validate image from file in C#

JPEG's don't have a formal header definition, but they do have a small amount of metadata you can use.

  • Offset 0 (Two Bytes): JPEG SOI marker (FFD8 hex)
  • Offset 2 (Two Bytes): Image width in pixels
  • Offset 4 (Two Bytes): Image height in pixels
  • Offset 6 (Byte): Number of components (1 = grayscale, 3 = RGB)

There are a couple other things after that, but those aren't important.

You can open the file using a binary stream, and read this initial data, and make sure that OffSet 0 is 0, and OffSet 6 is either 1,2 or 3.

That would at least give you slightly more precision.

Or you can just trap the exception and move on, but I thought you wanted a challenge :)

How to validate image file format in C#

Use Image.RawFormat. The result is an instance of the ImageFormat class which can be compared against the static properties of ImageFormat.

See the ImageFormat class properties for more details.

How to check if image file is valid?

First of all, don't try to use System.Drawing in .NET Core applications. It's deprecated and works only on Windows anyway. The MSDN docs themselves suggest using ImageSharp or SkiaSharp instead.

Image files start with bytes that identify the file format. You'll have to read at least some of the file's contents to read image metadata like the image size, resolution etc. You can use ImageSharp's Identify method to read only the format and image properties, without loading the entire image.

You can read an uploaded file's contents using IFormFile.OpenReadStream.

using var stream=image.OpenReadStream();
try
{
var imageInfo=Image.Identify(stream, out var format);
if(imageInfo!=null)
{
var formatName=format.Name;
var width=imageInfo.Width;
var height=imageInfo.Height;
}
}
catch(InvalidImageContentException exc)
{
//Invalid content ?
}

The format parameter is an IImageFormat value that contains information about the image format, including its name and mime types.

The IImageInfo object returned contains the image dimensions, pixel type, resolution etc.

The method documentation explains that the return value will be null if no suitable decoder is found:

The IImageInfo or null if a suitable info detector is not found.

But an exception will be thrown if the content is invalid:

InvalidImageContentException Image contains invalid content.

Without testing this, I assume that a text file will result in a null but a file with just a GIF header without valid content will result in an exception.

You can use ImageSharp to resize the image or convert it to another format. In that case it's not enough to just load the metadata. You can use Load to load the image from the stream, detect its format and then manipulate it.

using var stream=image.OpenReadStream();
var image=Image.Load(stream, out var format);

var formatName=format.Name;
if (notOk(formatName,image.Height,image.Width))
{
using var outStream=new MemoryStream();
image.Mutate(x => x.Resize(desiredWidth, desiredHeight));
image.SaveAsPng(outStream);
outStream.Position=0;
//Store the contents of `outStream`
}

How to check Is Valid Image File in C#

I think you can check the file header.

    public static ImageType CheckImageType(string path)
{
byte[] buf = new byte[2];
try
{
using (StreamReader sr = new StreamReader(path))
{
int i = sr.BaseStream.Read(buf, 0, buf.Length);
if (i != buf.Length)
{
return ImageType.None;
}
}
}
catch (Exception exc)
{
//Debug.Print(exc.ToString());
return ImageType.None;
}
return CheckImageType(buf);
}

public static ImageType CheckImageType(byte[] buf)
{
if (buf == null || buf.Length < 2)
{
return ImageType.None;
}

int key = (buf[1] << 8) + buf[0];
ImageType s;
if (_imageTag.TryGetValue(key, out s))
{
return s;
}
return ImageType.None;
}

public enum ImageType
{
None = 0,
BMP = 0x4D42,
JPG = 0xD8FF,
GIF = 0x4947,
PCX = 0x050A,
PNG = 0x5089,
PSD = 0x4238,
RAS = 0xA659,
SGI = 0xDA01,
TIFF = 0x4949
}

determine if file is an image

Check the file for a known header. (Info from link also mentioned in this answer)

The first eight bytes of a PNG file always contain the following (decimal) values: 137 80 78 71 13 10 26 10

Image validation in C#

FileInfo.Length will return the current file size in bytes.

long length = new System.IO.FileInfo(path).Length;

25 Kilobytes (even though your question implicitly asks about Kilobits), is 25000 bytes. Check if less than or greater than that value.

How Do I Validate a JPEG Image in C# / .Net is not corrupted

Taking JPEG reference structure from Wikipedia, maybe you can look for EOI byte from the stream?

Determine if uploaded file is image (any format) on MVC

In case it can helps anyone, Here is a static method for HttpPostedFileBase that checks if a given uploaded file is an image:

public static class HttpPostedFileBaseExtensions
{
public const int ImageMinimumBytes = 512;

public static bool IsImage(this HttpPostedFileBase postedFile)
{
//-------------------------------------------
// Check the image mime types
//-------------------------------------------
if (!string.Equals(postedFile.ContentType, "image/jpg", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(postedFile.ContentType, "image/jpeg", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(postedFile.ContentType, "image/pjpeg", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(postedFile.ContentType, "image/gif", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(postedFile.ContentType, "image/x-png", StringComparison.OrdinalIgnoreCase) &&
!string.Equals(postedFile.ContentType, "image/png", StringComparison.OrdinalIgnoreCase))
{
return false;
}

//-------------------------------------------
// Check the image extension
//-------------------------------------------
var postedFileExtension = Path.GetExtension(postedFile.FileName);
if (!string.Equals(postedFileExtension , ".jpg", StringComparison.OrdinalIgnoreCase)
&& !string.Equals(postedFileExtension , ".png", StringComparison.OrdinalIgnoreCase)
&& !string.Equals(postedFileExtension , ".gif", StringComparison.OrdinalIgnoreCase)
&& !string.Equals(postedFileExtension , ".jpeg", StringComparison.OrdinalIgnoreCase))
{
return false;
}

//-------------------------------------------
// Attempt to read the file and check the first bytes
//-------------------------------------------
try
{
if (!postedFile.InputStream.CanRead)
{
return false;
}
//------------------------------------------
// Check whether the image size exceeding the limit or not
//------------------------------------------
if (postedFile.ContentLength < ImageMinimumBytes)
{
return false;
}

byte[] buffer = new byte[ImageMinimumBytes];
postedFile.InputStream.Read(buffer, 0, ImageMinimumBytes);
string content = System.Text.Encoding.UTF8.GetString(buffer);
if (Regex.IsMatch(content, @"<script|<html|<head|<title|<body|<pre|<table|<a\s+href|<img|<plaintext|<cross\-domain\-policy",
RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Multiline))
{
return false;
}
}
catch (Exception)
{
return false;
}

//-------------------------------------------
// Try to instantiate new Bitmap, if .NET will throw exception
// we can assume that it's not a valid image
//-------------------------------------------

try
{
using (var bitmap = new System.Drawing.Bitmap(postedFile.InputStream))
{
}
}
catch (Exception)
{
return false;
}
finally
{
postedFile.InputStream.Position = 0;
}

return true;
}
}

Edit 2/10/2017: According to a suggested edit, added a finally statement to reset the stream, so we can use it later.

How to check if the uploaded image file is fake using ASP.NET C#?

As @Isma commented, define "broken".

But you can try to create a new System.Drawing.Image with it. If you want to validate anything else about it, then access it's properties. For instance you can check that the image is larger than 1 pixel if that suits your purpose. If an exception is thrown creating, or during your other checks, then it is (unlikely) a valid image.

    private static bool CheckImage(string filename)
{
try
{
using (var image = Image.FromFile(filename))
{
if(image.Height<2 && image.Width<2)
return false
}
return true;
}
catch (Exception ex)
{
// probably should log more information here
return false;
}
}


Related Topics



Leave a reply



Submit