php gd2 – znaki wodne, napisy, ramki – operacje na obrazku

Ostatnio przypadkowo trafiłem na instrukcję jak za pomocą css i obrazka PNG ustawić narożniki dla obrazka. Dla mnie wydało się to bardzo nieprofesjolanie, bo wiadomo, że w takim rozwiązaniu należy stosować ieHack oraz dochodzi zbędny kod html,css i js. Postanowiłem opisać jak należałoby to zrobić wykorzystując gd2, tzn napisałem generator obrazków do tego celu :) Dodatkowo naniesiemy napis niestandardową czcionką – znak wodny, podpis itp

Założenia

Nie będę się rozpisywał co i jak – wszystko wynika z kodu jaki jest poniżej – komentarze rozwiewają wątpliwości.

Potrzebne obrazki

Narożnik – będziemy go obracać aby wstawić w każdy z 4 rogów

Obrazek źródłowy

Zaczynamy!

Uwaga – jest to procedura która wykonuję się za każdym razem bez mechanizmu cache, nie nadaje się do produkcyjnego zastosowania – jest to tylko przykład/instrukcja/dowód jak należy takie działania wykonywać. W przypadku chęci wykorzystania tego produkcyjnie – proszę o kontakt pomogę dopracować ten kod :)

Kod działa następująco
– pobiera zdefiniowany plik – tu powinno być odczytywanie parametru z GET, oraz sprawdzenie w cache czy istnieje juz wygenerowany taki plik, jak tak to powinien on zostać wysłany a procedura zatrzymana – to temat na kolejny artykuł dlatego tutaj nie ująłem tej ‘sztuczki’ :)
– tworzy obrazek docelowy i go koloruje na szaro
– na obrazek docelowy nakłada plik źródłowy wyśrodkowanie (margines – 10px)
– dodaje ramki wokół obrazka źródłowego – o grubosci 2px
– obracając narożnik dodaje go do każdego z rogów pliku docelowego
– dodaje podpis zdjecia z cieniem (czyli na czarny napis o pozycji x/y nanosi biały napis o pozycji x-1/y-1)

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
<?


//nasz obrazek
$im = imagecreatefromjpeg('source.jpg');



//plik docelowy, ustalenie rozmiaru i pokolorowanie
//plik docelowy jest o 20px szerwszy i dluzszy - po to aby wykonać ramkę
$destinationSize  =  array(imagesx($im)+20, imagesy($im)+20);
$destination = imagecreatetruecolor($destinationSize[0],$destinationSize[1]);
$white = imagecolorallocate($destination, 230, 230, 230);
$border = imagecolorallocate($destination, 255, 255, 255);
$black = imagecolorallocate($destination, 30, 30, 30);
imagefill($destination, 0, 0, $white);

//do pliku docelowego wklejamy nasz zrodlowy, wysrodkowanie
// zaczynając od punku 10,10 i wklejając w skali 1:1
imagecopyresampled($destination, $im,10 ,10 , 0, 0, imagesx($im),imagesy($im),imagesx($im),imagesy($im));


//namalowanie ramki, o grubosci 2px
//lewa
imageline($destination, 10,0,10,$destinationSize[1], $border);
imageline($destination, 9,0,9,$destinationSize[1], $border);

//prawa
imageline($destination, $destinationSize[0]-10,0,$destinationSize[0]-10,$destinationSize[1], $border);
imageline($destination, $destinationSize[0]-9,0,$destinationSize[0]-9,$destinationSize[1], $border);

//top
imageline($destination, 0,10, $destinationSize[0],10, $border);
imageline($destination, 0,9, $destinationSize[0],9, $border);

//bottom
imageline($destination, 0,$destinationSize[1]-10, $destinationSize[0],$destinationSize[1]-10, $border);
imageline($destination, 0,$destinationSize[1]-9, $destinationSize[0],$destinationSize[1]-9, $border);





//nasz narożnik
$layer = imagecreatefrompng('corner.png');

//lewy gorny rog
imagecopyresampled($destination, $layer,0 ,0 , 0, 0, imagesx($layer),imagesy($layer),imagesx($layer),imagesy($layer));


//obracamy o 90 stopni
$layer = imagerotate($layer, 90,1);
//lewy dol
imagecopyresampled($destination, $layer,0 ,$destinationSize[1]-imagesy($layer) , 0, 0, imagesx($layer),imagesy($layer),imagesx($layer),imagesy($layer));

//kolejny obrot i prawy dol
$layer = imagerotate($layer, 90,1);
imagecopyresampled($destination, $layer,$destinationSize[0]-imagesx($layer) ,$destinationSize[1]-imagesy($layer) , 0, 0, imagesx($layer),imagesy($layer),imagesx($layer),imagesy($layer));


//kolejny obrot i prawy dol
$layer = imagerotate($layer, 90,1);
imagecopyresampled($destination, $layer,$destinationSize[0]-imagesx($layer) ,0 , 0, 0, imagesx($layer),imagesy($layer),imagesx($layer),imagesy($layer));


//sciagamy funckcje z php.net....
function calculateTextBox($font_size, $font_angle, $font_file, $text) {
    $box = imagettfbbox($font_size, $font_angle, $font_file, $text);

    $min_x = min(array($box[0], $box[2], $box[4], $box[6]));
    $max_x = max(array($box[0], $box[2], $box[4], $box[6]));
    $min_y = min(array($box[1], $box[3], $box[5], $box[7]));
    $max_y = max(array($box[1], $box[3], $box[5], $box[7]));

    return array(
        'left' => ($min_x >= -1) ? -abs($min_x + 1) : abs($min_x + 2),
        'top' => abs($min_y),
        'width' => $max_x - $min_x,
        'height' => $max_y - $min_y,
        'box' => $box
    );
}

//tworzymy napis
$size = calculateTextBox(22, 0, 'font.ttf', 'Hrubieszów');

//nadajemy cień do napisu
imagettftext($destination, 22, 0, 1+$destinationSize[0]-$size['width']-imagesx($layer)/2,1+$destinationSize[1]-$size['height'], $black,'font.ttf', 'Hrubieszów');
//piszemy wlasciwy widoczny tekst
imagettftext($destination, 22, 0, $destinationSize[0]-$size['width']-imagesx($layer)/2,$destinationSize[1]-$size['height'], $border,'font.ttf', 'Hrubieszów');



header('Content-Type: image/jpeg');
imagejpeg($destination, '', 100);

Wynik

Podsumowanie

Nie bójmy się używać gd2 – nie stosujmy iehack na png jak nie musimy – taki wygenerowany obrazek możemy skopiować i użyć gdzie indziej, np w prezentacji, jeżeli natomiast narożniki byśmy nałożyli poprzez css – takiej możliwości by nie było.

 

Tagi: , , ,

Komentarze: 8 do “php gd2 – znaki wodne, napisy, ramki – operacje na obrazku”

  1. 1 eRIZ

    Dla mnie wydało się to bardzo nieprofesjolanie, bo wiadomo, że w takim rozwiązaniu należy stosować ieHack oraz dochodzi zbędny kod html,css i js.

    Dla mnie nieprofesjonalne jest stosowanie takich obejść i świadome omijanie tego, co oferują technologie.

    Jeśli chodzi o narożniki, istnieją pseudoklasy :before i :after. Ja rozumiem, że chodzi Ci o ideę cross-browser, ale:

    Korzystając z Twojego sposobu nigdy nie wyplenimy IE6, etc (skoro wszystko działa, to po co mam zmieniać przeglądarkę)
    niepotrzebnie zajeżdżasz serwer (oczywiście, można cache’ować, ale też nie w nieskończoność)
    jeśli ktoś zechce np. wydrukować sobie zdjęcia, to nie będziesz miał możliwości przygotowania lekkich obrazków
    spada jakość obrazu (dokonujesz ponownej stratnej kompresji, co może nieraz doprowadzić do niepotrzebnego zwiększenia wagi pliku)

    nie stosujmy iehack na png jak nie musimy

    To lepiej nic nie robić i tkwić w epoce IE6. Dzisiaj mamy do dyspozycji m.in. <canvas />, o którym można tylko pomarzyć właśnie „dzięki” IE. Owszem, są obejścia w stylu VRML, ale to tylko obejścia.

    Idea cross-browser – tak, rozwiązywanie problemów – tak, karanie użytkowników normalnych przeglądarek gorszą jakością zdjęć – nie.

    To były moje trzy grosze; wybacz – musiałem. ;)

  2. 2 eRIZ

    ps. wycięło mi listę wyliczeniową…

  3. 3 Amiano

    A ja bym poprosil o linka gdzie jest to samo zrobione ale w html/css :) Fajny efekt ale nie chce tego robic w php.

  4. 4 Mateusz Żeromski

    @Amiano Link do html/css
    http://www.tarnaski.eu/blog/korzystaj-z-png/

    @eRIZ – stratna kompresja – no rozumiem Ciebie, dlatego robi się mininiaturki i duże zdjęcia. Zazwyczaj na serwerze trzymam zdjecia min 1000/1000 z ktorych robię mini i maxi – także to nie problem. Nie wyobrażam sobie żebym sam musial robić miniaturki – jak mam do tego autmat, a tworząc miniaturki – dodam narożniki. Serwera nie zajeżdżam bo zawsze ale to zawsze w takich przypadkach robię cache i spokojna głowa. O nieskonczonosci cache – hmmm, nie rozumiem… Cachowac nalezy sql, strony, obrazki itp, a przesyłane pliki do usera – gzipować :)

    Jeżeli zaś jakość zdjęcia jest konieczna – wtedy zazwyczaj ma ono dużą objętość i robi się ikonkę „download 5MB”, pokaż mi stronę na której wyświetlane obrazki sposobem lightbox mają rozmiary większe niż 1000/1000 – ale taką jakąś dobrą stronę :) – nie ma, obrazki na www powinny miec maksymalnie 500/600 wysokości a to z powodu panoramicznych ekranów – fotka powinna się mieścić w oknie przeglądarki. I tutaj już mamy wymóg kompresji.

    Nie rozumiem też Twojego podejścia – zrozumiałem że celowo należy tworzyć rzeczy które nie dzialają pod IE6, i tym sposobem zmuszać do zmniejszania ilosci użytkownikow tej przegladarki – kompletnie odpada moim zdaniem – 25% to ie6 :)

    Drukowanie zdjęcia – no cóż masz rację w tym przypadku.

    Aktualnie tworzę skomplikowany system gdzie podstawa to javascript – w tym przypadku kompletnie olewam IE6, i jeżeli ktoś będzie chcial korzystać z narzędzia – będzie musiał się przenieść na nowszą przeglądarkę, zresztą to narzędzie jest dla profesjonalistów :). Lecz jest to backend – frontend aplikacji jest spójny z IE6 :)

    Podsumowując – dzięki za 3 grosze lecz jednak nie przekonało mnie to do używania css/js aby uzyskać efekt narożników :)

  5. 5 eRIZ

    „zrozumiałem że celowo należy tworzyć rzeczy które nie dzialają pod IE6, i tym sposobem zmuszać do zmniejszania ilosci użytkownikow tej przegladarki – kompletnie odpada moim zdaniem – 25% to ie6 :)”

    Chodzi mi o to, aby projektować wg standardów (:before, :after, itp), a niedoróbki „przeglądarek” niwelować hackami albo podobnymi rozwiązaniami. Wszystkie prawidłowo renderujące CSS wg standardów będą miały minimum danych do ściągania, zaś użyszkodnicy pseudoprzeglądarek poczują po łączach.

    Poza tym, jeśli chodzi o np. wyszukiwarki grafik (Google Images, itp), taki obrazek z nałożonymi „fabrycznie” obrazkami wygląda nieestetycznie.

  6. 6 Marcin webdeweloper & grafik

    Mam problem z dostosowaniem tego skryptu aby tak jak generowany jest cień pod napisem, generował cień pod obrazkami.

    Pomoże ktoś?

    Gratulacje za artykuł!

    gg 8046811
    marcincook@gmail.com

  7. 7 Mike

    Warning: imagettfbbox() [function.imagettfbbox]: Could not find/open font

    co z tym zrobić ??

    wrzuciłem czcionkę do katalogu z plikiem php i nic ;/

  8. 8 ilona

    ej jak sie nazywa znak ktury wygląda jak łudka

Napisz komentarz



Wersja mobilna