ASPNL logo (1 kb)
vrijdag 16 mei 2008




Microsoft MVP

.NET Codewise Community
<< vorige | overzicht | volgende >>

Serversided afbeeldingen bewerken

Door Rutger Smit
22 april 2003

In deze tutorial gaan we bekijken hoe we met behulp van het .NET Framework in C# (in code behind) afbeeldingen op een site dynamisch kunnen voorzien van een eigen logo en tekst.

Hadden we ‘vroeger’, in classic ASP nog third-party componenten nodig voor het bewerken of maken van afbeeldingen (en als het een beetje tegen zat meerdere componenten), tegenwoordig hebben we in ASP.NET genoeg aan de standaard voorzieningen. Afbeeldingen genereren, bewerken en veranderen van formaat, het kan allemaal.

Voor deze tutorial ga ik er van uit dat de te bewerken afbeelding al op de server staat, en deze niet overschreven wordt door de door ons gewijzigde afbeelding. De afbeelding wordt als volgt aangeroepen:

<img src="/image.aspx?o=original.jpg&i=myIcon.ico&t=What are we going to do today?">

Om te beginnnen maken we eerst de aspx pagina. Deze is lekker kort. We definiëren de Language: C#, het code-behind bestand: image.aspx.cs en de Inherits: createImage.

<%@ Page Language="C#" src="image.aspx.cs" Inherits="createImage"%>

Nu het code behind bestand, het bestand waar het allemaal in moet gebeuren. We beginnen met het importeren van de benodigde namespaces.

using System;
using System.IO;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Drawing.Text;
using System.Configuration;

System: Algemene namespace, met algemene types en functies.
System.IO: Voor het openen van een bestand en het controleren of een bestand bestaat.
System.Drawing: Algemene namespace voor het kunnen werken met afbeeldingen.
System.Drawing.Drawing2D: Voor het verbeteren van de kwaliteit van de gegenereerde afbeelding.
System.Drawing.Imaging: Voor o.a. het Bitmap, Graphics en Image object.
System.Drawing.Text: Voor het schrijven van tekst op een afbeelding.
System.Configuration: Voor het uitlezen van waardes uit het web.config bestand.

In de pagina hebben we in het Page-directive bij Inherits “createImage” opgegeven, we gaan nu dus een class aanmaken met de naam createImage en geven aan dat deze bij het Page object hoort. Daaronder de Page_Init functie, deze wordt altijd gestart als de pagina opgevraagd wordt. Dit gebeurt voor alle andere gebeurtenissen in de pagina, maar de hebben we niet nodig, omdat daarin HTML gegenereerd wordt (en dat willen we juist niet).

public class pageLoad : System.Web.UI.Page
   void Page_Init(object sender, EventArgs e)

De variabele basePath vullen we met het fysieke pad naar de root van de website. Ter demonstratie haal ik deze uit de web.config, weet je ook meteen hoe dat werkt (je kunt het pad natuurlijk ook hard in je code zetten). Ook de variabelen uit de querystring zetten we in variabelen voor later gebruik.

--- web.config source ---
<?xml version="1.0" encoding="UTF-8" ?>

<configuration>
   <appSettings>
      <add key="wwwroot" value="C:\Inetpub\wwwroot\DynamicImages\" />
   </appSettings>
</configuration>
--- einde web.config source ---

   string basePath = ConfigurationSettings.AppSettings["wwwroot"];
   string original = Request.QueryString["o"];
   string icon = Request.QueryString["i"];
   string txt = Request.QueryString["t"];

Een niet onbelangrijke check is om te kijken of de bestanden waar we mee aan de slag willen wel bestaan.

   if(File.Exists(basePath+original) && File.Exists(basePath+icon))
   {
   //--- beide bestanden bestaan
   }
   else
   {
   //--- een van de bestanden bestaat niet
   }


We maken een nieuw Image object aan en laten deze een bestand van de harde schijf openen. In dit object zit nu onze originele afbeelding. Omdat we het Image niet kunnen bewerken maken we een Bitmap object aan. Het Graphics object is het object dat nodig is om het origineel te kunnen bewerken.

   System.Drawing.Image img = System.Drawing.Image.FromFile(basePath+original);
   Bitmap bmp = new Bitmap(img);
   Graphics g = Graphics.FromImage(bmp);


De volgende stap is het aanmaken van wat Font en Brush objects. Deze gaan we gebruiken om het origineel mee te bewerken.

   Font FontBottom = new Font("Arial Black", 8);
   SolidBrush WhiteBrush = new SolidBrush(Color.White);
   SolidBrush OrangeBrush = new SolidBrush(Color.Orange);
   PointF FloatPoint = new PointF(bmp.Width-125, bmp.Height-17);
   Icon ico = new Icon(basePath+icon);

Wat belangrijk is tijdens het bewerken van afbeeldingen is de volgorde van tekenen. Op het moment dat je een tekst weg schrijft naar de afbeelding en vervolgens een zwart vlak gaat tekenen, dan komt deze over de tekst heen en is die dus niet meer te lezen.

We gaan nu onze Fonts en Brushes en andere zaken op de originele foto loslaten. Als eerste twee keer FillRectangle. Dit zijn vierkante vlakken die je een startcoordinaat x,y en een eind coordinaat x,y moet geven (links boven en rechts onder). De eerste is een wit vlak in de rechter bovenhoek die als omlijsting zal dienen voor de icon die we later zullen plaatsen. De tweede is een oranje balk aan de onderkant van de foto. Vervolgens, als de basis vlakken getekend zijn, plaatsen we de icon in de rechter bovenhoek. DrawIcon heeft in dit geval drie parameters, het Icon object, het x coordinaat en het y coordinaat van de linker bovenhoek. Ook hier bereken ik de x- en y-coordinaten omdat ik niet altijd zal weten hoe breed het origineel is. We trekken er nog 8 van de x af en tellen er 8 bij de y bij zodat we een witte rand van het onderliggende vlak te zien krijgen.

   g.FillRectangle(WhiteBrush, (bmp.Width-ico.Width)-8, 0, bmp.Width, ico.Height+8);
   g.FillRectangle(OrangeBrush, 0, bmp.Height-16, bmp.Width, 16);
   g.DrawIcon(ico, (bmp.Width-ico.Width)-4, 4);
   g.DrawString(txt, FontBottom, WhiteBrush, 0, bmp.Height-16);

De regel code die nu komt is niet noodzakelijk. Als je het niet gebruikt kun je ook de namespace using System.Drawing.Drawing2D verwijderen. De SmoothingMode kun je gebruiken om de kwaliteit van de gegenereerde afbeelding wat te optimaliseren. Let er wel op dat hoe hoger je de kwaliteit zet, de meer de CPU van je server belast zal worden. Het is in dat soort gevallen raadzaam om de kwaliteit niet al te hoog te zetten.

   g.SmoothingMode = SmoothingMode.HighQuality;

Met Save slaan we de bewerkte afbeelding op in het Graphics object en is deze klaar om naar de client gestuurd te worden.

   g.Save();

Voordat we binaire data naar de client gaan sturen willen we eerst zeker weten dat er geen vreemde zaken vooraf naar de client gestuurd zijn. Door Response.Clear kunnen we met een schone lei beginnen. Response.ContentType gebruiken we om de browser van de client te vertellen dat de data die nu gaat komen geen text/html (zoals gebruikelijk met aspx pagina’s) maar van het type image/jpeg is.

   Response.Clear();
   Response.ContentType = "image/jpeg";

Nu daadwerkelijk de binaire data naar de client sturen. Met het bmp.Save wordt de bewerkte foto in het Bitmap object opgeslagen en uiteindelijk verstuurd.

   bmp.Save(Response.OutputStream, ImageFormat.Jpeg);

Nu zijn we er nog niet helemaal. Om alles netjes achter te laten gaan we even alle aangemaakte objecten vernietigen. Dit gebeurt met Dispose. Doe je dit niet, dan zal het origineel op de server gelocked zijn (kun je het niet deleten/overschrijven), dit komt omdat de webserver nog met dit bestand bezig zou zijn. Verder is het verstandig om het uitvoeren van de pagina te stoppen, zodat overige pagina gebeurtenissen niet uitgevoerd worden.

   g.Dispose();
   bmp.Dispose();
   img.Dispose();
   Response.End();

<< vorige | ^ naar boven | overzicht | volgende >>
copyright 2000-2007 ASPNL