I am writing to print text to an image using PHP. However, the function imagettftext() uses the baseline, whereas I need the text vertically centered.
So, I either need a method to print text with y not the distance from top to baseline, but from top to top of bounding box OR I need a method using which I could determine the distance between top of bounding box and baseline.
Apparently, I am confusing you. So, to make it clear: I am aware of the function imagettfbbox(). Using that function I can determine height and width of resulting text box. Its height, however, is utterly useless for vertical alignment when printing with imagettftext(), because the Y parameter is not the distance to the top of the box (or even the bottom, but at least something I could have used having the height) but the distance to the baseline of the text within.
EDIT: Why am I not accepting the latest answer?
See my latest comment below the answer, and use this image as a reference.
I do not know if the answer still interested.However, the imagettfbbox() function give you more information than simply the height and the width of the bounding box. It's designed exactly to return information needed by the imagettftext() to manage the text as you want.
The trick lies in the fact that the coordinates returned from imagettfbbox() are not related to the absolute top left corner, but to the baseline of the font for the particular text. This is the reason because the box is specified in point coordinates, and these are often negative.
In short:
$dims = imagettfbbox($fontsize, 0, $font, $text);
$ascent = abs($dims[7]);
$descent = abs($dims[1]);
$width = abs($dims[0])+abs($dims[2]);
$height = $ascent+$descent;
...
// In the example code, for the vertical centering of the text, consider
// the simple following formula
$y = (($imageHeight/2) - ($height/2)) + $ascent;
This works perfectly for my projects.
Hope this help.
Sorry for english.
Marco.
Not entirely sure what your asking...can you give an example? Perhaps imagettfbbox is what you need?
// get bounding box dims
$dims = imagettfbbox($fontsize, 0, $font, $quote);
// do some math to find out the actual width and height
$width = $dims[4] - $dims[6]; // upper-right x minus upper-left x
$height = $dims[3] - $dims[5]; // lower-right y minus upper-right y
edit: Here is an example of vertically centered text
<?php
$font = 'arial.ttf';
$fontsize = 100;
$imageX = 500;
$imageY = 500;
// text
$text = "FOOBAR";
// create a bounding box for the text
$dims = imagettfbbox($fontsize, 0, $font, $text);
// height of bounding box (your text)
$bbox_height = $dims[3] - $dims[5]; // lower-right y minus upper-right y
// Create image
$image = imagecreatetruecolor($imageX,$imageY);
// background color
$bgcolor = imagecolorallocate($image, 0, 0, 0);
// text color
$fontcolor = imagecolorallocate($image, 255, 255, 255);
// fill in the background with the background color
imagefilledrectangle($image, 0, 0, $imageX, $imageY, $bgcolor);
$x = 0;
$y = (($imageY/2) - ($bbox_height/2)) + $fontsize;
imagettftext($image, $fontsize, 0, $x, $y , $fontcolor, $font, $text);
// tell the browser that the content is an image
header('Content-type: image/png');
// output image to the browser
imagepng($image);
// delete the image resource
imagedestroy($image);
?>
Related
How do I centralize and align text above my main image?
The result of this code is this image:
https://i.imgur.com/Dk5pYJM.jpg
I wish it would look like this:
https://i.imgur.com/mED295l.jpg
but I do not understand much of moving the images and texts.
<?php
$fontname = 'verdana.ttf';
$i = 30;
$quality = 85;
function create_image($user){
global $fontname;
global $quality;
$file = md5($user[1]['text'].rand(30454, 343434)).".jpg";
//if (!file_exists($file)) {
$im = imagecreatefromjpeg("fundo.jpg");
$logo = imagecreatefromjpeg("img.jpeg");
$color['grey'] = imagecolorallocate($im, 255, 255, 255);
$y = imagesy($im) - $height - 365;
$font_size = 25;
$logo_x = imagesx($logo);
$logo_y = imagesy($logo);
foreach ($user as $value){
$x = center_text($value['text'], $font_size);
imagettftext($im, $font_size, 0, $x, $y+$i, $color["grey"], $fontname, $value['text']);
$i = $i+32;
}
imagecopymerge($im, $logo, 37, 370, 0, 0, $logo_x, $logo_y, 100);
imagejpeg($im, $file, $quality);
//}
return $file;
}
function center_text($string, $font_size) {
global $fontname;
$image_width = 720;
$dimensions = imagettfbbox($font_size, 0, $fontname, $string);
return ceil(($image_width - $dimensions[4]) / 2);
}
$user = array(
array('text'=> 'Our adge lacks gravitas. That’s whyaadasdasdasdasdsadasdasdasdas')
);
$filename = create_image($user);
?>
<img src="<?=$filename;?>" /><br/><br/>
Aligning text in an image using PHP's image functions is always a bit of a puzzle.
First, you need to know the x and y coordinates of the point at the bottom center of where the text should go (anchor point). This is probably half the width of the outer image for the x and the y value of the top of the smaller image in the center (minus a margin value) for the y.
After this, you have to calculate where your text has to be put (x and y) so that it will align above the smaller image in the center (centered above the anchor point).
For this you use imagettfbbox to calculate what the bounding box's coordinates will be if the text is put at x=0 y=0. Then you use these values to calculate the coordinates of the bottom center of this bounding box.
$bounding_box = imagettfbbox(......);
/* lower right x - lower left x, divided by 2 */
$relative_x = ( $bounding_box[2] - $bounding_box[0] ) / 2;
/* lower left y */
$relative_y = $bounding_box[1];
Subtracting these relative values from our first calculated anchor point, gives you the coordinates to put the text using imagettftext.
See http://php.net/manual/en/function.imagettfbbox.php for which array value is which coordinate value.
I am converting text to image using PHP's imagettftext function and then saving it to the server. The problem I'm having is getting it to save in the directory that I want, it has no problems saving to the current directory where the script runs.
Here is my code:
function txt2img($text, $fSize)
{
// Path to our font file
$fType = 'verdana.ttf';
// First we create our bounding box for the text
$bbox = imagettfbbox($fSize, 0, $fType, $text);
// We calculate the width and height using the x and y points.
// Width is: upper right corner, X position - upper left corner, X position
$width = $bbox[4] - $bbox[6] + 8;
// Height is: lower left corner, Y position - upper left corner, Y position
$height = $bbox[1] - $bbox[7] + 4;
// Determine the x position for the text to start
$x = 2;
// Determine the y position for the text to start
$y = $height - 4;
// Create the image
$im = imagecreatetruecolor($width, $height);
$black = imagecolorallocate($im, 0, 0, 0);
$white = imagecolorallocate($im, 255, 255, 255);
// Create the background color to match the website
$default = imagecolorallocate($im, 255, 238, 198);
// Set the background color
imagefilledrectangle($im, 0, 0, $width, $height, $default);
// Write it
imagettftext($im, $fSize, 0, $x, $y, $black, $fType, $text);
// Set the location to save the image.
//$save = "email_address.png";
$save = "../images/contact/email_address.png";
// Set the folder permissions to allow us to write to the folder.
chmod("../images/contact/",0755);
// .png tends to look better than a .jpg
imagepng($im,$save);
imagedestroy($im);
// Return the image dimensions so they can be stored in the database. This is used to properly diplay the image on the front end.
return ($width."+".$height);
}
If I use the $save location that is commented out, it works perfectly fine, it just isn't in the directory that I want it to be in. I have tried other paths, such as "/images/contact/email_address.png" but no joy. This also worked without the "chmod" permission change, I just added it as another option for troubleshooting. I have also gone directly to the folder and set the permissions for the user, again, no joy.
I'm running this on a local WAMP server. Also, $text has been checked and $fSize is the font size, which has also been checked. Because this works so well in the current directory, I feel this is not a coding issue as much as it is a directory issue, but that's just my view.
So it does save in the folder you're working in as per the commented out save. Have you tried images/contact/email_address.png"; and /images/contact/email_address.png"; without the dots ? The dots are going up a level and if that's above the root it will be unaccesable to php
I want to draw a simple curved line between two points. More specifically, the top left and bottom right corner of an image of arbitrary size.
I tried using imagearc, but apparently that's not what I'm looking for.
To illustrate what I mean:
I can't find any function to help me along, so any help would be appreciated :)
You could use ImageMagick instead of image gd. Image gd has no build-in support for curves.
If you don't have the possibility to use ImageMagick, you could still use imagesetpixel and create your own curve with a simple de casteljau algorithm
I solved it using imagearc after all.
The trick is to set the bottom left corner as the center, -90° start angle, 0° end angle and double the size of the image:
//GET VARS
$width = $_GET['width'];
$height = $_GET['height'];
//CREATE IMGS
$image = imagecreatetruecolor($width, $height);
$color = imagecolorallocate($image, 255, 0, 0);
imagearc( $image,
0, 0, //center point = bottom-left corner
$width*2, $height*2, //size = image size * 2
-90, //top left
0, //bottom right
$color);
//OUTPUT IMAGE
header('Content-Type: image/png');
imagepng($image);
//DESTROY IMAGE
imagedestroy($image);
Looks like this:
http://www.schizosplayground.com/pers/curvedlinetest.php?width=132&height=163
I solved a similar problem by generating a vector with points ($polygon) via any convinient function and then drew a lines inbetween the points:
$numberofpoints=count($polygon)/2-1; // XY coordinates, so points is just half and subtracting the end point
for ($i=0; $i < $numberofpoints;$i++) {
imageline($image, $polygon[2*$i], $polygon[2*$i+1], $polygon[2*$i+2], $polygon[2*$i+3], $Color); // connect two consecutive points with a line
}
Hope you are doing great.
I’m still a newbie with php so after making some reading and while checking some posts here I was able to put some text over an image with the imagecreatefrompng() function using the PHP GD, users will come to a form and they will be able to enter their name and the name will be written over the image , unfortunately I have been unable to align the text center horizontally, I tried all ways possible (my ways obviously and must be wrong) with imagettfbbox but I failed in all my attempts, could you please guys help me out a little bit to align the string center horizontally? Also since I’m using a kind of alternative big font I need that the size decrease if the name entered is kind of long so this way it will not surpass the image limits and will stay at the center. I’m getting the value of the text from a form as you may check at the beginning of my code:
<?php
$nombre=$_POST['nombre'];
//Set the Content Type
header('Content-type: image/jpeg');
// Create Image From Existing File
$jpg_image = imagecreatefromjpeg('fabian.jpg');
// Allocate A Color For The Text
$white = imagecolorallocate($jpg_image, 255, 255, 255);
// Set Path to Font File
$font_path = 'fabian.TTF';
// Set Text to Be Printed On Image , I set it to uppercase
$text =strtoupper($nombre);
// Print Text On Image
imagettftext($jpg_image, 75, 0, 50, 400, $white, $font_path, $text);
// Send Image to Browser
imagepng($jpg_image);
// Clear Memory
imagedestroy($jpg_image);
?>
Your help will be highly appreciated, later on I will break my head trying to save the image by clicking a submit button since I do not want the users to save the image by right clicking on it.
Thanks pals!
You need the width of the image and the width of the text to relate both.
// get image dimensions
list($img_width, $img_height,,) = getimagesize("fabian.jpg");
// find font-size for $txt_width = 80% of $img_width...
$font_size = 1;
$txt_max_width = intval(0.8 * $img_width);
do {
$font_size++;
$p = imagettfbbox($font_size, 0, $font_path, $text);
$txt_width = $p[2] - $p[0];
// $txt_height=$p[1]-$p[7]; // just in case you need it
} while ($txt_width <= $txt_max_width);
// now center the text
$y = $img_height * 0.9; // baseline of text at 90% of $img_height
$x = ($img_width - $txt_width) / 2;
imagettftext($jpg_image, $font_size, 0, $x, $y, $white, $font_path, $text);
You can use stil/gd-text class to align the text. Disclaimer: I am the author.
<?php
use GDText\Box;
use GDText\Color;
$jpg_image = imagecreatefromjpeg('fabian.jpg');
$textbox = new Box($jpg_image);
$textbox->setFontSize(75);
$textbox->setFontFace('fabian.TTF');
$textbox->setFontColor(new Color(255, 255, 255));
$textbox->setBox(
50, // distance from left edge
50, // distance from top edge
200, // textbox width
100 // textbox height
);
// text will be aligned inside textbox to center horizontally and to top vertically
$textbox->setTextAlign('center', 'top');
$textbox->draw(strtoupper($nombre));
However it is not a complete answer, because it can't decrease font size automatically.
Given the result of a call to imagettfbbox(), what is the correct, pixel-perfect point to provide to imagettftext() such that the text will not extend beyond its bounding box?
I am determining the width/height and x/y of the baseline from the bounding box like this:
$box = imagettfbbox($size, $angle, $font, $text);
$boxXCoords = array($box[0], $box[2], $box[4], $box[6]);
$boxYCoords = array($box[1], $box[3], $box[5], $box[7]);
$boxWidth = max($boxXCoords) - min($boxXCoords);
$boxHeight = max($boxYCoords) - min($boxYCoords);
$boxBaseX = abs(min($boxXCoords));
$boxBaseY = abs(min($boxYCoords));
I then draw a filled rectangle on my image of the dimensions of the bounding box:
imagefilledrectangle($image, 0, 0, $boxWidth - 1, $boxHeight - 1, $color);
After that, I draw the text:
imagettftext($image, $size, $angle, $boxBaseX, $boxBaseY, $color, $font, $text);
However, this causes the text to extend beyond the rectangle by a pixel or two. I have seen several attempts to fix this issue on PHP's imagettfbbox() documentation, but they all just suggest substracting a pixel or two here and there, which seems like a hack to me. What's happening here, and why should we need to fudge the numbers to get things right?
I believe there is no perfect way to place text with single-pixel precision on an image based on what imagettfbbox() returns and also using .ttf non-monospaced fonts. Over at the PHP manual many users have posted ways to accomplish this (with and without fudging the numbers); I recommend using jodybrabec's simple function over at the PHP manual, which calculates the exact bounding box. I have tested this one and only in extreme cases is the text positioned at most 1 pixel off in one direction. Nonetheless, if you add some padding (even if it is just 2 or 3 pixels) to your image your text will be within the dimensions of the image 100% of the time.
What happens when you don't subtract one from each of the dimensions in this line:
imagefilledrectangle($image, 0, 0, $boxWidth - 1, $boxHeight - 1, $color);
and instead do this:
imagefilledrectangle($image, 0, 0, $boxWidth, $boxHeight, $color);
The SlightlyMagic HQ Card Generator project renders cards for the strategy card game Magic: the Gathering. The generator is powered by PHP with an advanced text rendering engine built in. I don't know about logic behind the calculations, but the renderer is dead accurate for the purposes of this application. Here's the function that calculates proper bounding boxes (HQ Card Generator 8.x/scripts/classes/font.php):
private function convertBoundingBox ($bbox) {
// Transform the results of imagettfbbox into usable (and correct!) values.
if ($bbox[0] >= -1)
$xOffset = -abs($bbox[0] + 1);
else
$xOffset = abs($bbox[0] + 2);
$width = abs($bbox[2] - $bbox[0]);
if ($bbox[0] < -1) $width = abs($bbox[2]) + abs($bbox[0]) - 1;
$yOffset = abs($bbox[5] + 1);
if ($bbox[5] >= -1) $yOffset = -$yOffset;
$height = abs($bbox[7]) - abs($bbox[1]);
if ($bbox[3] > 0) $height = abs($bbox[7] - $bbox[1]) - 1;
return array(
'width' => $width,
'height' => $height,
'xOffset' => $xOffset, // Using xCoord + xOffset with imagettftext puts the left most pixel of the text at xCoord.
'yOffset' => $yOffset, // Using yCoord + yOffset with imagettftext puts the top most pixel of the text at yCoord.
'belowBasepoint' => max(0, $bbox[1])
);
}
I know this is a little late but imagettfbbox is in points not pixels.
pixel font size in imagettftext instead of point size