On-the-fly Generierung von Graphiken
Geschrieben von: Christoph Wille Etwas, das für ASP Programmierer ohne Unterstützung einer Komponente nicht machbar ist, ist das dynamische Erstellen von Graphiken - seien es Diagramme, Banner oder nur ein einfacher graphischer Counter. Dem ist unter ASP.NET glücklicherweise nicht mehr so - mit einfachsten Bordmitteln kann man dynamisch Graphiken erstellen, und an den Client schicken - mit maxmimaler Konfigurierbarkeit und Komfort. Voraussetzung um den Sourcecode dieses Artikels verwenden zu können ist eine Installation des Microsoft .NET Framework SDK's auf einem Webserver. Weiters setze ich voraus, daß der Leser die Programmiersprache C# zu einem gewissen Grad beherrscht - es finden sich etliche Artikel auf diesem Server, um das notwendige Wissen zu erlernen. Generieren einer GraphikBevor wir uns jetzt mit all dem Ballast von ASP.NET belasten, machen wir eine Trockenübung in einem simplen Kommandozeilenprogramm - und diesen Sourcecode verwenden wir dann als Ausgangsbasis für unser ASP.NET Script. Der Unterschied ist, daß das Kommandozeilenprogramm die Graphik in eine Datei speichert, wohingegen das ASP.NET Script die Graphik direkt an den Client schickt. Was soll also unser Beispielprogramm machen? Wie immer, starten wir mit dem allseits beliebten Programm "Hello World" - dieser Text soll in eine Grafikdatei geschrieben werden, und die Grafik soll exakt so groß sein, wie die der Text "Hello World" in der aktuell gewählten Schrift und Schriftgröße (also einfach ein zu großes Bitmap generieren gilt nicht!). Das folgende Script (pagecounter.cs) ist ein typisches, einfaches, Kommandozeilenprogramm: abgesehen von der Klasse rundherum (die muß sein), gibt es nur die Funktion Main, die aufgerufen wird, wenn das Programm abläuft. Und dort ist auch unser Grafikgenerierungscode zu Hause. using System; using System.IO; using System.Drawing; using System.Drawing.Imaging; public class CTestBitmapFunctionality { public static void Main() { Bitmap newBitmap = null; Graphics g = null ; try { Font fontCounter = new Font("Lucida Sans Unicode", 12); // calculate size of the string. newBitmap = new Bitmap(1,1,PixelFormat.Format32bppArgb); g = Graphics.FromImage(newBitmap); SizeF stringSize = g.MeasureString("Hello World", fontCounter); int nWidth = (int)stringSize.Width; int nHeight = (int)stringSize.Height; g.Dispose(); newBitmap.Dispose(); newBitmap = new Bitmap(nWidth,nHeight,PixelFormat.Format32bppArgb); g = Graphics.FromImage(newBitmap); g.FillRectangle(new SolidBrush(Color.White), new Rectangle(0,0,nWidth,nHeight)); g.DrawString("Hello World", fontCounter, new SolidBrush(Color.Black), 0, 0); newBitmap.Save("c:\\test.png", ImageFormat.Png); } catch (Exception e) { Console.WriteLine(e.ToString()); } finally { if (null != g) g.Dispose(); if (null != newBitmap) newBitmap.Dispose(); } } } Was macht dieser Sourcecode? Das Endergebnis ist auf alle Fälle die Grafik test.png auf der Platte c: Und wie entsteht diese Grafik? Dazu müssen wir uns den Sourcecode etwas genauer ansehen. Unsere wichtigste Vorgabe war, daß die Grafik genau so groß sein muß, wie der Text "Hello World" in der Schrift, in der der Text gerendert werden soll. Daher muß ich mir zuallererst die Größe des Textes ausrechnen, und dazu bediene ich mich einer Dummy-Grafik der Größe 1x1, und wenn ich mit dem Berechnen fertig bin, lösche ich die Grafik wieder - um mir danach eine Grafik in der richtigen Größe zu erzeugen. Ein interessanter Punkt des Sourcecodes ist das Objekt Graphics. Wozu brauche ich das, wenn ich ein Bitmap erstellen will? Der Grund hierfür ist, daß das mein Grafikkontext ist, in dem ich zeichne - einen Grafikkontext kann ich auf dem Bildschirm, auf dem Drucker, und im Speicher - einem Bitmap eben - verwenden. Der Grafikkontext erlaubt mir die Zeichenoperationen auf beliebigsten Geräten (auch wenn sie virtuell sind). Mit DrawString habe ich nun den Text "Hello World" auftragsgemäß auf weißem Hintergrund (mit FillRectangle erzeugt) ausgegeben. Die Grafik ist fertig. Nun muß ich sie auf die Festplatte speichern. Wer einmal selbst Grafikformate programmiert hat, weiß wie mühsam das sein kann. Nicht so mit GDI+ (Graphics Device Interface) - ein einfacher Befehl steht zur Verfügung: newBitmap.Save("c:\\test.png", ImageFormat.Png); Und das war's auch schon! Einfach das ImageFormat.Png auf ImageFormat.Jpeg ausgetauscht, und man bekommt eine JPEG Datei. Das ist genau das, worauf viele gewartet haben - einfachstes Arbeiten mit Grafiken. Es bleibt mir nun noch den Grund des Exception Handlings zu erklären: einige Funktionen können Exceptions liefern (zB zu wenig Speicher beim Erzeugen des Bitmaps, etc). Da man als guter Bürger aber hinter sich aufräumen soll, muß ich mich immer daraum kümmern, daß Graphics und Bitmap freigegeben werden - und genau das mache ich für alle Fälle im finally Block (weil der wird immer aufgerufen). Und hinter finally endet das Programm auch schon. "Theoretisch" funktioniert das Programm - allerdings nur in Sourcecodeform. Um es tatsächlich zum Laufen zu bringen, muß man es zuerst kompilieren: csc /R:System.DLL /R:System.Drawing.DLL pagecounter.cs Damit erhält man die EXE-Datei pagecounter.exe. Achtung: diese ist nur auf Systemen mit dem installierten Microsoft .NET Framework lauffähig! Das Ganze am WebserverAls Kommandozeilenapplikation hat es ja hervorragend funktioniert. Als ASP.NET Script soll es aber ein paar "Stückeln" mehr spielen können:
Wer jetzt sagt, das ist zu schwierig, der darf einen Blick auf den Sourcecode des ASP.NET Scripts für die Grafik werfen (pagecounter.aspx). Alles, was ich tun mußte, ist jede Menge Fehlerbehandlungscode einzuführen, der die übergegebenen Parameter auf die Gültigkeit überprüft. Das war der Großteil der notwendigen Änderungen. Eine weitere Notwendigkeit war, die Grafik an den Client zu schicken, anstatt sie einfach in eine Datei zu schreiben. Dieser neue Teil sieht wie folgt aus: MemoryStream tempStream = new MemoryStream(); newBitmap.Save(tempStream,ImageFormat.Png); Response.ClearContent(); Response.ContentType = "image/png"; Response.BinaryWrite(tempStream.ToArray()); Response.End(); Ich habe die Grafik einfach im Speicher "zwischengelagert" (in einem Memory Stream), und dann als Array von Bytes an die allseits bekannte Funktion BinaryWrite übergeben. Übrigens: die Funktion ClearContent brauche ich deswegen, weil im obersten Teil des Scripts Import Direktiven stehen, die als Leerzeilen an den Client geschickt würden - und somit die Gültigkeit der PNG Grafikdatei zerstören würden. Wer sich den Sourcecode genauer angeschaut hat, wird festgestellt haben, daß ich alle frei wählbaren Attribute als QueryString Parameter übergeben habe. Das kann zu einer ganz schön langen Wurst werden, und da ich ein fauler Mensch bin, habe ich mir ein bequemes Testformular gebastelt, in dem ich die verschiedenen Werte austesten kann: Das schöne an dieser ASP.NET Seite (pagecountertest.aspx) ist, daß ich die Grafik sofort auf der gleichen Seite präsentiert bekomme. Der Sourcecode für dieses Formular beinhaltet bereits server-side ASP.NET Controls. Das sozusagen als Appetizer auf spätere Artikel, wo wir genauer auf die Formularbehandlung (und Validierung) mit ASP.NET eingehen werden. SchlußbemerkungIn diesem Artikel haben wir im Eilzugstempo uns kurz die Features zur Grafikprogrammierung angeschaut. Mit ASP.NET und dem Framework steht uns Webseitenprogrammieren jetzt der volle Befehlsumfang der Windows-Grafikprogrammierung zur Verfügung, um dies in unseren Webprojekten einzusetzen. Die Phrase "geht nicht" dürfen wir also getrost aus unserem Wortschatz streichen. Download des CodesKlicken Sie hier, um den Download zu starten. Verwandte Artikel
.NET Komponenten in COM+ Clients einsetzen Links zu anderen Sites
Die aspDEdotnet Liste Wenn Sie jetzt Fragen haben...Wenn Sie Fragen rund um die in diesem Artikel vorgestellte Technologie haben, dann schauen Sie einfach bei uns in den Community Foren der deutschen .NET Community vorbei. Die Teilnehmer helfen Ihnen gerne, wenn Sie sich zur im Artikel vorgestellten Technologie weiterbilden möchten. Eine weitere sehr hilfreiche Resource ist das deutsche ASP.NET Wiki, das als zentrale Anlaufstelle für Tips, Tricks, Know How und alles Nützliche was man in seinem Alltag als (ASP).NET-Entwickler so braucht und entdeckt gedacht ist. Haben Sie Fragen die sich direkt auf den Inhalt des Artikels beziehen, dann schreiben Sie dem Autor! Unsere Autoren freuen sich über Feedback zu ihren Artikeln. Ein einfacher Klick auf die Autor kontaktieren Schaltfläche (weiter unten) und schon haben Sie ein für diesen Artikel personalisiertes Anfrageformular.
Und zu guter Letzt möchten wir Sie bitten, den Artikel zu bewerten. Damit helfen Sie uns, die Qualität der Artikel zu verbessern - und anderen Lesern bei der Auswahl der Artikel, die sie lesen sollten.
©2000-2006 AspHeute.com |