Komunitní aplikace na webu umožňují uživatelům sdílet kdeco. V tomto článku si ukážeme, jak uživateli prostřednictvím ASP.NET umožnit stažení obrázku, který už sídlí na nějaké URL, podobně jako nejmenovaná služba "obličejkniha".

Upload obrázku, který uživatel vyhledá na svém lokálním disku a vloží do políčka formuláře, je známá technika a řada dnešních aplikací ji nabízí. V článku se naučíme stáhnout data obrázku ze zadané url – a získat tak stream, se kterým potom v aplikaci můžeme naložit stejně, jakoby byl obrázek uploadován z uživatelova prohlížeče. Mám na mysli úpravy obrázku – změna velikosti, oříznutí, formátu…

Uložení obrázku na disk zde jen naznačíme, je potřeba stejně jako při běžném uploadu vyřešit možné kolize názvů souborů a případně uložení údajů o obrázku do databáze. Uvědomíme si, že pro upload se používá HttpPostedFile, kde ve vlastnosti InputStream je stream obrázku z prohlížeče klienta. Pokud vyjdeme z dobře známých aplikací, kde uživatel přes formulář uploaduje soubor ze svého prohlížeče, určitě v ní bude nějaká metoda na opracování rozměrů obrázku a jeho následné uložení na disk. Nejspíše tato metoda bude napsána tak, že umí zpracovat stream souboru, aby bylo možné vyrobit objekt Image (obrázek) a upravit jeho vlastnosti.

Taková metoda se nám bude hodit i pro ukládání obrázku staženého ze vzdáleného serveru, níže si proto probereme možný příklad takové metody Image_SaveToDisc().

Pohodlnosti uživatelů jistě přijde vhod i fakt, že se nemusí starat o formát zdrojového obrázku – jelikož předpokládané užiti je pro spíše menší a ilustrační fotografie, jakýkoli obrázek se nakonec uloží ve formátu JPEG.

Stažení obrázku – získání streamu souboru

Nejprve musíme ze vzdáleného serveru (stroje) stáhnout data obrázku. Použijeme několik vestavěných metod .net frameworku – pokud vše dopadne dobře, získáme data v podobě objektu Stream.

private void FetchImageFromUrl(String url,String path)
{
  // se zadanou URL si připravíme HttpWebRequest
  HttpWebRequest getImageRequest = (HttpWebRequest) WebRequest.Create(new Uri(url));
  // kdyby byl z našeho serveru potřeba přístup přes proxy, stačí odkomentovat následující
  
  //getImageRequest.Proxy = new WebProxy(); 
  //getImageRequest.Proxy.Credentials = new NetworkCredential();
  //getImageRequest.PreAuthenticate = true;
  //getImageRequest.Credentials = new System.Net.NetworkCredential(UserName,UserPassword);
  try
   {

    // HttpWebResponse nám vrátí stream odpovědi serveru
    using (System.Net.HttpWebResponse getImageResponse = (HttpWebResponse) getImageRequest.GetResponse())
    {
      if (getImageRequest.HaveResponse && getImageResponse.ContentLength != 0)
      {  // pokud se vůbec něco stáhlo a nemá nulovou délku, můžeme to uložit na disk

        Image_SaveToDisc(getImageResponse.GetResponseStream(), 300, 400, path);
      }
      else
      {
        //nepřečetlo se nebo má nulovou délku
      }

      // pěkně po sobě uklidíme
      getImageResponse.Close();
    }
  }
  catch (System.Net.WebException netEx)
  { // síťová chyba

  }
  catch(Exception Ex)
  { // jiná chyba
  }
}

Uložení streamu obrázku na disk

V metodě ImageSaveToDisc() zároveň aplikujeme trošku matematiky pro úpravu rozměrů obrázku – vpodstatě musíme rozhodnout, zda je obrázek "na výšku" nebo "na šířku". Delší stranu potom nastavíme na zadanou maximální hodnotu, zbylou stranu musíme dopočítat v poměru stran původního obrázku. Samozřejmě je možné dělat i složitější úpravy – třeba výřezy z příliš širokých obrázků a podobně, příklad jsem se však snažil ponechat co nejjednoduší.

private void Image_SaveToDisc(Stream image, int maxWidth, int maxHeight, string path)
{
  bool isLandscape = false;
 
  // ze streamu vytvoříme nový objekt obrázku
  using (System.Drawing.Image sourcePicture = System.Drawing.Image.FromStream(image, false, true))
  {
    // je obrázek "naležato"?
    isLandscape = (sourcePicture.Width > sourcePicture.Height);
    // velikost "delší" strany
 
    int longerSideLength = (isLandscape) ? sourcePicture.Width : sourcePicture.Height;

    // pokud má obrázek některou stranu větší než maximum, musíme zmenšit
    if (longerSideLength > maxWidth || longerSideLength > maxHeight)
    {
      // vypočteme poměr stran
      decimal originalAspectRatio = ((decimal)sourcePicture.Width / (decimal)sourcePicture.Height);

      // připravíme novou šířku 
      int newPictureWidth = (int)(Decimal.Round(((decimal)maxHeight * originalAspectRatio), 0));
      // připravíme novou výšku
      int newPictureHeight = maxHeight;

      // pokud dopočítaná šířka překročí maximální 
      if (newPictureWidth >= maxWidth)
      {
        // nastavíme maximální šířku

        newPictureWidth = maxWidth;
        // a dopočítáme výšku
        newPictureHeight = (int)(Decimal.Round(((decimal)maxWidth / originalAspectRatio), 0));
      }

      // připravíme "prázdný" obrázek o nových rozměrech
      using (Bitmap resizedPicture = new Bitmap(newPictureWidth, newPictureHeight))
      {

        // připravíme objekt Graphic nad prázdným obrázkem
        using (Graphics oGraphic = Graphics.FromImage(resizedPicture))
        {  // nastavíme vlastnosti pro úpravy obrázku
          oGraphic.CompositingQuality = CompositingQuality.HighQuality;
          oGraphic.SmoothingMode = SmoothingMode.HighQuality;
          oGraphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
          // a nakonec původní obrázek rozkreslíme do nového "prázdného"
          oGraphic.DrawImage(sourcePicture, 0, 0, newPictureWidth, newPictureHeight);

        }
        try
        { // uložíme nově upravený obrázek
          resizedPicture.Save(path, System.Drawing.Imaging.ImageFormat.Jpeg);
        }
        catch (Exception Ex)
        {
          //chyba při ukládání souboru;
        }

      }
    }
    else
    { // obrázek je menší než maximum, uložíme bez úprav
      try
      {
        sourcePicture.Save(path, System.Drawing.Imaging.ImageFormat.Jpeg);
      }
      catch (Exception Ex)

      {
        //chyba při ukládání souboru;
      }
    }
  }
} 

Příklad formuláře pro stažení obrázku z URL

Máme-li již v naší aplikaci formulář, který umožňuje upload souboru z formuláře, pak stačí poupravit metodu ukládání obrázku na disk tak, aby bylo možné zpracovávat stream získaný z vlastnosti InputStream. Pro názornost alespoň jednoduchá ukázka – povšimněte si důležitý import prostorů názvů a také napevno nastavené cesty pro ukládání obrázku:

<form id="form1" runat="server">
  <div>
    <p><asp:TextBox ID="TextBox1" runat="server"></asp:TextBox></p>

    <p><asp:Button ID="Button1" runat="server" Text="Uložit" onclick="Button1_Click" /></p>

  </div>
</form> 
using System;
using System.Net;
using System.Web.UI;
using System.IO;
using System.Web.UI.WebControls;
using System.Drawing;

using System.Drawing.Drawing2D;

public partial class FetchImage : System.Web.UI.Page
{
  protected void Page_Load(object sender, EventArgs e)
  {
  }

  protected void Button1_Click(object sender, EventArgs e)
  {

    FetchImageFromUrl(TextBox1.Text, "C:\\FetchImage\\FetchImage.jpg");
  }
} 

Skutečný formulář by měl určitě obsahovat validátor a splňovat řadu dalších požadavků, zde uvedený kód je jen příkladem řešení. Důležité je samozřejmě ošetřit chyby a výjimky a nejspíše také použít nějaké konfigurační údaje. Podstatné je také určit cestu, kam se soubor bude ukládat a také pod jakým názvem – aby se soubory nemohly navzájem přepsat.

Uvědomme si, že uživatelům dáváme k dispozici nástroj, kterým mohou porušit autorská práva – a na toto je v aplikaci upozornit. Některý obsah je dovoleno stáhnout, ale není dovoleno jej publikovat bez uvedení původního zdroje.

Příklad jednoduché stránky pro stahování obrázků si můžete stáhnout zde.

4 Příspěvků v diskuzi

  1. A ještě řešení v PHP:

    if (ereg(„^https?://“, $_POST[„TextBox1“]))
    copy($_POST[„TextBox1“], „data/FetchImage.jpg“);

  2. Samotné stažení a uložení souboru jde napsat hodně stručně i v ASP.NET (třeba metodou System.Net.WebClient.DownloadFile), ale o tom článek zjevně není.

Odpovědět