5

I am using .NET Core 3.0 MVC app with a file upload for users. These files assumed to be an image, but for obvious reasons, I validate the image before saving it to the server.

Now I have ran into an issue, when a user tries to upload a JPEG image (which seems to be fine as he had to email it to me for further inspection) and this image seems to be a WebP image or was converted from a WebP Image.

The issue is that one of the check for each image is

using (var bitmap = new Bitmap(postedFile.OpenReadStream()))
{
}

This threw an exception "Parameter is not valid" and because of this, validation fails.

If I read the buffer of the uploaded IFromFile, it starts with RIFFڶ\0\0WEBPVP8

This is how I knew, this is not a normal image.

Any way to decode or validate this image as any other?

Ian Kemp
  • 28,293
  • 19
  • 112
  • 138
Sugafree
  • 631
  • 2
  • 14
  • 30
  • 1
    Do you actually need to read the image? WebP is not supported by `Bitmap`. [There are libraries which can](https://stackoverflow.com/q/7566426/215552), but if you don't actually need to manipulate the image, I suggest just looking at the `Content-Type` HTTP header. – Heretic Monkey Dec 31 '19 at 14:51
  • I dont think `Content-Type` and `Header` would be enough to check if the file is valid. I check those libraries though. Thanks – Sugafree Dec 31 '19 at 14:53
  • From [here](https://learn.microsoft.com/en-us/dotnet/framework/winforms/advanced/types-of-bitmaps?view=netframework-4.8), you can find the supported formats are BMP, GIF, EXIF, JPEG, PNG and TIFF. – Fei Han Jan 01 '20 at 06:40

2 Answers2

1

I use Magick.NET to convert WebP images to PNG's (single frame) or GIF's (animated). My code looks like:

public static Bitmap NewBitmap(this FileInfo fi) {
    Bitmap bitmap = null;
    try {
        bitmap = new Bitmap(fi.FullName);
    } catch (Exception) {
      // use 'MagickImage()' if you want just the 1st frame of an animated image. 
      // 'MagickImageCollection()' returns all frames
        using (var magickImages = new MagickImageCollection(fi)) {
            var ms = new MemoryStream();                    
            if (magickImages.Count > 1) {
                magickImages.Write(ms, MagickFormat.Gif);
            } else {
                magickImages.Write(ms, MagickFormat.Png);
            }
            bitmap?.Dispose();
            bitmap = new Bitmap(ms);
            // keep MemoryStream from being garbage collected while Bitmap is in use
             bitmap.Tag = ms;
        }
    }
    return bitmap;
}

It's not superfast, especially for GIF's with many frames, but works well.

d ei
  • 493
  • 4
  • 16
0

Now to be clear, you probably shouldn't be using System.Drawing on web server apps, there are plenty of cross-platform imaging APIs out there like ImageSharp that support modern formats out of the box and allow you to read, identify, edit and stream images over network streams efficiently.

However, System.Drawing.Common does support WebP starting from .Net7, though of course only on Windows, since it uses GDI+ internally, and only in Windows version 10.0.17763.0 or newer.

Blindy
  • 65,249
  • 10
  • 91
  • 131