Ukládání obrázků do databáze

20. února 2003

Vytváříte si fotogalerii a chcete mít fotografie uložené v databázi? Pak je tento článek určen právě pro vás. Dozvíte se, jak pomocí ASP.NET uložit obrázek do databáze na MS SQL serveru.

Celé uložení obrázku do databáze lze rozdělit do dvou na sebe navazujících částí:

  • upload obrázku na server
  • uložení do databáze

O tom, jak dostat soubor na server, jste měli možnost si přečíst v článku Upload souboru na server pomocí ASP.NET.

Struktura databáze

Obsah uploadovaného obrázku je vhodné ukládat do sloupce typu image. V jistých případech by se dal použít i typ varbinary, který je ale omezen na 8000 bytů, což bude v řadě případů nedostatečné. Omezení typu image je 231-1 (2 147 483 647) bytů, což nemá pro náš účel význam.

CREATE TABLE [dbo].[Pictures] (
[id] [int] IDENTITY (1, 1) NOT NULL ,
[picture] [image] NULL ,
[namepicture] [varchar] (200) NOT NULL ,
[contenttype] [varchar] (200) NOT NULL ,
[inserted] [datetime] DEFAULT (getdate())
)

Jako další hodnotu budeme do databáze ukládat ContentType. Pro udržení „pořádku“ v databázi ukládáme popis obrázku a datum vložení obrázku. Datum se bude vkládat automaticky při vložení záznamu.

Uložená procedura

Nejen pro větší bezpečnost, ale i pro přehlednost kódu využijeme pro ukládání do databáze uloženou proceduru, které budeme předávat údaje určené pro uložení do tabulky.

CREATE PROCEDURE Add_picture @NamePicture VarChar(200), @ContentType VarChar(200),@Picture Image AS
Begin
INSERT INTO Pictures (picture,namepicture,contenttype) VALUES (@Picture,@NamePicture,@ContentType)
End

Formulář pro vkládání obrázku

Do formuláře umístíme input prvek typu file pomocí kterého se bude provádět výběr obrázku pro upload na server. Poté přidáme do formáře input pro vložení popisku obrázku a odesílací tlačítko, kterým se provede upload a uložení do databáze.

Pro zobrazení uploadovaného obrázku vložíme prvek <asp:Image> a nastavíme jej jako neviditelný. Dále jsou v příkladu použity ještě validátory, o jejichž použití si můžete více přečíst v článku ASP.NET – schvalovací prvky a jeden prvek <asp:Label> pro výpis hlášení aplikace.

<%@ Page language=“c#“ Codebehind=“default.aspx.cs“ AutoEventWireup=“false“ Inherits=“PictureToSQL.upload_file“ %>
<!DOCTYPE HTML PUBLIC „-//W3C//DTD HTML 4.0 Transitional//EN“ >
<HTML>
   <HEAD>
      <title>WebForm1</title>
      <meta name=“GENERATOR“ Content=“Microsoft Visual Studio 7.0″>
      <meta name=“CODE_LANGUAGE“ Content=“C#“>
      <meta name=“vs_defaultClientScript“ content=“JavaScript“>
      <meta name=“vs_targetSchema“ content=“http://schemas.microsoft.com/intellisense/ie5″>
   </HEAD>
   <body MS_POSITIONING=“GridLayout“>
      <form id=“Form1″ method=“post“ encType=“multipart/form-data“ runat=“server“ action=“WebForm1.aspx“>
         <INPUT style=“Z-INDEX: 101; LEFT: 122px; WIDTH: 311px; POSITION: absolute; TOP: 4px; HEIGHT: 22px“ type=“file“ runat=“server“ id=“soubor“ name=“soubor“ size=“32″>
         <asp:Label id=“Label3″ style=“Z-INDEX: 107; LEFT: 10px; POSITION: absolute; TOP: 10px“ runat=“server“ Width=“104px“ Height=“24px“>Soubor obrázku</asp:Label>
         <asp:TextBox id=“popis“ style=“Z-INDEX: 102; LEFT: 121px; POSITION: absolute; TOP: 34px“ runat=“server“ Width=“247px“></asp:TextBox>
         <asp:Button id=“Button1″ style=“Z-INDEX: 103; LEFT: 372px; POSITION: absolute; TOP: 31px“ runat=“server“ Text=“Uložit“ Width=“60px“></asp:Button>
         <asp:Image id=“obrazek“ style=“Z-INDEX: 104; LEFT: 8px; POSITION: absolute; TOP: 128px“ runat=“server“ Width=“109px“ Height=“75px“ Visible=“False“></asp:Image>
         <asp:Label id=“Label1″ style=“Z-INDEX: 105; LEFT: 9px; POSITION: absolute; TOP: 41px“ runat=“server“ Width=“88px“ Height=“24px“>Popis obrázku</asp:Label>
         <asp:Label id=“status“ style=“Z-INDEX: 106; LEFT: 10px; POSITION: absolute; TOP: 73px“ runat=“server“ Width=“420px“ Height=“26px“>Vložte obrázek a jeho popis a stiskněte tlačítko <b>
Uložit</b></asp:Label>
         <asp:RequiredFieldValidator id=“RequiredFieldValidator1″ style=“Z-INDEX: 108; LEFT: 10px; POSITION: absolute; TOP: 101px“ runat=“server“ ErrorMessage=“Cestu k obrázku nutno vložit“ ControlToValidate=“soubor“ Display=“None“></asp:RequiredFieldValidator>
         <asp:RequiredFieldValidator id=“RequiredFieldValidator2″ style=“Z-INDEX: 109; LEFT: 179px; POSITION: absolute; TOP: 101px“ runat=“server“ ErrorMessage=“Popis obrázku nutno vložit“ ControlToValidate=“popis“ Display=“None“></asp:RequiredFieldValidator>
         <asp:ValidationSummary id=“ValidationSummary1″ style=“Z-INDEX: 110; LEFT: 445px; POSITION: absolute; TOP: 14px“ runat=“server“ Width=“197px“ Height=“65px“ DisplayMode=“List“></asp:ValidationSummary>
      </form>
   </body>
</HTML>

Vzhled formuláře v návrhovém režimu VS.NET může vypadat třeba takto:

Formulář ve VS.NET

Omezení typu a velikosti obrázku

Zbývá jen nějakým spolehlivým způsobem ověřit, zda se jedná skutečně o obrázek. Nabízejí se dvě možnosti, buď použít vlastnost ContentType nebo otestovat příponu odesílaného souboru.

Bohužel pouze MSIE (testováno na verzi 6) poskytuje ContentType podle skutečného obsahu a nedá se zmást změnou přípony jako Mozilla (1.2.1) či Opera (7.0). Z toho vyplývá, že skutečně spolehlivý a přitom jednoduchý způsob, jak detekovat typ souboru, pravděpodobně neexistuje. Nejspolehlivějším způsobem by bylo analyzovat obsah předávaných dat. Tento způsob je ale poněkud složitější a přesahuje téma tohoto článku.

Pro jednoduchost celého příkladu použiji detekci typu souboru ContentType, který získáme jako vlastnost objektu HtmlInputFile. Nyní existují dvě možnosti. Spokojíme-li se pouze s tím, že ContentType obsahuje řetězec image, bude podmínka vypadat takto:

string ContentType;
ContentType=soubor.PostedFile.ContentType;
if (ContentType.LastIndexOf(„image“)==0)
{

Pokud však chcete mít větší kontrolu nad typem uploadovaných souborů, bude lepší přesně vyjmenovat jednotlivé řetězce ContentType:

string ContentType;
ContentType=soubor.PostedFile.ContentType;
if (ContentType == „image/jpeg“ || ContentType == „image/gif“ || ContentType == „image/pjpeg“)
{

Určitě budete chtít omezit i velikost obrázku, který budete ukládat do databáze. Máte možnost použít řešení popisované v článku Upload souboru na server pomocí ASP.NET a omezení provést přímo v souboru web.config pro celou web aplikaci. Druhou možností je využít vlastnosti ContentLength objektu HtmlInputFile a přímo v podmínce otestovat velikost zasílaného obrázku. Pozor však na to, že údaj poskytovaný vlastnosti ContentLength je v B (bytech) oproti položce maxRequestLength z web.congif, která je v kB (kilobytech).

if (soubor.PostedFile.ContentLength<640000
{

Načtení obrázku do paměti a získání rozměrů

Pro následné uložení do databáze je třeba mít připraven obsah souboru jako pole bytů. Velikost pole bude v závislosti na velikosti souboru. Nadefinujeme tedy dynamické pole a následně určíme jeho velikost podle hodnoty ContentLength.

Obsah uploadovaného souboru načteme do pole pomocí metody InputStream.Read objektu HtmlInputFile.

//nacteni obrázku do pole
byte[] Picture_content;
Picture_content = new byte[soubor.PostedFile.ContentLength];
soubor.PostedFile.InputStream.Read(Picture_content,0,soubor.PostedFile.ContentLength);

Pro získání rozměrů obrázku je třeba vytvořit novou instanci objektu Bitmap. Za tímto učelem použijeme konstruktor, který vyžaduje jako svůj vstup datový proud. Ten si vytvoříme z pole, jenž máme k dispozici z předchozího kroku.

// zjištění rozměrů obrázku. Lze však zjistit i více
MemoryStream stream = new MemoryStream();
stream.Write(Picture_content,0,Picture_content.Length);
Bitmap objBitmap = new Bitmap(stream);
Size SizePicture=objBitmap.Size;
objBitmap.Dispose();
stream.Close();

Uložení do databáze

Jelikož používáme MS SQL 7 a vyšší, použijeme pro připojení k databázi objekt SqlConnection. V případě použití jiné databáze by bylo nutné použít OleDbConnection. V tomto případě se však bude práce s parametry dotazu nepatrně lišit.

// vytvoření spojení do databáze
SqlConnection conn=new SqlConnection(sqlConnectionString);
// vytvoření SQL příkazu
SqlCommand cmd=new SqlCommand(„Add_picture“,conn);
// budeme používat uloženou proceduru
cmd.CommandType= CommandType.StoredProcedure;

Nezapomeňte pomocí parametru CommandType objektu SqlCommand sdělit, že hodláte použít uloženou proceduru.

// priprava parametru pro obrazek
SqlParameter prm_picture=new SqlParameter(„@Picture“,SqlDbType.Image);
prm_picture.Value=Picture_content;
cmd.Parameters.Add(prm_picture);
// priprava parametru pro popisek obrazku
SqlParameter prm_name=new SqlParameter(„@NamePicture“,SqlDbType.VarChar,200);
prm_name.Value=popis.Text;
cmd.Parameters.Add(prm_name);
// priprava parametru pro uložení ContentType
SqlParameter prm_contenttype=new SqlParameter(„@ContentType“,SqlDbType.VarChar,200);
prm_contenttype.Value=ContentType;
cmd.Parameters.Add(prm_contenttype);

Otevřeme spojení do databáze a provedeme uloženou proceduru s parametry, které jsme si připravili.

conn.Open();
cmd.ExecuteNonQuery();

Zpětné zobrazení obrázku

Po úspěšném uložení obrázku do databáze by uživatelé jistě uvítali možnost vidět obrázek, který na server právě zaslali. Existuje možnost obrázek „vytáhnout“ z databáze, ale proč to dělat, když jej máme stále ještě v paměti.

Některé z vás určitě napadne možnost vložit na stránku obrázek, který má uživatel na disku. Toto řešení je sice rychlé, ale nebude se řadě uživatelů líbit už jen proto, že jim stránka „sahá“ na disk.

Po řadě neuspěšných pokusů, jak zobrazit uploadovaný obrázek, aniž bych jej uložil na disk nebo „vytáhnul“ z databáze, jsem našel řešení s využítím sessions. Po uložení obrázku do databáze provedu uložení obrázku do session proměnné a jako zdroj obrázku uvedu aspx stránku.

Session[„Picture_content“]=Picture_content;
Session[„PictureContentType“]=ContentType;
obrazek.Height=SizePicture.Height;
obrazek.Width=SizePicture.Width;
obrazek.AlternateText=popis.Text;
obrazek.ImageUrl=“WebForm1.aspx“;
obrazek.Visible=true;
// ———–
private void Page_Load(object sender, System.EventArgs e)
{
if (!Page.IsPostBack)
if (Session[„Picture_content“]!= null && Session[„PictureContentType“]!= null)
{
Response.ContentType=Session[„PictureContentType“].ToString();
Response.BinaryWrite((byte[])Session[„Picture_content“]);
Session[„PictureContentType“]=null;
Session[„Picture_content“]=null;
}
}

Někomu se toto řešení bude líbit, někomu ne. Pokud máte nějaké své řešení, budu rád, když se o něj podělíte.

Kompletní zdrojový kód

Protože jsem až doposud nabízel různé varianty jak ošetřit to či ono, uvádím kompletní zdrojový kód funkce po stisku tlačítka uložit.

private void Button1_Click(object sender, System.EventArgs e)
{
   string ContentType;
   ContentType=soubor.PostedFile.ContentType;
   if (ContentType.LastIndexOf(„image“)==0)
   {
      if (soubor.PostedFile.ContentLength<640000)
      {
         obrazek.Visible=false;
         //nacteni obrázku do pole
         byte[] Picture_content;
         Picture_content = new byte[soubor.PostedFile.ContentLength];
         soubor.PostedFile.InputStream.Read(Picture_content,0,soubor.PostedFile.ContentLength);
         // zjištění rozměrů obrázku. Lze však zjistit i více
         MemoryStream stream = new MemoryStream();
         stream.Write(Picture_content,0,Picture_content.Length);
         Bitmap objBitmap = new Bitmap(stream);
         Size SizePicture=objBitmap.Size;
         objBitmap.Dispose();
         stream.Close();
         // připojovací řetězec do SQL serveru
         const string sqlConnectionString=“Data Source=localhost;User ID=sa;Password=asdf;Initial Catalog=PictureToSQL;“;
         // Vytvoření spojení do databáze
         SqlConnection conn=new SqlConnection(sqlConnectionString);
         // Vytvoření SQL příkazu
         SqlCommand cmd=new SqlCommand(„Add_picture“,conn);
         // Budeme používat uloženou proceduru
cmd.CommandType= CommandType.StoredProcedure;
         // priprava parametru pro obrazek
         SqlParameter prm_picture=new SqlParameter(„@Picture“,SqlDbType.Image);
         prm_picture.Value=Picture_content;
         cmd.Parameters.Add(prm_picture);
         // priprava parametru pro popisek obrazku
         SqlParameter prm_name=new SqlParameter(„@NamePicture“,SqlDbType.VarChar,200);
         prm_name.Value=popis.Text;
         cmd.Parameters.Add(prm_name);
         // priprava parametru pro uložení ContentType
         SqlParameter prm_contenttype=new          SqlParameter(„@ContentType“,SqlDbType.VarChar,200);
         prm_contenttype.Value=ContentType;
         cmd.Parameters.Add(prm_contenttype);
         try
         {
            // Otevření spojení do databáze
            conn.Open();
            // Provedení operace nad databázi
            cmd.ExecuteNonQuery();
            Session[„Picture_content“]=Picture_content;
            Session[„PictureContentType“]=ContentType;
            obrazek.Height=SizePicture.Height;
            obrazek.Width=SizePicture.Width;
            obrazek.AlternateText=popis.Text;
            obrazek.ImageUrl=“default.aspx“;
            status.Text=“Obrázek uložen do databáze“;
            obrazek.Visible=true;
         }
         catch(Exception vyjimka)
         {
            status.Text=“Nastala chyba pri ukládání obrázku“;
         }
         finally
         {
            conn.Close();
         }
      }
      else
      {
         // prilis velky
         status.Text=“Obrázek je příliš velký“;
      }
   }
   else
   {
      // nejde o obrazek
      status.Text=“Vkládaný soubor není obrázek“;
   }
}

Závěrem snad kromě možnosti stáhnout si zdrojové kódy ještě jedna připomínka – zde popisovaný postup ukládání nemusíte využít pouze pro obrázky, ale i pro ukládání libovolných souborů.

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

Předchozí článek ewords.kvalitne.cz
Štítky: Články

Mohlo by vás také zajímat

Nejnovější

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *