I want to check if the file is an actual .png/.jpg file that can be displayed (for example not being a .txt file with a changed file extension to .png). I also want to check if the width and height of the image is in a valid range. How can I achieve this?
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize]
public async Task<IActionResult> Create(IFormFile image)
{
// validate image
}
CodePudding user response:
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
You can also check Path.GetExtension Method
Here's a simple sample:
public static readonly List<string> ImageExtensions = new List<string> { ".JPG", ".JPE", ".BMP", ".GIF", ".PNG" };
private void button_Click(object sender, RoutedEventArgs e)
{
var folder = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
var files = Directory.GetFiles(folder);
foreach(var f in files)
{
if (ImageExtensions.Contains(Path.GetExtension(f).ToUpperInvariant()))
{
// process image
}
}
}
CodePudding user response:
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`
}