![]() |
|
URL dieses Artikels:
zu Ausgabe:
06.2003
Bunte Spielereien
PHP und die GD2-Bibliothek ersetzen das Bildbearbeitungsprogramm?
von Tobias Hauser
Navigation, Änderung und Beschriftung von bestehenden Bildern und Erzeugen von Diagrammen aus Daten sind nur einige Einsatzgebiete von dynamisch generierte Grafiken. Dieser Artikel zeigt, wie Sie mit der GD2-Bibliothek und ein wenig Forschergeist dynamische Grafiken für die unterschiedlichsten Bedürfnisse generieren.
Natürlich kann eine Grafikbibliothek und die dazugehörige Programmiersprache, in diesem Fall PHP, kein Grafikprogramm wie The GIMP oder Adobe Photoshop ersetzen. Viele automatisierte Effekte fehlen und die Programmierung von Grafiken ist auch nicht jedermanns Sache - vor allem Designer verzweifeln schnell. Dennoch, wenn es dynamisch sein soll, ist das Programmieren oder Ändern von Grafiken on-the-fly auf jeden Fall einen Blick wert. Dieser Artikel zeigt viele interessante Beispiele und simuliert Effekte mit PHP, die Sie sicher auch aus Grafikprogrammen kennen. Installation Die Installation der GD2 entnehmen Sie dem Artikel Neue Grafikwelt aus Ausgabe 2.03 des PHP Magazins. Geändert hat sich seit dem nur, dass in der Windows-Version die Erweiterung: extensions=php_gd2.dllschon in der php.ini eingetragen ist und nur noch der Kommentar entfernt werden muss. Buttons Der Reiz einer dynamischen Navigation liegt darin, beliebig viele unterschiedlich beschriftete Navigationselemente per Skriptsprache zu generieren. Wenn es dann noch schön aussehen soll, benötigen Sie Grafiken dazu. Sie könnten die Grafiken natürlich komplett mit der GD2 erstellen. Allerdings ist dies etwas umständlich, da manche Elemente, wie abgerundete Rechtecke, Schatten oder ähnliches nicht vorhanden sind und sehr umständlich simuliert werden müssten. Als praxistauglicher erweist sich die Variante, einen Button in einem Grafikprogramm vorzuzeichnen und den Text dynamisch mittels der GD2 hinzuzufügen. Allerdings sind auch bei dieser Variante ein paar Klippen zu umschiffen, wenn Sie Buttons mit 256 Farben verwenden: Ein PNG mit 256 Farben belegt, wenn es mit imagecreatefrompng() geladen wird, schon alle 256 Farben in der Palette. Wenn Sie eine Beschriftung mit einer eigenen Farbe erstellen, findet diese Farben keinen Platz mehr in der Farbpalette. Auch die Funktion imagecolorresolve() hilft hier nicht viel. Sie verwendet immer die nächstgelegene Farbe, scheitert allerdings im folgenden Beispiel daran, dass kein Rotton im Bild vorhanden ist: <?php Abb. 1: Die Farbe, die rot am nächsten kommt, ist hier ein "versupptes" Grau Für dieses Problem gibt es einige Lösungsmöglichkeiten. Bei der ersten nehmen Sie die benötigten Farben im Bildbearbeitungsprogramm schon in die Palette auf. Das ist aus Programmierersicht nicht sehr elegant, aber es funktioniert. Die zweite Lösung geht schon eher in Richtung Programmierung: Mit der Funktion imagecolorset(Bild, Index, Rot, Grün, Blau) können Sie eine Farbe mit dem Index bestimmen und durch den Farbwert ersetzen, den Sie als Parameter (Rot, Grün, Blau) angeben. Das Problem ist nur, dass dieser Farbwert normalerweise im Bild vorkommt und auch dort geändert wird. Sie haben also unter Umständen irgendwo ein paar rote Pixel im Bild. Um das zu verhindern, müssten Sie zuerst allen Pixeln mit dem Farbwert eine ähnliche, bereits vorhandene Farbe zuweisen. Das klingt nicht nur umständlich, sondern ist es auch. Die dritte Lösung ist dagegen um einiges eleganter. Zuerst erzeugen Sie ein Bild mit dem Ausgangsbutton: <?phpDieses Bild besitzt automatisch nur 256 Farben. Als zweites folgt ein Bild, das genauso groß ist, wie das 8bit-Original, allerdings als Truecolor-Bild: $bild = imagecreatetruecolor(150, 50);In dieses Bild kopieren Sie mit der Funktion imagecopy(Ziel-Bild, Quelle, Ziel X, Ziel Y, Quelle X, Quelle Y, Quelle Breite, Quelle Höhe) das 8bit-Bild in das Truecolor-Bild. imagecopy($bild, $bild_8bit, 0, 0, 0, 0, 150, 50);Nun können Sie das Bild mit imagetruecolortopalette(Bild, Dither, Farben) wieder in ein 8bit-Bild zurückverwandeln. Bei der Zahl der Farben wählen Sie einfach ein paar weniger als 256, um genug Raum für eigene, in PHP definierte Farben zu verwenden: imagetruecolortopalette($bild, false, 250);Das Dithering ist ein Boolean und gibt an, wie bei einer Farbreduktion verfahren wird. Ist Dithering aktiv (true), werden wegreduzierte Farben durch eine Kombination aus ähnlichen Farben simuliert. In unserem Beispiel ist die Farbreduktion nicht schwerwiegend, weswegen Dithering nicht notwendig ist. Am Schluss folgt ein roter Text, um zu zeigen, dass Sie nun eigene Farben definieren können: $rot = imagecolorallocate($bild, 205, 0, 0); Abb. 2: Aus dem Grau ist echtes Rot geworden. Wenn Sie auf eine dynamische Navigation setzen, können natürlich noch weitere Probleme auftreten. Für Ärger sorgt beispielsweise ein fehlendes Originalbild. Hierzu finden Sie in der PHP-Dokumentation unter www.php.net/manual/de/function.imagecreatefrompng.php ein einfaches Skript zum Fehlerhandling. Zusätzlich haben Sie die Möglichkeit, in das Skript weitere Automatismen einzubauen. Wenn Sie beispielsweise nicht wissen, wie groß das Originalbild ist, können Sie mit imagesx() und imagesy() Breite und Höhe ausmessen und automatisch in das neu erstellte Bild übernehmen: $bild_8bit = imagecreatefrompng("button.png");
Schwarz-WeißDie eben beschriebene Reduktion der Bildfarben mit imagetruecolortopalette() können Sie übrigens auch dazu verwenden, ein Farbbild in eine reine Schwarz-Weiß-Grafik umzuwandeln. Die ersten Schritte kommen Ihnen sicherlich schon bekannt vor: <?phpSie laden das JPEG-Truecolor-Bild. Da es am Schluss in ein PNG umgewandelt werden soll, müssen Sie den PNG-Header verwenden. Mit imagetruecolortopalette() reduzieren Sie das Bild auf zwei Farben. Sie sollten Dithering verwenden, um ein schöneres Ergebnis zu erzielen: imagetruecolortopalette($bild, true, 2);Die beiden Farben sind bis jetzt noch nicht Weiß bzw. Schwarz. Deswegen müssen Sie herausfinden, welche heller ist, also näher an Weiß liegt. Dies erledigt die Funktion imagecolorclosest(Bild, Rot, Grün, Blau). $ind = imagecolorclosest($bild, 255, 255, 255);Die Funktion liefert einen Indexwert (Variable $ind), den Sie in der Funktion imagecolorset (Bild, Index, Rot, Grün, Blau) verwenden können, um die hellere Farbe mit Weiß zu ersetzen: imagecolorset($bild, $ind, 255, 255, 255); Abb. 3: Aus dem Farbbild wurde eine Schwarz-Weiß-Grafik. Hintergrund transparent Bei vielen Buttons und Navigationselementen ist der Hintergrund nicht transparent. Dies macht sich spätestens dann bemerkbar, wenn Sie den Button vor einen anderen Hintergrund legen möchten. Ein einfaches Beispiel illustriert dies: Eine HTML-Seite enthält eine per PHP generierte Grafik. Ändert sich nun die Hintergrundfarbe von Weiß auf Grün, erscheint der Button sehr störend. <body style="background-color:darkgreen">Mit einigen Codezeilen lässt sich der Hintergrund dank der Transparenz-Möglichkeiten der GD2 allerdings sehr schön entfernen. Mit imagecolorresolve() finden Sie die Farbe heraus, die Weiß, also der hier störenden Hintergrundfarbe am nächsten kommt und machen sie dann mit imagecolortransparent(Bild, Farbe) durchsichtig. $hinter = imagecolorresolve($bild, 255, 255, 255);Beachten Sie allerdings, dass in einem Bild immer nur eine Farbe transparent sein kann. Die Transparenz ist also keine Eigenschaft der Farbe, sondern des Bildes. Außerdem unterstützen JPEGs im Gegensatz zu PNGs keine Transparenz. ![]() Abb. 4: Der weiße Rand stört vor einem grünen Hintergrund. Abb. 5: Weiß wird transparent und der Button passt sich in den Hintergrund ein. Wenn Sie das Endergebnis in Abbildung 5 ganz genau betrachten, können Sie erkennen, dass um den Button herum noch ein (fast) weißer Rand liegt. Der Grund dafür: der Effekt aus dem Bildbearbeitungsprogramm arbeitet an den Rändern mit Farbübergängen, um das Bild weniger pixelig erscheinen zu lassen. Sind diese Übergänge vor der falschen Hintergrundfarbe erstellt, lassen sie sich kaum entfernen beziehungsweise umfärben. In schlimmeren Fällen bleibt nur die Alternative, das Bild im Bildbearbeitungsprogramm nach zu bearbeiten und vor einen anderen Hintergrund zu legen. Nichts ist wie vorher Größere Änderungen an den Farben eines Bildes lassen sich am besten mit einer Schleife realisieren, die die einzelnen Farben durchlaufen. Dies ist allerdings nur bei einem Bild mit 8bit und einer Farbpalette wirklich einfach. Das folgende Beispiel zeigt, wie Sie ein 8bit-Bild in Graustufen umwandeln: $bild = imagecreatefrompng("button.png");
Nachdem Sie das Bild geladen haben, starten Sie eine Schleife, die die Indexwerte aller Farben durchläuft. Mit imagecolorstotal(Bild) finden Sie die Gesamtzahl der Farben des Bildes heraus und stoppen die Schleife. Für jeden Indexwert liefert imagecolorsforindex(Bild, Index) die RGB-Farbwerte als assoziativen Array. red steht für Rot, green für Grün und blue für Blau. Die Formel zur Graustufenberechnung ist einfach. Sie addieren die drei Farbwerte und bilden den Mittelwert, indem Sie die Summe durch 3 teilen. Da Graustufen immer aus drei gleichen Farbwerten bestehen, setzen Sie bei imagecolorset() den Mittelwert für Rot, Grün und Blau ein.
Abb. 6: PHP wandelt den Button in Graustufen um. Etwas eleganter erfolgt die Umwandlung, wenn die einzelnen Farbwerte gewichtet werden. Die notwendigen Werte hängen natürlich größtenteils vom Originalbild ab. Oftmals ist es für das Graustufen-Ergebnis am günstigsten, Grün am stärksten und Blau am zweitstärksten zu gewichten. Die Berechnung ändert sich nur in einer Zeile: $gst = $f["red"]*0.15 + $f["green"]*0.5 + $f["blue"]*0.35;Die Gewichtungen können Sie natürlich beliebig an die eigenen Bedürfnisse anpassen. 24bit-Bilder Die Umwandlung von Farbwerten ist leider für 24bit-Bilder nicht so einfach, wie für ihre 8bit-Pendants. Bei der Graustufenumwandlung besteht der praktischste Weg darin, zuerst das Truecolor-Bild mit imagetruecolortopalette() in ein 8bit-Bild mit 256 Farben umzuwandeln. Dabei gehen allerdings Farbabstufungen verloren, da das Truecolor-Bild zuerst reduziert wird und erst anschließend die Graustufenumwandlung erfolgt. Um das Bild verlustfrei in Graustufen zu konvertieren, ist mehr Arbeit nötig: Sie müssen jedes einzelne Pixel des Bildes in seinen Graustufenwert umwandeln: <?phpAnschließend folgen zwei ineinander verschachtelte Schleifen. Die erste Schleife geht alle Pixel reihenweise von oben nach unten durch. Die darin verschachtelte Schleife wandert über alle Pixel in jeder Reihe. for($i=0; $i<$y; $i++) {
Die Anweisung innerhalb der zweiten Schleife gilt für jeden Pixel. Zuerst stellen Sie die Position des Farbwerts an dem Pixel mit imagecolorat(Bild, x, y) fest. $pos = imagecolorat($bild, $j, $i);imagecolorsforindex(Bild, Index) liefert dann den Farbwert als assoziativen Array. Dieser kann dann auf die bekannte Art in einen Graustufenwert umgerechnet werden: $f = imagecolorsforindex($bild, $pos);Zum Schluss muss noch die Farbe zum Graustufenwert festgestellt und mit imagesetpixel(Bild, x, y, Farbe) gesetzt werden. Vorsicht, imagesetpixel() benötigt einen fertigen Farbwert und kann mit Rot, Grün und Blau nichts anfangen. $farbe = imagecolorresolve($bild, $gst, $gst, $gst);Die hier geschilderte Methode hat einen großen Vorteil und einen fast noch größeren Nachteil. Der Vorteil wird beim Vergleich von Abbildung 7 und 8 offensichtlich. Ohne die Reduktion sieht das Graustufenbild einfach besser aus. Der gravierende Nachteil dabei, ist die geringe Performance. Da jeder Pixel einzeln ausgelesen und geändert werden muss, dauert die Operation einige Zeit. Selbst beim Test mit einem starken und wenig belasteten lokalen System ist die Verzögerung schon spürbar. Empfehlenswert sind Umwandlungen von 24bit-Grafiken also eigentlich nur bei recht kleinen Bildern. Abb. 7: Die Farbreduktion ist deutlich zu sehen. Abb. 8: Alle Übergänge wirken bei der aufwendigeren Methode besser. Thumbnails Umfangreiche Bildsammlungen finden Sie im Web oftmals in einer stark verkleinerten Variante. Diese kleinen Bilder oder auch Thumbnails (von engl. Daumennagel) lassen sich auch mit PHP dynamisch generieren. Das Bild, das verkleinert werden soll, ist die Quelle: $quelle = imagecreatefromjpeg("glow.jpg");
Aus seinen Maßen bilden Sie die Größe des Thumbnails. In unserem Fall teilen wir durch 2, reduzieren also Breite und Höhe jeweils auf die Hälfte des Originals. $z_x = round($q_x / 2);Anschließend wird das Ziel-Bild mit dieser Größe angelegt. Beachten Sie, dass das Zielbild ein Echtfarbenbild sein sollte, damit für die Neuberechnung des Bildes mit geringerer Größe (Interpolation) genug Farben zur Verfügung stehen. $ziel = imagecreatetruecolor($z_x, $z_y);Die Interpolation selbst steckt in der Funktion imagecopyresampled(Ziel, Quelle, Start Ziel X, Start Ziel Y, Start Quelle X, Start Quelle Y, Breite Ziel, Höhe Ziel, Breite Quelle, Höhe Quelle). Sie verwendet Start-Koordinaten und Maße der Quelle und wandelt sie in die Maße des Ziels um: imagecopyresampled($ziel, $quelle, 0, 0, 0, 0, $z_x, $z_y, $q_x, $q_y);Vergessen Sie am Schluss nicht, beide Bilder aus dem Speicher zu tilgen: imagejpeg($ziel);Wenn Sie Original und Thumbnail im Browser vergleichen, fällt auf, dass die Verkleinerung durchaus ordentlich aussieht. Als Ergänzung lohnt sich ein Blick in die PHP-Dokumentation unter www.php.net/manual/de/function.imagecopyresampled.php, wo auch Funktionen zur bikubischen Interpolation diskutiert werden. Abb. 9: Links das Original, rechts die Verkleinerung mit PHP. Zufall Zum Abschluss erhält die Spielwiese der dynamischen Grafiken noch ein wenig Würze mit einem zufallsbasierten Bild. Listing 1 erzeugt ein Bild, das aus lauter Ellipsen besteht (fünfzig, um genau zu sein). Diese Ellipsen haben alle eine zufällige Größe und eine zufällige Farbe. Einzige Bedingung ist, dass keine Ellipse über den Rand des Bildes hinausragen darf. Eine Schleife erzeugt die Ellipsen. In der Schleife wird die Farbe mit den drei Farbwerten über eine Zufallszahl von 0 bis 255 zusammengesetzt. Die Koordinaten für den Mittelpunkt der Ellipse ($s_x und $s_y) sind ebenso von einer Zufallszahl abhängig, wie Breite und Höhe ($e_x, $e_y). Vier Fallunterscheidungen überprüfen, ob die Ellipse über die Grenzen des Bildes hinausragen würde. Ist dies der Fall, wird die Breite so angepasst, dass die Ellipse genau auf der Grenze endet. Zum Schluss verwendet imageellipse() die Angaben, um die Ellipse zu zeichnen (Listing 1).Listing 1 <?phpFazit Bildmanipulationen begeistern Designer und Programmierer gleichermaßen. Die dynamischen Möglichkeiten der GD in Verbindung mit PHP wissen auch in den hier gezeigten Beispielen zu überzeugen. In der Praxis stellt sich immer die Frage, wie viel wirklich dynamisch gestaltet werden muss und wann das Grafikprogramm doch besser geeignet ist. Natürlich verkleinert ein Bildbearbeitungsprogramm Bilder sauberer, dafür entfällt bei der dynamischen Variante der zusätzliche Speicherplatz für die Thumbnails. Bildkorrekturen und Graustufenumwandlungen nimmt ein Webdesigner normalerweise in GIMP oder Photoshop vor, wenn eine Website allerdings kurzfristig oder zufallsbasiert Grau-in-Grau wirken soll, ist die dynamische Bildänderung schneller und pfiffiger. Gerade der Zufall eröffnet auch neue Möglichkeiten der Gestaltung. Ändern Sie doch einfach mal zufällig die Farbe Ihres Logos, so dass jeder Nutzer eine andere Optik sieht. Wer jetzt schimpft, das wären doch alles nur Spielereien, der hat zumindest bei per Zufall generierten Bildern Recht. Aber steckt nicht in jedem PHP-Programmierer, der freudig, wütend, verbissen und zum Schluss hoffentlich stolz an seinem Skript bastelt, ein kleines Spielkind? Tobias Hauser (th@hauser-wenz.de) ist Autor, Trainer und Berater in den Bereichen Web-Design und Web-Entwicklung. Als Speaker treffen Sie ihn auf nationalen und internationalen Konferenzen. Links und Literatur
|
||
|