Magazyn T3
newsy, felietony, testy i tutoriale




Internet Maker

19/11/2008

Biblioteka GD – edytuj grafiki w PHP

Tagi: ,

Język PHP jest wykorzystywany najczęściej do tworzenia skryptów pracujących na tekście. Jednak dzięki dołączonej do PHP bibliotece GD, możliwa jest łatwa praca na grafice – od prostej obróbki po rysowanie własnych elementów i wstawianie tekstu. Dzięki temu PHP może zastąpić proste programy do obróbki grafiki, co przydaje się w aplikacjach internetowych.

Niejednokrotnie spotkałeś już w internecie
obrazy generowane w sposób dynamiczny.
Najczęściej pojawiają się one na rozmaitych
forach i blogach, gdy są tam stosowane jako
zabezpieczenie antyspamowe w formularzach
wprowadzania danych.

Działanie tego mechanizmu jest proste – komputer
losuje określone symbole, po czym nakłada
je na obrazek wysyłany do przeglądarki wraz ze
stroną. Obrazek taki często poddawany jest dodatkowej
obróbce, aby utrudnić życie botom. Człowiek
potrafi właściwie zinterpretować dane odczytane
z obrazu, podczas gdy maszyna nie potrafi czytać
obrazów w sposób tak inteligentny.

Pozwala to znacznie ograniczać ilość spamu
wrzucanego na fora i blogi. Mechanizm ten nie
byłby jednak możliwy do wykonania, gdyby nie
istniała możliwość generowania dynamicznych
obrazów na serwerze. Jednym z takich rozwiązań
jest dołączona do PHP biblioteka GD.
Przykładów zastosowań jest zresztą wiele
więcej. W niniejszym artykule znajdziesz jeszcze
kilka praktycznych wdrożeń, dowiesz się także, jak
wymyślić własne.

Otwieranie obrazu z pliku

Omawianie biblioteki GD warto rozpocząć od
podstaw. Taką najmniej skomplikowaną operacją,
jaką można wykonać z wykorzystaniem biblioteki
GD, jest otwarcie już istniejącego obrazu, a następnie
wysłanie go do przeglądarki (i w efekcie
wyświetlenie na ekranie). Czynność tę wykonasz,
korzystając z poniższej konstrukcji:

Użyte zostały tutaj dwie funkcje z biblioteki
graficznej. Pierwsza to {stala}imagecreatefromjpeg(){/stala}.
GD przechowuje obrazy w pamięci we własnym
formacie, stanowiącym generalnie dwuwymiarowy
obraz rastrowy o określonej głębi kolorów. Tego
typu obiekt – w powyższym przykładzie zapisany
pod zmienną $image – jest podstawową jednostką
pracy z obrazami w GD.

Dlatego chcąc załadować jakiś plik, system
musi w rzeczywistości dokonać jego konwersji
z formatu, w jakim dany plik jest zapisany (tutaj
JPEG), do formatu obrazu GD. W powyższym
przykładzie do takiego importu wykorzystana
została funkcja {stala}imagecreatefromjpeg(){/stala}. Funkcja ta
jako argument przyjmuje nazwę pliku lub adres
URL (możliwe jest także automatyczne pobieranie
obrazów z określonej lokalizacji internetowej),
zwraca natomiast obraz skonwertowany, w dużym
uproszczeniu, do bitmapy.

Istnieje możliwość importu danych z plików
różnego rodzaju. Oto dostępne metody:

  • {stala}imagecreatefromjpeg(){/stala} – omawiana już metoda importująca pliki JPEG (rozszerzenia .jpg, .jpeg),
  • {stala}imagecreatefrompng(){/stala} – import z pliku w formacie PNG,
  • {stala}imagecreatefromgif(){/stala} – import z pliku w formacie GIF,
  • {stala}imagecreatefromgd(){/stala} – import z pliku własnego formatu biblioteki GD (starsza wersja),
  • {stala}imagecreatefromgd2(){/stala} – import z pliku własnego formatu biblioteki GD2 (nowsza wersja),
  • {stala}imagecreatefromwbmp(){/stala} – import z pliku BMP (format Windows).

Dostępne jest również wsparcie dla formatów
XBM oraz XPM, te jednak obecnie są już rzadko
używane, nie będziemy więc ich szerzej omawiać.

W każdym przypadku importu uzyskiwany jest
ten sam obiekt GD2. Musisz mieć jednak świadomość,
że w związku z ograniczeniami określonych
formatów źródłowych, ten sam obraz uzyskany różnymi
sposobami może się różnić w jakości, ilości
kolorów i ogólnym efektem wizualnym.

Dość szeroko omówiliśmy już metody odpowiadające
za import pliku. W przytoczonym przykładzie
wykonywane jest jednak również wysłanie
obrazu do przeglądarki.

Odpowiada za to funkcja {stala}imagejpeg(){/stala}, do której
jako parametr przekazywany jest zasób obrazu
GD. Funkcja w wyniku swojego działania wyrzuci
do przeglądarki plik JPG. Ponadto trzeba pamiętać
o dodatkowym wysłaniu odpowiedniego nagłówka
informującego o typie przesyłanych danych.
Nagłówek „image/jpeg” sprawia, że przeglądarka
wyświetli dane jako obraz. Pominięcie tego kroku
prawdopodobnie zaowocuje wyświetleniem na
ekranie dużej ilości kompletnie niezrozumiałych
krzaczków.

Ponieważ funkcje otwierające plik, a następnie
eksportujące do określonego formatu są odrębne,
daje to pełną swobodę co do zmiany formatów.
Poniższy przykład otwiera ten sam obraz co poprzednio
jako JPEG, ale już do przeglądarki wysyła
go w formacie PNG.

header("Content-type: image/png");
$image = imagecreatefromjpeg("morze.jpg");
imagepng($image);

Doboru formatu plików graficznych należy
jednak dokonywać rozważnie i dostosowując je
do zawartości. Pliki typu JPG najlepiej nadają
się do różnorodnych zdjęć, nie mają bowiem
ograniczeń związanych z ilością obsługiwanych
kolorów, potrafią jednak generować charakterystyczne
nieostrości i przebarwienia. Problemu
tego nie mają obrazy typu GIF, jednak tutaj
paleta jest ograniczona jedynie do 256 kolorów.

Pliki PNG są pewnym kompromisem, pomiędzy
wiernym oddaniem kolorów a ich ilością. Pliki
tego typu mają jednak z reguły większy rozmiar.
Ponadto z ich obsługą ma problem przeglądarka
Internet Explorer 6 (dotyczy to szczególnie
przezroczystości).

Format BMP wiernie odwzorowuje plik oryginalny,
ponieważ jest to format bezstratny. Niestety
rozmiar plików jest tak duży, że zastosowanie BMP
w internecie jest bardzo niepraktyczne.

Zapisywanie obrazu do pliku

Wiesz już, w jaki sposób wysłać obraz do
przeglądarki. Ale co w sytuacji, gdy grafikę chcesz
zapisać bezpośrednio na serwerze? O tym twórcy
GD także pomyśleli. Każda z funkcji eksportujących
obraz do określonego formatu graficznego przyjmuje
drugi, opcjonalny parametr. Jeśli parametr
ten jest pusty, obraz zostanie wyrzucony wprost
do przeglądarki (lub na standardowe wyjście, jeśli
skrypt jest odpalany z shella).

Natomiast w przypadku, gdy drugi parametr
zawiera łańcuch znaków, zostanie on zinterpretowany
jako ścieżka do zapisu pliku wynikowego.
Spójrz na przykład:

$image = imagecreatefromjpeg("morze.jpg");
imagepng($image, "morze.png");

Powyższy kod dokona konwersji obrazu
z formatu JPG na PNG, zapisując zmianę na dysku.
Dla niektórych formatów plików dostępne są także
inne opcjonalne parametry. Na przykład dla plików
PNG oraz JPEG jako trzeci parametr można podać
oczekiwaną jakość pliku z zakresu od 0 do 100. Im
niższa jakość, tym mniejszy rozmiar.

imagejpeg($image, "morze.jpg", 80);

W powyższy sposób można zapisać na dysku
plik morze.jpg z jakością 80%.

imagejpeg($image, NULL, 70);

Przekazanie jako ścieżki do pliku słowa
kluczowego NULL pozwala sterować jakością
obrazu wysyłanego wprost do przeglądarki. Należy
przy tym pamiętać, że nie uda się uzyskać lepszej
jakości z pliku, który miał niezbyt dobrą jakość
w oryginale.

Import obrazu z łańcucha

Zdarza się, że zawartość obrazu w postaci
binarnej zostanie zapisana do łańcucha znaków.
W taki sposób również można zaimportować obraz.
Najprostszy przykład takiej sytuacji demonstruje
poniższy kod:

header("Content-type: image/png");
$content = file_get_contents("morze.jpg");
$image = imagecreatefromstring($content);
imagepng($image);

Podany kod odczytuje plik JPG (jednak pobrany
uprzednio do łańcucha {stala}$content{/stala}), a następnie
wysyła go do przeglądarki jako PNG. Nie jest to
szczególnie użyteczna funkcjonalność – jak już
wiesz, ten sam efekt możesz osiągnąć używając
funkcji {stala}imagecreatefromjpeg(){/stala}. Możliwość otwierania
obrazów wprost z łańcucha przydaje się
jednak przy bardziej zaawansowanych rozwiązaniach.

Być może w którymś ze swoich projektów
postanowisz przechowywać obrazy bezpośrednio
w bazie danych. Choć w przypadku prostych stron
bazujących na zwykłych rozwiązaniach hostingowych
może to nie być rozwiązanie idealne (nie
zawsze będzie zresztą możliwe ze względu na
ograniczenia w wielkości baz danych), to przy
dedykowanych systemach bazodanowych dla projektów
bazujących na obróbce obrazów, przechowywanie
ich w bazie może być bardzo praktyczne.

Wówczas funkcja {stala}imagecreatefromstring(){/stala} przydaje
się idealnie do importu ilustracji pobranych wprost
z bazy danych.

Zmiana rozmiaru obrazu

Prawdopodobnie wiesz już wszystko o rozpoczynaniu
i kończeniu pracy z GD. Czas przejść do
funkcji, które umożliwiają modyfikacje zaimportowanego
obrazu. Jedna z najprostszych czynności
dotyczy zmiany rozmiaru obrazu – mowa o funkcji
{stala}imagecopyresized(){/stala}. Jej zastosowanie najprościej
omówić na przykładzie:

header("Content-type: image/jpeg");
$image = imagecreatefromjpeg("morze.jpg");
getimagesize("morze.jpg");
$new_width = 1024;
// Zmiana proporcjonalna
$new_height = $height * $new_width /$width;
$image_new = imagecreatetruecolor($new_width, $new_height);
imagecopyresized($image_new, $image, 0, 0, 0, 0, $new_width, $new_height,$width, $height);
imagejpeg($image_new);

Po otwarciu pliku odczytywana jest jego
oryginalna rozdzielczość. Służy do tego funkcja
{stala}getimagesize(){/stala}, która zwraca dwuelementową
tablicę zawierającą szerokość i wysokość obrazu.
W powyższym przykładzie szerokość zostanie
zmniejszona do 1024 (zakładając, że oryginalny
obraz jest większy), natomiast wysokość wyliczona
zostaje proporcjonalnie.

Zmiana wielkości obrazu oznacza w GD
stworzenie nowego zasobu, który będzie pusty,
a następnie przekopiowanie do niego ilustracji
pierwotnej, wraz ze zmianą rozmiaru. Pierwszą
czynność realizuje funkcja {stala}imagecreatetruecolor(){/stala},
która dostarcza obrazu o zadanej szerokości i wysokości
oraz w pełnej palecie kolorów.

Serce powyższego przykładu stanowi funkcja
{stala}imagecopyresized(){/stala}. Przeanalizujmy kolejne
parametry:

  • Parametr 1 – obiekt nowego obrazu, do którego dane będą kopiowane,
  • Parametr 2 – obiekt oryginalnego obrazu,
  • Parametr 3 i 4 – współrzędne X i Y punktu, od którego rozpocznie się nanoszenie skopiowanego obrazu,
  • Parametr 5 i 6 – współrzędne X i Y punktu, od którego rozpocznie się odczytywanie obrazu z wzorca,
  • Parametr 7 i 8 – szerokość i wysokość kopiowanego obrazu na docelowym obiekcie,
  • Parametr 9 i 10 – szerokość i wysokość kopiowanego obrazu na pierwotnym obiekcie.

Jak widzisz, jest to bardzo uniwersalna funkcja.
Pozwala nie tylko zmniejszać obrazy, ale także
powiększać, a nawet wycinać z nich odpowiednie
fragmenty wraz z automatyczną zmianą rozmiaru
tych fragmentów.

W naszym przykładzie kopiowany był cały
obraz, dlatego kopiowanie rozpoczęło się w punkcie
(0,0), skopiowana została pełna szerokość
i wysokość, a wstawianie do docelowego obiektu
także rozpoczęło się od punktu (0,0), ale zastosowano
już nowe rozmiary do określenia zakresu
kopiowania.

Wycinanie fragmentu

Wiesz już, że funkcja {stala}imagecopyresized(){/stala} ma
szerokie zastosowanie. Pozwala między innymi
na wycinanie fragmentów obrazu. Poniższy kod
pokazuje, jak to zrobić:

header("Content-type: image/jpeg");
$image = imagecreatefromjpeg("tygrys.jpg");
list($width, $height) = getimagesize("tygrys.jpg");
$new_width = 780;
$new_height = 840;
$image_new = imagecreatetruecolor($new_width, $new_height);
imagecopyresized($image_new, $image, 0, 0, 140, 100, $new_width, $new_height, 260, 280);
imagejpeg($image_new);

W przykładzie pobierany jest obraz tygrysa,
z którego zostanie wycięta, a następnie trzykrotnie
powiększona głowa. Zasada działania skryptu jest
podobna jak poprzednim razem. Stworzony został
nowy, pusty obraz w pełnej palecie kolorów (true
color).

Następnie dokonywane jest kopiowanie
z obrazu oryginalnego, z tą różnicą, że tym razem
kopiowanie rozpoczyna się w punkcie o współrzędnych
(140, 100) wzorca. Skopiowanych jest tylko
260 pikseli szerokości i 280 pikseli wysokości.
Tak wycięty prostokąt jest nanoszony na obraz
o wysokości 780×840 pikseli, zaczynając od lewego
górnego rogu. Biblioteka GD automatycznie
dokona powiększenia obrazu.

Warto również zwrócić uwagę na funkcję
{stala}imagecopyresampled(){/stala}, która przyjmuje identyczne
parametry i działa w sposób analogiczny do
{stala}imagecopyresized(){/stala}. Jednak oprócz prostej zmiany
rozmiaru dokonywane jest również ponowne
przeliczenie każdego pikselu i ładniejsze wyrenderowanie
obrazu po przekształceniu.

Nanoszenie tekstu

Biblioteka GD oferuje przydatną funkcjonalność
pozwalającą na nanoszenie tekstu na obrazy. Obsługa
jest tutaj bardzo prosta. Na początek warto
zapoznać się z metodą definiującą używany kolor
- przyda się do wprowadzania tekstu:

$r = 0;
$g = 0;
$b = 0;
$black = imagecolorallocate($image, 0, 0, 0);

Jako pierwszy parametr musisz przekazać
obiekt obrazu GD. Kolejne trzy parametry to
kolejne składowe palety RGB – czerwony, zielony
i niebieski. Możesz tutaj używać liczb od 0 do 255.
Stworzenie koloru za pomocą przedstawionej funkcji
{stala}imagecolorallocate(){/stala} jest konieczne dla każdej
barwy, której będziesz chciał używać w swoich
obrazach, przy nanoszeniu rozmaitych zmian.
Gdy masz już zdefiniowany kolor, czas przejść
do nanoszenia tekstu na obraz:

$rozmiar = 20;
$pochylenie = 0;
$x = 20;
$y = 20;
$font = 'arial.ttf';
imagettftext($image, $rozmiar, $pochylenie, $x, $y, $black, $font,'Tekst do wyświetlenia');

Przekazywane do funkcji {stala}imagegetttftext(){/stala}
parametry to kolejno – zasób obrazu GD, rozmiar
czcionki (w naszym przykładzie 20pt), kąt tekstu,
położenie tekstu na obrazie (punkt X,Y początku
napisu), kolor (stworzony przed chwilą), ścieżka
do pliku TTF z czcionką oraz właściwy tekst do
wyświetlenia.

Funkcja dokonuje naniesienia tak przygotowanego
tekstu na obraz. Jest to czynność, która nie
może zostać odwrócona w dalszej części działania
programu. Biblioteka GD nie działa bowiem na
warstwach i wszystkie zmiany wprowadzane są
wprost na obraz, usuwając informacje o tym, co
znajdowało się „pod spodem”. Dotyczy to także
wszelkich innych działań na obrazie.

Nieco szerzej omówimy parametr odpowiadający
za kąt pochylenia tekstu. GD pozwala na nanoszenie
nie tylko napisu poziomego, ale również
innych napisów umieszczonych pod dowolnym
kątem. Należy jednak przez to rozumieć nachylenie
całego napisu, a nie poszczególnych znaków.

Wartość tę należy podawać wyrażoną w stopniach
- od 0 do 360. Jest ona interpretowana
w kierunku odwrotnym do ruchu wskazówek
zegara. Wartość równa zeru to klasyczny tekst
pisany w linii poziomej, w kierunku od lewego do
prawego:

putenv('GDFONTPATH=' . realpath('.'));
$font = 'courier_new.ttf';
$white = imagecolorallocate($image, 255, 255, 255);
imagettftext($image, 50, 90, 100, 1600, $white, $font, 'Pozdrowienia z nad morza');

Powyższy przykład spowoduje wypisanie
napisu pionowo, obróconego o 90 stopni w lewo.
Przy okazji warto zwrócić uwagę na jeszcze jedną
zastosowaną konstrukcję. Dzięki ustawieniu
zmiennej środowiskowej GDFONTPATH, bezpośrednio
wskazany został katalog, w którym należy
szukać pliku czcionki ustawionej tutaj jako $font.

Domyślna ścieżka może wskazywać na jeden
z katalogów systemowych, na który standardowy
użytkownik usługi hostingowej może mieć
niewielki wpływ.

Wprowadzenie tekstu przez korzystanie
z czcionek TTF (czcionki TrueType) jest najprostszym
sposobem. Jest to format czcionek powszechnie
używany w systemie Windows i wystarczy wejść
do katalogu „fonts” w głównym folderze tego
systemu, aby skopiować interesujące czcionki
wprost na serwer FTP. Należy pamiętać o tym, że
w przypadku czcionki pogrubionej czy pisanej kursywą
mamy do czynienia tak naprawdę z odrębnymi
plikami TTF – należy więc odnaleźć i skopiować
odpowiedni z nich.

Nie jest to jedyna metoda. Biblioteka GD
pozwala również na używanie czcionek FreeType 2,
używanych natywnie przez systemy Linux. Służy do
tego funkcja {stala}imagefttext(){/stala}, która działa na identycznej
zasadzie jak metoda omawiana powyżej.

Możliwe jest ponadto używanie fontów
w formacie dla dokumentów typu PostScript (PS).
Wówczas należy używać funkcji {stala}imagepsloadfont(){/stala}
oraz {stala}imagepstext(){/stala}, które działają odmiennie od
pozostałych. Jednak z uwagi na mniejszą popularność
tego rodzaju czcionek, nie będziemy tych
funkcji w tym miejscu szerzej omawiać.

Automatyczne wypełnianie dokumentów

Czas na szerszy przykład zastosowania systemu
czcionek. GD pozwala na automatyczne generowanie
rozmaitych dokumentów urzędowych. Jednym
z najprostszych jest przekaz pocztowy, który może
być dołączany np. klientom sklepów internetowych
i usług zamawianych online do otrzymywanych
faktur.

W jaki sposób można zrealizować wykonanie
tego rodzaju przekazu? Wystarczy pobrać ze strony
odpowiedniej instytucji, a w razie braku takiej
możliwości – zeskanować druk dokumentu. Musisz
go zaimportować do GD – będzie stanowić tło
nowego obrazu. Na to nanosisz właściwy tekst.

Prawda, że proste? A oto jak wygląda ta kwestia
w praktyce:

W tym miejscu kilka uwag. Po pierwsze, druki
urzędowe najlepiej jest wypełniać czcionką o stałej
szerokości – taką jest Courier New. Dzięki temu
szerokość tekstu jest w pełni przewidywalna, a co
za tym idzie, wiadomo, ile znaków można wpisać,
aby zmieścić się w określonej rubryce.

Ponadto w wybranym druku przekazu pocztowego
znajdują się kratki na wstawianie liter.
Warto jednak wiedzieć, że zgodnie z odpowiednimi
zarządzeniami w przypadku nadruku realizowanego
przez system informatyczny, nie ma obowiązku
wstawiania liter idealnie do kratki. Nie należy
jednak wykraczać z liczbą znaków ponad liczbę
przewidzianych kratek.

Technicznie powyższy kod jest powtórzeniem
wszystkiego o czym pisaliśmy wcześniej. Na
początku inicjowane są dane – w tablicy, dla
łatwiejszej ich obsługi. Następuje import wzoru
pustego dokumentu z obrazu PNG. Tworzony jest
łańcuch ze ścieżką do czcionki, a także inicjujemy
kolor czarny.

Kolejne linie to już wstawianie tekstu w odpowiednich
miejscach formularza. Tekst wpisywany
jest czcionką 14, w linii poziomej. Oczywiście
wielkość czcionki oraz miejsce wstawienia tekstu
zależy nie tylko od wzoru formularza, ale także od
jego rozdzielczości.

Dokument polecenia przekazu należy do tych,
które trzeba w urzędzie pocztowym złożyć w kilku kopiach. Dla GD nie jest to szczególnie trudne
wyzwanie. Wystarczy, że kilkakrotnie skopiujesz
wypełniony formularz:

$width = imagesx($image);
$height = imagesy($image);
// Nowy obraz ma dwa razy wieksza szerokosc i wysokosc
$new_width = $width * 2;
$new_height = $height * 2;
$image_new = imagecreatetruecolor($new_width, $new_height);
for ($x = 0; $x <= $width; $x += $width) {
  for ($y = 0; $y <= $height; $y +=$height) {
    imagecopyresized($image_new, $image, $x, $y, 0, 0, $width, $height, $width,$height);
  }
}
imagepng($image_new);

Na początek musimy pobrać długość i szerokość
obrazu stworzonego w poprzednim przykładzie,
aby na jego podstawie stworzyć nowy obraz
- dwa razy szerszy i dwa razy dłuższy (łącznie
generowane będą bowiem cztery kopie przekazu).
We wcześniejszej części artykułu poznałeś już
funkcję {stala}getimagesize(){/stala}, która służy do pobierania
rozdzielczości pliku. Wówczas konieczne było
jednak podanie ścieżki do pliku.

Do obsługi tego samego zadania, ale w odniesieniu
do obrazów, które zostały już zaimportowane
i przechowywane są w postaci zasobu, służą
funkcje {stala}imagesx(){/stala} oraz {stala}imagesy(){/stala}. Pobierają one
kolejno szerokość i wysokość obrazu.
Następnie na bazie tych danych utworzony
zostaje nowy obraz - znaną już funkcją {stala}imagecreatetruecolor(){/stala}.

Kopiowanie odbywa się w pętlach,
które zawierają łącznie po dwa przebiegi (po jednym
dla każdej z nich), dokonując czterokrotnego
kopiowania oryginalnego formularza.

Rysowanie kształtów

Biblioteka GD pozwala nie tylko na wprowadzanie
do obrazów tekstów, ale także na
rysowanie kształtów. Do wyboru są różne formy
- począwszy od prostych linii, poprzez prostokąty,
koła, a skończywszy na rozmaitych kształtach
tworzonych za pośrednictwem poligonów. Służy do
tego szereg następujących funkcji:

  • {stala}imageline(){/stala} - rysuje linię,
  • {stala}imagerectangle(){/stala} - rysuje prostokąt,
  • {stala}imageellipse(){/stala} - rysuje elipsy i okręgi,
  • {stala}imagepolygon(){/stala} - służy do tworzenia bardziej złożonych wielokątów.

Każda z tych funkcji ma także swój odpowiednik
pozwalający na rysowanie z wypełnieniem,
czyli odpowiednio: {stala}imagefilledline(){/stala}, {stala}imagefilledrectangle(){/stala},
{stala}imagefilledellipse(){/stala}, {stala}imagefilledpolygon(){/stala}.

Oto przykłady zastosowania tych funkcji:

$image = imagecreatetruecolor(500, 500);
$white = imagecolorallocate($image, 255, 255, 255);
imagefilledrectangle($image, 0, 0, 500, 500, $white);

W taki sposób możesz stworzyć wypełniony
prostokąt w kolorze białym. Przy okazji służy on
tutaj jako jeden ze sposobów na ustawienie koloru
tła nowo stworzonego obrazu (prostokąt wypełnia
cały obraz).

Parametry przekazywane do metody {stala}imagefilledrectangle(){/stala}
to kolejno - zasób obrazu,
współrzędne X i Y lewego górnego narożnika
oraz współrzędne prawego dolnego narożnika.
Ostatnim przekazywanym parametrem jest kolor
- prostokąt będzie w całości wypełniony bielą.
Gdyby zastosować funkcję {stala}imagerectangle(){/stala}, biała
byłaby jedynie obwódka.

Oto najprostsza funkcja, rysująca linię pomiędzy
dwoma punktami:

$red = imagecolorallocate($image, 255, 0, 0);
imageline($image, 30, 40, 460, 350, $red);

Linia rozpocznie się w punkcie (30,40) i będzie
biegnąć do (460, 350). Charakteryzuje ją kolor
czerwony.

W taki sposób możesz wykorzystać jednocześnie
zarówno funkcję {stala}imageellipse(){/stala}, jak i {stala}imagefilledellipse(){/stala}
do rysowania koła wraz z obwódką:

$green = imagecolorallocate($image, 0, 255, 0);
$gray = imagecolorallocate($image, 230, 230, 230);
imagefilledellipse($image, 250, 250, 300, 200, $gray);
imageellipse($image, 250, 250, 300, 200, $green);

Środek koła będzie miał kolor jasnoszary,
natomiast obwódka ma kolor zielony. Parametry
liczbowe oznaczają kolejno - współrzędne X i Y
środka okręgu, następnie jego długość w poziomie
i wysokość w pionie. Jeśli wartość długości i szerokości
są równe, biblioteka GD narysuje okrąg
o zadanej średnicy.

{stala}Imagepolygon(){/stala} to sposób na rysowanie bardziej
skomplikowanych, ale regularnych kształtów.
Funkcja ta dostarcza narzędzia dorysowania
wielokątów. Ich rysowanie odbywa się poprzez
dostarczenie współrzędnych wszystkich kolejnych
wierzchołków - ich liczba jest praktycznie nieograniczona:

$blue = imagecolorallocate($image, 0, 0, 255);
$points = Array(430, 50, 150, 200, 100, 150, 100, 400, 150, 450, 400, 300);
imagepolygon($image, $points, 6, $blue);

Trzy kluczowe parametry przekazywane do
funkcji to: tablica ze współrzędnymi, ich liczba
oraz użyty kolor. Tablica jest jednowymiarowa,
zawiera współrzędne X i Y kolejnych punktów
używane naprzemiennie (np. X1, Y1, X2, Y2
itd.). Wartość numeryczna określająca liczbę
wierzchołków powinna stanowić długość tablicy
podzieloną na 2. Aby zastosować wielokąt
z wypełnieniem, sięgnij po funkcję {stala}imagefilledpolygon(){/stala}.

Tworzenie wykresu

Żeby zaprezentować rysowanie obiektów wraz
z nakładaniem napisów w praktyce, pokażemy,
jak stworzyć bardzo prosty skrypt rysujący wykres
słupkowy. Na początek krótkie przygotowanie
obrazu oraz zdefiniowanie kolorów:

$image = imagecreatetruecolor(500, 500);
$gray = imagecolorallocate($image, 230, 230, 230);
$red = imagecolorallocate($image, 220, 0, 0);
$white = imagecolorallocate($image, 255, 255, 255);
// Inny sposob na kolorowanie tla
imagefill($image, 0, 0, $gray);

Obraz tworzony przez funkcję {stala}imagecreatetruecolor(){/stala}
jest domyślnie czarny. We wcześniejszych
przykładach pokazaliśmy, w jaki sposób można
zmienić kolor tła, nakładając prostokąt o szerokości
i wysokości równiej parametrom obrazu.

Nie jest to jedyny sposób. Do tego celu równie
dobrze nadaje się użyta powyżej funkcja {stala}imagefill(){/stala}.
Wypełnia ona kolorem cały jednolity obszar, zaczynając
od wskazanego punktu (w przykładzie 0,0).

Jeśli obszar nie jest jednolity, wypełniona zostanie
tylko jego część - w taki sposób można np. wypełniać
kolorem wnętrza określonych kształtów.

Poniższy kod ma na celu przygotowanie
danych, czyli podstawowe informacje o poszczególnych
słupkach wykresu - każdy z nich jest
określany przez swoją wartość oraz przez opis:

$dane = array(
  array( "wartosc" => 200, "opis" => "Slupek 1" ),
  array( "wartosc" => 90, "opis" => "Slupek 2" ),
  array( "wartosc" => 150, "opis" => "Slupek 3" )
);
$razem = 0;
$najwyzszy = 0;
foreach ($dane as $slupek) {
  $razem += $slupek["wartosc"];
  if ($slupek["wartosc"] > $najwyzszy)
    $najwyzszy = $slupek["wartosc"];
}

Ponieważ proporcje pomiędzy wysokością słupków
będą wyliczane automatycznie, potrzebna jest
do tego zsumowana wartość wszystkich słupków,
a także zapamiętana wartość najwyższego z nich.
Poniżej ustalane są pewne parametry konfiguracyjne,
związane głównie z umiejscowieniem
wykresu na obrazie:

// Maksymalna wysokosc dla najwyzszego slupka
$wysokosc = 350;
// Wysokosc podstawy slupka (najnizszy punkt slupka)
$podstawa = 400;
// Szerokosc slupka
$szerokosc = 60;
// Startowa wspolrzedna X pierwszego slupka
$x = 70;
// Odstep X miedzy slupkami
$odstep = 150;
//Oto właściwa funkcja będąca głównym silnikiem prezentowanego algorytmu:
foreach ($dane as $slupek) {
  // Wyliczenie wysokosci slupka z proporcji
  $wysokosc_slupka = $slupek['wartosc'] * $wysokosc / $najwyzszy;
  $y = $podstawa - $wysokosc_slupka;
  imagefilledrectangle($image, $x, $y,$x + $szerokosc, $podstawa, $red);
  // Wartosc
  imagestring($image, 10, $x + 15, $y + 20, $slupek['wartosc'], $white);
  // Opis
  imagestring($image, 10, $x, $podstawa + 30, $slupek['opis'], $red);
  $x += $odstep;
}

Jest to pętla, która zajmuje się w kolejnych
przejściach obróbką poszczególnych słupków
ze zbioru naszych danych. Pierwszą czynnością,
jaką należy wykonać jeszcze przed rozpoczęciem
rysowania - jest określenie wysokości słupka. Przeliczenie
dokonywane jest na podstawie proporcji,
przy czym najwyższy słupek otrzyma pełną przewidzianą
wysokość, zaś wysokość niższych słupków
będzie proporcjonalnie mniejsza.

Wyliczana jest także pomocnicza wartość
$y. Ponieważ słupki rozpoczynają się w jednym
miejscu u dołu wykresu ($podstawa), więc różnić
się będą punktem wysokością stanowiącą górną
krawędź rysowanego prostokąta. Określa ją właśnie
wartość $y.

W kolejnym kroku następuje już właściwe
rysowanie prostokąta, z którego powstanie słupek.
Ma on kolor czerwony. Jego uzupełnieniem są
informacje tekstowe - wartość liczbowa nieco
poniżej górnej krawędzi wierzchołka oraz opis
znajdujący się pod słupkami.

Możesz tutaj zauważyć zastosowanie do
wyświetlania tekstu funkcji {stala}imagestring(){/stala}, która
nie była dotąd omawiania. To najprostsza funkcja
obsługująca wyświetlanie tekstu. Od wcześniej
omawianych różni się tym, że nie przyjmuje jako
parametru nazwy czcionki - funkcja ta pracuje na
jednej znanej sobie czcionce systemowej, której
nie można zmienić.

Jedyne definiowalne parametry
to rozmiar (tutaj 10), współrzędne, właściwy tekst
oraz kolor. Ponieważ {stala}imagestring(){/stala} nie obsługuje
polskich znaków, prawdopodobnie będziesz często
wybierał inne możliwości tworzenia tekstu.
Na koniec tworzenia wykresu należałoby
oczywiście jeszcze wysłać obraz do przeglądarki,
jednym ze znanych już sposobów.

Korzystanie z przezroczystości

Tworzone dotychczas obiekty charakteryzowały
się tym, że całkowicie przykrywały znajdujące się
pod nimi dane graficzne. Tymczasem wiele programów
graficznych pozwala na nakładanie grafiki
przy użyciu częściowej przezroczystości i tzw. "kanału
alpha", definiującego stopień zakrycia starego
obrazu przez nowo nakładany element (w programach
znane jako właściwość "opacity"). Biblioteka
GD również dostarcza takich możliwości:

$image = imagecreatefromjpeg("gory.jpg");
$blue = imagecolorallocatealpha($image, 0, 0, 255, 50);
imagefilledrectangle($image, 50, 50, 300, 300, $blue);

Przykład ten otwiera obraz JPG, a następnie nanosi
na niego częściowo przejrzysty prostokąt. Jest
to możliwe dzięki zastosowaniu funkcji {stala}imagecolorallocatealpha(){/stala},
będącej rozszerzeniem dobrze już
nam znanej {stala}imagecolorallocate(){/stala}. Różnica polega
na definiowaniu dodatkowej składowej alpha,
która określa stopień przezroczystości danego
koloru. Jest to wartość z zakresu od 0 do 127,
gdzie 0 oznacza całkowitą nieprzejrzystość (pełne
zakrycie kolorem), a 127 całkowitą przezroczystość.

W przykładzie zastosowano wartość 50.
Kolejny przykład dotyczy importu plików,
korzystających z transparencji. Takimi formatami są
na przykład GIF oraz PNG, które mają możliwość
przechowywania informacji o tym, które piksele
są przezroczyste. W czasie nanoszenia takiego
obrazu elementy przezroczyste nie zakryją obrazu,
na który są nanoszone.

Poniższy kod wczytuje dwa obrazy, a następnie
kopiuje drugi na pierwszy:

$image = imagecreatefromjpeg("gory.jpg");
$image2 = imagecreatefromgif("znak.gif");
list($width, $height) =  getimagesize("watermark.gif");
imagecopy($image, $image2, 400, 300, 0, 0, $width, $height);

Ponieważ drugi z wczytywanych obrazów to GIF,
w którym zapisano transparencję, więc w efekcie
skopiowane zostaną tylko nieprzezroczyste elementy.
Łatwo widać to na nietypowych kształtach.
Jeśli na przykład GIF zawiera elipsę, to w takiej
postaci zostanie ona wklejona na zdjęcie. Gdyby
ta sama elipsa została odczytana np. z pliku JPG
albo z GIF bez zapisu przezroczystości, kopiowanie
odbyłoby się wraz z całym oryginalnym tłem
i w efekcie skopiowany zostałby kształt prostokąta.

GD dla zaawansowanych

W artykule omówionych zostało wiele najważniejszych
funkcji graficznych dostarczanych wraz
z biblioteką GD. Istnieje jeszcze sporo innych, choć
rzadziej używanych funkcji. Ich listę znajdziesz na
stronie projektu PHP, gdzie znajduje się osobny
dział poświęcony GD (http://pl2.php.net/gd).
Zachęcamy także do odwiedzenia oficjalnej strony
internetowej biblioteki GD, działającej pod adresem
http://www.libgd.org.