0

I'm unable to retrieve an image from a url. Previously I was unable to connect to the site at all until I set HttpClient headers. I'm able to retrieve images from other sources but not this particular one.

Code for retrieving image:

var img = new BitmapImage();
        img.BeginInit();
        img.UriSource = new Uri("https://i1.adis.ws/i/jpl/jd_083285_a?qlt=80&w=600&h=425&v=1&fmt=webp", UriKind.RelativeOrAbsolute);
        img.EndInit();
        Console.Out.WriteLine();
        ImageShoe.Source = img;

If I try to retrieve a different image using a different url, for example https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png it works fine.

Update:

Seems that using a byte array is the way to go but I'm still not sure what is wrong here.

        HttpClient client = new HttpClient();
        client.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
        var url = "https://i1.adis.ws/i/jpl/jd_083285_a?qlt=80&w=600&h=425&v=1&fmt=webp";//baseUrl + productUrl;
        var result = await client.GetByteArrayAsync(new Uri(
        MemoryStream buf = new MemoryStream(result);
        var image = new BitmapImage();
        image.StreamSource = buf;
        this.ImageShoe.Source = image;
Max
  • 71
  • 1
  • 9
  • it doesn't have a .fileformat at the end so you cannot parse it as WPF doesn't know what to do with the data. try this: https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RE1Mu3b?ver=5c31.png – Denis Schaf Mar 15 '19 at 20:28
  • I considered that might be an issue but using a url such as https://img-prod-cms-rt-microsoft-com.akamaized.net/cms/api/am/imageFileData/RE1Mu3b?ver=5c31 is fine. Do you have any idea as to how i can get the image then? – Max Mar 15 '19 at 20:31
  • download it and add it to your project resources? or do you need to load it dynamically? – Denis Schaf Mar 15 '19 at 20:31
  • Well wasn't that a coincidence haha. I need to load it dynamically. – Max Mar 15 '19 at 20:32
  • you should still have the image locally in case the service is down or there is no internet connection you just need a source to get the microsoft logo tha tis updated? – Denis Schaf Mar 15 '19 at 20:34
  • why do you want to get it from there? this link is not permanent and might be gone in a week or a month or maybe a year? – Denis Schaf Mar 15 '19 at 20:36
  • I used the miscrosoft logo as a test. I edited the code and put in the exact url I'm using. Having the image stored locally is possible and is something I was considering but considering that I'd have to save it manually for thousands of images, that's not really an option. – Max Mar 15 '19 at 20:38
  • I'm scraping the images from a site and so whether or not it is there in a week is not a concern. The url is hardcoded for test purposes – Max Mar 15 '19 at 20:41
  • The problem is that the path you provided is an HTTP request for an WEBP object, not a JPG or PNG you cannot parse an WEBP page to an image. – Denis Schaf Mar 15 '19 at 20:46
  • 1
    check this link https://stackoverflow.com/questions/7566426/webp-library-for-c-sharp – Denis Schaf Mar 15 '19 at 20:49
  • 1
    @DenisSchaf While it is true that WPF can't decode WebP, it is plain nonsense to say that "*WPF doesn't know what to do with the data*" when there is no appropriate extension. The encoding format is determined by a magic number in the first couple of bytes in the frame buffer. This is why you can pass an encoded frame in any of the supported image formats as byte array in a MemoryStream to the StreamSource property of a WPF BitmapImage without explicitly specifying the encoding format. You can try this by renaming e.g. a .png file to .jpg. It is still decoded as PNG. – Clemens Mar 15 '19 at 21:42
  • @Clemens I did try this as well but I'm not exactly sure what I'm doing wrong by going about this method. I've updated my attempt but I'm a bit lost as to what I'm doing wrong. – Max Mar 15 '19 at 23:39
  • I'm not sure why you were having problems... the code in your first example works fine (even with the exact URL you have). It seems more likely it was an issue with that particular server or file at the time, or maybe even your internet connection. – Herohtar Oct 17 '19 at 03:24

1 Answers1

7

WPF does not natively support the WebP image format.

You could simply request a supported format like PNG, by using fmt=png instead of fmt=webp in the request URL:

ImageShoe.Source = new BitmapImage(
    new Uri("https://i1.adis.ws/i/jpl/jd_083285_a?qlt=80&w=600&h=425&v=1&fmt=png"));

If you really need WebP support, the following methods downloads a WebP image and first converts it to a System.Drawing.Bitmap with help of the libwebp wrapper for .NET library. A second conversion then converts from System.Drawing.Bitmap to BitmapImage:

The wrapper library is available via NuGet, but you also have to download the wrapped libwebp library for the desired platform, i.e. x86 or x64, as explained on the wrapper library's home page.

private async Task<BitmapImage> LoadWebP(string url)
{
    var httpClient = new HttpClient();
    var buffer = await httpClient.GetByteArrayAsync(url);
    var decoder = new Imazen.WebP.SimpleDecoder();
    var bitmap = decoder.DecodeFromBytes(buffer, buffer.Length);
    var bitmapImage = new BitmapImage();

    using (var stream = new MemoryStream())
    {
        bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
        stream.Position = 0;

        bitmapImage.BeginInit();
        bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
        bitmapImage.StreamSource = stream;
        bitmapImage.EndInit();
    }

    return bitmapImage;
}

I've tested it with

ImageShoe.Source = await LoadWebP(
    "https://i1.adis.ws/i/jpl/jd_083285_a?qlt=80&w=600&h=425&v=1&fmt=webp");
Clemens
  • 123,504
  • 12
  • 155
  • 268
  • Thanks! Not sure which approach I'll take but this is great :) – Max Mar 16 '19 at 14:32
  • Choosing a supported image format seems far more sensible. – Clemens Mar 16 '19 at 15:21
  • Absolutely, it's just a matter of parsing urls from multiple sites with various url formatting. If possible I'd prefer not to make exceptions for individual sites but seems like I might have to. I think my biggest issue is that in my head I think "There's definitely an api for that" and so I spend more time looking for solutions or the best possible way instead of just getting results – Max Mar 16 '19 at 17:21
  • The statement at the top of this answer is false. I can load WebP images in WPF using `BitmapImage` both via `UriSource` and `StreamSource`, locally as well as directly from a web URL. No extra libraries or converters required. – Herohtar Oct 17 '19 at 03:20
  • 1
    @Herohtar You might have installed a WebP codec. That is third party software. Windows/WPF do not natively support WebP. – Clemens Oct 20 '19 at 14:27
  • I think you're right... WebP doesn't work on my other computer with the same version of Windows and .NET, and looking at the reference source for .NET it seems that if it can't use any of the standard decoders it makes some native Windows API call to find decoders there. I'm not sure what the difference between my computers is though, because I never explicitly installed a WebP codec that I'm aware of. – Herohtar Oct 20 '19 at 14:46
  • For noobs like me: you can find BitmapImage in [System.Windows.Media.Imaging](https://learn.microsoft.com/en-us/dotnet/api/system.windows.media.imaging.bitmapimage?view=net-5.0). – sisisisi Sep 14 '21 at 20:01