简体   繁体   English

如何从 URL 下载图像

[英]How to download image from URL

Is there a way to download an image directly from a url in c# if the url does not have an image format at the end of the link?如果url在链接末尾没有图像格式,有没有办法直接从c#中的url下载图像? Example of URL:网址示例:

https://fbcdn-sphotos-h-a.akamaihd.net/hphotos-ak-xpf1/v/t34.0-12/10555140_10201501435212873_1318258071_n.jpg?oh=97ebc03895b7acee9aebbde7d6b002bf&oe=53C9ABB0&__gda__=1405685729_110e04e71d969d392b63b27ec4f4b24a

I know how to download the image when the url ends with an image format.我知道如何在 url 以图像格式结尾时下载图像。 Eg:例如:

http://img1.wikia.nocookie.net/__cb20101219155130/uncyclopedia/images/7/70/Facebooklogin.png

Simply You can use following methods.只需您可以使用以下方法。

using (WebClient client = new WebClient()) 
{
    client.DownloadFile(new Uri(url), @"c:\temp\image35.png");
    // OR 
    client.DownloadFileAsync(new Uri(url), @"c:\temp\image35.png");
}

These methods are almost same as DownloadString(..) and DownloadStringAsync(...).这些方法与 DownloadString(..) 和 DownloadStringAsync(...) 几乎相同。 They store the file in Directory rather than in C# string and no need of Format extension in URi他们将文件存储在目录中而不是 C# 字符串中,并且不需要在 URI 中使用格式扩展名

If You don't know the Format(.png, .jpeg etc) of Image如果您不知道图像的格式(.png、.jpeg 等)

public void SaveImage(string imageUrl, string filename, ImageFormat format)
{    
    WebClient client = new WebClient();
    Stream stream = client.OpenRead(imageUrl);
    Bitmap bitmap;  bitmap = new Bitmap(stream);

    if (bitmap != null)
    {
        bitmap.Save(filename, format);
    }
        
    stream.Flush();
    stream.Close();
    client.Dispose();
}

Using it使用它

try
{
    SaveImage("--- Any Image URL---", "--- Any Image Path ---", ImageFormat.Png)
}
catch(ExternalException)
{
    // Something is wrong with Format -- Maybe required Format is not 
    // applicable here
}
catch(ArgumentNullException)
{   
    // Something wrong with Stream
}

Depending whether or not you know the image format, here are ways you can do it :根据您是否知道图像格式,您可以使用以下方法:

Download Image to a file, knowing the image format下载图像到文件,知道图像格式

using (WebClient webClient = new WebClient()) 
{
   webClient.DownloadFile("http://yoururl.com/image.png", "image.png") ; 
}

Download Image to a file without knowing the image format在不知道图像格式的情况下将图像下载到文件

You can use Image.FromStream to load any kind of usual bitmaps (jpg, png, bmp, gif, ... ), it will detect automaticaly the file type and you don't even need to check the url extension (which is not a very good practice).您可以使用Image.FromStream加载任何类型的常用位图(jpg、png、bmp、gif、...),它会自动检测文件类型,您甚至不需要检查 url 扩展名(这不是一个很好的做法)。 Eg:例如:

using (WebClient webClient = new WebClient()) 
{
    byte [] data = webClient.DownloadData("https://fbcdn-sphotos-h-a.akamaihd.net/hphotos-ak-xpf1/v/t34.0-12/10555140_10201501435212873_1318258071_n.jpg?oh=97ebc03895b7acee9aebbde7d6b002bf&oe=53C9ABB0&__gda__=1405685729_110e04e71d9");

   using (MemoryStream mem = new MemoryStream(data)) 
   {
       using (var yourImage = Image.FromStream(mem)) 
       { 
          // If you want it as Png
           yourImage.Save("path_to_your_file.png", ImageFormat.Png) ; 

          // If you want it as Jpeg
           yourImage.Save("path_to_your_file.jpg", ImageFormat.Jpeg) ; 
       }
   } 

}

Note : ArgumentException may be thrown by Image.FromStream if the downloaded content is not a known image type.注意:如果下载的内容不是已知的图像类型,则Image.FromStream可能会抛出 ArgumentException。

Check this reference on MSDN to find all format available. 在 MSDN 上查看此参考以查找所有可用格式。 Here are reference toWebClient and Bitmap .这里参考了WebClientBitmap

For anyone who wants to download an image WITHOUT saving it to a file:对于想要下载图像而不将其保存到文件的任何人:

Image DownloadImage(string fromUrl)
{
    using (System.Net.WebClient webClient = new System.Net.WebClient())
    {
        using (Stream stream = webClient.OpenRead(fromUrl))
        {
            return Image.FromStream(stream);
        }
    }
}

.NET has changed a bit over the years, making the other answers on this post pretty dated: .NET 多年来发生了一些变化,使得这篇文章中的其他答案相当过时:

  • They use Image from System.Drawing (which is not available for .NET Core) to find the image format他们使用System.Drawing Image (不适用于 .NET Core)来查找图像格式
  • They use System.Net.WebClient which is deprecated他们使用已弃用的System.Net.WebClient

We don't recommend that you use the WebClient class for new development.我们不建议您使用WebClient类进行新的开发。 Instead, use the System.Net.Http.HttpClient class.而是使用System.Net.Http.HttpClient类。

.NET Core asynchronous solution .NET Core 异步解决方案

Getting the file extension获取文件扩展名

The first part of getting the file extension is to remove all the unnecessary parts from the URL.获取文件扩展名的第一部分是从 URL 中删除所有不必要的部分。 We can use Uri.GetLeftPart() with UriPartial.Path to get everything from the Scheme up to the Path .我们可以使用Uri.GetLeftPart()和 UriPartial.Path 来获取从SchemePath
In other words, https://www.example.com/image.png?query&with.dots becomes https://www.example.com/image.png .换句话说, https://www.example.com/image.png?query&with.dots变成https://www.example.com/image.png

After that, we can use Path.GetExtension() to get only the extension (in my previous example, .png ).之后,我们可以使用Path.GetExtension()仅获取扩展名(在我之前的示例中, .png )。

var uriWithoutQuery = uri.GetLeftPart(UriPartial.Path);
var fileExtension = Path.GetExtension(uriWithoutQuery);

Downloading the image下载图像

From here it should be straight forward.从这里开始应该是直截了当的。 Download the image with HttpClient.GetByteArrayAsync , create the path, ensure the directory exists and then write the bytes to the path with File.WriteAllBytesAsync()使用HttpClient.GetByteArrayAsync下载图像,创建路径,确保目录存在,然后使用File.WriteAllBytesAsync()将字节写入路径

private async Task DownloadImageAsync(string directoryPath, string fileName, Uri uri)
{
    using var httpClient = new HttpClient();

    // Get the file extension
    var uriWithoutQuery = uri.GetLeftPart(UriPartial.Path);
    var fileExtension = Path.GetExtension(uriWithoutQuery);

    // Create file path and ensure directory exists
    var path = Path.Combine(directoryPath, $"{fileName}{fileExtension}");
    Directory.CreateDirectory(directoryPath);

    // Download the image and write to the file
    var imageBytes = await httpClient.GetByteArrayAsync(uri);
    await File.WriteAllBytesAsync(path, imageBytes);
}

Note that you need the following using directives.请注意,您需要以下 using 指令。

using System;
using System.IO;
using System.Threading.Tasks;
using System.Net.Http;

Example usage示例用法

var folder = "images";
var fileName = "test";
var url = "https://cdn.discordapp.com/attachments/458291463663386646/592779619212460054/Screenshot_20190624-201411.jpg?query&with.dots";

await DownloadImageAsync(folder, fileName, new Uri(url));

Notes笔记

  • It's bad practice to create a new HttpClient for every method call.为每个方法调用创建一个新的HttpClient是不好的做法。 It is supposed to be reused throughout the application.它应该在整个应用程序中重复使用。 I wrote a short example of an ImageDownloader (50 lines) with more documentation that correctly reuses the HttpClient and properly disposes of it that you can find here .我写了一个ImageDownloader的简短示例(50 行),其中包含更多正确重用HttpClient并正确处理它的文档,您可以在此处找到。

.net Framework allows PictureBox Control to Load Images from url .net 框架允许 PictureBox 控件从 url 加载图像

and Save image in Laod Complete Event并在Laod Complete Event中保存图像

protected void LoadImage() {
 pictureBox1.ImageLocation = "PROXY_URL;}

void pictureBox1_LoadCompleted(object sender, AsyncCompletedEventArgs e) {
   pictureBox1.Image.Save(destination); }

Try this it worked for me试试这个它对我有用

Write this in your Controller在你的控制器中写这个

public class DemoController: Controller

        public async Task<FileStreamResult> GetLogoImage(string logoimage)
        {
            string str = "" ;
            var filePath = Server.MapPath("~/App_Data/" + SubfolderName);//If subfolder exist otherwise leave.
            // DirectoryInfo dir = new DirectoryInfo(filePath);
            string[] filePaths = Directory.GetFiles(@filePath, "*.*");
            foreach (var fileTemp in filePaths)
            {
                  str= fileTemp.ToString();
            }
                return File(new MemoryStream(System.IO.File.ReadAllBytes(str)), System.Web.MimeMapping.GetMimeMapping(str), Path.GetFileName(str));
        }

Here is my view这是我的观点

<div><a href="/DemoController/GetLogoImage?Type=Logo" target="_blank">Download Logo</a></div>

Most of the posts that I found will timeout after a second iteration.我发现的大多数帖子在第二次迭代后都会超时。 Particularly if you are looping through a bunch if images as I have been.特别是如果你像我一样遍历一堆图像。 So to improve the suggestions above here is the entire method:因此,改进上面的建议是整个方法:

public System.Drawing.Image DownloadImage(string imageUrl)
    {
        System.Drawing.Image image = null;

        try
        {
            System.Net.HttpWebRequest webRequest = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(imageUrl);
            webRequest.AllowWriteStreamBuffering = true;
            webRequest.Timeout = 30000;
            webRequest.ServicePoint.ConnectionLeaseTimeout = 5000;
            webRequest.ServicePoint.MaxIdleTime = 5000;

            using (System.Net.WebResponse webResponse = webRequest.GetResponse())
            {

                using (System.IO.Stream stream = webResponse.GetResponseStream())
                {
                    image = System.Drawing.Image.FromStream(stream);
                }
            }

            webRequest.ServicePoint.CloseConnectionGroup(webRequest.ConnectionGroupName);
            webRequest = null; 
        }
        catch (Exception ex)
        {
            throw new Exception(ex.Message, ex);

        }


        return image;
    }

This method did it for me,这个方法对我来说,

I got the main code from here我从这里得到了主要代码

then using this fix然后使用此修复程序

I was able to make a method that could get around the dreaded forbidden 403 error我能够制作一种可以绕过可怕的禁止 403 错误的方法

Here is the method这是方法

    private static void DownloadImage(string url, string saveFilename)
    {
        var httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
        // we need the user agent and default credentials if not,
        //  we get a forbidden request 303 error, which pretty much means the server thinks we are a bot -- which we are.... hehehehehehe
        httpWebRequest.UserAgent = "Case Banana"; // note -- this string can be anything you like, I recommend making it atleast 10 characters
        httpWebRequest.UseDefaultCredentials = true;

        var httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();
        if ((httpWebResponse.StatusCode != HttpStatusCode.OK &&
            httpWebResponse.StatusCode != HttpStatusCode.Moved &&
            httpWebResponse.StatusCode != HttpStatusCode.Redirect)
            || !httpWebResponse.ContentType.StartsWith("image", StringComparison.OrdinalIgnoreCase))
        {
            return;
        }

        using (var stream = httpWebResponse.GetResponseStream())
        {
            using (var fileStream = File.OpenWrite(saveFilename))
            {
                var bytes = new byte[4096];
                var read = 0;
                do
                {
                    if (stream == null)
                    {
                        continue;
                    }
                    read = stream.Read(bytes, 0, bytes.Length);
                    fileStream.Write(bytes, 0, read);
                } while (read != 0);
            }
        }
    }

Everyone has given a great solution for this problem but theere is a main issue behind all solutions given by everyone and that it will not create SSL/TLS secure channel if the image is hosted on https So, what should we do then?对于这个问题,每个人都给出了很好的解决方案,但是每个人给出的所有解决方案背后都有一个主要问题,如果图像托管在 https 上,它将不会创建 SSL/TLS 安全通道 那么,我们应该怎么做? Answer is simple just add these 2 lines before creating a WebClient request答案很简单,只需在创建 WebClient 请求之前添加这两行

ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM