Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Write text on the image in proportion

Tags:

text

php

image

gd

So I have the image: enter image description here

and I want to add text under the image (make demotivational image). So I extend it height and add additional height to the bottom. What I need is write the text:

Top text

bottom longer text

also I need these words to be centered on the image. So the ouput should be:image 2

everything is on PHP GD library. The problem is - I don't know how to calculate proportion of font size and center it. My function which is not working, calculate font size wrong and align text wrong..

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'])
        )
    );
}

it should have the default font size for title and subtitle and decrease it to lower only in that case when text is longer and not fit in the wrapper..

like image 908
Arnas Pečelis Avatar asked Aug 27 '15 12:08

Arnas Pečelis


1 Answers

Since it seems to be pretty difficult to determine if text is wider than its bounding box without being able to actually "see" it, this is the solution I came up with.

I used a 1000px wide image and resized it to 600. Of course you evidently have all of this worked out already.

I'm not all that great at writing answers (although the code has been tested and does work) so I hope this helps.

<?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>

Basically what you are doing is

  1. Creating two images for the first line and second line
  2. Checking to see if those images are wider than your existing image and if so
  3. Resizing them to fit your original image width
  4. Finally merging all three images into one.

Your default text sizes can be changed here... $font_size = 22 and $font_size = 16 for the first and second line respectively.

Don't forget to upload your ttf font file and point to it correctly.

And finally, you can add code at the end to delete your two temporary files once your done with them.

Partial credit to jodebrabec for the calculateTextBox function I modified and used here. You can find it here

Sample output with short textThis shows fonts at default size

Sample output with long text This shows same image with long text resized to fit

like image 122
Kuya Avatar answered Oct 07 '22 05:10

Kuya