Good way to check if file extension is of an image or not
Asked Answered
M

5

24

I have this file types Filters:

    public const string Png = "PNG Portable Network Graphics (*.png)|" + "*.png";
    public const string Jpg = "JPEG File Interchange Format (*.jpg *.jpeg *jfif)|" + "*.jpg;*.jpeg;*.jfif";
    public const string Bmp = "BMP Windows Bitmap (*.bmp)|" + "*.bmp";
    public const string Tif = "TIF Tagged Imaged File Format (*.tif *.tiff)|" + "*.tif;*.tiff";
    public const string Gif = "GIF Graphics Interchange Format (*.gif)|" + "*.gif";
    public const string AllImages = "Image file|" + "*.png; *.jpg; *.jpeg; *.jfif; *.bmp;*.tif; *.tiff; *.gif";
    public const string AllFiles = "All files (*.*)" + "|*.*";

    static FilesFilters()
    {
        imagesTypes = new List<string>();
        imagesTypes.Add(Png);
        imagesTypes.Add(Jpg);
        imagesTypes.Add(Bmp);
        imagesTypes.Add(Tif);
        imagesTypes.Add(Gif);
   }

OBS: Is there any default filters in .NET or a free library for that?

I need a static method that checks if a string is an image or not. How would you solve this?

    //ext == Path.GetExtension(yourpath)
    public static bool IsImageExtension(string ext)
    {
        return (ext == ".bmp" || .... etc etc...)
    }

Solution using Jeroen Vannevel EndsWith. I think it is ok.

    public static bool IsImageExtension(string ext)
    {
        return imagesTypes.Contains(ext);
    }
Meatiness answered 19/7, 2013 at 0:17 Comment(1)
You might also want to consider doing it by detecting the MIME Type, its more "trust worthy" that file extension,Aphanite
M
17

You could use .endsWith(ext). It's not a very secure method though: I could rename 'bla.jpg' to 'bla.png' and it would still be a jpg file.

public static bool HasImageExtension(this string source){
 return (source.EndsWith(".png") || source.EndsWith(".jpg"));
}

This provides a more secure solution:

string InputSource = "mypic.png";
System.Drawing.Image imgInput = System.Drawing.Image.FromFile(InputSource);
Graphics gInput = Graphics.fromimage(imgInput);
Imaging.ImageFormat thisFormat = imgInput.rawformat;
Mccullum answered 19/7, 2013 at 0:20 Comment(7)
"I could rename 'bla.jpg' to 'bla.png' and it would still be a jpg file" Yeah I know that, but this leads to another problem... I think I will leave with this because all images will be loaded as a Bitmap object. endsWith is nice.Meatiness
If you have a list of allowed imagetypes just use return imageTypes.Contains(ext); in accordance to @Alejandro's example.Mccullum
Opsss! Thank you!! By the way: is there any default filters in .NET or a free library for that?Meatiness
Not that I know off, but I haven't done any search for it either.Mccullum
does this secure solution 100% safe? can we use it to save images as we want? I mean we can save gInput as png for example right? and it would be safe?Adiaphorous
@DaveLucre If you desperately want to change the code to account for lowercase then you should use the .EndsWith overload with a StringComparison argument. ToLower() for string comparison is not done.Mccullum
@JeroenVannevel since you so desperately want to suppress any solution suggested by others, perhaps you can follow your own advice and implement the suggested solution yourself.Jeans
T
17
private static readonly string[] _validExtensions = {"jpg","bmp","gif","png"}; //  etc

public static bool IsImageExtension(string ext)
{
    return _validExtensions.Contains(ext.ToLower());
}

If you want to be able to make the list configurable at runtime without recompiling, add something like:

private static string[] _validExtensions;

private static string[] ValidExtensions()
{
    if(_validExtensions==null)
    { 
        // load from app.config, text file, DB, wherever
    }
    return _validExtensions
}

public static bool IsImageExtension(string ext)
{
    return ValidExtensions().Contains(ext.ToLower());
}
Turkmen answered 19/7, 2013 at 5:38 Comment(3)
Make sure you include using System.Linq; to get access to the Contains extension method.Auvergne
Note that this will only work with all lowercase extensions -- remember that Windows's file system is case insensitive, but C#'s string comparison is not. It's not uncommon for extensions to be all caps, e.g., somefile.PNG. This overload of Contains can fix this limitation. For example, use ValidExtensions().Contains(ext, StringComparer.OrdinalIgnoreCase);, note that you need using System.Linq; to take advantage of that Contains overload.Nap
@daniellmb nitpicking: Technically you don't need LINQ for List.Contains(T), but you do need LINQ for Enumerable.Contains(this IEnumerable<T>,T, Comparer), the latter extension method overload would help resolve some issues in the code in this post.Nap
F
5

An option would be to have a list of all possible valid image extensions, then that method would only check if the supplied extension is within that collection:

private static readonly HashSet<string> validExtensions = new HashSet<string>()
{
    "png",
    "jpg",
    "bmp"
    // Other possible extensions
};

Then in the validation you just check against that:

public static bool IsImageExtension(string ext)
{
    return validExtensions.Contains(ext);
}
Fusible answered 19/7, 2013 at 0:28 Comment(2)
Good extra info is here https://mcmap.net/q/63095/-define-what-is-a-hashsetVallery
Note that this will only work with all lowercase extensions -- remember that Windows's file system is case insensitive, but C#'s string comparison (by default) is not. It's not uncommon for extensions to be all caps, e.g., somefile.PNG. Consider adding StringComparer.OrdinalIgnoreCase to your HashSet as Oliver did in his answer.Nap
E
5

This method automatically creates a filter for the OpenFileDialog. It uses the informations of the image decoders supported by Windows. It also adds information of "unknown" image formats (see default case of the switch statement).

private static string SupportedImageDecodersFilter()
{
    ImageCodecInfo[] encoders = ImageCodecInfo.GetImageDecoders();

    string allExtensions = encoders
        .Select(enc => enc.FilenameExtension)
        .Aggregate((current, next) => current + ";" + next)
        .ToLowerInvariant();
    var sb = new StringBuilder(500)
        .AppendFormat("Image files  ({0})|{1}", allExtensions.Replace(";", ", "),
                      allExtensions);
    foreach (ImageCodecInfo encoder in encoders) {
        string ext = encoder.FilenameExtension.ToLowerInvariant();
        // ext = "*.bmp;*.dib;*.rle"           descr = BMP
        // ext = "*.jpg;*.jpeg;*.jpe;*.jfif"   descr = JPEG
        // ext = "*.gif"                       descr = GIF
        // ext = "*.tif;*.tiff"                descr = TIFF
        // ext = "*.png"                       descr = PNG

        string caption;
        switch (encoder.FormatDescription) {
            case "BMP":
                caption = "Windows Bitmap";
                break;
            case "JPEG":
                caption = "JPEG file";
                break;
            case "GIF":
                caption = "Graphics Interchange Format";
                break;
            case "TIFF":
                caption = "Tagged Image File Format";
                break;
            case "PNG":
                caption = "Portable Network Graphics";
                break;
            default:
                caption = encoder.FormatDescription;
                break;
        }
        sb.AppendFormat("|{0}  ({1})|{2}", caption, ext.Replace(";", ", "), ext);
    }
    return sb.ToString();
}

Use it like this:

var dlg = new OpenFileDialog {
    Filter = SupportedImageDecodersFilter(),
    Multiselect = false,
    Title = "Choose Image"
};

The code above (slightly modified) can be used to find available image file extensions. In order to test if a given file extension denotes an image, I would put the valid extension in a HashSet. HashSets have an
O(1) access time! Make sure to choose a case insensitive string comparer. Since the file extensions do not contain accented or non Latin letters, the culture can safely be ignored. Therefore I use an ordinal string comparison.

var imageExtensions = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
imageExtensions.Add(".png");
imageExtensions.Add(".bmp");
...

And test if a filename is an image:

string extension = Path.GetExtension(filename);
bool isImage = imageExtensions.Contains(extension);
Expellant answered 17/2, 2014 at 17:35 Comment(0)
N
4

I just had to do something similiar. Here is my solution:

    private bool IsImage(string fileExtension)
    {
        return GetImageFileExtensions().Contains(fileExtension.ToLower()));
    }

    private static List<string> GetImageFileExtensions()
    {
        return ImageCodecInfo.GetImageEncoders()
                             .Select(c => c.FilenameExtension)
                             .SelectMany(e => e.Split(';'))
                             .Select(e => e.Replace("*", "").ToLower())
                             .ToList();            
    }
Natalyanataniel answered 23/2, 2019 at 22:13 Comment(1)
This adds a dependency to System.Drawing.Imaging which is not cross platform. Doesn't work in .Net Standard / Core.Bannockburn

© 2022 - 2024 — McMap. All rights reserved.