12

Is there a way I can detect an image URL, like:

http://mysite.com/image.jpg

but with other formats as well? I am using C# with .NET 4.0.

Something like

bool isImageUrl(string URL){
}

edit I meant if the URL points to an image. Eg, the URL

http://mysite.com/image.jpg

is a valid image, but

http://mysite.com/image

is not.

svbnet
  • 1,070
  • 3
  • 11
  • 29

6 Answers6

17

You can detemine it using the HEAD method of Http (without downloading the whole image)

bool IsImageUrl(string URL)
{
    var req = (HttpWebRequest)HttpWebRequest.Create(URL);
    req.Method = "HEAD";
    using (var resp = req.GetResponse())
    {
        return resp.ContentType.ToLower(CultureInfo.InvariantCulture)
                   .StartsWith("image/");
    }
}
L.B
  • 114,136
  • 19
  • 178
  • 224
  • 6
    Note that not all servers will handle `HEAD`, and that you should pass `OrdinalIgnoreCase` to `StartsWith`. – SLaks Jun 18 '12 at 12:45
  • It works only when the image is valid,perhaps a try catch to prevent System.Net.WebException. – Tim Apr 28 '20 at 07:33
  • As of .NET 6, `WebRequest` is now considered obsolete. Source: https://learn.microsoft.com/en-us/dotnet/core/compatibility/networking/6.0/webrequest-deprecated. Consider using `HttpClient` instead if you're using one of the newer versions. – Quickz Jul 03 '22 at 19:17
8

You can send an HTTP request to the URL (using HttpWebRequest), and check whether the returned ContentType starts with image/.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
3

You could of course simply check whether the URL ends with a known image file extension. However, a safer method is to actually download the resource and check, whether the content you get actually is an image:

public static bool IsUrlImage(string url)
{
    try
    {
        var request = WebRequest.Create(url);
        request.Timeout = 5000;
        using (var response = request.GetResponse())
        {
            using (var responseStream = response.GetResponseStream())
            {
                if (!response.ContentType.Contains("text/html"))
                {
                    using (var br = new BinaryReader(responseStream))
                    {
                        // e.g. test for a JPEG header here
                        var soi = br.ReadUInt16();  // Start of Image (SOI) marker (FFD8)
                        var jfif = br.ReadUInt16(); // JFIF marker (FFE0)
                        return soi == 0xd8ff && jfif == 0xe0ff;
                    }
                }
            }
        }
    }
    catch (WebException ex)
    {
        Trace.WriteLine(ex);
        throw;
    }
    return false;
}
Dirk Vollmar
  • 172,527
  • 53
  • 255
  • 316
  • 2
    While this will work, I hate to encourage it. Can you imagine the number of web requests a single application could generate to a bunch of innocent web servers with something like this? I know we're here to help, but now I feel uneasy about answering this one... – dodexahedron Jun 18 '12 at 12:33
  • Huh? What does the WebRequest class have to do with my comment? In any case, yes, I realize that a URI carries no innate meaning. I am simply commenting on the fact that, while this is a *technically correct* solution, it is not necessarily a *good* or *the* right solution, for the given application. Consider the case where someone builds an index of a bunch of images. A single request to a web page with 1000 image links on it thus generates 1000 HTTP requests. Yay. Again, I realize we're just here to answer questions, but the question itself leads me to believe the use will be inelegant. – dodexahedron Jun 18 '12 at 12:47
  • It's not any different. I just didn't want to make the same comment on the three posts with the same answer. :P My issue is not with the method. I simply chose to put it on your post since it was the best example of the three posts with the same answer. – dodexahedron Jun 18 '12 at 12:56
2

You could just check the string with .EndsWith() for each of a set of strings you define.

If you want to know if the object at that URL is actually an image, you will have to perform the web request yourself and check the content-type HTTP header.

Even that may be inaccurate, however, depending on the server.

dodexahedron
  • 4,584
  • 1
  • 25
  • 37
  • 1
    Wrong. http://www.gravatar.com/avatar/7deca8ec973c3c0875e9a36e1e3e2c44?s=64&d=identicon&r=PG – SLaks Jun 18 '12 at 12:27
  • Both can be wrong or right (download all images to check their type?), the problem is in the question itself – Panagiotis Kanavos Jun 18 '12 at 12:28
  • It's as correct as the question allows it to be. Some older web servers will not have correct MIME type mappings, anyway, especially for jpeg2000, png, and perhaps a few other formats that will end up coming across as application/octet-stream. – dodexahedron Jun 18 '12 at 12:31
2

You can send a HEAD type request using HttpClient which will allow you to make a conclusion on whether it's an image without having to download the whole thing.

Example

bool IsImageUrl(string url)
{
    using var client = new HttpClient();
    var response = client.Send(new HttpRequestMessage(HttpMethod.Head, url));
    return response.Content.Headers.ContentType.MediaType
        .StartsWith("image/", StringComparison.OrdinalIgnoreCase);
}

Extra info

I based the solution on @L.B's answer. Consider this as an alternative for .NET 6+, since after that version, the WebRequest class is considered obsolete (Source: Microsoft documentation)

Quickz
  • 1,626
  • 2
  • 11
  • 21
0

An option would be to use HttpClient from System.Net.Http rather than

HttpClient client = new HttpClient();

HttpResponseMessage res = await client.GetAsync("https://picsum.photos/200/300");

bool IsTypeImage = res.ToString().Contains("Content-Type: image");

Anatoly
  • 20,799
  • 3
  • 28
  • 42