Jak pobrać obraz z adresu url

105

Czy istnieje sposób na pobranie obrazu bezpośrednio z adresu URL w języku C #, jeśli adres URL nie ma formatu obrazu na końcu linku? Przykład adresu 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

Wiem, jak pobrać obraz, gdy adres URL kończy się formatem obrazu. Na przykład:

http://img1.wikia.nocookie.net/__cb20101219155130/uncyclopedia/images/7/70/Facebooklogin.png
Ifwat Ibrahim
źródło

Odpowiedzi:

136

Po prostu możesz użyć następujących metod.

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

Te metody są prawie takie same, jak DownloadString (..) i DownloadStringAsync (...). Przechowują plik w katalogu, a nie w ciągu C # i nie wymagają rozszerzenia formatu w URi

Jeśli nie znasz formatu (.png, .jpeg itp.) Image

public void SaveImage(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();
}

Użyj tego

try
{
    SaveImage("--- 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
}
Charlie
źródło
4
@Arsman Ahmad to zupełnie inne pytanie, którego należy szukać lub zadawać gdzie indziej. Ten wątek służy do pobierania pojedynczego obrazu.
AzNjoE
79

W zależności od tego, czy znasz format obrazu, czy nie, oto sposoby na zrobienie tego:

Pobierz obraz do pliku, znając format obrazu

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

Pobierz obraz do pliku bez znajomości formatu obrazu

Możesz użyć Image.FromStreamdo załadowania dowolnego rodzaju zwykłych bitmap (jpg, png, bmp, gif, ...), automatycznie wykryje typ pliku i nie musisz nawet sprawdzać rozszerzenia adresu URL (co nie jest zbyt dobre ćwiczyć). Na przykład:

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

}

Uwaga: ArgumentException może zostać zgłoszony przez Image.FromStream jeśli pobrana zawartość nie jest znanym typem obrazu.

Sprawdź to odniesienie w witrynie MSDN, aby znaleźć wszystkie dostępne formaty. Oto odniesienie do WebClienti Bitmap.

Idealnie 28
źródło
2
Zauważ, że potrzebujesz "using System.Drawing;" for Image.FromStream ()
dlchambers
3
Zauważ, że zamiast prosić bibliotekę obrazowania o wykrycie formatu obrazu, możesz również spojrzeć na nagłówki odpowiedzi, aby zobaczyć, jakiego formatu według źródła używa obrazwebClient.ResponseHeaders["Content-Type"]
bikeman868
Byłoby to również znacznie bardziej wydajne pod względem pamięci niż rozszerzenie skompresowanego obrazu do nieskompresowanego obiektu Bitmap i pozwoliłoby na zapisanie obrazu w jego oryginalnym formacie z oryginalną kompresją itp.
bikeman868
20

Dla każdego, kto chce pobrać obraz BEZ zapisywania go do pliku:

Image DownloadImage(string fromUrl)
{
    using (System.Net.WebClient webClient = new System.Net.WebClient())
    {
        using (Stream stream = webClient.OpenRead(fromUrl))
        {
            return Image.FromStream(stream);
        }
    }
}
Brian Cryer
źródło
11

Nie jest konieczne użycie, System.Drawingaby znaleźć format obrazu w identyfikatorze URI. System.Drawingnie jest dostępny, .NET Corechyba że pobierzesz pakiet System.Drawing.Common NuGet i dlatego nie widzę żadnych dobrych odpowiedzi na to pytanie dla wielu platform.

Ponadto mój przykład nie używa, System.Net.WebClientponieważ Microsoft wyraźnie odradza używanieSystem.Net.WebClient .

Nie zalecamy używania tej WebClientklasy do nowego rozwoju. Zamiast tego użyj klasy System.Net.Http.HttpClient .

Pobierz obraz i zapisz go do pliku bez znajomości rozszerzenia (wiele platform) *

* Bez starych System.Net.WebClienti System.Drawing.

Ta metoda asynchronicznie pobierze obraz (lub dowolny plik, o ile identyfikator URI ma rozszerzenie pliku) przy użyciu rozszerzenia, System.Net.Http.HttpClienta następnie zapisze go w pliku, używając tego samego rozszerzenia pliku, co obraz w identyfikatorze URI.

Pobieranie rozszerzenia pliku

Pierwszą częścią uzyskiwania rozszerzenia pliku jest usunięcie wszystkich niepotrzebnych części z identyfikatora URI.
Używamy Uri.GetLeftPart () z UriPartial.Path dostać wszystko od Schemegóry do Path.
Innymi słowy, https://www.example.com/image.png?query&with.dotsstaje się https://www.example.com/image.png.

Następnie używamy Path.GetExtension (), aby uzyskać tylko rozszerzenie (w moim poprzednim przykładzie .png).

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

Pobieranie obrazu

Stąd powinno być prosto. Pobierz obraz za pomocą HttpClient.GetByteArrayAsync , utwórz ścieżkę, upewnij się, że katalog istnieje, a następnie zapisz bajty w ścieżce za pomocą File.WriteAllBytesAsync () (lub File.WriteAllBytesjeśli korzystasz z .NET Framework)

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

Zauważ, że potrzebujesz następujących dyrektyw using.

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

Przykładowe użycie

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

Uwagi

  • Tworzenie nowego HttpClientdla każdego wywołania metody jest złą praktyką . Powinien być ponownie używany w całej aplikacji. Napisałem krótki przykład ImageDownloader(50 wierszy) z większą dokumentacją, która poprawnie ponownie wykorzystuje HttpClienti prawidłowo usuwa, którą można znaleźć tutaj .
MarcusOtter
źródło
5

.net Framework umożliwia kontrolce PictureBox ładowanie obrazów z adresu URL

i zapisz obraz w Laod Complete Event

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

void pictureBox1_LoadCompleted(object sender, AsyncCompletedEventArgs e) {
   pictureBox1.Image.Save(destination); }
Ali Humayun
źródło
4

Spróbuj to zadziałało dla mnie

Napisz to w swoim kontrolerze

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

Oto mój pogląd

<div><a href="/DemoController/GetLogoImage?Type=Logo" target="_blank">Download Logo</a></div>
Chandan Kumar
źródło
1

Większość znalezionych postów przekroczy limit czasu po drugiej iteracji. Szczególnie jeśli przeglądasz kilka obrazów, tak jak ja. Tak więc, aby poprawić powyższe sugestie, jest cała metoda:

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;
    }
Be05x5
źródło