Using the imagettftext function with multiple lines? - php

I'm creating transparent text -> png images with php and so far so good. The only problem is that I want the ability to have the text word wrap due to a fixed width.. Or alternatively be able to insert breaklines into the text. Has anyone had any exp doing this? here is my code...
<?php
$font = 'arial.ttf';
$text = 'Cool Stuff! this is nice LALALALALA LALA HEEH EHEHE';
$fontSize = 20;
$bounds = imagettfbbox($fontSize, 0, $font, $text);
$width = abs($bounds[4]-$bounds[6]);
$height = abs($bounds[7]-$bounds[1]);
$im = imagecreatetruecolor($width, $height);
imagealphablending($im, false);
imagesavealpha($im, true);
$trans = imagecolorallocatealpha($im, 255, 255, 255, 127);
// Create some colors
$white = imagecolorallocate($im, 255, 255, 255);
$grey = imagecolorallocate($im, 128, 128, 128);
$black = imagecolorallocate($im, 0, 0, 0);
imagecolortransparent($im, $black);
imagefilledrectangle($im, 0, 0, $width, $height, $trans);
// Add the text
imagettftext($im, $fontSize, 0, 0, $fontSize-1, $grey, $font, $text);
imagepng($im, "image.png");
imagedestroy($im);
?>

Try this:
$text = 'Cool Stuff! this is nice LALALALALA LALA HEEH EHEHE';
$text = wordwrap($_POST['title'], 15, "\n");

Simply explode the text on spaces to get an array of words, then start building lines by looping through the words array, testing the addition of each new word via imagettfbbox to see if it creates a width that exceeds the maxwidth you set. If it does, start the next word on a fresh new line. I find it easier to simply create a new string with special line breaks characters added, and then just explode that string again to create an array of lines, each of which you will write onto the final image separately.
Something like this:
$words = explode(" ",$text);
$wnum = count($words);
$line = '';
$text='';
for($i=0; $i<$wnum; $i++){
$line .= $words[$i];
$dimensions = imagettfbbox($font_size, 0, $font_file, $line);
$lineWidth = $dimensions[2] - $dimensions[0];
if ($lineWidth > $maxwidth) {
$text.=($text != '' ? '|'.$words[$i].' ' : $words[$i].' ');
$line = $words[$i].' ';
}
else {
$text.=$words[$i].' ';
$line.=' ';
}
}
Where the pipe character is the line break character.

Of all the answers posted I liked Genius in trouble's the best but it just adds a linebreak every 15 characters rather than letting the text "flow" as it would in a modern word processor with variable line lengths depending on font choice & which characters are used (e.g. lowercase L takes less horizontal space than uppercase W--l vs. W).
I came up with a solution which I've released as open source at https://github.com/andrewgjohnson/linebreaks4imagettftext
To use you would simply change:
$font = 'arial.ttf';
$text = 'Cool Stuff! this is nice LALALALALA LALA HEEH EHEHE';
$fontSize = 20;
$bounds = imagettfbbox($fontSize, 0, $font, $text);
$width = abs($bounds[4]-$bounds[6]);
To:
$font = 'arial.ttf';
$text = 'Cool Stuff! this is nice LALALALALA LALA HEEH EHEHE';
$fontSize = 20;
$bounds = imagettfbbox($fontSize, 0, $font, $text);
$width = abs($bounds[4]-$bounds[6]);
// new code to add the "\n" line break characters to $text
require_once('linebreaks4imagettftext.php'); //https://raw.githubusercontent.com/andrewgjohnson/linebreaks4imagettftext/master/source/linebreaks4imagettftext.php
$text = \andrewgjohnson\linebreaks4imagettftext($fontSize, 0, $font, $text, $width);
Here is an example of the before & after with a longer piece of text:

If your string not have a any space you can try this :
$text = 'Cool Stuff!thisisniceLALALALALALALAHEEHEHEHE';
$text = wordwrap($_POST['title'], 15, "\n",true); //TRUE = Wrap

Related

PHP GD center multiple lines (dynamically text)

Im drawing a dynamically text on a image centersized with GD library.
Whats the best way to align all lines center?
<?php
function imagettfstroketext(&$image, $size, $angle, $x, $y, &$textcolor, &$strokecolor, $fontfile, $text, $px) {
for($c1 = ($x-abs($px)); $c1 <= ($x+abs($px)); $c1++)
for($c2 = ($y-abs($px)); $c2 <= ($y+abs($px)); $c2++)
$bg = imagettftext($image, $size, $angle, $c1, $c2, $strokecolor, $fontfile, $text);
return imagettftext($image, $size, $angle, $x, $y, $textcolor, $fontfile, $text);
}
$image = "12.png";
$font = "./impact.ttf";
$font_size = "50";
$image_2 = imagecreatefrompng($image);
$black = imagecolorallocate($image_2, 255,255,255);
$black2 = imagecolorallocate($image_2, 0,0,0);
$image_width = imagesx($image_2);
$image_height = imagesy($image_2);
$margin = 35;
$text = "This is the Text. It is dynamically long. This text will be split using the function under this text.";
//explode text by words
$text_a = explode(' ', $text);
$text_new = '';
foreach($text_a as $word){
//Create a new text, add the word, and calculate the parameters of the text
$box = imagettfbbox($font_size, 0, $font, $text_new.' '.$word);
//if the line fits to the specified width, then add the word with a space, if not then add word with new line
if($box[2] > $image_width - $margin*2){
$text_new .= "\n".$word;
} else {
$text_new .= " ".$word;
}
}
$text_box = imagettfbbox($font_size,0,$font,$text_new);
$text_width = $text_box[2]-$text_box[0]; // lower right corner - lower left corner
$text_height = $text_box[3]-$text_box[1];
$x = ($image_width/2) - ($text_width/2);
$y = ($image_height/2) - ($text_height/2);
$font_color = imagecolorallocate($image_2, 255, 255, 255);
$font_color2 = imagecolorallocate($image_2, 0, 0, 0);
$stroke_color = imagecolorallocate($image_2, 0, 0, 0);
$white = imagecolorallocate($im, 255, 255, 255);
$black = imagecolorallocate($im, 0, 0, 0);
$grey = imagecolorallocate($im, 175, 175, 175);
imagettfstroketext($image_2, $font_size ,0,$x,$y,$font_color, $stroke_color, $font, $text_new, 0);
header ("Content-type: image/png");
imagejpeg($image_2, "../img/output.png");
imagedestroy($image_2);
?>
This is what it looks right now:
This is what it should look like:
Using three times "imagettfstroketext" with adding "$y+50" would do the trick but the text is dynamic.
Any suggestions?
best regards
I would create a temporary image on one line, storing the accumulated length in an array. Then determine exactly which words fit on a line, and the offset to center each line. Then create the image.
Alternatively you can create separate images for each line, then combine them with the right offset.

How we can change the font opacity and shadowing in imagettftext function?

I am creating a Text-Image on given template in which all parameter are dynamic,Its working fine! and creating image like,my php script is,
<?php
// To fetch template info from database
$template_query = mysql_query("SELECT * FROM templates WHERE templateID = '".$fetch['templateID']."'");
$temp_data = mysql_fetch_assoc($template_query);
//create and save images
$temp = '../'. $temp_data['blank_templates'];
//check image type
$image_extension = strtolower(substr(strrchr($temp_data['blank_templates'], "."), 1));
$im = imagecreatefromjpeg($temp);
$black = hexdec($temp_data['font_color']);
// Replacing path by your own font path
$font = '..'.$temp_data['font_file_upload'];
// Break it up into pieces 125 characters long
$no_of_characters_line = $temp_data['no_of_characters_line'];
$lines = explode('|', wordwrap($message, $no_of_characters_line, '|'));
// Starting Y position and X position
$y = $temp_data['position_from_top'];
$x = $temp_data['position_from_left'];
$font_size = $temp_data['font_size'];
$rotation_angle = $temp_data['rotation'];
$line_height = $temp_data['line_height'];
foreach ($lines as $line)
{
imagettftext($im, $font_size,$rotation_angle, $x, $y, $black, $font, $line);
// Increment Y so the next line is below the previous line
$y += $line_height;
}
$id = uniqid();
$save = '../messagesimage/'.$id. '.'.$image_extension;
$path_save = substr($save, 3);
// Using imagepng() results in clearer text compared with imagejpeg()
imagejpeg($im,$save);
imagedestroy($im);
Which is creating image like..!
Now I want to add the ability to change font opacity and shadowing dynamically,Is it possible ? If yes then please help me to do this ..
Thanks in Advance
Wow, you've been waiting a while.
To give your text some transparency, you'll need to define your text color with an alpha channel.
$black = imageallocatecoloralpha(0,0,0,16);
To give your text some shadow
$shadow = imageallocatecoloralpha(0,0,0,64); // more transparent
imagettftext($im, $font_size,$rotation_angle, $x+1, $y+1, $shadow, $font, $line);
imagettftext($im, $font_size,$rotation_angle, $x, $y, $black, $font, $line);
Even later, but it seems the current answer is incorrect.
To define a color with transparency, you use the function imagecolorallocatealpha():
$black = imagecolorallocatealpha($image, 0, 0, 0, 50);
Shadows, like Michael pointed out, are quite simple(Just use the correct function name, and make sure you add the image object). However, if you want a more shadowy looking shadow, blur it a bit:
$shadow = imagecolorallocatealpha($im, 0, 0, 0, 50);
//Draw shadow text
imagettftext($im, $font_size, 0, $x, $y, $shadow, $fontn, $text);
//Blur
imagefilter($im, IMG_FILTER_GAUSSIAN_BLUR);
//Draw text
imagettftext($im, $font_size, 0, $x, $y, $white, $fontn, $text);
After applying the above shadow method to an image, it renders similar to this:

Underline text using imagettftext

My question is, how do I underline all the text in the image?Code:
function createImage($text)
{
$text .= "\n";
$text = wordwrap($text, 40, "\n");
$newlines = substr_count($text, "\n");
if($newlines == 0)
{
$height = 30;
}
else
{
$height = 30*$newlines-$newlines*7;
}
putenv('GDFONTPATH=' . realpath('.'));
header('Content-Type: image/png');
$im = imagecreatetruecolor(315, $height);
$white = imagecolorallocate($im, 255, 255, 255);
$grey = imagecolorallocate($im, 128, 128, 128);
$black = imagecolorallocate($im, 0, 0, 0);
$purple = imagecolorallocate($im, 97, 26, 139);
imagefilledrectangle($im, 0, 0, 399, $height, $white);
$font = 'arialbd.ttf';
imagettftext($im, 11, 0, 10, 20, $purple, $font, $text);
imagepng($im);
imagedestroy($im);
}
createImage("Stackoverflow Stackoverflow Stackoverflow Stackoverflow Stackoverflow Stackoverflow Stackoverflow Stackoverflow Stackoverflow Stackoverflow Stackoverflow Stackoverflow ");
RESULT
http://i.imgur.com/Jdr7HPy.png
I want all the text to be underlined, I've found some solutions but they're only from left to right, not depending on words.
Use the Unicode underline combining character U+0332.
You will need a loop to or clever array merge to modify the text,
$e = explode(' ', $text);
for($i=0;$i<count($e);$i++) {
$e[$i] = implode('̲', str_split($e[$i]));
}
$text = implode(' ', $e);
You can do this by finding out dimensions of the text in pixels using imagettfbbox(), then use it as reference to draw lines beneath the text. I've played around with it and here's my try:
function createImage($text){
putenv('GDFONTPATH=' . realpath('.'));
$text = wordwrap($text, 40, "\n");
$padding = 10; // padding around text
$uOffs = 2; // distance between the line and the text above it
$uHeight = 1; // height of the under-line
$lines = explode("\n", $text); // split text in lines
$lineLengths = array(); // will store length of each line
$textSize = 11;
$font = 'arialbd.ttf';
// bounding box of all text
$textBoundingBox = array_map('abs', imagettfbbox($textSize, 0, $font, $text));
list($blx, $bly, $brx, $bry, $trx, $try, $tlx, $tly) = $textBoundingBox;
// calculate image dimensions based on the bounding box data
$x = max($brx, $trx) + ($padding * 4);
$y = max($blx, $bly) + ($padding * 4);
$img = imagecreatetruecolor($x, $y);
// determine length of each line of text
foreach($lines as $i => $line){
$box = imagettfbbox($textSize, 0, $font, $line);
$lineLengths[$i] = max($box[2], $box[4]);
}
$white = imagecolorallocate($img, 255, 255, 255);
$grey = imagecolorallocate($img, 128, 128, 128);
$black = imagecolorallocate($img, 0, 0, 0);
$purple = imagecolorallocate($img, 97, 26, 139);
imagefilledrectangle($img, 0, 0, $x - 1, $y - 1, $white);
imagettftext($img, $textSize, 0, $padding + min($tlx, $blx), $padding + min($tly, $bly), $purple, $font, $text);
// starting Y position of the under-line
$uY = $padding + min($tly, $bly);
// underline text...
foreach($lineLengths as $length){
imagefilledrectangle($img, $padding + min($tlx, $blx), $uY + $uOffs, $padding + $length, $uY + $uOffs + $uHeight, $purple);
$uY += 19;
}
header('Content-Type: image/png');
imagepng($img);
imagedestroy($img);
}
Result:
This is a little more flexible that using Unicode chars because you have control over the line height, and position relative to the text above it.

how to generate multiple texts using php

How can i generate multiple texts using the imagecreatetruecolor() method? I have the following code, but this displays either the first font or the second - not both:
<?php
// Set the content-type
header('Content-type: image/png');
// The text to draw
$text = 'Hello Farooqi';
$x = 0;
$y = 0;
$w = 50;
$h = 50;
$s = 13;
// Create the image
$im = imagecreatetruecolor($w , $s);
imagesavealpha($im, true);
// Create some colors
$white = imagecolorallocate($im, 255, 255, 255);
$black = imagecolorallocate($im,0,0,0);
$text_color = imagecolorallocate($im, 200,200, 91);
$blue = imagecolorallocate($im,0,0,180);
$alpha = imagecolorallocatealpha($im, 0, 0, 0, 127);
//imagefilledrectangle($im, 0, 0, 150, 25, $black);
imagefill($im, 0, 0, $alpha);
// Replace path by your own font path
$font = 'Calibri Bold.ttf';
// Add the text
$dimensions = imagettftext($im, $s, 0, $x, $y, $black, $font, $text);
$textWidth = ($dimensions[2]);
$imm = imagecreatetruecolor($w , $s);
imagesavealpha($imm, true);
$bluem = imagecolorallocate($imm,50,50,50);
$alpham = imagecolorallocatealpha($imm, 0, 0, 0, 127);
imagefill($imm, 0, 0, $alpham);
imagettftext($imm, $s, 0, $x+3, $y+3, $bluem, $font, $text);
// Using imagepng() results in clearer text compared with imagejpeg()
imagepng($im);
imagepng($imm);
imagedestroy($im);
imagedestroy($imm);
?>
Here above in these last 4 lines only one line appears, and that's the first one. How can I have both lines?
Please help. Thanks in advance.
The imagepng($im); will be called and outputted to your HTML code and as the header is set to an image it will display this image. No matter your imagepng($inm) that comes afterwards.
A better way would be to create two different PHP files. One that does your script and ends in imagepng($im); and another one that ends in imagepng($inm);
And then in your master PHP (header = text/html) file you just mention these 2 files in your image source:
<img src="functions/first_image.php" />
<img src="functions/second_image.php" />

How to create multiple line-breaks in a dynamic image when needed?

Currently I've got the following working just fine without any problems (yet).
header ("Content-type: image/png");
$string = $_REQUEST['text'];
$font = 15;
$width = 300;
$height = 350;
$image = imagecreate($width, $height);
$back = ImageColorAllocate($image, 255, 255, 255);
$border = ImageColorAllocate($image, 0, 0, 0);
ImageFilledRectangle($image, 0, 0, $width, $height, $border);
ImageFilledRectangle($image, 1, 1, $width-2, $height-2, $back);
$text_color = imagecolorallocate($image, 255, 0, 0);
ImageStringWrap($image, $font, 3, 2, $string, $text_color, $width-2 );
imagepng($image);
function ImageStringWrap($image, $font, $x, $y, $text, $color, $maxwidth) {
$fontwidth = ImageFontWidth($font);
$fontheight = ImageFontHeight($font);
if ($maxwidth != NULL) {
$maxcharsperline = floor($maxwidth / $fontwidth);
$text = wordwrap($text, $maxcharsperline, "\n", false);
}
while (list($numl, $line) = each($lines)) {
ImageString($image, $font, $x, $y, $line, $color);
$y += $fontheight;
}
}
While the above works great, one thing I've been failing to work is be able to get line breaks like would come out akin to nl2br().
The text that this is pulling from in $_REQUEST['text'] is from the database, which was originally inserted from a textarea and passed to this script via URL. Naturally when people type in a textarea, there are line breaks that come from that. While printing it to the browser via text is easy, I can't seem to get the same result within an image.
I haven't spend a long time working with the GD library, but after searching around I really can't find anything about how to do this. Is it just not possible?

Categories