Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Generowanie grafiki GD, TEKST
Forum PHP.pl > Forum > PHP
Gray
Witam, znalazłem pewien tutorial odnośnie tworzenia grafiki za pomocą GD. Zmodyfikowałem delikatnie kod który tam był opisany i w efekcie posiadam taki kod:

  1. <?php
  2. $tekst=$_POST['tekst'];
  3.  
  4. $data_img=date('dmYHis');
  5. $uploaddir = 'img/upload/'.$data_img.'-slowo.png';
  6.  
  7. $im = @imagecreate(200, 100)
  8. or die("Cannot Initialize new GD image stream");
  9. $background_color = imagecolorallocate($im, 0, 0, 0);
  10. $text_color = imagecolorallocate($im, 255, 255, 255);
  11. imagestring($im, 1, 5, 5, $tekst, $text_color);
  12. imagepng($im, $uploaddir);
  13. ImageDestroy($im);
  14. ?>


Oczywiście do jego obsługi wystarczy prosty formularz z oknem textowym "tekst". Ale do rzeczy, kod ten tworzy czarny prostokąt i na nim biały napis. Chciał bym móc manipulować tym tekstem i wielkością prostokąta. Dokładniej mówiąc chciał bym móc ustawić marginesy dla tekstu i jego wyśrodkowanie lub wyjustowanie, odpowiednie zawijanie wierszy w przypadku dłuższego tekstu, skalowanie wielkości prostokąta względem ilości tekstu i wielkości czcionki lub na odwrót, wielkości czcionki względem wielkości prostokąta. I czy jest możliwość stosowania zaawansowanych opcji do samej czcionki, takich jak używa się w css.

Pozdrawiam,
Gray
croc
PHP GD nie posiada takich opcji. Jedyne co możesz zrobić to poszukać gotowych rozwiązań lub samemu się pobawić matematycznie, ale to będzie dużo pracy.
Pawel_W
imagettfbbox
to Ci pomoże do zabawy z wielkością prostokąta (marginesy itp.)

w przykładzie masz pokazane jak wyśrodkować tekst, na siłę mógłbyś za pomocą tej funkcji robić zawijanie wierszy
Gray
Dzięki Paweł_W za podpowiedz, w gruncie rzeczy myslałem o tej funkcji ale łudziłem się, że będzie coś co wymaga mniej kombinowania. Jakoś to ogarnę jednak jak wyśrodkować czcionkę względem siebie, tzn. po podzieleniu tekstu na wiersze funkcją wordwrap() aby układały się one pod sobą wyśrodkowane a nie ustawione do lewej? coś w tym stylu:

aaaaaaaaaaaaa
aaaaa
aaaaaaaaa


Czyli <center> lub jakiś sposób na wyjustowanie?
croc
W odpowiedzi na to pytanie nie ma nic o czym nie wiesz. Tak jak napisałem powyżej, to zabawa matematyczna - musisz podzielić tekst na słowa i sprawdzać czy kolejne mieszczą się w wierszu. Jeśli nie, to schodzisz niżej. Możesz też w ten sposób próbować wyjustować, tzn. jak już masz gotowy wiersz, to obliczyć odstępy między słowami/literami takie, by zapełnić wiersz.
Gray
Hmm, z tym dzieleniem na słowa i sprawdzaniem czy się mieszczą jest problem. Sprawdzić to potrafię tylko pod względem ilości znaków, w sumie nawet nie tyle potrzeba sprawdzać wyrazy co wiersze. Jednak jak sprawdzić czy ciąg znaków mieści się w danym polu pod względem szerokości w pikselach a nie ilości znaków?
Jak wiadomo każda literka jest innej szerokości, i tak o ile wpasuję sobie idealnie ciąg znaków iiiiiiiiii to inny ciąg np. WWWWWWWWWW kompletnie nie będzie pasował mimo takiej samej ilości znaków.

Istnieje jakaś funkcja lub sposób podobny do wordwrap(); która jako wyznacznik miejsca dzielenia ciągu przyjmuje szerokość w pikselach a nie ilość znaków?

Jestem początkujący w PHP dlatego proszę o pomoc i ewentualne dokładne wytłumaczenie.

Pozdrawiam,
Gray.
dwwa
jak dobrze pamiętam to funkcja imageftbbox() ci pomoże

tu zobacz
http://www.viawww.wortale.net/135-Centerow...u-w-PHP-GD.html
Gray
Ta właśnie jestem w trakcie maglowania tej funkcji, zrobiłem takie coś i wydaje się w miarę działać:

  1. <?php
  2. // Create a 300x150 image
  3. $im = imagecreatetruecolor(550, 400);
  4. $black = imagecolorallocate($im, 0, 0, 0);
  5. $white = imagecolorallocate($im, 255, 255, 255);
  6.  
  7. // Set the background to be black
  8. $background_color = imagecolorallocate($im, 0, 0, 0);
  9.  
  10. // Path to our font file
  11. $font = './book.ttf';
  12.  
  13. // ustawienie tekstu
  14. $text = "FGHFGH GTH RHGTRGH TRTRIOHR OT GGUGH G GEGU EUI OGHGUIOG UIOG UO GEFUIOGERU IOGERUIOG UIO ERO EEUIOG GEHGERUI GHIOJEOG VO EO QEROGI ER";
  15.  
  16. ////////////////////////////////////////////////////////PĘTLA
  17. $wielkoscczcionki=20;
  18. $enter=40;
  19. $szerokosc=531;
  20. while($szerokosc>490){
  21.  
  22. $newtext = wordwrap($text, $enter, "\n", TRUE);
  23. $bboxx = imagettfbbox($wielkoscczcionki, 0, $font, $newtext);
  24. $szerokosc = $bboxx[4] - $bboxx[6];
  25. $enter--;
  26. }
  27. /////////////
  28.  
  29. // Write it
  30. imagettftext($im, $wielkoscczcionki, 0, 30, 40, $white, $font, $newtext);
  31.  
  32.  
  33. // Output to browser
  34. header('Content-Type: image/png');
  35.  
  36. imagepng($im);
  37. imagedestroy($im);
  38. ?>


Chciał bym prosić kogoś o jakieś wskazówki szczególnie dotyczące pętli while, pisałem ją sam, wydaje się działać ale mogłem coś zawalić.
croc
Twoja metoda nie ma sensu. Porównaj wyniki z użyciem "słów" złożonych z samych liter "i" z takich z samymi "W". Mój sposób jest chyba jedynym sensownym. Badanie szerokości bloku po każdym dodaniu słowa. Kolega Pawel_W podał Ci nazwę funkcji do badania szerokości bloku.
dwwa
http://pl.php.net/manual/en/function.imagettftext.php

a dokładniej chodzi mi o funkcje napisaną przez użytkownika w komentarzu do funkcji imagettftext
  1. <?php
  2. function wrap($fontSize, $angle, $fontFace, $string, $width){
  3.  
  4. $ret = "";
  5.  
  6. $arr = explode(' ', $string);
  7.  
  8. foreach ( $arr as $word ){
  9.  
  10. $teststring = $ret.' '.$word;
  11. $testbox = imagettfbbox($fontSize, $angle, $fontFace, $teststring);
  12. if ( $testbox[2] > $width ){
  13. $ret.=($ret==""?"":"\n").$word;
  14. } else {
  15. $ret.=($ret==""?"":' ').$word;
  16. }
  17. }
  18.  
  19. return $ret;
  20. }
  21. ?>

a jak to ci nie pomoże to szukaj w google "php gd pietrzenie tekstu"
croc
No właśnie. Dokładnie o coś takiego chodzi. Problem w tym, że ta funkcja testuje jedynie czy słowo mieści się w wierszu, a to tylko wierzchołek góry lodowej - działaj, kolego.
Gray
Wiem, że podał, już wcześniej ktoś inny ją podał i ja ją wykorzystuję w pętli którą podałem wyżej:

  1. $wielkoscczcionki=20;
  2. $enter=40;
  3. $szerokosc=531;
  4. while($szerokosc>490){
  5.  
  6. $newtext = wordwrap($text, $enter, "\n", TRUE);
  7. $bboxx = imagettfbbox($wielkoscczcionki, 0, $font, $newtext);
  8. $szerokosc = $bboxx[4] - $bboxx[6];
  9. $enter--;
  10. }


Sprawdza ona szerokość podzielonego na wiersze tekstu przy początkowo przyjętej ilości znaków po której następuje "enter" jako 40. Jeśli wykryje, że ta szerokość jest większa niż pożądana to zmniejsza ilość znaków po których następuje "enter" o 1. Będzie zmniejszało długość pojedynczego wiersza aż całość zmieści się w podanej szerokości czyli 490.

Staram się napisać teraz podobną pętlę do wysokości, jednak nie będzie redukowała ona długości pojedynczego wiersza, zamiast tego będzie zmniejszała wielkość czcionki. Jednak póki co nie bardzo mi to wychodzi.
croc
wordwrap jest tutaj bezużyteczny.
Gray
tzn. nie wiem czy jest bezużyteczny w bardzo zoptymalizowanej wersji której ja pewnie nie wymyślę, jednak w mojej pętli wordwrap dzieli ciąg znaków na wiersze jeden pod drugim, w każdym wierszu max 40znaków. I jeśli pętla wykryje ze 40 znaków to za dużo przy ustalonej szerokości to zmniejsza wiersz o 1. Wtedy wordwrap dostaje polecenie podziału ciągu na wiersze jeden pod drugim, 39 znaków na wiersz itd.

Oczywiście można zauważyć, że imageftbbox() sprawdza szerokość już po podziale przez wordwrap.
croc
Bezużyteczny, bo - jak napisałem powyżej - jeden ciąg długości X znaków może być 2 razy dłuższy/krótszy niż drugi. Optymalizacją się nie martw, ale co się stanie jak wordwrap wygeneruje Ci tak, że zmieściłoby się jeszcze jedno słowo? Nie martw się optymalizacją zanim nie działa jak powinno smile.gif Zrób explode(' ', $string) i dodawaj klocek po klocku. Wchodzi - dodajemy do wiersza. Nie wchodzi? Schodzimy niżej.
Pawel_W
obiło mi się kiedyś o uszy coś takiego jak phpHyphenator, który dzieli tekst tak, aby ładnie się "justował" - może to Ci pomoże, chociaż nie wiem dokładnie czy cały skrypt jest napisany w php smile.gif
croc
Temat jest bardzo ciekawy. To może przydać: http://www.google.pl/search?gcx=w&sour...stify+algorithm

EDIT
Ja jestem w trakcie pisania nakładki obiektowej dla GD (bardziej dla praktyki niż użyteczności). Zainspirowany tym tematem zacząłem robić metodę wypisywania tekstu jako bloku. Póki co zrobiłem sobie centrowanie tekstu. Efekt jest taki:


Kod metody:
  1. public function text($text, $width, $font, $size, Color $color, $x, $y) {
  2. $fontFileName = './'.$font.'.ttf';
  3. $words = explode(' ', $text);
  4. $rows = array();
  5. $row = '';
  6. $rowWidth = 0;
  7. foreach($words as $word) {
  8. $element = ($row === '' ? null : ' ').$word;
  9. $box = imagettfbbox ($size, 0, $fontFileName, $element);
  10. $elementWidth = $box[2] - $box[0];
  11. if($rowWidth + $elementWidth <= $width) {
  12. $row .= $element;
  13. $rowWidth += $elementWidth;
  14. }
  15. else {
  16. array_push($rows, $row);
  17. $row = $word;
  18. $rowWidth = $elementWidth;
  19. }
  20. }
  21. foreach($rows as $row) {
  22. $box = imagettfbbox ($size, 0, $fontFileName, $row);
  23. imagettftext($this->source, $size, 0, $x + ($width - ($box[2] - $box[0]) >> 1), $y, $color->identifier, $fontFileName, $row);
  24. $y += $size << 1;
  25. }
  26. }

A powyższy obrazek wywołałem tak:
  1. $image = new Image(400, 300, new Color(0, 0, 0));
  2. $image->gradient(new Color(235, 245, 255), new Color(215, 235, 255));
  3. $image->text(file_get_contents('text.txt'), $image->getWidth(), 'arial', 12, new Color(0, 123, 255), 0, 20);
  4. $image->show();


Metoda oczywiście zawiera błędy. Fajnie byłoby, gdyby udało się stworzyć rozwiązanie, które służyłoby do wypisywania tekstu z dowolnym sposobem wyrównania.

Zastanawia mnie jak najlepiej rozwiązać justowanie:
  1. wydłużać tylko spacje
  2. wydłużać spacje i odstępy między literami po równo
  3. wydłużać spacje bardziej niż odstępy między literami

Wydaje mi się, że sposób 3. jest najlepszy, ale jaki współczynnik obrać? smile.gif
Gray
Heh fajnie, że kogoś to zainspirowało. Ja jestem początkujący w PHP więc raczej w samym pisaniu niewiele pomogę. Jedynie zauważyłem, że w programach tekstowych np. Word justowanie polega na zwiększaniu spacji pomiędzy wyrazami. Najlepiej w całym bloku wszystkie spacje zwiększać o tyle samo i ewentualne nadwyżki/niedobory redukować spacjami na końcu wiersza.
croc
Cytat(Gray @ 26.10.2011, 01:53:48 ) *
i ewentualne nadwyżki/niedobory redukować spacjami na końcu wiersza.

Obawiam się, że to już nie będzie justowanie. Justowanie to dokładne rozłożenie od lewej do prawej. Trzeba policzyć długość spacji w każdym wierszu, która przeważnie będzie liczbą zmiennoprzecinkową. Potem trzeba wstawiać spację po spacji, uwzględniając zaokrąglenie dla danej pozycji. Przykład:

średnia długość spacji: 1.7px
licznik: 1.7
SPACJA 1: 2px
licznik: 3.4
3.4 - 2 = 1.4
SPACJA 2: 1px
licznik: 5.1
5.1 - 3 = 2.1
SPACJA 3: 2px
licznik: 6.8
6.8 - 5 = 1.8
SPACJA 4: 2px
itd.
Gray
Nie bardzo rozumiem, poco liczyć długość wszystkich spacji w każdym wierszu (może to przez tą późną godzinę)? Nie łatwiej by było sprawdzać długość każdego wiersza w pixelach i te krótsze wiersze "wydłużać", wstawiając równomiernie spacje między wyrazami?
croc
Nie możemy sobie wstawiać "spacji", bo spacja ma określoną długość, a my potrzebujemy przerwy o konkretnej szerokości. Najlepiej moim zdaniem policzyć szerokość bloku niezawierającego spacji i potem rysować słowo po słowie, zwiększając przy tym współrzędną X o długość spacji.

Jeżeli damy wszystkim spacjom po równo, to zostanie kilka pikseli. Jeśli średnia długość spacji wynosi 5.8, to niektóre ze spacji będą miały 5 pikseli, a większość 6. To drabinkowe zaokrąglanie jest fajne, bo rozłoży te różnice równomiernie. (czyli np. [6, 6, 6, 5, 6, 6, 6, 5, 6, 6], a nie [6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5]. Niby to tylko 1 piksel, ale zawsze.
Gray
Małe pytanie odnośnie GD i tekstu... dlaczego kiedy generuję tekst w cudzysłowach to nie wygląda on tak: "tekst" tylko tak: \"tekst\"

Pozdrawiam,
Gray
croc
stripslashes smile.gif
Gray
pomogło, dzięki!
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.