Log in

View Full Version : GD Image - Line Break?



Vernier
08-15-2012, 11:31 AM
Hi guys,

I need to be able to have multiple strings in a gd image and create a line break between each one. How could I do this?

I currently have this:


<?php
header("Content-type: image/png");
$string =
'Your IP Address: '.$_SERVER['REMOTE_ADDR'].
'Your OS: '.getOS($_SERVER['HTTP_USER_AGENT']);

function getOS($userAgent) {
// Create list of operating systems with operating system name as array key
$oses = array (
'iPhone' => '(iPhone)',
'Windows 3.11' => 'Win16',
'Windows 95' => '(Windows 95)|(Win95)|(Windows_95)', // Use regular expressions as value to identify operating system
'Windows 98' => '(Windows 98)|(Win98)',
'Windows 2000' => '(Windows NT 5.0)|(Windows 2000)',
'Windows XP' => '(Windows NT 5.1)|(Windows XP)',
'Windows 2003' => '(Windows NT 5.2)',
'Windows Vista' => '(Windows NT 6.0)|(Windows Vista)',
'Windows 7' => '(Windows NT 6.1)|(Windows 7)',
'Windows NT 4.0' => '(Windows NT 4.0)|(WinNT4.0)|(WinNT)|(Windows NT)',
'Windows ME' => 'Windows ME',
'Open BSD'=>'OpenBSD',
'Sun OS'=>'SunOS',
'Linux'=>'(Linux)|(X11)',
'Safari' => '(Safari)',
'Macintosh'=>'(Mac_PowerPC)|(Macintosh)',
'QNX'=>'QNX',
'BeOS'=>'BeOS',
'OS/2'=>'OS/2',
'Search Bot'=>'(nuhk)|(Googlebot)|(Yammybot)|(Openbot)|(Slurp/cat)|(msnbot)|(ia_archiver)'
);

foreach($oses as $os=>$pattern){ // Loop through $oses array
// Use regular expressions to check operating system type
if(eregi($pattern, $userAgent)) { // Check if a value in $oses array matches current user agent.
return $os; // Operating system was matched so return $oses key
}
}
return 'Unknown'; // Cannot find operating system so return Unknown
}
$font = 2;
$width = imagefontwidth($font) * strlen($string);
$height = imagefontheight($font);

$image = imagecreatetruecolor ($width,'100px');
$white = imagecolorallocate ($image,255,255,255);
$black = imagecolorallocate ($image,0,0,0);
imagefill($image,0,0,$white);

imagestring ($image,$font,0,0,$string,$black);

imagepng ($image);
imagedestroy($image);
?>
I need a line break between the concatenated string.

Thanks

keyboard
08-16-2012, 01:01 AM
I need a line break between the concatenated string.


What concated string?

Do you mean -


$string =
'Your IP Address: '.$_SERVER['REMOTE_ADDR'].
'Your OS: '.getOS($_SERVER['HTTP_USER_AGENT']);


If so, try



$string =
'Your IP Address: '.$_SERVER['REMOTE_ADDR']. "\n" .
'Your OS: '.getOS($_SERVER['HTTP_USER_AGENT']);

or



$string =
'Your IP Address: '.$_SERVER['REMOTE_ADDR']. '<br />'.
'Your OS: '.getOS($_SERVER['HTTP_USER_AGENT']);

This doesn't work!!! :D

djr33
08-16-2012, 01:07 AM
If that doesn't work (and it might not), then you may need to insert the line breaks manually-- either always be sure no line is too long or explode() the string into maximum-length chunks (lines) and write each line separately, moving the coordinates down 10-20px depending on the size of the font.
I've never found the GD text functions to be intuitive, but you should be able to get something that works. The real trick is if you want to wrap the text, because it's very hard to know how wide that text will be and where it needs to wrap. The number of characters will only be a bad approximation. One option is to preview it by writing the text and then measuring the number of pixels, and there might be another trick I can't remember.

Nile
08-16-2012, 01:11 AM
What concated string?

Do you mean -


$string =
'Your IP Address: '.$_SERVER['REMOTE_ADDR'].
'Your OS: '.getOS($_SERVER['HTTP_USER_AGENT']);


If so, try



$string =
'Your IP Address: '.$_SERVER['REMOTE_ADDR']. "\n" .
'Your OS: '.getOS($_SERVER['HTTP_USER_AGENT']);

or



$string =
'Your IP Address: '.$_SERVER['REMOTE_ADDR']. '<br />'.
'Your OS: '.getOS($_SERVER['HTTP_USER_AGENT']);
Your second solution will definitely not work. The GD library doesn't render HTML. Let me try your first solution.

Edit:
Your first solution gets something like this:

http://cl.ly/image/2X453b1P3F1p/Screen%20shot%202012-08-15%20at%208.16.53%20PM.png

The best thing to do here is to go with Daniel's solution. To get the height of your font, you can use imagefontheight. If you're going to create a custom function to determine when to wrap the text, looping through all the letters in the string and adding them using the imagefontwidth function would be very helpful.

bernie1227
08-16-2012, 03:59 AM
What is this? Nile posting? :p

Nile
08-16-2012, 04:41 AM
What is this? Nile posting? :p
I'm still here every once in a while.

OP - Try the imagefontwidth function in order to create a function that will wrap your text so that it fits in the image. I'll take a stab at this also tomorrow and post back with results.

Vernier
08-16-2012, 02:33 PM
Thanks for the replys guys.

The problem is the separate string lengths will vary depending on there IP or OS.

I don't really want:

Your IP is: 127.0.0.1 Your O
S is: Linux

I need it to be in this format:
Your IP is: 127.0.0.1
Your OS is: Linux

Thanks :)

Nile
08-16-2012, 02:53 PM
Thanks for the replys guys.

The problem is the separate string lengths will vary depending on there IP or OS.

I don't really want:

Your IP is: 127.0.0.1 Your O
S is: Linux

I need it to be in this format:
Your IP is: 127.0.0.1
Your OS is: Linux

Thanks :)

It seems as if you didn't read Daniel's or my comment.

Use the imagefontheight() function to determine how tall the font is, then separate the strings into two different strings. Call both of the strings through different functions. The second light should have the same y coordinate as the first line PLUS (+) the imagefontheight(). This will not be explained again.


If anybody is interested, I've made animagewrapttftext function that will wrap text around the width of an image. Use it like imagettftext. The only difference is that once the text reaches the edge of the image, it wraps.

View an example and its source at http://eg.jfein.net/wraptext/


function calculateTextBox($size, $angle, $fontfile, $text) { //found on http://php.net/manual/en/function.imagettfbbox.php
$rect = imagettfbbox($size, $angle, $fontfile, $text);

$minX = min(array($rect[0],$rect[2],$rect[4],$rect[6]));
$maxX = max(array($rect[0],$rect[2],$rect[4],$rect[6]));
$minY = min(array($rect[1],$rect[3],$rect[5],$rect[7]));
$maxY = max(array($rect[1],$rect[3],$rect[5],$rect[7]));

return array(
"left" => abs($minX) - 1,
"top" => abs($minY) - 1,
"width" => $maxX - $minX,
"height" => $maxY - $minY,
"box" => $rect
);
}

function imagewrapttftext($image, $size, $angle, $x, $y, $color, $fontfile, $text) {
if(empty($text)){
return true; // satisfied; job complete.
}
for($i = 0, $relWidth = $x; $i < strlen($text); $i++){
$boundingbox = calculateTextBox($size, $angle, $fontfile, $text[$i]);
$tallestLetter = calculateTextBox($size, $angle, $fontfile, "|");
$relWidth += $boundingbox['width'];
if($relWidth > imagesx($image)){
$tempString = explode(" ", substr($text, 0, $i));
$offsetIdentifier = array_pop($tempString);
imagettftext($image, $size, $angle, $x, $y, $color, $fontfile, implode(" ", $tempString));
$newText = substr($text, $i - strlen($offsetIdentifier), strlen($text));
imagewrapttftext($image, $size, $angle, $x, $y + $tallestLetter['height'], $color, $fontfile, $newText);
break;
}
if($i == strlen($text)-1){
imagettftext($image, $size, $angle, $x, $y, $color, $fontfile, $text);
return true; //satisfied; job complete.
break;
}
}
}



A smarter solution, actually, maybe to just explode the string by spaces and test word by word instead of character by character and then back tracing to the last space. If I'm in the mood I'll work on that tomorrow.