There might be many reasons you need to add text on top of an existing image. The main reason for me was to add the title of a post, on top of a "template" background image to generate SEO images.
I've added comments in the code below to denote what it does. The code uses Laravel for the public_path()
helper, but should be fairly straightforward to use native PHP or another framework instead:
// Get the template image that we want to add text to $image = public_path('social/social-template.png'); // Create a GD Image object $image = imagecreatefromstring($image); // Define the color and font size of our text $navy = imagecolorallocate($image, 20, 45, 111); $font_size = 128; $font_path = public_path('fonts/Jokker-Semibold.woff'); // Wrap the text based on a maximum width (see next code block) $text = $this->wrapText('This is my title', $font_size, $font_path); // Add the text to the image imagettftext( image: $image, size: $font_size, angle: 0, x: 210, y: 550, color: $navy, font_filename: $font_path, text: trim($text) ); // Store the image imagepng($image, public_path("social/images/this-is-my-title.png")); // Clear memory imagedestroy($image);
Defining a max width and wrapping the text isn't very straightforward, as each font will result in a different width of the text. Luckily, GD also provides some methods to calculate that:
public function wrapText(string $text, int $font_size, string $font_path): string { // A variable to store our result in $wrapped = ''; // Split the text into an array of words $words = explode(' ', $text); foreach ($words as $word) { // Calculate the size of the current result + the additional word $teststring = "{$wrapped} {$word}"; $testbox = imagettfbbox($font_size, 0, $font_path, $teststring); // If the test box width is larger than our max allowed width, // add a line break before the word, otherwise add a space if ($testbox[2] > 1900) { $wrapped .= "\n".$word; } else { $wrapped .= ' '.$word; } } return $wrapped; }
If you prefer to work with HTML & CSS to generate images, take a look at browsershot