# Dynamische Bildgenerierung – PHP‑Variante

Die Welterfahrung des Menschen schlägt sich in den bleibenden Gestalten der Musik, Literatur und Malerei nieder.
Hans-Georg Gadamer, dt. Philosoph

Die Möglichkeit, mit PHP zur Laufzeit Grafiken zu erzeugen, hat ein breites Einsatzgebiet, so etwa grafische Schaltflächen, kleine Vorschaubilder (Thumbnails) oder Diagramme.

# Die GD-Library und PHP

Die GD-Library stellt in PHP alle wichtigen Funktionen für Grafiken und Bilder zur Verfügung. Auf diese Weise können Sie neue Grafiken auf Basis bereits existierender Grafiken oder vollständig neu erzeugen. Die GD-Library ist den PHP-Distributionen bereits als DLL beigelegt, muss jedoch zuvor erst aktiviert werden. Damit Sie nun nicht in jedem Script die entsprechende DLL (php_gd.dll) dynamisch laden müssen, ist es sinnvoll, das Laden der DLL bereits in der php.ini zu aktivieren.

Sie können die php.ini mit einem beliebigen Texteditor öffnen, da der Inhalt der Datei in reinem Text vorliegt und somit problemlos zu lesen ist. Diese Datei wird normalerweise im Verzeichnis C:\Windows abgelegt. Suchen Sie in der Datei die Zeile extension=php_gd.dll. Wenn am Anfang der Zeile ein Semikolon steht, müssen Sie dieses entfernen. Fehlt das Semikolon, ist die GD-Library bereits aktiviert. Speichern Sie die vorgenommenen Änderungen an der php.ini ab.

Welche Grafikformate unterstützt werden, hängt jedoch von der Version der GD-Library ab. Bei Versionen, die älter als 1.6 sind, unterstützt die GD-Library das JPEG- und das GIF-Format. Aufgrund des Lizenzproblems mit dem GIF-Format wird bei neueren Versionen das GIF-Format nicht mehr unterstützt und stattdessen das PNG-Format verwendet.

Bei den aktuellen PHP-Versionen liegt die GD-Library meist in zwei verschiedenen Versionen vor: meistens in der Version 1.6.2 und in der Version 2.0+. Je nachdem, welche dieser beiden Versionen Sie verwenden möchten, müssen Sie eine andere Konfiguration in der php.ini vornehmen. Möchten Sie die Version 1.6 verwenden, müssen Sie, wie erwähnt, lediglich das Semikolon vor der Zeile extension=php_gd.dll entfernen. Möchten Sie jedoch die Version 2.0+ verwenden, müssen Sie die Zeile extension=php_gd.dll durch extension=php_gd2.dll ersetzen (natürlich ohne Semikolon).

# Eine erste dynamische Grafik

Vor jeder Grafikoperation müssen Sie zuerst mit der Funktion imagecreate eine leere Grafik erstellen. Die Funktion erwartet als Parameter die Breite und die Höhe der neuen Grafik in Pixel. Wenn die neue Grafik erzeugt werden konnte, liefert die Funktion einen Zeiger auf die Grafik zurück. Sie liefert FALSE, falls die Grafik nicht erstellt werden konnte.

int imagecreate(int width, int heigth)

Ein Beispiel-Aufruf:

$image = imagecreate(175,25);

In der Variablen $image wird ein Zeiger auf die neue Grafik gespeichert. Die neue Grafik ist 175 Pixel breit und 25 Pixel hoch.

# Farben

Zu Beginn ist die Farbpalette einer Grafik leer. Eine neue Farbe muss also zunächst definiert werden, damit sie in die Farbpalette der Grafik eingefügt wird. Dies ermöglicht die Funktion imageColorAllocate. Als ersten Parameter erwartet sie den Zeiger auf die Grafik und anschließend die einzelnen Farbwerte der Farbe. Die Farbwerte werden als Zahlen zwischen 0 und 255 angegeben, wobei 0 für keinen Anteil steht und 255 für den maximalen Farbanteil. Die Funktion gibt anschließend die Farb-ID der Farbe in der Palette zurück. php

int imageColorAllocate(int image, int red, int green, int blue)

Beispiele:

$white = imageColorAllocate($image,255,255,255);  
$black = imageColorAllocate($image,0,0,0);  
$red = imageColorAllicate($image,255,0,0);  
$green = imageColorAllocate($image,0,255,0);  
$blue = imageColorAllocate($image,0,0,255);

Durch dieses System stehen Ihnen 16,6 Millionen Farben zur Verfügung. Dies dürfte für eigentlich jede Grafik vollkommen ausreichend sein.

Die erste Farbe, die Sie definieren, wird als Hintergrundfarbe verwendet. Wenn Sie also in die Grafik zeichnen möchten, sollten Sie immer zwei Farben definieren, damit nicht alles in der gleichen Farbe wie der Hintergrund gezeichnet wird.

# Text einfügen

Die Funktion imageString zeichnet eine Zeichenkette in eine Grafik.

int imageString(int image, int font, int x, int y, string str, int color)

Als ersten Parameter erwartet die Funktion den Zeiger auf die Grafik. Für den zweiten Parameter font können Sie eine Zahl zwischen 1 bis 5 angeben. Diese Werte stehen für interne Zeichensätze, die die GD-Library zur Verfügung stellt. Zwar können Sie auch andere Schriftarten wie z. B. TrueType-Schriften verwenden, damit werden Sie sich aber erst später beschäftigen. Die Parameter x und y definieren die Position, an der die Zeichenkette eingefügt wird. x gibt die horizontale und y die vertikale Position an. Dabei steht (0,0) für die linke obere Ecke. Die einzufügende Zeichenkette wird als Parameter str übergeben und die Farbe, in der die Zeichenkette dargestellt werden soll, als Parameter color.

imageString($image,5,50,10,'Test',$black);

Dieses Beispiel fügt nun die Zeichenkette Test in der Farbe Schwarz an der Position (50,10) in die Grafik ein. Der gewählte Zeichensatz ist 5.

Es gibt jedoch etwas zu beachten: An der Position, die Sie mit den Parametern x und y an die Funktion übergeben, wird die linke obere Ecke des auszugebenden Textes ausgerichtet. Um eine Zeichenkette nun sowohl horizontal als auch vertikal zentriert in der Grafik auszugeben, müssen Sie die x- und die y-Position zuvor abhängig von der Zeichenkettenlänge und -höhe errechnen.

Es gibt zwei Funktionen, die die Höhe und die Breite eines einzelnen Zeichens ermitteln. Dies sind imageFontWidth und imageFontHeight. Beide Funktionen erwarten lediglich den Zeichensatz, dessen Höhe und Breite ermittelt werden soll. Die Höhe und Breite wird dann von den Funktionen in Pixel zurückgegeben.

int imageFontHeight(int font)  
int imageFontWidth(int font)

Die Höhe einer einzeiligen Zeichenkette lässt sich sehr einfach berechnen:

$str_height = imageFontHeight(5);

Bei der Länge der Zeichenkette muss zusätzlich noch die Anzahl der Zeichen berücksichtigt werden. Diese erhalten Sie mit der Funktion strLen.

$str_width = imageFontWidth(5) * strLen('Test');

Nach dieser Vorarbeit ist das zentrierte Positionieren der Zeichenkette kein Problem mehr. Von der Breite der Grafik wird die Breite der Zeichenkette in Pixel abgezogen und von der Höhe der Grafik die Höhe der Zeichenkette. Beide Werte müssen lediglich noch durch 2 geteilt werden.

$str_x = (175$str_width) / 2;  
$str_y = (25$str_height) / 2;

# Ausgabe des Bildes

Wenn Sie alle Änderungen an der Grafik durchgeführt haben, müssen Sie die Grafik natürlich noch ausgeben. Dies ermöglichen die Funktionen imagePng und imageJPEG. Welche der beiden Sie verwenden, hängt davon ab, in welchem Format Sie die Grafik ausgeben möchten. Soll die Datei im PNG-Format ausgegeben werden, müssen Sie die Funktion imagePng benutzen, und für die Ausgabe im JPEG-Format verwenden Sie die Funktion imageJPEG. Beide Funktionen erwarten als ersten Parameter auf jeden Fall den Zeiger auf die Grafik. Der zweite Parameter ist optional und gibt einen Dateinamen an, unter dem die Grafik gespeichert wird. Geben Sie den Parameter nicht an, wird die Grafik im Browser ausgegeben. Wird der Parameter angegeben, erfolgt die Ausgabe in der angegebenen Datei.

int imagePng(int image [, string filename])  
int imageJPEG(int image [, string filename [, int quality]])

Wenn Sie die Grafik im JPEG-Format ausgeben und außerdem als Datei speichern, können Sie zusätzlich noch die Qualität der Grafik in Prozent angeben. Möchten Sie die Qualität festlegen, die Grafik aber im Browser ausgeben, müssen Sie als Dateinamen eine leere Zeichenkette übergeben.

imagePng($image,"/images/tmp_image.png");  
imageJPEG($image,"/images/tmp_image.jpg",75);

In beiden Beispielen wird die erzeugte Grafik im Verzeichnis images gespeichert. Bei der Speicherung als JPEG-Grafik wurde als Qualität 75  % angegeben.

Zur Ausgabe im Browser müssen Sie zusätzlich noch den MIME-Typ ausgeben, ähnlich wie bei PDF-Dokumenten. Der MIME-Typ für PNG-Grafiken lautet image/png und für JPEG-Grafiken image/jpg.

Vor dem Aufruf einer der beiden Funktionen sollten Sie den entsprechenden MIME-Typ ausgeben, falls die Ausgabe im Browser erfolgen soll. Also

header('Content-Type: image/png');

oder

header('Content-Type: image/jpg');

Nachdem die Grafik dann im Browser ausgegeben worden ist, ist es auf jeden Fall ratsam, den durch die Grafik belegten Speicher wieder freizugeben. Die Freigabe erfolgt durch den Aufruf der Funktion imageDestroy. Als Parameter müssen Sie lediglich den Zeiger auf die Grafik übergeben.

int imageDestroy(int image)

Als zusammenhängendes Script könnte dies folgendermaßen aussehen:

<?php

  $width = 175;
  $height = 25;
  $font = 5;
  $str = 'Ein Text';
  
  $image = imageCreate($width,$height);
  
  $yellow = imageColorAllocate($image,255,255,0);
  $blue = imageColorAllocate($image,0,0,255);
  
  $str_x = ($width - (imageFontWidth($font) * strLen($str))) / 2;
  $str_y = ($height - imageFontHeight($font)) / 2;
  imageString($image,$font,$str_x,$str_y,$str,$blue);
  
  header('Content-Type: image/png');
  imagePng($image);
  imageDestroy($image);
  
?>

Listing 1.1: Ausgabe einer Grafik mit Schriftzug

Da die Breite und Höhe der Grafik sowie der gewählte Schriftzug und die Zeichenkette mehrmals im Script benötigt werden, wurden zu Beginn des Scripts vier Variablen mit den entsprechenden Werten definiert. Anschließend wird die Grafik erzeugt, und der Zeiger in der Variablen $image gespeichert. Im nächsten Schritt werden zwei Farben definiert. Die erste Farbe wird automatisch als Hintergrundfarbe verwendet. Damit die Zeichenkette sowohl horizontal als auch vertikal zentriert ausgegeben wird, werden in den Variablen $str_x und $str_y die berechneten x- und y-Koordinaten gespeichert. Dann wird die Zeichenkette in die Grafik eingefügt. Anschließend wird an den Browser der entsprechende MIME-Typ gesendet, die Grafik ausgegeben und der belegte Speicher schlussendlich freigegeben. Im Browser sieht das dann wie in Abbildung 1.1 gezeigt aus.

Mit PHP erzeugte Grafik
Abbildung 1.1: Mit PHP erzeugte Grafik

# Grafiken verändern

Neben der Möglichkeit, eine vollständig neue Grafik zu erstellen, können Sie auch eine Grafik auf Basis einer bereits existierenden erzeugen. Anstelle der Funktion imageCreate müssen Sie dann jedoch eine der spezielleren Funktionen verwenden. Welche Funktion Sie dann genau wählen, hängt vom Format der Basisgrafik ab. Liegt die Grafik im JPEG-Format vor, müssen Sie die Funktion imageCreateFromJPEG und bei PNG die Funktion imageCreateFromPng verwenden.

Als Parameter müssen Sie selbstverständlich den Dateinamen übergeben, unabhängig davon, welche Funktion Sie verwenden. Anschließend erhalten Sie einen Zeiger auf die neue Grafik.

int imageCreateFromJPEG(string filename)  
int imageCreateFromPng(string filename)

Konnte die Datei nicht geöffnet werden, liefern beide Funktionen eine leere Zeichenkette zurück.

$image = imageCreateFromJPEG('basejpeg.jpg');  
$image = imageCreateFromPng('basepng.png');

Überprüfen Sie vor weiteren Manipulationen an der Grafik den Rückgabewert der Funktion. Konnte die Grafik nicht geladen werden, wird eine Fehlermeldung erzeugt, die vom Browser als Verbindungsabbruch interpretiert wird. In einem solchen Fall sollten Sie eine leere Grafik erzeugen. Mögliche Fehlermeldungen können Sie dann mit dem @ vor der Funktion unterdrücken. Mit einer einfachen if-Anweisung lässt sich ein Fehler beim Öffnen der Basisgrafik behandeln.

$image = @imageCreateFromPNG('basepng.png');  
if(!$image)  
{  
  $image = imageCreate(175,25);  
  $bg = imageColorAllocate($image,51,102,153);  
}

Für den Fall, dass die Grafik basepng.png nicht geöffnet werden konnte (aus welchem Grund auch immer), wird im nachfolgenden if-Anweisungsblock eine leere Grafik mit Hintergrundfarbe definiert. Sollten danach Manipulationen an der Grafik erfolgen, ist dies nicht weiter tragisch, da diese dann lediglich auf einem einfachen Hintergrund und nicht auf Basis einer Grafik erfolgen.

# Abmessungen

Wenn Sie eine Grafik als Basis einer neuen verwenden, heißt das nicht, dass Sie zuvor auch die exakten Abmessungen der Basisgrafik kennen. Denn eine neue Grafik, die auf einer vorhandenen basiert, erhält dieselben Abmessungen wie die ursprüngliche. Um die Breite und Höhe ermitteln zu können, stehen die Funktion imagesx und imagesy zur Verfügung. imagesx ermittelt die Breite der neuen Grafik und imagesy die Höhe. Beide Werte entsprechen den Abmessungen in Pixel. Als Parameter erwarten beide Funktionen den Zeiger auf die Grafik.

int imagesx(int image)  
int imagesy(int image)

Im folgenden Listing werden die zuvor genannten Funktionen verwendet, um auf Basis einer existierenden Grafik eine neue zu erstellen. Zusätzlich wird ein Text exakt in der Mitte der Grafik ausgegeben.

<?php

  $font = 5;
  $str = 'Schaltfläche';

  $image = @imageCreateFromPng('basepng.png');
  if(!$image)
  {
    $image = imageCreate(175,25);
    $blue = imageColorAllocate($image,51,102,153);
  }
  
  $white = imageColorAllocate($image,255,255,255);
  
  $str_x = (imagesx($image) - (imageFontWidth($font) * strLen($str))) / 2;
  $str_y = (imagesy($image) - imageFontHeight($font)) / 2;
  imageString($image,$font,$str_x,$str_y,$str,$white);
  
  header('Content-Type: image/png');
  imagePng($image);
  imageDestroy($image);
  
?>

Listing 1.2: Neue Grafik mit Text auf Basis einer existierenden Grafik

Nach der Definition der Variablen $font und $str wird versucht, eine neue Grafik zu erstellen, die auf der Grafik basepng.png basieren soll. Tritt dabei ein Fehler auf, wird einfach eine leere Grafik erzeugt, die eine blaue Hintergrundfarbe erhält. Die Position, an der die Zeichenkette eingefügt werden soll, wird mit den Funktionen imagesx und imagesy berechnet. Die Ausgabe im Browser ist in Abbildung 1.2 dargestellt.

Ausgabe des Scripts aus Listing 1.2 im Browser
Abbildung 1.2: Ausgabe des Scripts aus Listing 1.2 im Browser

# Zeichnen

Das Einfügen von Text in eine Grafik ist natürlich nur eine der Möglichkeiten, die Ihnen zur Verfügung stehen. Sie können auch Formen wie Rechtecke, Kreise oder Linien in die Grafik zeichnen.

# Punkte und Linien

Zwei der einfachsten Formen, die Sie in eine Grafik einfügen können, sind Punkte und Linien. Bei Punkten wird an einer beliebigen Stelle die Farbe eines Pixels verändert. Einen Punkt bzw. einen Pixel zu setzen, ermöglicht die Funktion imagesetpixel. Als Parameter erwartet sie sowohl den Zeiger auf die Grafik als auch die x/y-Position, an der die Farbe des Pixels verändert werden soll. Die neue Farbe wird als letzter Parameter übergeben.

int imagesetpixel(int image, int x, int y, int color)

Ein Beispiel:

$red = imagecolorallocate($image,80,0,0);  
for($i = 10; $i < 110; $i++)  
{  
  imagesetpixel($image,$i,15,$red);  
}

Dieses Beispiel würde insgesamt 100 Pixel auf die Farbe Rot setzen. Da die veränderten Pixel hintereinander auf einer Höhe liegen, kann man eine solche Schleife auch zum Zeichnen einer Linie verwenden. Einfacher wäre es jedoch, die entsprechende Funktion zu verwenden.

Die Funktionen imageline und imagedashedline zeichnen beide eine Linie in die Grafik, mit dem Unterschied, dass imagedashedline eine gestrichelte Linie zeichnet und imageline eine durchgezogene.

int imageline(int image, int x1, int y1, int x2, int y2, int color)  
int imagedashedline(int image, int x1, int y1, int x2, int y2,   
                    int color)

Um nun eine Linie zu zeichnen, müssen Sie zum einen den Zeiger auf die Grafik angeben und zum anderen den Start- und Endpunkt. Zusätzlich sollten Sie natürlich noch eine Farbe angeben. Die Start- und Endpunkte unterteilen sich dabei in die x- und y-Koordinaten.

<?php

  $image = imageCreate(175,20);
  
  $bg = imageColorAllocate($image,255,255,255);
  $red = imageColorAllocate($image,255,0,0);
  $green = imageColorAllocate($image,0,255,0);
  $blue = imageColorAllocate($image,0,0,255);
  
  for($i=10; $i<=165; $i++)
  {
    imageSetPixel($image,$i,5,$red);
  }
  
  imageLine($image,10,10,165,10,$green);
  
  imageDashedLine($image,10,15,165,15,$blue);
  
  header('Content-Type: image/png');
  imagePng($image);
  imageDestroy($image);
  
?>    

Listing 1.3: PHP-Script, das drei Linien auf unterschiedliche Weise im Browser ausgibt

In Listing 1.3 werden vier Farben definiert; eine für den Hintergrund und drei zum Zeichnen. Anschließend wird eine Linie in der Farbe Rot gezeichnet, indem einfach mehrere Pixel hintereinander auf die Farbe gesetzt werden. Danach wird eine Linie in Grün vom Punkt (10,10) zum Punkt (165,10) gezeichnet. Es folgt eine weitere, diesmal gestrichelte Linie vom Punkt (10,15) zum Punkt (165,15). Zum Schluss wird die Grafik im Browser ausgegeben.

Im Browser sieht das dann folgendermaßen aus:

Ausgabe des Listing 1.3 im Browser
Abbildung 1.3: Ausgabe des Listing 1.3 im Browser

# Rechtecke

Auch für die Grundform Rechteck existieren zwei Funktionen: imageRectangle und imageFilledRectangle. Während imageRectangle nur den Rahmen eines Rechtecks zeichnet, erzeugt imageFilledRectangle ein flächiges Rechteck.

int imageRectangle(int image, int x1, int y1, int x2, int y2, int color)  
int imageFilledRectangle(int image, int x1, int y1, int x2, int y2, int color)

Neben dem Zeiger auf die Grafik erwarten die Funktionen natürlich noch weitere Parameter: zum einen die beiden Eckpunkte links oben (x1,y1) und rechts unten (x2,y2) und zum anderen die Farbe für die Linie bzw. die Fläche.

<?php

  $image = imageCreate(200,100);
  
  $bg = imageColorAllocate($image,0,0,0);
  $yellow = imageColorAllocate($image,255,255,0);
  
  imageRectangle($image,10,10,90,90,$yellow);
  imageFilledRectangle($image,110,10,190,90,$yellow);
  
  header('Content-Type: image/png');
  imagePng($image);
  imageDestroy($image);
  
?>

Listing 1.4: PHP-Script, das zwei Rechtecke in eine Grafik zeichnet

Das PHP-Script aus Listing 1.4 zeichnet zwei verschiedene Rechtecke in eine Grafik, einmal ein Rechteck nur mit Außenlinie und einmal ein gefülltes Rechteck.

Ausgabe des Listing 1.4 im Browser
Abbildung 1.4: Ausgabe des Listing 1.4 im Browser

# Kreise und Kreisbögen

Die beiden Funktionen imageEllipse und imageFilledEllipse ermöglichen das Zeichnen einer Ellipse bzw. eines Kreises. Wie auch schon bei Rechtecken stehen Ellipsen mit Außenrand und gefüllte Ellipsen zur Verfügung.

int imageEllipse(int image, int x, int y, int width, int height,int color)
int imageFilledEllipse(int image, int x, int y, int width, int height, int color)

Die beiden Parameter x und y zentrieren die Ellipse an der angegebenen Position in der Grafik. Mit width bestimmen Sie die Breite und mit height die Höhe der Ellipse. color definiert die Farbe, in der die Ellipse gezeichnet werden soll. Leider funktioniert die Funktion erst mit der GD-Version 2.0.2+. Daher wird im folgenden Listing lediglich die Funktion imageFilledEllipse verwendet.

<?php

  $image = imageCreate(300,200);
  
  $bg = imageColorAllocate($image,0,0,0);
  $yellow = imageColorAllocate($image,255,255,0);
  
  imageFilledEllipse($image,50,50,90,90,$yellow);
  imageFilledEllipse($image,150,50,90,90,$yellow);
  imageFilledEllipse($image,100,150,180,90,$yellow);
  imageFilledEllipse($image,250,100,90,180,$yellow);
  
  header('Content-Type: image/png');
  imagePng($image);
  imageDestroy($image);
  
?>

Listing 1.5: Ausgabe von Kreisen und Ellipsen in eine Grafik

Nach den obligatorischen Definitionen der neuen Grafik und der Farben werden mit der Funktion imageFilledEllipse zwei Kreise und zwei Ellipsen in die Grafik eingefügt.

Ausgabe des Listing 1.5
Abbildung 1.5: Ausgabe des Listing 1.5

Es ist auch möglich, lediglich einen Kreisbogen zu zeichnen, und zwar mit der Funktion imageArc. Diese Funktion erwartet jedoch sehr viele Parameter, zuallererst natürlich den Zeiger auf die Grafik. Anschließend folgen die Position in der Grafik, die als Mittelpunkt für den Kreisbogen verwendet werden soll, sowie die Breite und die Höhe. Zusätzlich folgen dann der Anfangs- und der Endwinkel sowie schlussendlich die Farbe.

int imageArc(int image, int x, int x, int width, int height, int start_ang, int end_ang, int color)

Die Winkel können mit einer Zahl zwischen 0 und 360 angegeben werden, wobei 0 rechts, 90 unten, 180 links und 270 oben ist. Das folgende Beispiel soll dies verdeutlichen.

<?php

  $image = imageCreate(300,200);
  
  $bg = imageColorAllocate($image,0,0,0);
  $yellow = imageColorAllocate($image,255,255,0);
  
  imageArc($image,100,100,150,150,180,270,$yellow);
  imageArc($image,200,100,150,150,0,180,$yellow);
  
  header('Content-Type: image/png');
  imagePng($image);
  imageDestroy($image);
  
?>

Listing 1.6: Zeichnen von zwei Kreisbögen

In Listing 1.6 werden zwei Kreisbögen in die Grafik gezeichnet. Der erste Kreisbogen besitzt seinen Mittelpunkt an den Koordinaten (100,100). Die Breite und Höhe des fiktiven Kreises bzw. der Ellipse, von der dieser Kreisbogen stammt, beträgt jeweils 150 Pixel. Der Ausschnitt, den der Kreisbogen darstellt, reicht vom Winkel 180 bis zum Winkel 270. Dies entspricht einem Viertel. Der zweite Kreisbogen erhält den Mittelpunkt (200,100) und ebenfalls die Abmessungen von je 150 Pixel Breite und Höhe. Als Ausschnitt wurde diesmal der Bereich von 0 bis 180 gewählt, also die Hälfte. Im Browser sieht das dann so wie in Abbildung 1.6 dargestellt aus.

Ausgabe des Listing 1.6 im Browser
Abbildung 1.6: Ausgabe des Listing 1.6 im Browser

Obwohl die Funktion imageEllipse erst ab der Version 2.0.2+ zur Verfügung steht, können Sie dieses Problem mit der Funktion imageArc umgehen. Als Startwinkel müssen Sie einfach nur 0 und als Endwinkel 360 angeben, und schon erhalten Sie einen Kreis bzw. eine Ellipse nur mit Außenrand.

imageArc(50,50,90,90,0,360,$yellow);  
  // Zeichnet einen Kreis nur mit Außenrand  
imageArc(100,50,180,90,0,360,$yellow);  
  // Zeichnet eine Ellipse nur mit Außenrand

# Flächen füllen

Die Funktion imageFill in Verbindung mit Formen, die nur einen Außenrand besitzen, ermöglicht verschiedene Effekte. Unter anderem können Sie dadurch eine Form mit einem andersfarbigen Rahmen versehen. Die Funktion imageFill füllt einen Bereich mit einer neuen Farbe. Alle Pixel, die dieselbe Farbe haben wie der Startpixel, werden mit der neuen Farbe versehen.

int imageFill(int image, int x, int x, int color)

Im folgenden Listing wird diese Möglichkeit dazu verwendet, einen Kreis, der nur einen Außenrand besitzt, mit einer anderen Farbe einzufärben.

<?php

  $image = imageCreate(300,200);
  
  $bg = imageColorAllocate($image,0,0,0);
  $yellow = imageColorAllocate($image,255,255,0);
  $orange = imageColorAllocate($image,255,150,0);
  
  imageArc($image,150,100,90,90,0,360,$yellow);
  imageFill($image,150,100,$orange);
  
  header('Content-Type: image/png');
  imagePng($image);
  imageDestroy($image);
  
?>

Listing 1.7: Füllen eines Kreises mit einer Farbe

Zuerst wird ein Kreisbogen gezeichnet und anschließend die Funktion imageFill ausgeführt. Da der Startpunkt von imageFill innerhalb des Kreises liegt, werden alle Pixel mit der Farbe Schwarz durch die neue Farbe ersetzt, und zwar nur bis zum Rand des Kreises.

Ausgabe des Listing 1.7 im Browser
Abbildung 1.7: Ausgabe des Listing 1.7 im Browser

# Transparenz

Grafiken, die mit der Funktion imageCreate erstellt werden, besitzen eine 8-Bit-Farbpalette. Es stehen Ihnen also 256 Farben zur Verfügung. Mit imageCreateTrueColor erstellen Sie eine neue Grafik mit einer TrueColor-Palette. Das Besondere daran ist, dass Ihnen nun auch Transparenz zur Verfügung steht. Eine Farbe besteht dann aus vier Teilen: Rot, Grün, Blau und Alpha (Transparenzgrad). Dieser Transparenzgrad kann zwischen 0 und 127 liegen, wobei 0 für keine Transparenz und 127 für durchsichtig steht.

resource imageCreateTrueColor(int width, int height)

Da eine TrueColor-Palette fest definiert ist, müssen Sie sich mit der Funktion imageColorResolveAlpha den Index der Farbe, die Sie verwenden möchten, auslesen lassen. Die Funktion erwartet als Parameter den Zeiger auf die Grafik und alle vier Farbanteile. Alternativ können Sie Farben, die nicht transparent werden sollen, auch weiterhin mit imageColorAllocate definieren.

int imageColorResolveAlpha(int image, int red, int green, int blue, int alpha)

Nun fehlt nur noch eine dritte Funktion, mit der Sie die Transparenz aktivieren oder deaktivieren können: imageAlphaBlending. Diese Funktion erwartet als Parameter den Zeiger auf die Grafik und entweder TRUE oder FALSE. Wenn die Transparenz aktiviert werden soll, müssen Sie TRUE übergeben. Zum Deaktivieren übergeben Sie FALSE.

int imageAlphaBlending(int image, boolean alphamode)
<?php

  $image = imageCreateTrueColor(300,200);
  
  imageAlphaBlending($image,true);
  $bg = imageColorAllocate($image,0,0,0);
  $yellow = imageColorAllocate($image,255,255,0);
  $blue = imageColorResolveAlpha($image,0,0,255,50);
  
  imageFilledEllipse($image,100,100,150,150,$yellow);
  imageFilledRectangle($image,150,50,250,150,$blue);
  
  header('Content-Type: image/png');
  imagePng($image);
  imageDestroy($image);
  
?>

Listing 1.8: Grafik mit TrueColor-Palette

Die Ausgabe des Listing 1.8 mit deaktivierter Transparenz zeigt Ihnen Abbildung 1.8 auf der linken Seite. Die Ausgabe im Browser, wenn Sie die Transparenz aktivieren (imageAlphaBlending($image,true)), finden Sie auf der rechten Seite der Abbildung 1.8.

Ausgabe des Listing 1.8 mit deaktivierter (links) und aktivierter Transparenz (rechts)
Abbildung 1.8: Ausgabe des Listing 1.8 mit deaktivierter (links) und aktivierter Transparenz (rechts)

# Erweiterte Textausgabe

Intern kennt die GD-Library fünf verschiedene Schriften, deren Unterschiede sich jedoch auf die Größe und Schriftdicke beschränken. Abbildung 1.9 zeigt eine Übersicht dieser Schriftvarianten.

Die fünf internen Schriftvarianten
Abbildung 1.9: Die fünf internen Schriftvarianten

Es gibt jedoch die Möglichkeit, auch andere Schriftarten zu verwenden. Dies können entweder Bitmap- oder TrueType-Fonts sein. Bitmap-Fonts werden mit der Funktion imageLoadFont geladen. Da das Format der Bitmap-Fonts jedoch binären Abhängigkeiten unterliegt, müssen Sie die Schriften auf dem System erstellen, auf dem Sie die Schrift verwenden wollen. Es ist also sinnvoller, TrueType-Fonts zu verwenden.

Diese werden mit der Funktion imageTTFText verwendet und ersetzen die Funktion imageString. Da die Funktion imageTTFText eine Menge Parameter kennt, folgt zuerst die Syntax:

int imageTTFText(int image, int size, int angle, int x, int y, int color, string fontfile, string text)

Als Parameter image müssen Sie wie immer den Zeiger auf die Grafik angeben. Als size geben Sie die Größe der Schrift in Pixel an. angle ist der Winkel, in dem die Schrift ausgegeben werden soll. Er wird in Grad angegeben. 0 oder 360 entspricht dabei rechts (3 Uhr), 90 ist unten (6 Uhr), 180 ist links (9 Uhr) und 270 ist oben (12 Uhr). Die Parameter x und y definieren die Position, an der der Text platziert werden soll. color kann eine beliebige Farbe sein, die mit imageColorAllocate oder imageColorResolveAlpha ermittelt wurde. Die TrueType-Schrift, in der der Text gezeichnet werden soll, wird als Parameter fontfile angegeben. Benötigt werden dabei der Pfad und der Name der Datei. TrueType-Schriften enden in der Regel auf .ttf. Schlussendlich wird der auszugebende Text als Parameter text übergeben.

Um diese Funktion jedoch verwenden zu können, muss die GD-Library in der Version 2.x installiert und das Modul FreeType eingebunden sein (in der GD-Library). Falls Sie Zweifel haben, ob dies bei Ihnen der Fall ist, sollten Sie die Funktion phpinfo aufrufen und unter GD nachsehen, ob die Unterstützung aktiviert ist.

Das folgende Listing gibt einen Text in der Schriftart Arial aus:

<?php

  $image = imageCreate(400,100);
  
  $bg = imageColorAllocate($image,255,255,255);
  $black = imageColorAllocate($image,0,0,0);
  
  imageTTFText($image,50,0,25,25,$black,'arial','Arial');
  
  header('Content-Type: image/png');
  imagePng($image);
  imageDestroy($image);
  
?>

Listing 1.9: Ausgabe eines Textes mit einer TTF-Schrift

Ausgabe des Listing 1.9
Abbildung 1.10: Ausgabe des Listing 1.9

Die Ausgabe in Abbildung 1.11 wurde erzeugt, indem der Winkel der Schrift auf 90 gesetzt wurde.

imageTTFText($image,50,90,25,25,$black,'verdana.ttf','Verdana');

Um 90 Grad gedrehter Text
Abbildung 1.11: Um 90 Grad gedrehter Text

Dieser Effekt lässt sich auch auf die interne Schrift der GD-Library anwenden. Die Funktion imageStringUp zeichnet einen String dann vertikal.

int imageStringUp(int image, int font, int x, int y, string text, int color)

Bei der Angabe der Koordinaten x und y müssen Sie beachten, dass an den angegebenen Werten die linke untere Ecke der Zeichenkette beginnt (aus vertikaler Sicht betrachtet). Das folgende Listing ist ein Beispiel für diese Funktion:

<?php

  $image = imageCreate(50,120);
  $text = 'vert. Text';
  
  $bg = imageColorAllocate($image,255,255,255);
  $black = imageColorAllocate($image,0,0,0);
  
  $str_x = 10 + imageFontWidth(5) * strLen($text);
  imageStringUp($image,5,10,$str_x,$text,$black);
  
  header('Content-Type: image/png');
  imagePng($image);
  imageDestroy($image);
  
?>

Listing 1.10: Ausgabe einer Zeichenkette in vertikaler Richtung

Damit der String in der Grafik vollkommen zu sehen ist, wurde die y-Koordinate abhängig von der gewählten Schrift und Länge der Zeichenkette berechnet.

Ausgabe des Listing 1.10 im Browser
Abbildung 1.12: Ausgabe des Listing 1.10 im Browser

# Thumbnails erzeugen

Häufig wird die GD-Library auf Webseiten verwendet, um so genannte Thumbnails zu erzeugen. Dies sind Miniaturversionen von Bildern, die als Vorschau verwendet werden. Bei Galerien mit großen und ladeintensiven Bildern bieten sie dem Benutzer eine Orientierungshilfe. Er kann auf die Vorschau klicken und erhält die große Version. Die einfachste Möglichkeit wäre nun, in einem HTML-Dokument die Größe der Bilder auf 100 Pixel zu setzen, was aber dazu führt, dass alle Bilder zuvor in der Originalgröße geladen werden müssen. Die zu ladende Datenmenge verringert sich dadurch aber nicht. Besitzer eines Analogmodems werden Ihnen alles andere als dankbar sein, auch wenn die Großansichten der Bilder später umso schneller dargestellt werden. Die Geduld, die der User zuvor aufbringen muss, steht dazu in keinerlei Verhältnis, wenn er vorab mehrere Minuten warten muss, ehe die Bilder vollständig heruntergeladen sind.

Sehr viel besser wäre es, die Bilder noch auf dem Server zu verkleinern und so mit einer geringeren Größe an den Benutzer zu senden. Mit der GD-Library ist das ohne Probleme möglich.

Die Vorgehensweise ist dabei sehr einfach. Zuerst wird das Originalbild geöffnet und anschließend in eine neue Grafik kopiert. Beim Kopieren wird das Originalbild verkleinert. Das verkleinerte Bild wird dann an den Browser gesendet.

Die wichtigste Funktion zum Erzeugen von Thumbnails ist imageCopyResized. Sie kopiert das Originalbild und verkleinert es gleichzeitig.

int imageCopyResized(int dst_im, int src_im, int dst_x, int dst_y, int src_x, int src_y, int dst_w, int dst_h, int src_w, int src_h)

Aufgrund der Vielzahl an Parametern werde ich zunächst Klarheit schaffen. Die Abkürzung dst steht für »destination«, ins Deutsche übersetzt bedeutet dies »Ziel«. src steht für »source« und bedeutet »Quelle«. Diese beiden Abkürzungen werden bei den Parametern verwendet, um unterscheiden zu können, welcher Parameter sich auf welches Bild bezieht.

Die beiden Parameter dst_im und src_im stehen jeweils für die beiden Grafiken. Der Zeiger auf die Originalgrafik wird als Parameter src_im übergeben und der Parameter auf die neue Grafik als Parameter dst_im.

Den zu kopierenden Original-Bildausschnitt geben Sie mit den Parametern src_x, src_y, src_w und src_h an. Die Form dieses Bildausschnitts ist rechteckig. Die linke obere Ecke des Ausschnitts wird durch src_x und src_y definiert. Die Ausmaße des Ausschnitts, also die Breite und die Höhe, werden mit den Parametern src_w und src_h angegeben. Äquivalent dazu geben die Parameter dst_x, dst_y, dst_w und dst_h die Position und Größe des Ausschnitts in der Zielgrafik an. Je nachdem, ob der Zielbildausschnitt kleiner oder größer ist, wird der Originalausschnitt entweder gestaucht oder gestreckt.

imageCopyResized($image_dst,$image_src,10,10,50,50,100,50,50,25);

Dieser Beispielaufruf würde aus der Originalgrafik einen Ausschnitt von 50 × 25 Pixel kopieren, der an der Position (50,50) beginnt. Er wird dann in der Größe 100 × 25 an der Position (10,10) in die neue Grafik eingefügt. Der Ausschnitt wird also vergrößert.

<?php

  /* Variablen setzen */
  $src_file = $_GET['file'];
  $max_w = 100;
  $max_h = 100;
  $dst_w = 0;
  $dst_h = 0;
  
  /* Dateityp ermitteln und öffnen */
  $pos = strrpos($src_file,'.') + 1;
  $file_ext = substr($file,$pos);
  switch(strToLower($file_ext))
  {
    case 'png' :
      $image_src = imageCreateFromPng($src_file);
      break;
    case 'jpg':
    case 'jpeg':
      $image_src = imageCreateFromJPEG($src_file);
      break;
  }
  
  /* Bildgröße ermitteln */
  $src_w = imagesx($image_src);
  $src_h = imagesy($image_src);
  
  /* Abmessungen festlegen */
  if($src_w > $src_h)
  {
    $dst_w = $max_w;
    $dst_h = $max_h / ($src_w / $src_h);
  }
  elseif($src_w < $src_h)
  {
    $dst_h = $max_h;
    $dst_w = $max_w / ($src_h / $src_w);
  }
  else
  {
    $dst_h = $max_h;
    $dst_w = $max_w;
  }
  
  /* Bild kopieren und ausgeben */
  $image_dst = imageCreateTrueColor($dst_w,$dst_h);
  imageCopyResized($image_dst,$image_src,0,0,0,0,$dst_w,$dst_h,$src_w,$src_h);
  header('Content-Type: image/png');
  imagePng($image_dst);
  imageDestroy($image_src);
  imageDestroy($image_dst);
  
?>

Listing 1.11: PHP-Script zum Erzeugen von Thumbnails

Das Listing 1.11 ist ein Beispiel dafür, wie die Funktion imageCopyResized in einem Script-Kontext verwendet werden kann, um Thumbnails zu erzeugen. Zu Beginn werden erst einmal vier Variablen definiert. $src_file erhält den in der URL als file übergebenen Dateinamen der Grafik. Die Variable $max_px definiert die maximale Breite und Höhe des Thumbnails. Die 100 Pixel sollten als Vorschau für ein Bild vollkommen ausreichend sein. Anschließend werden noch die Variablen $dst_w und $dst_h definiert und jeweils der Wert 0 zugewiesen. Diese Variablen erhalten später die errechneten Abmessungen des Thumbnails.

Im nächsten Teil des Scripts wird versucht, anhand des Dateinamens den Typ der Originalgrafik zu ermitteln, um ein Höchstmaß an Flexibilität bei den verwendbaren Grafiken zu ermöglichen. Die Funktion strrpos liefert das letzte Vorkommen eines Zeichens innerhalb einer Zeichenkette. Dies wird verwendet, um die Endung der Datei ermitteln zu können. Da der Punkt dabei nicht erforderlich ist, wird 1 zu $pos hinzuaddiert. Danach liefert die Funktion substr von der angegebenen Position $pos bis zum Ende alle Zeichen zurück. In der anschließenden switch-Anweisung wird dann der Wert der extrahierten Zeichenkette unterschieden Je nachdem, welche Dateiendung es ist, wird entweder die Funktion imageCreateFromPng oder imageCreateFromJPEG zum Öffnen der Originalgrafik verwendet. Der Zeiger auf die Grafik wird in der Variablen $image_src gespeichert.

Nachdem die Originalgrafik geöffnet worden ist, wird ihre Breite in der Variablen $src_w und ihre Höhe in $src_h gespeichert.

Das nun folgende if-Konstrukt bewirkt, dass die Proportionen der Grafik auch als Thumbnail beibehalten werden können. Ist die Originalgrafik breiter als hoch, wird die Zielgrafik auf die maximale Breite ($max_px) gesetzt. Die Höhe der Zielgrafik errechnet sich dann aus dem Verhältnis von Breite zu Höhe der Originalgrafik. Ist die Quellgrafik höher als breit, wird der Zielgrafik die maximale Höhe zugewiesen und die Breite anhand des Verhältnisses von Breite zu Höhe der Originalgrafik gesetzt. Sollte die Quellgrafik so breit wie hoch sein, wird der Zielgrafik die maximale Breite und maximale Höhe zugewiesen.

Nun wird die Zielgrafik erstellt. Da sowohl PNG- als auch JPG-Grafiken über mehr als 256 Farben verfügen, wird auch der Zielgrafik eine TrueColor-Palette zugewiesen, indem sie mit imageCreateTrueColor erstellt wird. Als Größe werden die in $dst_w und $dst_h errechneten Werte verwendet. Anschließend wird die vollständige Originalgrafik kopiert und in der Größe an die Zielgrafik angepasst. Zum Schluss folgt die Ausgabe im Browser und die Freigabe der belegten Ressourcen.

Beachten Sie dabei, dass die Zielgrafik nicht von der Originalgrafik abhängig ist. Ob Sie nun JPG oder PNG verwenden, ist egal. Ich habe mich an dieser Stelle für PNG entschieden. Wenn Sie jedoch JPG verwenden, haben Sie die Möglichkeit, zusätzlich noch die Qualität der Grafik festzulegen und somit zusätzlich, wenn auch nur einige wenige, Bytes einzusparen.

In einem HTML-Dokument könnte das Script aus Listing 1.11 dann folgendermaßen verwendet werden:

<img src="thumbs.php?file=phpbig.png">

Natürlich wird hier davon ausgegangen, dass das Listing unter dem Namen thumbs.php gespeichert wurde. Die Abbildung 1.13 ist ein Screenshot eines HTML-Dokuments, das einmal die Grafik phpbig.png in der Originalgröße und einmal in der verkleinerten Version darstellt. Die verkleinerte Version wurde übrigens mit einem img-Element und PHP-Scripts als Quelle eingebunden.

Thumbnails mit PHP
Abbildung 1.13: Thumbnails mit PHP

# Anwendungsbeispiele

Natürlich kann die GD-Library in Verbindung mit PHP auch zum Zeichnen von Diagrammen oder Ähnlichem verwendet werden. Dies gestaltet sich in den meisten Fällen jedoch etwas umständlich. Denn häufig müssen viele verschiedene Parameter berechnet und Abhängigkeiten für die Ausgabe in der Grafik gelöst werden.

# Kreisdiagramm

Die meisten Parameter müssen bei einem Balken- oder gar Säulendiagramm berechnet werden (wie z. B. die Eckpunkte, Abstände und Ähnliches), die wenigsten bei einem Kreisdiagramm. Dort ändert sich nämlich immer nur der Start- und Endwinkel.

Da die Funktion imageArc für ein Kreisdiagramm nicht nutzbar ist (es zeichnet nur die Außenlinie), muss die Funktion imageFilledArc verwendet werden. Diese Funktion zeichnet ein gefülltes Kreisstück.

int imageFilledArc(int image, int x, int y, int width, int height, int ang_start, int ang_end, int color, int style)

Als ersten Parameter erwartet die Funktion den Zeiger auf eine Grafik, der als image übergeben wird, gefolgt vom Mittelpunkt des Kreises als Parameter x und y. Die Parameter width und height definieren die Breite und Höhe des Kreises, von dem das Kreisstück gezeichnet werden soll. ang_start gibt den Startwinkel und ang_end den Endwinkel des Kreisstücks an. Die Farbe des Segments wird als Parameter color übergeben. Der letzte Parameter definiert den Stil des Kreissektors. Eine oder mehrere der folgenden Konstanten können eingesetzt werden.

  • IMG_ARC_PIE
    Verbindet den Start- und Endwinkel als Bogen.
  • IMG_ARC_CHORD
    Verbindet den Start- und Endwinkel mit einer Geraden.
  • IMG_ARC_NOFILL
    Verhindert, dass das Kreisstück mit Farbe gefüllt wird.
  • IMG_ARC_EDGED
    In Verbindung mit IMG_ARC_NOFILL werden der Start- und Endwinkel mit dem Mittelpunkt verbunden.

Die einzelnen Konstanten lassen sich mit einem bitweisen OR verbinden.

imageFilledArc($image, 100, 100, 75, 75, 90, 180, $black, IMG_ARC_PIE OR IMG_ARC_NOFILL);

Hier wird ein Kreissektor mit dem Mittelpunkt (100,100) und einer Breite und Höhe von 75 Pixel gezeichnet. Der Startwinkel ist 90, der Endwinkel 180 und die Farbe $black. Als Stil wurde festgelegt, dass das Kreisdiagramm einen Bogen aufweisen soll und nicht mit der Farbe gefüllt wird, sondern dass nur eine Außenlinie gezeichnet werden soll.

Das Script zum Zeichnen des Diagramms folgt nun in Listing 1.12.

<?php

  /* Variablen vordefinieren */
  $poll_file = $_GET['pollfile'];
  $poll_title = '';
  $poll_values = Array();
  $poll_captions = Array();
  $poll_sum = 0;
  
  /* Daten laden */
  $pf = fopen($poll_file,"r");
  if($pf)
  {
    $poll_title       = trim(fgets($pf));
    $poll_captions[0] = trim(fgets($pf));
    $poll_values[0]   = trim(fgets($pf));
    $poll_captions[1] = trim(fgets($pf));
    $poll_values[1]   = trim(fgets($pf));
    $poll_captions[2] = trim(fgets($pf));
    $poll_values[2]   = trim(fgets($pf));
    $poll_captions[3] = trim(fgets($pf));
    $poll_values[3]   = trim(fgets($pf));
    fclose($pf);
  }  
  
  /* Gesamtsumme bilden */
  for($i=0; $i<count($poll_values); $i++)
  {
    $poll_sum += $poll_values[$i];
  }
  
  /* Grafik erzeugen */
  $image = imageCreate(400,300);
  $bg = imageColorAllocate($image,255,255,255);
  $black = imageColorAllocate($image,0,0,0);
  $poll_col[0] = imageColorAllocate($image,225,0,0);
  $poll_col[1] = imageColorAllocate($image,0,225,0);
  $poll_col[2] = imageColorAllocate($image,0,0,225);
  $poll_col[3] = imageColorAllocate($image,128,128,128);
  
  /* Start- und Endwinkel setzen */
  $ang_start = 270;
  $ang_end = 270;

  /* Teilst�cke zeichnen */
  for($i=0; $i<count($poll_values); $i++)
  {
    /* Winkel berechnen */
    $ang_start = $ang_end;
    $ang_part = $poll_values[$i] / $poll_sum * 360;
    $ang_end = $ang_start + $ang_part;
    
    /* Kreisbogen zeichnen */
    imageFilledArc($image,125,175,225,225,$ang_start,$ang_end,$poll_col[$i],IMG_ARC_PIE);
  }
  
  /* Texte ausgeben */
  imageString($image,3,10,20,$poll_title,$black);
  $pos_sy = 100;
  for($i=0; $i<count($poll_captions); $i++)
  {
    $perc = round($poll_values[$i] / $poll_sum * 100);
    $output = $poll_captions[$i].' '.$perc.'%';
    imageString($image,2,275,$pos_sy,$output,$poll_col[$i]);
    $pos_sy += 20;
  }
  
  /* Grafik ausgeben */
  header('Content-Type: image/png');
  imagePng($image);
  imageDestroy($image);
  
?>

Listing 1.12: PHP-Script, das ein Kreisdiagramm zeichnet

Auf den ersten Blick mag dieses Listing ein wenig kompliziert aussehen. Das trifft jedoch nur zum Teil zu. Sehen Sie sich das Script einmal genauer an, und Sie werden feststellen, dass viele Dinge auf den zweiten Blick schon verständlicher werden.

Gleich zu Beginn wird die Variable $poll_file definiert. Der Wert, der ihr zugewiesen wird, ist der Wert, der in der URI übergeben wurde. Der Aufruf des Scripts sollte also folgendermaßen aussehen:

list1.12.php?pollfile=poll1.txt

Die restlichen Variablen, die danach definiert werden, werden mit Oder auch nicht, siehe $poll_values und $poll_captions.verschiedenen Startwerten initialisiert.

Im folgenden Abschnitt wird nun die in der URI übergebene Datei geöffnet und zeilenweise ausgelesen. Der Aufbau der Datei könnte bzw. müsste laut Listing 1.12 folgendermaßen aussehen:

Welches Betriebssystem verwenden Sie am häufigsten?
Windows
75
Linux
65
MacOS
55
Anderes
45

In der ersten Zeile steht die Frage. Anschließend folgen dann in je zwei Zeilen der Titel der Auswahlmöglichkeit und der Wert. Basierend auf diesem Schema wird die Datei dann auch eingelesen. Die einzelnen Zeilen werden mit der Funktion fgets eingelesen und unterschiedlichen Variablen zugewiesen. Die Zeile 1 wird an die Variable $poll_title übergeben. Die Zeilen 2, 4, 6 und 8 werden an das Array $poll_captions übergeben und die Zeilen 3, 5, 7 und 9 an das Array $poll_values. Da fgets auch mögliche Whitespace-Zeichen (also Zeilenvorschübe und ‑umbrüche) zurückgibt, werden diese mit der Funktion trim herausgefiltert.

In einer for-Schleife werden nun alle Werte des Arrays $poll_values addiert und der Variablen $poll_sum zugewiesen, da die Summe der Werte später für die Berechnung der Kreissektoren und Prozentwerte benötigt wird.

Im nächsten Schritt wird dann die Grafik mit 400 Pixel Breite und 300 Pixel Höhe erzeugt, und es werden sechs Farben definiert. $bg wird als Hintergrundfarbe und $black zur Ausgabe der Überschrift verwendet. Die anderen vier Farben werden dem Array $poll_col zugewiesen und für die Kreissektoren genutzt.

Anschließend werden der Start- und der Endwinkel definiert. Als Wert wurde für beide 270 angegeben. Dies bedeutet, dass das erste Teilstück oben beginnt und das letzte oben endet.

In der nun folgenden Schleife werden die einzelnen Kreissektoren gezeichnet. Dabei arbeitet die Schleife alle Elemente des Arrays $poll_values einzeln ab. Zu Beginn jedes Durchlaufs wird der Startwinkel auf den letzten Endwinkel gesetzt, damit die einzelnen Kreissektoren auch aneinander hängen. Dann wird in $ang_part der Winkel des aktuellen Kreissektors berechnet. Diese Berechnung erfolgt durch einen einfachen Dreisatz, da die Summe der Werte dem Winkel 360 und der aktuelle Wert dem Winkel x entspricht.

summe = 360  
aktueller wert = x

Daraus ergibt sich folgende Formel (in Programmierschreibweise):

x = summe / aktueller wert × 360.

Der neue Endwinkel entspricht dann dem Startwinkel + x (bzw. $ang_part).

Nun muss mit imageFilledArc lediglich der Kreissektor gezeichnet werden. Als Mittelpunkt des Kreises wurde der Punkt (125,175) gewählt, und der Durchmesser des Kreises wurde auf 225 Pixel festgelegt (einzeln als Breite und Höhe angegeben). Damit auch ein vernünftiger Kreissektor gezeichnet wird, wird als Stil IMG_ARC_PIE verwendet.

Im nächsten Schritt werden die Textausgaben erzeugt. Dabei werden sowohl der Titel der Umfrage als auch die Bezeichnungen der einzelnen Kreissektoren mit den dazugehörigen Prozentwerten in den entsprechenden Farben ausgegeben. Die Prozentwerte werden mit der gleichen Formel wie die Winkel berechnet – nur dass die Summe der Werte 100  % entspricht.

Zum Schluss wird die Grafik an den Browser gesendet und der belegte Speicher wieder freigegeben. Im Browser könnte dies dann wie in Abbildung 1.14 gezeigt aussehen.

Ausgabe des Listing 1.12 im Browser
Abbildung 1.14: Ausgabe des Listing 1.12 im Browser

Das Script aus Listing 1.12 ist jedoch noch nicht ganz perfekt. So müsste z. B. bei der Berechnung der Winkel zuvor überprüft werden, ob die Gesamtsumme 0 ist, ansonsten quittiert PHP den Versuch mit der Fehlermeldung: Division durch 0. Auch die errechneten Prozentwerte müssen nicht immer 100  % ergeben. Dies kann um 1  % variieren, da die Rundung der Werte nicht unbedingt korrekt erfolgen muss.

# Zeichensalat

Das nun folgende Beispiel ist mehr eine Spielerei als ein wirkliches Anwendungsbeispiel, verdeutlicht aber die Funktionsweise von imageColorAt und imageColorsForIndex. Die Funktion imageColorAt ermittelt den Farbindex eines Pixels innerhalb einer Grafik.

int imageColorAt(int image, int x, int y)

Als erster Parameter muss der Zeiger auf die Grafik übergeben werden und als Parameter x und y die Koordinaten des Pixels, dessen Farbwert ermittelt werden soll. Die Funktion gibt dann den entsprechenden Index zurück.

Diesen Index können Sie an die Funktion imageColorsForIndex übergeben und erhalten dann die entsprechenden Farbwerte.

array imageColorsForIndex(int image, int color_index)

Die Funktion gibt ein assoziatives Array mit den Farbanteilen Rot, Grün und Blau zurück. Die Schlüssel der einzelnen Elemente lauten red für Rot, green für Grün und blue für Blau.

Das folgende Listing verwendet diese beiden Funktionen, um ein Bild als Zeichensalat auszugeben.

<?php
  /* Variablen definieren */
  $img_file = $_GET['imgfile'];
  $colormode = $_GET['colmode'];
  $img_w = 0;
  $img_h = 0;
  
  /* Dateityp ermitteln und öffnen */
  $pos = strrpos($img_file,'.') + 1;
  $file_ext = substr($img_file,$pos);
  switch(strToLower($file_ext))
  {
    case 'png' :
      $image = imageCreateFromPng($img_file);
      break;
    case 'jpg':
    case 'jpeg':
      $image = imageCreateFromJPEG($img_file);
      break;
  }
  
  /* Grafikabmessungen ermitteln */
  $img_w = imagesx($image);
  $img_h = imagesy($image);
    
  /* Zeichenausgabe im Browser */
  echo "<html><head><title>$img_file als Zeichensalat</title></head>";
  echo '<body style="background-color:#000000"><pre style="font-size:4px;">';
  for($i=0; $i<$img_h; $i+=2)
  {
    for($j=0; $j<$img_w; $j++)
    {
      $color = imageColorAt($image,$j,$i);
      $rgb = imageColorsForIndex($image,$color);
      switch($colormode)
      {
        case 'normal':
          printf('<font color="#%02x%02x%02x">@</font>',$rgb['red'],$rgb['green'],$rgb['blue']);
          break;
        case 'reverted':
          printf('<font color="#%02x%02x%02x">@</font>',$rgb['blue'],$rgb['green'],$rgb['red']);
          break;
        case 'inverted':
          printf('<font color="#%02x%02x%02x">@</font>',255-$rgb['red'],255-$rgb['green'],255-$rgb['blue']);
          break;
        default:
          printf('<font color="#%02x%02x%02x">@</font>',$rgb['red'],$rgb['green'],$rgb['blue']);
          break;
      }
    }
    echo "\n";
  }
  imageDestroy($image);
  echo '</pre></body></html>';
?>

Listing 1.13: PHP-Script, das eine Grafik als Zeichensalat ausgibt

Das Script erwartet beim Aufruf zwei Parameter: imgfile und colmode. Diese beiden werden zu Beginn des Scripts den beiden Variablen $img_file und $colormode zugewiesen. Anschließend wird der Typ der angegebenen Grafik anhand der Dateiendung ermittelt und mit der entsprechenden Funktion geöffnet (dies kennen Sie bereits aus Abschnitt 1.6, Thumbnails erzeugen).

Im nächsten Schritt werden die Abmessungen der Grafik festgestellt und in den Variablen $img_w und $img_h gespeichert.

Nun folgt die eigentliche Ausgabe der Grafik im Browser. Zuerst wird ein normaler Beginn eines HTML-Dokuments ausgegeben, der mit dem Start-Tag eines pre-Elements endet. Nun folgen zwei ineinander verschachtelte for-Schleifen. Die erste Schleife wird durchlaufen, solange $i kleiner als $img_h ist. Die Inkrementierung erfolgt dabei in zwei Schritten. Die zweite, innere Schleife wird durchlaufen, solange $j kleiner als $img_w ist.

Innerhalb der Schleifen ermittelt die Funktion imageColorAt den Palettenindex der Farbe des Pixels an Position ($j,$i). In der nächsten Zeile ermittelt dann imageColorsForIndex die einzelnen Farbanteile des Palettenindex. In der switch-Anweisung wird überprüft, ob $colormode den Wert normal, reverted oder inverted besitzt. Je nachdem, welcher Modus gesetzt wurde, wird ein anderer Anweisungsblock der switch-Anweisung ausgeführt. Alle geben jedoch ein font-Element im Browser aus, das als Wert für das color-Attribut die drei ermittelten Farbanteile und ein @-Zeichen im Gültigkeitsbereich erhält.

  • normal
    Die Farben werden ganz normal in hexadezimaler Formatierung in der Reihenfolge RRGGBB ausgegeben.
  • reverted
    Die Farben werden in hexadezimaler Formatierung, aber in der Reihenfolge BBGGRR ausgegeben.
  • inverted
    Die Farbwerte werden von 255 abgezogen und in der Reihenfolge RRGGBB in hexadezimaler Formatierung ausgegeben.

Wurde kein Modus für die Farbe gesetzt, wird der Modus normal verwendet. Wie das Ganze im Modus reverted im Browser aussieht, sehen Sie in Abbildung 1.15.

Sollten Sie sich nun fragen, warum ich das Ganze als Zeichensalat bezeichne, sollten Sie sich einfach den Quelltext des ausgegebenen HTML-Dokuments ansehen. Sie werden dann verstehen, was ich meine. Bei der Ausgabe der Grafik phpbig.png umfasst das HTML-Dokument exakt 495.148 Zeichen, was in etwa 483 kB sind. Einen wirklich sinnvollen Einsatz gibt es für dieses Script also nicht, es ist jedoch eine recht nette Spielerei.

Im Internet finden Sie unter der Adresse http://www.sebastian-r.de/asciiart/ ein weiteres Beispiel. Abhängig von den einzelnen Farbwerten werden dort zusätzlich noch unterschiedliche Zeichen verwendet.

Ausgabe des Listing 1.13 durch den Aufruf von list1.13.php?imgfile=phpbig.png&colmode=reverted
Abbildung 1.15: Ausgabe des Listing 1.13 durch den Aufruf von list1.13.php?imgfile=phpbig.png&colmode=reverted

# Zusammenfassung

  • Die GD-Library stellt in PHP verschiedene Funktionen zur Grafikmanipulation zur Verfügung.
  • Eine neue Grafik wird mit der Funktion imageCreate oder imageCreateTrueColor erzeugt.
  • Eine vorhandene Grafik kann mit imageCreateFromPng oder imageCreateFromJPEG geöffnet werden.
  • Zeichenketten können mit der Funktion imageString ausgegeben werden.
  • Farben werden durch imageColorAllocate oder imageColorResolveAlpha definiert.
  • Formen wie Linien, Rechtecke, Kreise oder Kreisbögen werden mit den Funktionen imageLine, imageDashedLine, imageRectangle, imageFilledRectangle, imageEllipse, imageFilledEllipse, imageArc und imageFilledArc in die Grafik gezeichnet.
  • Mit der Funktion imagePng oder imageJPEG wird eine erzeugte Grafik an den Browser gesendet, und mit imageDestroy wird der belegte Speicher einer Grafik wieder freigegeben.

# Fragen und Übungen

  1. Welchen Unterschied weisen Grafiken auf, die mit imageCreate oder imageCreateTrueColor erzeugt wurden?
  2. Welche Funktion müssen Sie verwenden, um eine (teil)transparente Farbe zu definieren? Welche Voraussetzungen müssen erfüllt sein?
  3. Was bewirkt die Funktion imageCopyResized?
  4. Finden Sie eine Möglichkeit, wie aus einem Farbbild, ohne eine GD-Funktion zu verwenden, ein Graustufenbild werden kann.
  5. Versuchen Sie Ihre Idee der Farbe-Graufstufen-Umwandlung umzusetzen, indem Sie ein Script schreiben, das eine Grafik öffnet und in Graustufen umgewandelt im Browser ausgibt.