Напишите текст на изображении пропорционально

Итак, у меня есть изображение: введите описание изображения здесь

и я хочу добавить текст под изображение (сделать демотивационное изображение). Поэтому я увеличиваю его высоту и добавлю дополнительную высоту на дно. Мне нужно написать текст:

Заголовок

нижний длинный текст

также мне нужно, чтобы эти слова были сосредоточены на изображении. Итак, выход должен быть: изображение 2

все находится на библиотеке PHP GD. Проблема в том, что я не знаю, как рассчитать пропорцию размера шрифта и центрировать его. Моя функция, которая не работает, неправильно вычисляет размер шрифта и неправильно выравнивает текст.

private function __generate_text_pref($type) { $data = array(); switch ($type) { case 'title': $data['percent'] = 0.9; $data['text_width_percent'] = 0.8; break; case 'subtitle': $data['percent'] = 0.92; $data['text_width_percent'] = 0.6; break; default: $data['percent'] = 0.86; $data['text_width_percent'] = 0.8; break; } list($img_width, $img_height) = getimagesize($this->settings['__temp_image']); // find font-size for $txt_width = 80% of $img_width... $data['font_size'] = 1; $txt_max_width = intval($data['text_width_percent'] * $img_width); do { $data['font_size'] ++; $p = imagettfbbox($data['font_size'], 0, $this->settings['font'], $this->settings['__title']); $txt_width = $p[2] - $p[0]; // $txt_height=$p[1]-$p[7]; // just in case you need it } while ( $txt_width <= $txt_max_width ); //$data['font_size'] = ($data['font_size'] > 24) ? 24 : $data['font_size']; return array( 'font_size' => $data['font_size'], 'asys' => array( 'x' => (($img_width - $txt_width) / 2), 'y' => ($img_height * $data['percent']) ) ); } 

он должен иметь размер шрифта по умолчанию для заголовка и субтитров и уменьшать его, чтобы опустить только в том случае, когда текст длиннее и не помещается в обертку.

Поскольку кажется довольно сложно определить, является ли текст более широким, чем его ограничивающая рамка, не имея возможности фактически «видеть» его, это решение, с которым я столкнулся.

Я использовал изображение шириной 1000 пикселей и изменил его размер до 600. Конечно, вы, очевидно, уже все это уже разработали.

Я не так хорош в написании ответов (хотя код был протестирован и работает), поэтому я надеюсь, что это поможет.

 <?php $FormAction = $_SERVER['PHP_SELF']; if ((isset($_POST["MM_insert"])) && ($_POST["MM_insert"] == "form1")) { // if form is submitted // get original image $fileName = $_FILES["ImageName"]["name"]; // The file name $fileTempLoc = $_FILES["ImageName"]["tmp_name"]; // File in the PHP tmp folder $type = strtolower(substr(strrchr($fileName,"."),1)); if($type == 'jpeg') { $type = 'jpg'; } // Temporary upload image name $original_image = $_FILES['ImageName']['tmp_name']; // Name to save the image as - in this case the same as the original $new_image = $_FILES['ImageName']['name']; // Get the image dimensions $uploaded_size = getimagesize($original_image); $uploaded_imgw = $uploaded_size[0]; $uploaded_imgh = $uploaded_size[1]; // Maximum image width and height $max_width = "600"; $max_height = "600"; // Thumbnail image width and height $thumbnail_max_width = "100"; $thumbnail_max_height = "100"; // Check to see if we need to resize the image if ($uploaded_imgw > 600 || $uploaded_imgh > 600) { // if image is larger than 600x600 // Resize image using GD2 cmd // Get new dimensions list($width_orig, $height_orig) = getimagesize($original_image); $ratio_orig = $width_orig/$height_orig; // resize our image proportionately maintaining its original aspect if ($thumbnail_max_width/$thumbnail_max_height > $ratio_orig) { $width = $max_width*$ratio_orig; //576 $height = $max_height; } else { $height = $max_height/$ratio_orig; // 576 $width = $max_width; //600 } // Resample / Resize the image $orig_image_p = imagecreatetruecolor($width, $height); if($type == "gif" || $type == "png"){ imagecolortransparent($orig_image_p, imagecolorallocate($orig_image_p, 0, 0, 0)); } if($type == "jpg") { $temp_image = imagecreatefromjpeg($original_image); } if($type == "gif") { $temp_image = imagecreatefromgif($original_image); } if($type == "png") { $temp_image = imagecreatefrompng($original_image); } imagecopyresampled($orig_image_p, $temp_image, 0, 0, 0, 0, $width, $height, $width_orig, $height_orig); if($type == "jpg") { imagejpeg($orig_image_p, $original_image, 80); } if($type == "gif") { imagegif($orig_image_p, $original_image); } if($type == "png") { imagepng($orig_image_p, $original_image, 9); } move_uploaded_file($original_image, '../../Images/'.$new_image); imagedestroy($temp_image); imagedestroy($orig_image_p); } else { // if image is smaller than 900x900 $small_image_p = imagecreatetruecolor($uploaded_imgw, $uploaded_imgh); if($type == "gif" || $type == "png"){ imagecolortransparent($small_image_p, imagecolorallocate($small_image_p, 0, 0, 0)); } if($type == "jpg") { $small_temp_image = imagecreatefromjpeg($original_image); } if($type == "gif") { $small_temp_image = imagecreatefromgif($original_image); } if($type == "png") { $small_temp_image = imagecreatefrompng($original_image); } imagecopyresampled($small_image_p, $small_temp_image, 0, 0, 0, 0, $uploaded_imgw, $uploaded_imgh, $uploaded_imgw, $uploaded_imgh); if($type == "jpg") { imagejpeg($small_image_p, $original_image, 80); } if($type == "gif") { imagegif($small_image_p, $original_image); } if($type == "png") { imagepng($small_image_p, $original_image, 9); } move_uploaded_file($original_image, '../../Images/'.$new_image); imagedestroy($small_temp_image); imagedestroy($small_image_p); } // end if smaller than 600x600 // Get the image we will work with $new_img_src = '../../Images/'.$new_image; list($new_width, $new_height) = getimagesize($new_img_src); if($type == 'jpg') { $im = imagecreatefromjpeg($new_img_src); } if($type == 'png') { $im = imagecreatefrompng($new_img_src); } if($type == 'gif') { $im = imagecreatefromgif($new_img_src); } // Create a blank canvas for our new image $new_image_p = imagecreatetruecolor($new_width, $new_height); if($type == "gif" || $type == "png"){ imagecolortransparent($new_image_p, imagecolorallocate($new_image_p, 0, 0, 0)); } if($type == 'jpg') { $new_temp_image = imagecreatefromjpeg($new_img_src); } if($type == 'png') { $new_temp_image = imagecreatefrompng($new_img_src); } if($type == 'gif') { $new_temp_image = imagecreatefromgif($new_img_src); } imagecopyresampled($new_image_p, $new_temp_image, 0, 0, 0, 0, $new_width, $new_height, $new_width, $new_height); // set dimensions for our canvas $adj_width = $new_width+40; $adj_height = $new_height+120; $bkgrd = imagecreatetruecolor($adj_width, $adj_height); imagefilledrectangle($bkgrd, 0, 0, $adj_width, $adj_height, 0x000000); $sx = imagesx($bkgrd)-imagesx($bkgrd)+20; $sy = imagesy($bkgrd)-imagesy($bkgrd)+20; // Place our original image on the canvas centered and 20px from the top imagecopymerge($bkgrd, $new_image_p, $sx, $sy, 0, 0, imagesx($bkgrd), imagesy($bkgrd), 100); // Save the image to file and free memory if($type == "jpg") { imagejpeg($bkgrd, $new_img_src, 80); } if($type == "gif") { imagegif($bkgrd, $new_img_src); } if($type == "png") { imagepng($bkgrd, $new_img_src, 9); } imagedestroy($im); imagedestroy($new_image_p); imagedestroy($bkgrd); //Now we create our text as images to be merged with our new image // check width of bounding box function calculateTextBox($text,$fontFile,$fontSize,$fontAngle) { /************ simple function that calculates the *exact* bounding box (single pixel precision). The function returns an associative array with these keys: left, top: coordinates you will pass to imagettftext width, height: dimension of the image you have to create *************/ $rect = imagettfbbox($fontSize,$fontAngle,$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 ); } $text_string = $_POST['TopLine']; //"This is a very long first line to see what happens if it is too long"; $font_ttf = "arial.ttf"; $font_size = 22; $text_angle = 0; $text_padding = 10; // Img padding - around text $the_box = calculateTextBox($text_string, $font_ttf, $font_size, $text_angle); $imgWidth = $the_box["width"] + $text_padding; $imgHeight = $the_box["height"] + $text_padding; $image = imagecreatetruecolor($imgWidth,$imgHeight); imagefill($image, imagecolorallocate($image, 0, 0, 0)); $color = imagecolorallocate($image, 255, 255, 255); imagettftext($image, $font_size, $text_angle, $the_box["left"] + ($imgWidth / 2) - ($the_box["width"] / 2), $the_box["top"] + ($imgHeight / 2) - ($the_box["height"] / 2), $color, $font_ttf, $text_string); // save file imagepng($image, '../../Images/NewTopImg.png', 9); // destroy the image and start over imagedestroy($image); $text_string = $_POST['BottomLine']; //"This is a very long second line to see what happens if it is too long. Even a longer line than the first one."; $font_ttf = "arial.ttf"; $font_size = 16; $text_angle = 0; $text_padding = 10; // Img padding - around text $the_box = calculateTextBox($text_string, $font_ttf, $font_size, $text_angle); $imgWidth = $the_box["width"] + $text_padding; $imgHeight = $the_box["height"] + $text_padding; $image = imagecreatetruecolor($imgWidth,$imgHeight); imagefill($image, imagecolorallocate($image, 0, 0, 0)); $color = imagecolorallocate($image, 255, 255, 255); imagettftext($image, $font_size, $text_angle, $the_box["left"] + ($imgWidth / 2) - ($the_box["width"] / 2), $the_box["top"] + ($imgHeight / 2) - ($the_box["height"] / 2), $color, $font_ttf, $text_string); // save file imagepng($image, '../../Images/NewBottomImg.png', 9); imagedestroy($image); // Now merge the three images together //function merge($filename_x, $filename_y, $filename_result) { // Get dimensions for specified images $filename_vs = '../../Images/'.$new_image; $filename_x = '../../Images/NewTopImg.png'; $filename_y = '../../Images/NewBottomImg.png'; list($width_x, $height_x) = getimagesize($filename_x); list($width_y, $height_y) = getimagesize($filename_y); list($width_vs, $height_vs) = getimagesize($filename_vs); // before we go any farther lets find out if our text is wider than our image if($width_x > $new_width) { // if it is too wide lets resize it // create smaller image using GD2 cmd to the smallest side $line1_img_src = '../../Images/NewTopImg.png'; $line1_img_path = '../../Images/NewTopImg.png'; list($src_width, $src_height) = getimagesize($line1_img_src); $min = $new_width; // set our max width to that of the original image $ratio = $src_height/$src_width; $line1_width = $min; $Line1_height = round($min * $ratio); $blank_image_line1 = imagecreatetruecolor($line1_width, $Line1_height); imagecolortransparent($blank_image_line1, imagecolorallocate($blank_image_line1, 0, 0, 0)); $image = imagecreatefrompng($line1_img_src); imagecopyresampled($blank_image_line1, $image, 0, 0, 0, 0, $line1_width, $Line1_height, $src_width, $src_height); imagepng($blank_image_line1, $line1_img_path, 9); imagedestroy($blank_image_line1); imagedestroy($image); // Because we resized the first line we need to get the new dimensions $filename_x = '../../Images/NewTopImg.png'; list($width_x, $height_x) = getimagesize($filename_x); // End resize first line } // Now lets check line two if($width_y > $new_width) { // if it is too wide lets resize it // create smaller image using GD2 cmd to the smallest side $line2_img_src = '../../Images/NewBottomImg.png'; $line2_img_path = '../../Images/NewBottomImg.png'; list($src_width, $src_height) = getimagesize($line2_img_src); $min = $new_width; // set our max width to that of the original image $ratio = $src_height/$src_width; $line2_width = $min; $line2_height = round($min * $ratio); $blank_image_line2 = imagecreatetruecolor($line2_width, $line2_height); imagecolortransparent($blank_image_line2, imagecolorallocate($blank_image_line2, 0, 0, 0)); $image = imagecreatefrompng($line2_img_src); imagecopyresampled($blank_image_line2, $image, 0, 0, 0, 0, $line2_width, $line2_height, $src_width, $src_height); imagepng($blank_image_line2, $line2_img_path, 9); imagedestroy($blank_image_line2); imagedestroy($image); // Because we resized the second line we need to get the new dimensions $filename_y = '../../Images/NewBottomImg.png'; list($width_y, $height_y) = getimagesize($filename_y); // End resize second line } // Create new image with desired dimensions $image = imagecreatetruecolor($width_vs, $height_vs); // Load images and then copy to destination image if($type == "gif" || $type == "png"){ imagecolortransparent($image, imagecolorallocate($image, 0, 0, 0)); } if($type == 'jpg') { $image_vs = imagecreatefromjpeg($filename_vs); } if($type == 'png') { $image_vs = imagecreatefrompng($filename_vs); } if($type == 'gif') { $image_vs = imagecreatefromgif($filename_vs); } $image_x = imagecreatefrompng($filename_x); $image_y = imagecreatefrompng($filename_y); //set location for merged images $vs_x = imagesx($image); // width of our completed image $vs_y = imagesy($image);// height of our completed image $x_x = $width_x; // width of the top line $x_x = ($vs_x/2)-($x_x/2); $x_y = $new_height+30; // height of the original img + 20px we dropped it from the top of the canvas + 10px more for spacing below our "picture" placed on the canvas $y_x = $width_y; // width of the bottom line $y_x = ($vs_x/2)-($y_x/2); $y_y = $new_height+70; // height of the original img + 20px we dropped it from the top of the canvas + 40px more for spacing below the first line of text imagecopy($image, $image_vs, 0, 0, 0, 0, $width_vs, $height_vs); imagecopy($image, $image_x, $x_x, $x_y, 0, 0, $width_vs, $height_vs); imagecopy($image, $image_y, $y_x, $y_y, 0, 0, $width_vs, $height_vs); // set dimensions for our canvas $adj_width = $new_width+40; $adj_height = $new_height+120; $bkgrd = imagecreatetruecolor($adj_width, $adj_height); imagefilledrectangle($bkgrd, 0, 0, $adj_width, $adj_height, 0x000000); $sx = imagesx($bkgrd)-imagesx($bkgrd)+20; $sy = imagesy($bkgrd)-imagesy($bkgrd)+20; // Place our original image on the canvas centered and 20px from the top imagecopymerge($bkgrd, $new_image_p, $sx, $sy, 0, 0, imagesx($bkgrd), imagesy($bkgrd), 100); // Save the image to file and free memory if($type == "jpg") { imagejpeg($image, $filename_vs, 80); } if($type == "gif") { imagegif($image, $filename_vs); } if($type == "png") { imagepng($image, $filename_vs, 9); } // Clean up imagedestroy($image); imagedestroy($image_x); imagedestroy($image_y); imagedestroy($image_vs); //merge($filename_x, $filename_y, $filename_vs); } // end if form submitted ?> <table width="800" border="0" cellspacing="0" cellpadding="5" align="center"> <tr> <td><div id="FormContainer"> <table width="100%" border="0" cellpadding="0" cellspacing="0"> <tr> <td><div id="Heading">IMAGE UPLOAD</div></td> </tr> </table> <form enctype="multipart/form-data" id="form1" name="form1" method="post" action="<?php echo $FormAction; ?>"> <table border="0" align="center" cellpadding="5" cellspacing="0"> <tr> <td colspan="2">Only JPG, JPEG, PNG and GIF files are allowed.</td> </tr> <tr> <td>&nbsp;</td> <td>&nbsp;</td> </tr> <tr> <td><div align="right" class="Strong">File:</div></td> <td><input name="ImageName" type="file" id="ImageName" size="50" /></td> </tr> <tr> <td>&nbsp;</td> <td>&nbsp;</td> </tr> <tr> <td nowrap="nowrap" class="ElementTitle"><div align="right">Line 1 Text:</div></td> <td><input name="TopLine" type="text" id="TopLine" value="This is a very long first line to see what happens if it is too long" size="75" maxlength="100" /></td> </tr> <tr> <td nowrap="nowrap" class="ElementTitle"><div align="right">Line 2 Text:</div></td> <td><input name="BottomLine" type="text" id="BottomLine" value="This is a very long second line to see what happens if it is too long. Even a longer line than the first one." size="75" maxlength="100" /></td> </tr> <tr> <td>&nbsp;</td> <td>&nbsp;</td> </tr> <tr> <td colspan="2"><table width="150" border="0" align="center" cellpadding="5" cellspacing="0"> <tr> <td><div align="center" style="width:80px; height:37px;"> <input name="Submit" type="submit" class="Submit" value="Upload" /> </div></td> <td><div align="center" style="width:75px; height:37px;"> <input name="Submit22" type="reset" class="Submit" value="Reset" /> </div></td> </tr> </table></td> </tr> <tr> <td>&nbsp;</td> <td>&nbsp;</td> </tr> </table><input type="hidden" name="MM_insert" id="MM_insert" value="form1"> </form> </div><!-- end form container --> </td> </tr> <tr> <td>&nbsp;</td> </tr> </table> 

В основном, что вы делаете, это

  1. Создание двух изображений для первой и второй строк
  2. Проверка того, являются ли эти изображения более широкими, чем существующее изображение, и если это так
  3. Изменение размера их в соответствии с вашей исходной шириной изображения
  4. Наконец, слияние всех трех изображений в одно.

Здесь можно изменить размер текста по умолчанию … $font_size = 22 и $font_size = 16 для первой и второй строк соответственно.

Не забудьте загрузить файл шрифта ttf и указать на него правильно.

И, наконец, вы можете добавить код в конце, чтобы удалить два временных файла после их завершения.

Частичный кредит jodebrabec для функции calculateTextBox, который я модифицировал и использовал здесь. Вы можете найти это здесь

Пример вывода с коротким текстом Это показывает шрифты с размером по умолчанию

Пример вывода с длинным текстом Это показывает одно и то же изображение с длинным текстовым изменением размера

Для удобства выравнивания текста вам необходимо использовать команду imagettfbbox() . При заданных правильных параметрах он вернет границы вашего текстового поля в массив, что позволит вам вычислить координаты x и y, которые необходимо использовать для центрирования или выравнивания текста.

Пример горизонтального центрирования:

 <?php $tb = imagettfbbox(17, 0, 'airlock.ttf', 'Hello world!'); ?> $tb would contain: Array ( [0] => 0 // lower left X coordinate [1] => -1 // lower left Y coordinate [2] => 198 // lower right X coordinate [3] => -1 // lower right Y coordinate [4] => 198 // upper right X coordinate [5] => -20 // upper right Y coordinate [6] => 0 // upper left X coordinate [7] => -20 // upper left Y coordinate ) 

Для горизонтального выравнивания нам нужно вычесть ширину «текстового поля» {$ tb 2 или $ tb [4]} из ширины изображения, а затем вычесть на два.

Говоря, что у вас есть изображение шириной 200 пикселей, вы можете сделать что-то вроде этого:

 <?php $x = ceil((200 - $tb[2]) / 2); // lower left X coordinate for text //array imagettftext ( resource $image , float $size , float $angle , int $x , int $y , int $color , string $fontfile , string $text ) imagettftext($im, 17, 0, $x, $y, $tc, 'airlock.ttf', 'Hello world!'); // write text to image ?> 

Это даст вам идеальное горизонтальное выравнивание по центру для вашего текста, дайте или возьмите 1 пиксель


ссылка: imagettftext , imagettfbbox

Я не совсем уверен, что это то, что вы ищете, но writeCenteredText () будет писать центрированный текст в заданной строке $ y. Если текст слишком длинный для строки, он переносится на следующую строку и центрирует этот текст. Дайте мне знать, если я не понял проблему.

 <?php // Create a 100*30 image $im = imagecreate(300, 300); // White background and blue text $bg = imagecolorallocate($im, 255, 255, 255); $textcolor = imagecolorallocate($im, 0, 0, 255); function writeCenteredText($image,$y,$textString,$color) { // half way of image = (width / 2) // half way of text = ($strPixLen / 2); //split the string into chunks that fit the image width $splitString = str_split($textString, imagesx($image) / imagefontwidth(1) ); foreach($splitString as $key => $value) { $strPixLen = strlen($value) * imagefontwidth(1); $x = (imagesx($image) / 2) - ($strPixLen / 2); imagestring($image, 1, $x, imagefontheight(1) * $y , $value, $color); ++$y; } } writeCenteredText($im,0,'Centered Text',$textcolor); writeCenteredText($im, 1 ,'Centered Text2',$textcolor); writeCenteredText($im, 2 ,'Longer Centered Text',$textcolor); writeCenteredText($im, 3 ,'This is really long Centered Text',$textcolor); writeCenteredText($im, 4 ,'If the optional split_length parameter is specified, the returned array will be broken down into chunks with each being split_length in length, otherwise each chunk will be one character in length.',$textcolor); // Output the image header('Content-type: image/png'); imagepng($im); imagedestroy($im); exit; ?> 

Пример вывода:

введите описание изображения здесь