Search code examples
c#pictureboxonvif

How to load picturebox image when the connection to the image's site is not private?


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);

Solution

  • 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;
    });