Introductie Dit artikel laat zien hoe je een Image in een C# applicatie kan opslaan in een database en het kan ophalen uit de database om het te laten zien. Voor de database gebruiken we MS SQL maar voor andere databases zoals MySql gaat het vrijwel het dezelfde. Dit kan gebruikt worden in zowel een ASP.NET web applicatie als een desktop applicatie.
Achtergrond De HTML img tag en Image control in C# zoeken altijd een image op de harde schijf van de desktop of op een of ander fysieke locatie op een server. Dit kan problemen geven bij het zoeken en werken met de images. Het kost namelijk steeds relatief veel tijd om een image bestand te openen en te lezen. Beter is het om bij het verwerken van veel images deze in een database op te slaan en van daaruit te lezen en verwerken. Hierdoor kan bijvoorbeeld in een Web applicatie gewerkt worden met een dynamische pagina waar de plaatjes uit de database worden geladen. This article shows how to display dynamic images from database, how to convert image to bytearray and how to use generic handlers.
Gebruik van de Code We willen eerst een image opslaan in een database. Daarvoor moeten we een tabel definieren waar de image in opgeslagen wordt. Als voorbeeld gebruiken we de volgende tabel: Tabel Naam: plaatjes Kolom naam
Data Type
Primary Key
Nullable
imgId
int
Yes
No
pic1
longblob
No
Yes
Je kunt de kolom imgId als autoincrement kolom definiëren zodat je dit veld niet hoeft te vullen Als we een plaatje hebben in een object van de classe Image dan moeten we deze eerst omzetten naar een byte arry voordat we de gegevens in de database table kunnen invoegen // using System.Drawing; // using System.IO; private byte[] ConvertImageToByteArray(Image imageToConvert) { Bitmap bitMap = new Bitmap(ImageToConvert); // to overcome internal GDI+ error ImageConverter converter = new ImageConverter(); Return (byte[]) converter.ConvertTo(bitMap,typeof(byte[])); }
Om de image nu naar de database te schrijven kunnen we de volgende methode gebruiken. // using System.Drawing; // using System.Data.SqlClient; // Upload image to database, kan public, protected of private zijn afhankelijk van de // situatie public bool saveImageToDatabase(Image imageToSave) { // maak van de image een byte array byte[] tempArray = ConvertImageToByteArray(imageToSave); // nodige sql opdracht (imgId = primary key autoincrement so don’t add) String Sql = "Insert into [Plaatjes] (pic1) Values (@Pic)"; SqlConnection conn = null; try { try { // setup connectie uiteraard CONNECTIONSTRING moet een relevante waarde hebben conn = new SqlConnection( CONNECTIONSTRING ) conn.Open(); // setup de eigelijke sql command SqlCommand insertCommand = new SqlCommand( Sql, conn); // met parameters vermijd je injection attacks insertCommand.Parameters.Add("Pic", SqlDbType.Image, 0).Value = tempArray; // voer het sql insert commando uit! int queryResult = insertCommand.ExecuteNonQuery(); // als er 1 rij is toegevoegd is alles goed gegaan anders foutje if (queryResult == 1) return true; else return false; } catch (Exception ex) { return false; // er ging hier iets mis } } finally { // handel onafgewerkte zaken af if (conn != null) conn.Close(); } }
Haal Image uit de database. Willen we nu in een desktop applicatie gebruik maken van de opgeslagen images moeten we hem natuurlijk uitlezen uit de database. Voor een Web applicatie liggen de zaken iets ingewikkelder. We kijken eerst naar het probleem bij een desktop applicatie. We kunnen dan gebruik maken van de volgende methode (uitgaande van onze database) // using System.Data.SqlClient; // using System.IO; public Image readImageFromDatabase (int imgIdentifier) { SqlDataReader rdr = null; SqlConnection conn = null; SqlCommand selcmd = null; Image img ; String Sql = "select pic1 from Plaatjes where imgId=@ID"; try { conn = new SqlConnection(CONNECTIONSTRING); selcmd = new SqlCommand(Sql,conn); selcmd.Parameters.AddWithValue("@ID",imgIdentifier); conn.Open(); rdr = selcmd.ExecuteReader(); if (rdr.Read()) { img = ConvertByteArrayToImage(byte[])rdr["pic1"]); } if (rdr != null) rdr.Close(); } catch { img = null; } finally { if (conn != null) conn.Close(); } return img; }
De methode om een byte array om te zetten naar een Image is als volgt: private Image ConvertByteArrayToImage(byte[] byteArray) { using (MemoryStream ms = new MemoryStream(byteArray, 0, byteArray.Length)) { return new Bitmap(ms); } }
Een Image tonen in een Web Applicatie Een HTML tag en een aspx image control kijkt naar een fysieke locatie van een Image bestand in zijn SRC= of ImageUrl attribuut. Je kunt deze locatie echter ook uit een speciale handler (behandelaar pagina) laten bestaan. Deze handler (imgHandler.ashx, LET OP de extensie) heeft geen enkele HTML ‘decoratie’ want we laten geen pagina zien, maar gedraagt zich als een Image die op gehaald wordt van een bestandslocatie. Om dit te kunnen doen moeten we hier speciale dingen doen. We moeten namelijk de ProcessRequest gebeurtenis (event) van de “pagina” aanpassen zodat deze de gewenste afbeelding (Image) uit de database leest en deze als antwoord (response) terug geeft. Om de aspx pagina zich te laten gedragen als een image moeten we gebruik maken van de functie Response.BinaryWrite(). public void ProcessRequest (HttpContext context) { System.Data.SqlClient.SqlDataReader rdr = null; System.Data.SqlClient.SqlConnection conn = null; System.Data.SqlClient.SqlCommand selcmd = null; try { conn = new System.Data.SqlClient.SqlConnection (System.Configuration.ConfigurationManager.ConnectionStrings ["ConnectionString"].ConnectionString); selcmd = new System.Data.SqlClient.SqlCommand ("select pic1 from msg where msgid=" + context.Request.QueryString["imgid"], conn); conn.Open(); rdr = selcmd.ExecuteReader(); while (rdr.Read()) { context.Response.ContentType = "image/jpg"; context.Response.BinaryWrite((byte[])rdr["pic1"]); } if (rdr != null) rdr.Close(); } finally { if (conn != null) conn.Close(); } }
In de code, zien we dat de ProcessRequest gebeurtenis de database opent en de image laad waarvan de imgID gelijk is aan die doorgegeven werd aan de request query string. De code moet worden aangepast als je verschillende image formaten gebruikt (GIF, PNG etc). Bijvoorbeeld door in de database op te nemen welk type image formaat een plaatje is. Dit kan dan gebruikt worden bij het lezen en schrijven van en naar de database. En bij het aangeven van de “content type” van de response op een html verzoek.
In een webpagina kunnen we nu een plaatje tonen door bijvoorbeeld de volgende asp Image control aanduiding in de HTML weergave van een aspx pagina:
imgid wordt mee gestuurd al seen onderdeel van de querystring naar de “pagina” ImgHandler.ashx om zo de juiste afbeelding uit de database te kunnen halen en het dan te laten zien.