decocode decocode deco    

Farbverläufe mit PHP #

Zur Veranschaulichung der Grafikfunktionen von PHP sei hier ein Skript vorgestellt, mit dem man Grafiken mit beliebigen Farbverläufen herstellen kann, die sich z. B. als Hintergrundgrafik für bestimmte Seitenelemente verwenden lassen.

Zunächst erzeugt das Skript (Dateiname index.php) ein einfaches HTML-Dokument, das die Grafik als CSS-Eigenschaft referenziert (Zeile 13):

Quelltext auswählen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php
  if (!$_GET['gradient']) {
    header("content-type: text/html; charset=utf-8");
    echo "<!DOCTYPE HTML>
<html lang='de'>
  <head>
    <title>Farbverläufe mit PHP</title>
    <meta charset='UTF-8'>
    <meta name='robots' content='noindex, nofollow'>
    <style type='text/css'>
      * { margin:0; padding:0; }
      body { background-color:#007acc; }
      #image { background:#ffffff url(./index.php?gradient=300,200,b036b0) scroll; width:300px; height:200px; margin:200px auto; }
    </style>
  </head>
  <body>
    <div id='image'></div>
  </body>
</html>";
  } else {
    function rgb($im, $hex) {
      return imagecolorallocate($im, hexdec(substr($hex, 0, 2)), hexdec(substr($hex, 2, 2)), hexdec(substr($hex, 4, 2)));
    }
    $p = explode(",", $_GET['gradient']);
    $im = @imagecreatetruecolor($p[0], $p[1]) or die("Cannot initialize new GD image stream!");
    imagefill($im, 0, 0, rgb($im, $p[2]));
    header("content-type: image/png");
    imagepng($im);
    imagedestroy($im);
  }
?>

Über die Query-Variable gradient wird der Teil der Skriptes ausgeführt, der das Bild erzeugt. Dieser Abschnitt (ab Zeile 21) enthält gegenwärtig nur den elementaren Code für die Ausgabe einer einfachen Grafik. Im weiteren Verlauf wird nur noch dieser Abschnitt betrachtet.

Als erstes wird in Zeile 21 die Funktion rgb() definiert, mit der die übliche hexadezimale Angabe von Farben in HTML in dezimale Werte umgerechnet wird. In Zeile 24 werden die Werte der Variable gradient in ein Array geschrieben. In Zeile 25 wird das Bild mit der Größe $p[0] (Breite) und $p[1] (Höhe) initialisiert. Anschließend wird die Grafik mit der Hintergrundfarbe $p[2] gefüllt. In Zeile 27 wird der Content-Typ der Grafik festgelegt (hier PNG). In Zeile 28 wird die Grafik erzeugt und in Zeile 29 schließlich beendet.

PHP Grafik-Beispiel

Bisher wurden in der Variable gradient lediglich die Werte für Breite, Höhe und Hintergrundfarbe der Grafik übergeben. Für einen Farbverlauf benötigt man aber noch weitere Angaben: Richtung, Beginn, Weite, Anfangsfarbe und Endfarbe. Man beachte, dass die Koordinaten in PHP-Grafiken bei 0 in der linken, oberen Ecke beginnen. Daher wird die Werteliste in Zeile 13 in folgender Weise geändert:

gradient=300,200,b036b0,h,50,200,990000,ff9900

Das Skript wird ebenfalls erweitert:

Quelltext auswählen
1
2
3
4
5
6
7
8
9
10
11
12
    function rgb($im, $hex) {
      return imagecolorallocate($im, hexdec(substr($hex, 0, 2)), hexdec(substr($hex, 2, 2)), hexdec(substr($hex, 4, 2)));
    }
    $p = explode(",", $_GET['gradient']);
    $im = @imagecreatetruecolor($p[0], $p[1]) or die("Cannot initialize new GD image stream!");
    imagefill($im, 0, 0, rgb($im, $p[2]));
    for ($s = $p[4]; $s < ($p[4] + $p[5]); $s++) {
      imageline($im, $s, 0, $s, ($p[1] - 1), rgb($im, $p[6]));
    }
    header("content-type: image/png");
    imagepng($im);
    imagedestroy($im);

In Zeile 7 wird eine Schleife definiert, die den Bereich des Farbverlaufs abdeckt, beginnend mit $p[4] und mit einer Weite von $p[5]. In Zeile 8 wird nun eine Linie über die gesamte Bildhöhe auf der x-Achse an Position $s mit der Farbe $p[6] gezeichnet.

PHP Grafik-Beispiel

Das Ergebnis ist zwar noch kein Farbverlauf, aber immerhin ein farbiger Balken an der richtigen Stelle. Vorher gilt es aber noch die Richtungsangabe zu verwerten. Bislang wird die Angabe ignoriert und der Balken grundsätzlich in horizontaler Richtung aufgebaut, entsprechend $p[3]="h". Wenn gilt, $p[3]=="v", dann soll der Balken in vertikaler Richtung aufgebaut werden:

Quelltext auswählen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    function rgb($im, $hex) {
      return imagecolorallocate($im, hexdec(substr($hex, 0, 2)), hexdec(substr($hex, 2, 2)), hexdec(substr($hex, 4, 2)));
    }
    $p = explode(",", $_GET['gradient']);
    $im = @imagecreatetruecolor($p[0], $p[1]) or die("Cannot initialize new GD image stream!");
    imagefill($im, 0, 0, rgb($im, $p[2]));
    for ($s = $p[4]; $s < ($p[4] + $p[5]); $s++) {
      if ($p[3] == "h") {
        $x1 = $s;
        $y1 = 0;
        $x2 = $s;
        $y2 = $p[1] - 1;
      } elseif ($p[3] == "v") {
        $x1 = 0;
        $y1 = $s;
        $x2 = $p[0] - 1;
        $y2 = $s;
      }
      imageline($im, $x1, $y1, $x2, $y2, rgb($im, $p[6]));
    }
    header("content-type: image/png");
    imagepng($im);
    imagedestroy($im);

PHP Grafik-Beispiel

Jetzt wird es interessant, denn jetzt geht es an den eigentlichen Farbverlauf. Um einen Algorithmus zu schaffen, der die farblichen Abstufungen zwischen der Anfangs- und der Endfarbe berechnet, ist es hilfreich, wenn man versteht, wie Farben am Bildschirm realisiert werden. Die Farbdarstellung eines Monitors geschieht nach der additiven Farbsynthese, wonach jede Farbe aus den drei Grundfarben Rot, Grün und Blau zusammengesetzt wird. Die Farbangaben in HTML erfolgen üblicherweise in sechsstelligen hexadezimalen Werten, wobei jeweils zwei Stellen eine der Grundfarben repräsentieren. Jede Grundfarbe kann daher in 256 Schattierungen auftreten (00 bis FF). Die Angabe #0066FF bedeutet daher dezimal: 0 Anteile Rot, 102 Anteile Grün und 255 Anteile Blau. Für einen Farbverlauf muss man nun lediglich die anteilsmäßige Änderung der einzelnen Farbkomponenten ermitteln und diese zu einer neuen Farbangabe zusammenführen.

Quelltext auswählen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
    function rgb($im, $hex) {
      return imagecolorallocate($im, hexdec(substr($hex, 0, 2)), hexdec(substr($hex, 2, 2)), hexdec(substr($hex, 4, 2)));
    }
    $p = explode(",", $_GET['gradient']);
    $im = @imagecreatetruecolor($p[0], $p[1]) or die("Cannot initialize new GD image stream!");
    imagefill($im, 0, 0, rgb($im, $p[2]));
    $r1 = hexdec(substr($p[6], 0, 2));
    $g1 = hexdec(substr($p[6], 2, 2));
    $b1 = hexdec(substr($p[6], 4, 2));
    $r2 = hexdec(substr($p[7], 0, 2));
    $g2 = hexdec(substr($p[7], 2, 2));
    $b2 = hexdec(substr($p[7], 4, 2));
    $dr = ($r2 - $r1) / $p[5];
    $dg = ($g2 - $g1) / $p[5];
    $db = ($b2 - $b1) / $p[5];
    for ($s = $p[4]; $s < ($p[4] + $p[5]); $s++) {
      if ($p[3] == "h") {
        $x1 = $s;
        $y1 = 0;
        $x2 = $s;
        $y2 = $p[1] - 1;
      } elseif ($p[3] == "v") {
        $x1 = 0;
        $y1 = $s;
        $x2 = $p[0] - 1;
        $y2 = $s;
      }
      $step = $s - $p[4];
      $r = str_pad(dechex(round($r1 + $dr * $step)), 2, "0", STR_PAD_LEFT);
      $g = str_pad(dechex(round($g1 + $dg * $step)), 2, "0", STR_PAD_LEFT);
      $b = str_pad(dechex(round($b1 + $db * $step)), 2, "0", STR_PAD_LEFT);
      imageline($im, $x1, $y1, $x2, $y2, rgb($im, $r.$g.$b));
    }
    header("content-type: image/png");
    imagepng($im);
    imagedestroy($im);

In den Zeilen 7 bis 12 werden die Dezimalwerte der Farbkomponenten der Anfangs- und Endfarbe ermittelt. In den Zeilen 13 bis 15 werden die jeweiligen Abstufungen errechnet. In den Zeilen 29 bis 31 werden die neuen Farbwerte der Komponenten für die aktuelle Linie ermittelt, und in Zeile 32 wird die Farbangabe aus $r.$g.$b zusammengesetzt.

PHP Grafik-Beispiel

Möchte man mehrere Farbverläufe in einer Grafik realisieren, so ist dies ebenfalls möglich. Dazu wird an die Werteliste der Variable gradient einfach eine weitere Werteliste durch Semikolon getrennt angehängt. Zum Beispiel:

gradient=300,200,b036b0,h,50,200,990000,ff9900;x,x,x,v,50,100,008400,be1b5f

Grundsätzlich ist so eine beliebige Zahl von Farbverläufen innerhalb einer Grafik möglich. Die Angaben für Breite, Höhe und Hintergrundfarbe werden für die weiteren Farbverläufe ignoriert und können daher beliebige Werte enthalten.

Das Skript wird folgendermaßen angepasst:

Quelltext auswählen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
    function rgb($im, $hex) {
      return imagecolorallocate($im, hexdec(substr($hex, 0, 2)), hexdec(substr($hex, 2, 2)), hexdec(substr($hex, 4, 2)));
    }
    $gr = explode(";", $_GET['gradient']);
    $p = explode(",", $gr[0]);
    $width = $p[0]; $height = $p[1];
    $im = @imagecreatetruecolor($width, $height) or die("Cannot initialize new GD image stream!");
    imagefill($im, 0, 0, rgb($im, $p[2]));
    foreach ($gr as $p) {
      $p = explode(",", $p);
      $r1 = hexdec(substr($p[6], 0, 2));
      $g1 = hexdec(substr($p[6], 2, 2));
      $b1 = hexdec(substr($p[6], 4, 2));
      $r2 = hexdec(substr($p[7], 0, 2));
      $g2 = hexdec(substr($p[7], 2, 2));
      $b2 = hexdec(substr($p[7], 4, 2));
      $dr = ($r2 - $r1) / $p[5];
      $dg = ($g2 - $g1) / $p[5];
      $db = ($b2 - $b1) / $p[5];
      for ($s = $p[4]; $s < ($p[4] + $p[5]); $s++) {
        if ($p[3] == "h") {
          $x1 = $s;
          $y1 = 0;
          $x2 = $s;
          $y2 = $height - 1;
        } elseif ($p[3] == "v") {
          $x1 = 0;
          $y1 = $s;
          $x2 = $width - 1;
          $y2 = $s;
        }
        $step = $s - $p[4];
        $r = str_pad(dechex(round($r1 + $dr * $step)), 2, "0", STR_PAD_LEFT);
        $g = str_pad(dechex(round($g1 + $dg * $step)), 2, "0", STR_PAD_LEFT);
        $b = str_pad(dechex(round($b1 + $db * $step)), 2, "0", STR_PAD_LEFT);
        imageline($im, $x1, $y1, $x2, $y2, rgb($im, $r.$g.$b));
      }
    }
    reset($gr);
    header("content-type: image/png");
    imagepng($im);
    imagedestroy($im);

Zunächst werden in Zeile 4 die Wertelisten für jeden Farbverlauf in das Array $gr geladen. In Zeile 5 bis 6 werden die Werte für Breite und Höhe in den Variablen $width und $height zwischengespeichert, die dann in Zeile 25 und 29 verwendet werden. In Zeile 9 bis 38 wird nun jede einzelne Werteliste in einer Schleife aus dem Array $gr in das Array $p geladen und in einen Farbverlauf umgesetzt. Eher aus ästhetischen Gründen wird der interne Zeiger des Arrays $gr in Zeile 39 zurück gesetzt.

Das Ergebnis sind zwei sich überlagernde Farbverläufe in einer Grafik.

PHP Grafik-Beispiel

Transparenz gefällig? #

Wenn man das obige Skript mit den Erkenntnissen aus dem Artikel ›Grafiken mit Transparenz‹ verbindet, ist es möglich, Farbverläufe mit Transparenzen zu erzeugen.

Dazu kann man als vierte Angabe neben den hexadezimalen Werten für den Rot-, Grün- und Blauanteil noch den Wert für die Transparenz angeben, wobei 00 für keine Transparenz und ff für völlige Transparenz steht. Zum Beispiel:

gradient=300,200,b036b000,h,50,200,99000000,ff990066;x,x,x,v,50,100,00840044,be1b5f00

Quelltext auswählen
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
    function rgba($im, $hex) {
      return imagecolorallocatealpha(
        $im,
        hexdec(substr($hex, 0, 2)),
        hexdec(substr($hex, 2, 2)),
        hexdec(substr($hex, 4, 2)),
        hexdec(substr($hex, 6, 2))
      );
    }
    $gr = explode(";", $_GET['gradient']);
    $p = explode(",", $gr[0]);
    $width = $p[0]; $height = $p[1];
    $im = @imagecreatetruecolor($width, $height) or die("Cannot initialize new GD image stream!");
    imagefilledrectangle($im, 0, 0, $width, $height, rgba($im, $p[2]));
    if ($_GET['t'] == 1 || $_GET['t'] == 2) imagealphablending($im, FALSE); else imagealphablending($im, TRUE);
    foreach ($gr as $p) {
      $p = explode(",", $p);
      $r1 = hexdec(substr($p[6], 0, 2));
      $g1 = hexdec(substr($p[6], 2, 2));
      $b1 = hexdec(substr($p[6], 4, 2));
      $a1 = hexdec(substr($p[6], 6, 2));
      $r2 = hexdec(substr($p[7], 0, 2));
      $g2 = hexdec(substr($p[7], 2, 2));
      $b2 = hexdec(substr($p[7], 4, 2));
      $a2 = hexdec(substr($p[7], 6, 2));
      $dr = ($r2 - $r1) / $p[5];
      $dg = ($g2 - $g1) / $p[5];
      $db = ($b2 - $b1) / $p[5];
      $da = ($a2 - $a1) / $p[5];
      for ($s = $p[4]; $s < ($p[4] + $p[5]); $s++) {
        if ($p[3] == "h") {
          $x1 = $s;
          $y1 = 0;
          $x2 = $s;
          $y2 = $height - 1;
        } elseif ($p[3] == "v") {
          $x1 = 0;
          $y1 = $s;
          $x2 = $width - 1;
          $y2 = $s;
        }
        $step = $s - $p[4];
        $r = str_pad(dechex(round($r1 + $dr * $step)), 2, "0", STR_PAD_LEFT);
        $g = str_pad(dechex(round($g1 + $dg * $step)), 2, "0", STR_PAD_LEFT);
        $b = str_pad(dechex(round($b1 + $db * $step)), 2, "0", STR_PAD_LEFT);
        $a = str_pad(dechex(round($a1 + $da * $step)), 2, "0", STR_PAD_LEFT);
        imageline($im, $x1, $y1, $x2, $y2, rgba($im, $r.$g.$b.$a));
      }
      if ($_GET['t'] == 1 || $_GET['t'] == 3) imagealphablending($im, FALSE); else imagealphablending($im, TRUE);
    }
    reset($gr);
    header("content-type: image/png");
    imagesavealpha($im, TRUE);
    imagepng($im);
    imagedestroy($im);

Mit imagealphablending($im, TRUE) wird festgelegt, ob der Alphakanal, also die transparente Farbe eines Farbverlaufs mit der darunter liegenden Farbe verschmelzen soll. Dies ist für den unteren, horizontalen Farbverlauf in den Beispielen 3 und 4, für den oberen, vertikalen Farbverlauf in den Beispielen 2 und 4 der Fall. In den anderen Fällen mit imagealphablending($im, FALSE) wird die Farbe, die von dem Farbverlauf überdeckt wird, ignoriert, so dass der Hintergrund der Grafik durchscheint.

PHP Grafik-Beispiel PHP Grafik-Beispiel
PHP Grafik-Beispiel PHP Grafik-Beispiel