Derzeit online: ca. 108 User  
Spenden via PayPal PHP für dich ist auch als Buch erhältlich - im handlichen Format, zum Nachschlagen, Mitnehmen oder gemütlichen nebenbei Lesen. Mit noch mehr Informationen, zusätzlichen Beispielen und Übungsaufgaben.
Jetzt in der aktualisierten Version bei Amazon oder BoD bestellen!


Schnipsel

PHP - Eine herabschmelzende Kerze mit gd-lib erzeugen

Dieses Mal wollen wir, dass die Kerze nicht einfach nur herumsteht und brennt, sondern dass sie zusätzlich herab brennt. Wir beginnen dafür mit dem ursprünglichen Code, der Kerze, ändern ihn aber zunächst an zwei Stellen ab. Zuerst schreiben wir eine Raute (#) vor die Headerangabe, damit diese von PHP als Kommentar betrachtet und nicht ausgeführt wird. Dann ändern wir noch ganz am Ende die Funktion imagepng, so dass unser Bild wieder in eine Datei geschrieben wird. Das Bild lassen wir dann natürlich auch wieder anzeigen.

Für die bessere Übersichtlichkeit habe ich dieses Mal im Code die Zeilennummern mit angeben. Diese gehören nicht zum eigentlichen Code!
  1. <?php
  2. #Header("Content-Type: image/png");
  3. $breite = 150;
  4. $hoehe = 300;
  5. $kerze = imagecreatetruecolor($breite, $hoehe);
  6. $hintergrundfarbe = imagecolorallocate($kerze, 200, 200, 200);
  7. imagefill($kerze, 0, 0, $hintergrundfarbe);
  8. $kerzendicke = 100;
  9. $kerzenfarbe = imagecolorallocate($kerze, 160, 119, 191);
  10. $kerze_x1 = ($breite - $kerzendicke) / 2;
  11. $kerze_y1 = 80;
  12. $kerze_x2 = $kerze_x1 + $kerzendicke;
  13. $kerze_y2 = $hoehe - $kerze_x1;
  14. imagefilledrectangle($kerze, $kerze_x1, $kerze_y1, $kerze_x2, $kerze_y2,$kerzenfarbe);
  15. $schwarz = imagecolorallocate($kerze, 0, 0, 0);
  16. $docht_x1 = $kerze_x1 + ($kerzendicke / 2) - 1;
  17. $docht_y1 = $kerze_y1 - 13;
  18. imagefilledrectangle($kerze, $docht_x1, $docht_y1, $docht_x1+2, $docht_y1+10,$schwarz);
  19. $flamme = imagecreatefrompng("flamme.png");
  20. $flammenbreite = 26;
  21. $flammenhoehe = 60;
  22. $flamme_x1 = $kerze_x1 + ($kerzendicke / 2) - ($flammenbreite / 2);
  23. $flamme_y1 = $kerze_y1 - $flammenhoehe - 2;
  24. imagecopy($kerze, $flamme, $flamme_x1, $flamme_y1, 0, 0, $flammenbreite,$flammenhoehe);
  25. imagepng($kerze, "kerze.png");
  26. ?>
  27. <img src="kerze.png" alt="Kerze" />
Angezeigt wird dann wieder die schon aus dem ersten Teil bekannte Kerze:

Kerze

Wenn die Kerze ein Stück herunter gebrannt ist, ist sie natürlich nicht mehr so hoch wie vorher. Für uns heißt das, wir lassen sie einfach ein Stück weiter unten beginnen. Da wir in unserem Code die meisten Werte bereits in Variablen speichern fällt uns das sehr leicht. Wir müssen eine einzige Variable verändern, nämlich die Variable kerze_y1. Damit legen wir nicht nur die Startposition der Kerze fest, sondern haben zusätzlich auch noch die Position des Dochtes und der Flamme bestimmt und daher auch verändert.

Wenn ich den Wert jetzt also z. B. auf 120 erhöhe, würde die Kerze so aussehen:

Kerze

Das funktioniert zwar sehr einfach, ist aber für unser Vorhaben zu statisch, wir wollen schließlich eine immer weiter herab schmelzende Kerze und nicht einfach nur eine kleinere Kerze. Wir müssen also dazu übergehen, den Startpunkt nicht fix in unsere PHP-Datei zu schreiben sondern ebenfalls zu berechnen.

Im ersten Schritt verändern wir dafür die Positionen der einzelnen Anweisungen etwas. Wir setzen die zwei Variablen zur Flammengröße flammenbreite und flammenhoehe vor die ersten Berechnungen, also spätestens in die Zeile 9 und 10. Ich persönlich finde es übersichtlicher, wenn solche Angaben direkt am Anfang der Datei stehen und werde sie daher direkt nach den Variablen, die unsere Bildhöhe und -breite definieren in die Zeilen 5 und 6 setzen:
  1. <?php
  2. #Header("Content-Type: image/png");
  3. $breite = 150;
  4. $hoehe = 300;
  5. $flammenbreite = 26;
  6. $flammenhoehe = 60;
  7. $kerze = imagecreatetruecolor($breite, $hoehe);
  8. $hintergrundfarbe = imagecolorallocate($kerze, 200, 200, 200);
  9. imagefill($kerze, 0, 0, $hintergrundfarbe);
  10. $kerzendicke = 100;
  11. $kerzenfarbe = imagecolorallocate($kerze, 160, 119, 191);
  12. $kerze_x1 = ($breite - $kerzendicke) / 2;
  13. $kerze_y1 = 80;
  14. $kerze_x2 = $kerze_x1 + $kerzendicke;
  15. $kerze_y2 = $hoehe - $kerze_x1;
  16. imagefilledrectangle($kerze, $kerze_x1, $kerze_y1, $kerze_x2, $kerze_y2, $kerzenfarbe);
  17. $schwarz = imagecolorallocate($kerze, 0, 0, 0);
  18. $docht_x1 = $kerze_x1 + ($kerzendicke / 2) - 1;
  19. $docht_y1 = $kerze_y1 - 13;
  20. imagefilledrectangle($kerze, $docht_x1, $docht_y1, $docht_x1+2, $docht_y1+10, $schwarz);
  21. $flamme = imagecreatefrompng("flamme.png");
  22. $flamme_x1 = $kerze_x1 + ($kerzendicke / 2) - ($flammenbreite / 2);
  23. $flamme_y1 = $kerze_y1 - $flammenhoehe - 2;
  24. imagecopy($kerze, $flamme, $flamme_x1, $flamme_y1, 0, 0, $flammenbreite, $flammenhoehe);
  25. imagepng($kerze, "kerze.png");
  26. ?>
  27. <img src="kerze.png" alt="Kerze" />
Jetzt können wir im nächsten Schritt beginnen, die Variable kerze_y1 zu berechnen. Wir verwenden dafür die Flammenhöhe (Variable flammenhoehe) und als oberen Abstand den Rand, der schon an allen anderen Seiten unserer Kerze existiert und dem Wert in der Variable kerze_x1 entspricht.
  1. $kerze_y1 = $flammenhoehe + $kerze_x1;
Wenn wir jetzt die Kerze etwas weiter nach unten gebrannt haben wollen, müssen wir nur noch die Pixel, die bereits weg sein sollen, hinzu addieren. Wollen wir also z. B. dass unsere Kerze bereits 50 Pixel nach unten gebrannt ist, verwenden wir:
  1. $kerze_y1 = $flammenhoehe + $kerze_x1 + 50;
Oder wir machen es gleich ganz ordentlich und schreiben auch diesen Wert in eine Variable:
  1. $abgebrannt = 50;
  2. $kerze_y1 = $flammenhoehe + $kerze_x1 + $abgebrannt;
Das sieht dann so aus:

Kerze

Jetzt sieht die Kerze zwar immer noch bei jedem Aufruf gleich aus, aber die wichtigsten Vorarbeiten sind endlich erledigt. Als nächstes können wir uns mal wieder ans Rechnen machen.

Wir werden ein Datum festlegen, ab dem unsere Kerze brennt, ausrechnen, wie lange dieses Startdatum bereits zurück liegt und den Wert in der Variable abgebrannt dementsprechend erhöhen. Für unser Beispiel gehe ich davon aus, dass unsere Kerze am 9.11.2017 angezündet wurde.
  1. $startdatum = mktime(0,0,0,11,9,2017);
  2. $brenndauer = time() - $startdatum;
  3. $brenndauer = $brenndauer / (60 * 60);
  4. $brenndauer = round($brenndauer,0);
  5. $abgebrannt = $brenndauer;
Zuerst legen wir also ein Startdatum fest. Dafür benötigen wir die Funktion mktime. Diese sorgt dafür, dass PHP das Datum in einen Timestamp umrechnet. Die Angaben bei mktime sind Stunden, Minuten, Sekunden, Monat, Tag, Jahr. Bitte gib alle Zeilen ohne führende Null ein (also nicht 04, sondern 4) und beachte, dass zuerst der Monat und dann erst der Tag angegeben wird.

Der zweite Schritt besteht darin, zu berechnen, wie viel Zeit seit diesem Startzeitpunkt bereits vergangen ist. Dafür ziehen wir einfach das Startdatum vom aktuellen Timestamp ab. Da wir diesen ganz einfach über time() bekommen können, benötigen wir keine extra Variable dafür. Damit hätten wir Anzahl der Sekunden.

Wir wollen aber lieber nur Stunden als Wert haben und dividieren das daher noch durch "60 (Sekunden) * 60 (Minuten)", weil jede Stunde 3600 (60 * 60) Sekunden hat.

Da wir auch noch einen ganzzahligen Wert haben wollen, runden wir das bisherige Ergebnis noch mit der Funktion round, der wir als ersten Wert die Zahl, die gerundet werden soll - also unsere Variable brenndauer - und als zweiten Wert die Anzahl der gewünschten Nachhkommastellen - bei uns keine und daher 0 - übergeben.

Im letzten Schritt weisen wir der Variable abgebrannt noch den Wert der Brenndauer zu.

Ich bevorzuge an dieser Stelle eine zusammengesetzte Schreibweise, daher sieht der Code bei mir dann so aus:
  1. $startdatum = mktime(0,0,0,11,9,2017);
  2. $brenndauer = round((time() - $startdatum) / (60 * 60));
  3. $abgebrannt = $brenndauer;
Und unsere Kerze sieht jetzt so aus:

Kerze

Ups, da ist wohl was schief gelaufen. Unsere Kerze sieht ja gar nicht mehr wie eine richtige Kerze aus. Eher wie ein kleines Häufchen Elend. Was ist passiert?

Da wir als Wert für abgebrannt einfach die Brenndauer in Stunden angegeben haben, kommen wir bei einem Brennbeginn am 9.11.2017 auf eine Brenndauer von 322 Stunden. Bei einer Bildhöhe von 300 Pixel beginnt die Kerze also erst bei -22 Pixel. Das ist viel zu tief.

Eine erste Maßnahme besteht darin, die Kerze weniger stark brennen zu lassen. Statt dem einen Pixel, das sie zur Zeit pro Stunde herunter brennt, könnten wir sie nur halb so stark brennen lassen, indem wir einfach unsere Berechnung ein wenig verändern:
  1. $brenndauer = round((time() - $startdatum) / (60 * 60));
  2. $abgebrannt = $brenndauer / 2;
Damit brennt die Kerze zwar langsamer, aber irgendwann wird sie dennoch herunter gebrannt sein. Wir müssen also die Höhe, die abgebrannt ist begrenzen und z. B. sagen, dass die Kerze um maximal 180 Pixel abgebrannt sein darf:
  1. $brenndauer = round((time() - $startdatum) / (60 * 60));
  2. $abgebrannt = $brenndauer / 2;
  3. if($abgebrannt > 180)
  4. $abgebrannt = 180;
Wir überprüfen also mit einer if-Anweisung, ob die Variable abgebrannt über 180 Pixel liegt und setzen sie, sofern dies der Fall ist, bei 180 fest. Und so sieht das dann aus:

Kerze

Schöner wäre es jetzt natürlich, den Wert, den die Kerze maximal hinunter brennen darf, nicht fix zu setzen, sondern wiederum zu berechnen. Das könnte dann so aussehen:
  1. $brenndauer = round((time() - $startdatum) / (60 * 60));
  2. $abgebrannt = $brenndauer / 2;
  3. $max_abgebrannt = $hoehe - (2 * $kerze_x1 ) - $flammenhoehe - 20;
  4. if($abgebrannt > $max_abgebrannt)
  5. $abgebrannt = $max_abgebrannt;
Hier legen wir zusätzlich eine Variable max_abgebrannt fest und berechnen sie aus der Gesamhöhe des Bild, abzüglich zweimal Rand (Variable kerze_x1) für oben und unten, abzüglich der Flammenhöhe, abzüglich 20 Pixel, die wir als Mindesthöhe für die Kerze haben wollen. Die Kerze wird dann nie kleiner als 20 Pixel sein:

Kerze

Einen Fehler hat die Kerze in meinen Augen jetzt aber immer noch: Wenn sie am untersten Rand ist, geht so eine Kerze üblicherweise aus und brennt nicht noch munter weiter, wie unsere das im Moment noch macht. Wir wollen also die Kerze löschen, wenn sie zu klein geworden ist. Dafür verwenden wir eine weitere if-Anweisung, die dafür sorgt, dass die Flamme nur dann ins Bild kopiert wird, wenn die Kerze tatsächlich noch groß genug ist, um zu brennen.
  1. if($abgebrannt < $max_abgebrannt)
  2. imagecopy($kerze, $flamme, $flamme_x1, $flamme_y1, 0, 0, $flammenbreite, $flammenhoehe);
Hier wird einfach überprüft, ob die Variable abgebrannt kleiner als die maximale Höhe ist und nur dann wird die Flamme ins Bild kopiert. Ansonsten sehen wir einfach nur den Docht.

Kerze

Am Ende musst du die Raute vor der Header-Angabe wieder entfernen und auch die letzte Zeile wieder auf den ursprünglichen Wert ändern, damit du die Datei wieder direkt als Bild einbinden kannst.

Natürlich sind den Möglichkeiten hier bei weitem noch keine Grenzen gesetzt. Wir könnten statt der Flamme auch noch Rauch auf die Kerze setzen, wenn sie ausgegangen ist, oder in das Bild schreiben, seit wann die Kerze schon brennt. Ebenso ist es möglich, die Datei dahingehend zu verändern, dass man Parameter mit übergeben kann und die Kerze somit direkt beim Einbinden dynamisch gestalten kann. Du kannst sie auch stärker oder schwächer brennen lassen. Diese Kerze kann aber genauso die Grundlage für einen ganze Adventskranz voller Kerzen sein.

Kerze Kerze Kerze Kerze Kerze

Was auch immer du daraus machst, hier ist noch einmal der vollständige Code:
  1. <?php
  2. Header("Content-Type: image/png");
  3. $breite = 150;
  4. $hoehe = 300;
  5. $flammenbreite = 26;
  6. $flammenhoehe = 60;
  7. $kerze = imagecreatetruecolor($breite, $hoehe);
  8. $hintergrundfarbe = imagecolorallocate($kerze, 200, 200, 200);
  9. imagefill($kerze, 0, 0, $hintergrundfarbe);
  10. $kerzendicke = 100;
  11. $kerzenfarbe = imagecolorallocate($kerze, 160, 119, 191);
  12. $kerze_x1 = ($breite - $kerzendicke) / 2;
  13. $startdatum = mktime(0,0,0,11,9,2017);
  14. $brenndauer = round((time() - $startdatum) / (60 * 60));
  15. $abgebrannt = $brenndauer / 2;
  16. $max_abgebrannt = $hoehe - (2 * $kerze_x1 ) - $flammenhoehe - 20;
  17. if($abgebrannt > $max_abgebrannt)
  18. $abgebrannt = $max_abgebrannt;
  19. $kerze_y1 = $flammenhoehe + $kerze_x1 + $abgebrannt;
  20. $kerze_x2 = $kerze_x1 + $kerzendicke;
  21. $kerze_y2 = $hoehe - $kerze_x1;
  22. imagefilledrectangle($kerze, $kerze_x1, $kerze_y1, $kerze_x2, $kerze_y2, $kerzenfarbe);
  23. $schwarz = imagecolorallocate($kerze, 0, 0, 0);
  24. $docht_x1 = $kerze_x1 + ($kerzendicke / 2) - 1;
  25. $docht_y1 = $kerze_y1 - 13;
  26. imagefilledrectangle($kerze, $docht_x1, $docht_y1, $docht_x1+2, $docht_y1+10, $schwarz);
  27. $flamme = imagecreatefrompng("flamme.png");
  28. $flamme_x1 = $kerze_x1 + ($kerzendicke / 2) - ($flammenbreite / 2);
  29. $flamme_y1 = $kerze_y1 - $flammenhoehe - 2;
  30. if($abgebrannt < $max_abgebrannt)
  31. imagecopy($kerze, $flamme, $flamme_x1, $flamme_y1, 0, 0, $flammenbreite, $flammenhoehe);
  32. imagepng($kerze);
  33. ?>


Autor: Claudia Unkelbach
© 2001 - 2017 Claudia Unkelbach
Gießener Straße 75, 35396 Gießen