3

I have a link given by an ONVIF ip camera that contains a snapshot taken by the said camera.

When I try to open this link on a browser like chrome, I get the following prompt:

Your connection to this site is not private

When I try to load this image from a c# windows form picturebox, I get the following error:

Load:

picturebox0.Load(mySnapUrl);

Error:

System.Net.WebException: 'The remote server returned an error: (401) Unauthorized.'

I can see the image in my browser once I enter the appropriate username and password.

Is there any way I could load such an image in a picturebox?

EDIT 1:

I tried this solution to manually load the image on a web client in which I added credentials by hand and I still get the same error at the downloadData line.

var webClient = new WebClient();
var credentialCache = new CredentialCache();
credentialCache.Add(new Uri(mySnapUrl), "Basic", new NetworkCredential(user, password));
webClient.Credentials = credentialCache;
var imgStream = new MemoryStream(webClient.DownloadData(mySnapUrl));//Error
picturebox0.Image = new System.Drawing.Bitmap(imgStream);
LoukMouk
  • 503
  • 9
  • 29
  • 4
    If the camera vendor doesn't provide any technical details, you can use a tool such as Fiddler (or the browser embedded developer tools / F12) to sniff the wire and check what's the authentication. Also, you don't need a CredentialCache, you can just set wc.Credentials = new NetworkCredential(u,p) – Simon Mourier Feb 26 '19 at 09:15
  • 1
    Have you tried [this](https://stackoverflow.com/a/26016919/3110834)? – Reza Aghaei Feb 27 '19 at 02:35
  • @SimonMourier if you want the bounty, just copy the answer I gave. I'll delete mine. – LoukMouk Mar 01 '19 at 18:17
  • @RezaAghaei same goes to you. First one to do will get it! – LoukMouk Mar 01 '19 at 18:17
  • 1
    @LoukMo - such (rare) courtesy deserves a reward, please keep your answer :-) – Simon Mourier Mar 01 '19 at 19:21
  • @LoukMo Thanks, Simon has already answered the question in the first comment, so the bounty is his. You can remove your answer so he can post his answer with more details. – Reza Aghaei Mar 01 '19 at 19:47
  • @SimonMourier - If you answer and get the bounty everyone wins. I'm detecting 6 digits... – Jeremy Thompson Mar 05 '19 at 01:07
  • You probably can also try `http://user:password@hostname/image.png` – dereli Mar 05 '19 at 05:42
  • @dereli I tried your solution but it doesn't work. Thanks again for everyone's help! I know it's hard to test such a niche problem because not everyone has access to test with this type of exception. – LoukMouk Mar 06 '19 at 13:23
  • @LoukMo, that's not unexpected. That part of the RFC has always been debated and AFAIU, it's been deprecated: https://tools.ietf.org/html/rfc3986#section-3.2.1 – dereli Mar 07 '19 at 07:32
  • @dereli I've worked with many types of ONVIF conformant cameras and it's the first time I was asked to do such identification to have access to a snapshot. It makes sense thought. No one wants everyone to be able to take picture of your cameras only by knowing the url to access the said snapshot. – LoukMouk Mar 07 '19 at 13:36

1 Answers1

4

As @Simon Mourier and @Reza Aghaei said in the comments, I didn't need to add a CredentialCache but only Credentials. The solution is similar to this one.

Solution:

var webClient = new WebClient();
webClient.Credentials = new NetworkCredential(user, password);
var imgStream = new MemoryStream(webClient.DownloadData(mySnapUrl));//Good to go!
picturebox0.Image = new System.Drawing.Bitmap(imgStream);

Edit:

I personally had to be able to load the said image asynchronously, because I used to load my images with picturebox0.LoadAsync(mySnapUrl).

I got the big idea from this source.

To be able to to the same with an image that needs credentials, I created an async Task to load the image...

private async Task<Image> GetImageAsync(string snapUrl, string user, string password)
{
    var tcs = new TaskCompletionSource<Image>();

    Action actionGetImage = delegate ()
    {
        var webClient = new WebClient();
        webClient.Credentials = new NetworkCredential(user, password);
        var imgStream = new MemoryStream(webClient.DownloadData(snapUrl));
        tcs.TrySetResult(new System.Drawing.Bitmap(imgStream));
    };

    await Task.Factory.StartNew(actionGetImage);

    return tcs.Task.Result;
}

... and then set the image with the following:

var result = GetImageAsync(mySnapUrl, user, password);
result.ContinueWith(task =>
{
    picturebox0.Image = task.Result;
});
LoukMouk
  • 503
  • 9
  • 29