...

View Full Version : PHP/GD Library: autosize font



doublej2k
11-19-2010, 12:33 AM
I'm creating a web application which uses GD library to write text to an image. How it works is theirs a form which asks the end-user four questions. The user inputs there data, clicks submit and the action processes the image. Thus, giving you a customized image.

I've have two problems, they are as follows:


When an user types two or more character strings, it causes each string to line break. I need to keep the text on one line.
If the user types a long string of characters(14+ specifically), i need the text string to auto size down and not exceed the bounding box.


The two files I am using are below. If you would like to see a demo of the app visit http://s203396048.onlinehome.us/paw_create/index.php

Thanks in advance to whomever can help me with this issue.

index.php

<?php
// Include MySQL class
require_once('inc/mysql.class.php');
// Include database connection
require_once('inc/global.inc.php');
// Include functions
require_once('inc/functions.inc.php');
// Start the session
session_start();

// Edit the query to point to the right table
$query = "SELECT * FROM jj_image";
$result = mysql_query($query);
$i = 0;
while ($row = mysql_fetch_assoc($result))
{
$colors[$i] = $row['color'];
$i++;
}
?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" dir="ltr" lang="en-US">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Paw Create</title>

<link href="assets/css/styles.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
<script type="text/javascript" src="assets/js/jquery.validate.js"></script>
<script type="text/javascript" src="assets/js/main.js"></script>
</head>

<body>

<div id="container">

<div id="left-box">
<?php
$aData = array('text' => $_POST['text'],'color' => $_POST['color'],'image' => $_POST['image']);
$color = $_POST['color'];
$text = $_POST['text'];
$image = $_POST['image'];
$qs = http_build_query($aData);
$renderedImage = '<img src="processImage.php?' . $qs . '" />';
$defaultImage = "<img src='images/default.jpg'/>";
if(empty($_POST)) {
print($defaultImage);
}
if(isset($_POST['preview'])) {
print($renderedImage);
}
if(isset($_POST['reset'])) {
print($defaultImage);
}
else {
}
?>
</div>

<div id="right-box">
<div id="imageMakerForm">
<p>Welcome to the macypaws.com Paw Creator. This three step process allows you create your own unique custom paw wich you can proudly display where ever you like.</p><br/>

<form action="<?php echo $PHP_SELF; ?>" method="post" name="imageMakerFormPost" id="imageMakerFormPost">

<label for="image">Choose a paw color</label>
<ul id="colors">
<?php
foreach($colors as $color)
{
echo "<li id=\"$color\" class=\"square\" ><a href=\"#\" onclick=\"addImageColor('$color')\">$color</a></li>";
}
?>
</ul>

<input type="hidden" id="image" value="<?php print $image; ?>" name="image">
<br /><br />

<label for="">Choose the text color</label>
<ul id="colors2">
<?php
foreach($colors as $color)
{
echo "<li id=\"$color\" class=\"square2\" ><a href=\"#\" onclick=\"addTextColor('$color')\">$color</a></li>";
}
?>
</ul>
<input type="hidden" id="color" value="<?php print $color; ?>" name="color">
<?php
$error = isset($_GET['color']) ? $_GET['color'] : NULL;
if ('color' == $error) {echo '<p>Please select a text color!</p>';}
?>
<br/><br/>

<label for="text">What's your pet name?</label>
<input type="text" value="<?php print $text; ?>" id="text" class="required" name="text" />
<br/>

<input type="submit" name="preview" value="preview" id="previewImageMaker" class="button" style="float:right;" />
<input type="submit" name="reset" value="reset" class="button" style="float:right;" onclick="clear_form_elements(this.form)"/>

</form>
</div><!-- imageMakerForm -->

</div><!-- end right-box -->
</div>

</body>
</html>


processImage.php

<?

header("Content-type: image/png");

define('GDBB_TOP', 5);
define('GDBB_LEFT', 0);
define('GDBB_BOTTOM', 1);
define('GDBB_RIGHT', 2);

class DrawFont {

function DrawFont($details) {
// Get size in pixels, must convert to points for GD2.
// Because GD2 assumes 96 pixels per inch and we use more "standard" 72.
$this->textSizeMax = $details['size'];
$this->font = $details['font'];
$this->text = $details['text'];
$this->image = $details['image'];
$this->color = $details['color'];
$this->textAlign = "C";

$this->imageHSize = $details['imageHSize'];
$this->imageVSize = $details['imageVSize'];

$this->marginL = $details['marginL'];
$this->marginR = $details['marginR'];

$this->marginT = $details['marginT'];
$this->marginB = $details['marginB'];

$this->ComputeTextDimensions($this->font, $this->text);

}


/**
* Compute the dimensions of the text.
*/
function ComputeTextDimensions($fontFile, $text)
{
$this->textAreaWidth = $this->imageHSize - $this->marginL - $this->marginR;
$this->textAreaHeight = $this->imageVSize - $this->marginT - $this->marginB;

// Handle text on several lines
$this->lines = explode(' ', $text);
$this->lineNb = count($this->lines);

if ($this->lineNb == 1)
{

$this->textSize[0] = $this->textSizeMax;

$bb = ImageTTFBBox($this->textSize[0], 0, $fontFile, $text);
$this->textWidth[0] = $bb[GDBB_RIGHT] - $bb[GDBB_LEFT];
$this->maxTextWidth = $this->textWidth[0];
$this->textHeight[0] = $bb[GDBB_BOTTOM] - $bb[GDBB_TOP];


$this->textSize[0] = $this->textSizeMax;
while ($this->textWidth[0] > $this->textAreaWidth && $this->textSize[0] > 1) {

$this->textSize[0]--;

$bb = ImageTTFBBox($this->textWidth[$i], 0, $fontFile, $text);
$this->textWidth[0] = $bb[GDBB_RIGHT] - $bb[GDBB_LEFT];
$this->maxTextWidth = $this->textWidth[0];
$this->textHeight[0] = $bb[GDBB_BOTTOM] - $bb[GDBB_TOP];
}
}
else
{
for ($i = 0; $i < $this->lineNb; $i++)
{
$this->textSize[$i] = $this->textSizeMax;

$bb = ImageTTFBBox($this->textSize[$i], 0, $fontFile, $this->lines[$i]);
$this->textWidth[$i] = $bb[GDBB_RIGHT] - $bb[GDBB_LEFT];
$this->maxTextWidth = max($this->maxTextWidth, $this->textWidth[$i]);
$this->textHeight[$i] = $bb[GDBB_BOTTOM] - $bb[GDBB_TOP];

while ($this->textWidth[$i] > $this->textAreaWidth && $this->textSize[$i] > 1) {

$this->textSize[$i]--;

$bb = ImageTTFBBox($this->textSize[$i], 0, $fontFile, $this->lines[$i]);
$this->textWidth[$i] = $bb[GDBB_RIGHT] - $bb[GDBB_LEFT];
$this->maxTextWidth = max($this->maxTextWidth, $this->textWidth[$i]);
$this->textHeight[$i] = $bb[GDBB_BOTTOM] - $bb[GDBB_TOP];
}
}
}

/*
// Is the given text area width too small for asked text?
if ($this->maxTextWidth > $this->textAreaWidth)
{
// Yes! Increase button size
$this->textAreaWidth = $this->maxTextWidth;
$this->imageHSize = $this->textAreaWidth + $this->marginL + $this->marginR;


}
*/

// Now compute the text positions given the new (?) text area width
if ($this->lineNb == 1)
{
$this->ComputeTextPosition(0, $this->textSize[0], $fontFile, $text, false);
}
else
{
for ($i = 0; $i < $this->lineNb; $i++)
{
$this->ComputeTextPosition($i, $this->textSize[$i], $fontFile, $this->lines[$i], false);
}
}
}

/**
* Compute xText and yText (text position) for the given text.
*/
function ComputeTextPosition($index, $textSize, $fontFile, $text, $centerAscDesc)
{
switch ($this->textAlign)
{
case 'L':
$this->xText[$index] = $this->marginL;
break;
case 'R':
$this->xText[$index] = $this->marginL +
$this->textAreaWidth - $this->textWidth[$index];
break;
case 'C':
default:
$this->xText[$index] = $this->marginL +
($this->textAreaWidth - $this->textWidth[$index]) / 2;
break;
}

if ($centerAscDesc)
{
// Must compute the difference between baseline and bottom of BB.
// I have to use a temporary image, as ImageTTFBBox doesn't use coordinates
// providing offset from the baseline.
$tmpBaseline = 5;
// Image size isn't important here, GD2 still computes correct BB
$tmpImage = ImageCreate(5, 5);
$bbt = ImageTTFText($tmpImage, $this->textSizeMax, 0, 0, $tmpBaseline,
$this->color, $fontFile, $text);
// Bottom to Baseline
$baselinePos = $bbt[GDBB_BOTTOM] - $tmpBaseline;
ImageDestroy($tmpImage);
$this->yText[$index] = $this->marginT + $this->textAreaHeight -
($this->textAreaHeight - $this->textHeight) / 5 - $baselinePos + 0.5;
}
else
{
// Actually, we want to center the x-height, ie. to keep the baseline at same pos.
// whatever the text is really, ie. independantly of ascenders and descenders.
// This provide better looking buttons, as they are more consistent.
$bbt = ImageTTFBBox($textSize, 0, $fontFile, "moxun");
$tmpHeight = $bbt[GDBB_BOTTOM] - $bbt[GDBB_TOP];
$this->yText[$index] = $this->marginT + $this->textAreaHeight -
($this->textAreaHeight - $tmpHeight) / 4.5 + 0.5;
}
}

/**
* Add the text to the button.
*/
function DrawText()
{

$this->maxTextHeight = 0;

// find maxTextHeight
for ($i = 0; $i < $this->lineNb; $i++)
{
if ($this->textHeight[$i] > $this->maxTextHeight) {
$this->maxTextHeight = $this->textHeight[$i];
}
}

for ($i = 0; $i < $this->lineNb; $i++)
{
// Increase slightly line height
$yText = $this->yText[$i] + $this->maxTextHeight * 1.1 *
($i - ($this->lineNb - 1) / 2);

ImageTTFText($this->image, $this->textSize[$i], 0,
$this->xText[$i], $yText, $this->color, $this->font, $this->lines[$i]);


}
}

}


// Script starts here
$image_file=$_GET['image'];//image file
$im = imagecreatefromjpeg($image_file);//create the image from the image file
$color = $_GET['color'];
if ($color == 'pink') {
$color = ImageColorAllocate($im, 201, 29, 115);
}
if ($color == 'lightPink') {
$color = ImageColorAllocate($im, 236, 121, 167);
}
if ($color == 'purple') {
$color = ImageColorAllocate($im, 78, 39, 150);
}
if ($color == 'lavendar') {
$color = ImageColorAllocate($im, 161, 115, 191);
}
if ($color == 'green') {
$color = ImageColorAllocate($im, 94, 158, 51);
}
if ($color == 'blue') {
$color = ImageColorAllocate($im, 242, 400, 24);
}
if ($color == 'orange') {
$color = ImageColorAllocate($im, 94, 158, 51);
}
if ($color == 'white') {
$color = ImageColorAllocate($im, 255, 255, 255);
}
if ($color == 'grey') {
$color = ImageColorAllocate($im, 128, 128, 128);
}
if ($color == 'black') {
$color = ImageColorAllocate($im, 0, 0, 0);
}

$details = array("image" => $im,
"font" => "macyFont.ttf",
"text" => $_GET['text'],
"color" => $color,
"size" => 40,
"imageHSize" => 482,
"imageVSize" => 500,
"marginL" => 10,
"marginR" => 10,
"marginT" => 5,
"marginB" => 5);

$dofontobj =& new DrawFont($details);
$dofontobj->DrawText();

imagepng($im);
imagedestroy($im);
unset($px);

?>

doublej2k
11-20-2010, 08:21 PM
From the first post, I've found a solution to problem #1 (multiple words causing line breaks).

In processImage.php on line 82 change:

$this->lines = explode(' ', $text);
to

$this->lines = explode('|', $text);

Due to my lack of experience with GD, I'm not sure if this is the correct way of stopping line breaks but it works. Hopefully this helps someone using this same code. However, I still face the issue of increasing and decreasing the text within the bounding box.

In processImage.php on line 52 the
$this->textSizeMax; is set to 40 in the details array which tells me the font will not exceed 40 but it will not downsize if the text string exceeds the bounding box. The first "if" statement for the "computeTextDimensions" function has
$this->textSize[0]--;. One would assume this is telling the font to decrease if the "textWidth" is greater then "textAreaWidth" & "textSize" is greater then 1 but it doesn't.

I know, It's a tough one. If I find the solution, I'll be sure to post it. Thanks in advance to who ever can help.



EZ Archive Ads Plugin for vBulletin Copyright 2006 Computer Help Forum