7. Dynamiczne generowanie grafiki 7.1. Biblioteka GD Dynamiczne generowanie kodu HTML to podstawowe zastosowanie języka PHP. Często jednak to nie wystarczy i mieszanka: dynamiczny HTML plus statyczna grafika, okazuje się za słaba. Dlatego PHP można opcjonalnie wyposażyć w moduł umożliwiający programowe tworzenie grafiki, a następnie wyemitowanie jej do przeglądarki w powszechnie przyjętym formacie JPEG, PNG czy GIF. Moduł ten korzysta z biblioteki GD (http://www.boutell.com/gd/). Standardowo PHP4 nie jest kompilowane z GD, musi to zrobić sam administrator, dodatkowo GD może obsługiwać (lub nie) czcionki wektorowe w formacie TrueType, za pośrednictwem biblioteki FreeType. Grafikę w GD możemy generować bądź to zaczynając od pustego obrazka, bądź też ładując jakąś gotową grafikę i dokonując na niej manipulacji. Repertuar biblioteki obejmuje podstawowe funkcje graficzne (punkty, linie, wielokąty, elipsy), generację tekstu (szczególnie ładnie wygląda wygładzany tekst generowany z wektorowych czcionek TrueType), operacje na blokach obrazu, skalowanie, filtry i inne. Gotowy obrazek można wysłać do przeglądarki, można też go przechować na dysku. Biblioteka umożliwia tworzenie zarówno obrazków paletowych (mała ilość kolorów, ale też małe rozmiary pliku), jak i obrazków w pełnym kolorze (24 bity RGB).
7.2. Sprawdzenie możliwości graficznych Ze względu na opcjonalność samej biblioteki GD, jak i jej wielu komponentów, istnieje w PHP funkcja gd_info() pozwalająca na zbadanie istnienia i możliwości GD w instalacji PHP, na której wykonywany jest skrypt. Wynikiem działania tej bezparametrowej funkcji jest tablica asocjacyjna prezentująca wersję i możliwości modułu dynamicznej generacji grafiki. 'GD Version' 'Freetype Support' 'Freetype Linkage' 'T1Lib Support' 'GIF Read Support' 'GIF Create Support' 'JPG Support' 'PNG Support' 'WBMP Support' 'XBM Support' łańcuch tekstowy opisujący wersję biblioteki wartość logiczna określa obsługę czcionek TrueType rodzaj biblioteki obsługującej czcionki TT (FreeType 1/2) wartość logiczna obsługa czcionek PostScript typ 1 wartość logiczna odczyt obrazków GIF wartość logiczna zapis obrazków GIF wartość logiczna zapis/odczyt obrazków JPEG wartość logiczna zapis/odczyt obrazków PNG wartość logiczna zapis/odczyt obrazków WBMP wartość logiczna zapis/odczyt obrazków NetPBM Z gd_info() warto korzystać pisząc kod przenośny między różnymi serwerami, w przypadku braku którejś z funkcji można dzięki niej szybko zdiagnozować problem.
7.3. Emitowanie grafiki Skrypt PHP generujący obrazek różni się od skryptu generującego stronę w HTML. Przede wszystkim nie jest to dokument HTML, zatem pozbawiony jest całkowicie nagłówka. Dlatego kod generujący obrazek nigdy nie zaczyna się od <HTML>, to spowodowałoby wygenerowanie nagłówka odpowiedzi HTTP z typem zawartości text/html co na pewno nie jest dobrym typem MIME dla obrazka. Dlatego od razu, w pierwszej linii, startujemy z kodem PHP. Niemniej jakiś nagłówek trzeba wygenerować, minimum to wymagane pole Content-Type. Ze skryptu wysyłamy je w sposób następujący: <? header('content-type: image/png'); Oczywiście jeżeli docelowym formatem jest JPEG lub GIF, odpowiednio modyfikujemy zawartość pola. Po załatwieniu sprawy nagłówka, rozpoczynamy pracę z grafiką od stworzenia czystego bufora, bądź załadowania obrazka z pliku (o czym dalej). Następnie dokonujemy na obrazku wszelakich manipulacji. W momencie, gdy jest gotowy, wysyłamy go do przeglądarki funkcją imagepng(), imagejpeg(), czy też imagegif(). Ten ostatni format nie jest generalnie zalecany. Dopiero jedna z tych funkcji powoduje wysłanie danych obrazka do przeglądarki. Bardzo ważną sprawą jest wyłączenie komunikatów o błędach we wszystkich funkcjach, które takie mogą zgłosić. W przeciwnym wypadku komunikat wmiesza się w binarne dane obrazka, powodując jego uszkodzenie. Komunikaty o błędach wyłączamy używając operatora @.
7.4. Tworzenie czystego obrazka - imagecreate() Jeżeli pracę z obrazem zaczynamy od zera, musimy najpierw stworzyć powierzchnię do rysowania. Służą do tego dwie funkcje: imagecreate() tworzy bufor do pracy z paletą kolorów, oraz imagecreatetruecolor(), tworząca bufor dla obrazka 24-bitowego: $obraz = @imagecreate(szerokosc, wysokosc); $obraz24 = @imagecreatetruecolor(szerokosc, wysokosc); Obie funkcje zwracają wartość typu zasób, której używamy później jako identyfikatora obrazu. Po zakończeniu rysowania obrazu, oraz wyemitowaniu go do przeglądarki, można zniszczyć bufor roboczy funkcją imagedestroy(). Jeżeli tego nie zrobimy, bufor zostanie zniszczony automatycznie przy wyjściu ze skryptu. imagedestroy($obraz); 7.5. Ładowanie obrazka z pliku Bardzo często umieszczamy naszą grafikę na jakimś gotowym tle. Najprościej w takim wypadku stworzyć bufor do rysowania z załadowanego z dysku obrazka, przy pomocy zestawu funkcji: createimagefromgif(), createimagefrompng(), createimagefromjpeg(). Parametrem tych funkcji jest ścieżka do pliku z obrazkiem, jeżeli włączone jest traktowanie zasobów HTTP jako plików, to ścieżka może być adresem URL. Powstały bufor z obrazkiem ma takie rozmiary jak oryginał, rodzaj (paleta/truecolor) również zależy od obrazka.
7.6. Więcej o emitowaniu obrazka Funkcje emitujące obrazek posiadają możliwość przekierowania obrazka z przeglądarki klienta do lokalnego pliku na serwerze. Oprócz tego imagejpeg() pozwala na regulację jakości obrazka (siły kompresji) od 0 (najgorsza jakość) do 100 (najlepsza jakość). Domyślną jakością obrazka JPEG jest 75. Oto przykłady: imagepng($obrazek, '/home/user/public_html/obrazki/ob1.png'); imagejpeg($obrazek, 'ob2.jpg', 90); Jeżeli chcemy podregulować jakość obrazka JPEG wysyłanego do przeglądarki, po prostu pomijamy drugi parametr: imagejpeg($obrazek,, 45); Niektóre formaty (PNG przede wszystkim) pozwalają na progresywne wyświetlanie obrazka. GD umożliwia na wykorzystanie tej cechy przy pomocy funkcji imageinterlace(), którą możemy włączyć dla danego obrazka progresywność: imageinterlace($obrazek, 1); Oczywiście włączanie i wyłączanie progresywności w czasie rysowania nie ma znaczenia. Liczy się stan tego ustawienia w momencie wykonywania emisji obrazka. Warto pamiętać, że progresywność zwiększa czas emisji obrazka i jego rozmiar w bajtach.
7.7. Rysowanie i kolory Przed narysowaniem czegokolwiek jakimś kolorem, trzeba sobie ten kolor zarezerwować (również przy obrazkach 24-bitowych, różnica jest taka, że na obrazku takim można mieć praktycznie nieograniczoną ilość kolorów, na obrazku paletowym ilość kolorów wynika z wielkości palety). Do przydziału kolorów służy funkcja imagecolorallocate(): $kolor = imagecolorallocate($obrazek, r, g, b); Wynikiem jest numer koloru używany dalej przy rysowaniu. Na obrazkach paletowych funkcja ta może zwrócić -1, jeżeli wykorzystamy wszystkie kolory z palety. Zarezerwowane kolory można zwalniać funkcją imagecolordeallocate(): imagecolordeallocate($obrazek, $kolor); Pozostawienie niezwolnionych kolorów nie niesie ze sobą żadnyck konsekwencji, zostaną automatycznie zwolnione przy usuwaniu bufora. Pierwsze wywołanie tej funkcji dla danego obrazka ustawia mu kolor tła, jeżeli obrazek jest w trybie paletowym (obrazki 24-bitowe mają zawsze czarne tło).
7.8. Rysowanie: pojedyncze piksele imagesetpixel($obrazek, x, y, $kolor); (0, 0) x y $kolor to numer koloru otrzymany z imagecolorallocate().
7.9. Rysowanie: linie imageline($obrazek, x1, y1, x2, y2, $kolor); (0, 0) x1 x2 y2 y1 $kolor to numer koloru otrzymany z imagecolorallocate().
7.10. Rysowanie: prostokąty imagerectangle($obrazek, x1, y1, x2, y2, $kolor); (0, 0) x1 y1 x2 y2 $kolor to numer koloru otrzymany z imagecolorallocate().
7.11. Rysowanie: wypełnione prostokąty imagefilledrectangle($obrazek, x1, y1, x2, y2, $kolor); (0, 0) x1 y1 x2 y2 $kolor to numer koloru otrzymany z imagecolorallocate().
7.12. Rysowanie: elipsy imageellipse($obrazek, x, y, w, h, $kolor); (0, 0) x x2 y h w $kolor to numer koloru otrzymany z imagecolorallocate().
7.13. Rysowanie: wypełnione elipsy imagefilledellipse($obrazek, x, y, w, h, $kolor); (0, 0) x x2 y h w $kolor to numer koloru otrzymany z imagecolorallocate().
7.14. Rysowanie: wielokąty $ile = 3; $wierzcholki = array(x0, y0, x1, y1, x2, y2); imagepolygon($obrazek, $wierzcholki, $ile, $kolor); (0, 0) x0, y0 x1, y1 x2, y2 $wierzcholki to tablica zawierająca jako kolejne elementy współrzędne x i y wierzchołków Wielokąt jest automatycznie zamykany linią od ostatniego do pierwszego wierzchołka. $kolor to numer koloru otrzymany z imagecolorallocate().
7.14. Rysowanie: wypełnione wielokąty $ile = 3; $wierzcholki = array(x0, y0, x1, y1, x2, y2); imagefilledpolygon($obrazek, $wierzcholki, $ile, $kolor); (0, 0) x0, y0 x1, y1 x2, y2 $wierzcholki to tablica zawierająca jako kolejne elementy współrzędne x i y wierzchołków Wielokąt jest automatycznie zamykany linią od ostatniego do pierwszego wierzchołka. $kolor to numer koloru otrzymany z imagecolorallocate().
7.14. Rysowanie: fragmenty łuków imagearc($obrazek, x, y, w, h, s, e, $kolor); (0, 0) x x2 e y h s w $kolor to numer koloru otrzymany z imagecolorallocate(). Kąty s i e są liczone w stopniach, zawsze w kierunku ruchu wskazówek zegara.
7.15. Rysowanie: fragmenty elips imagefilledarc($obrazek, x, y, w, h, s, e, $kolor); (0, 0) x x2 e y h s w $kolor to numer koloru otrzymany z imagecolorallocate(). Kąty s i e są liczone w stopniach, zawsze w kierunku ruchu wskazówek zegara.