Location: PHPKode > scripts > Thaana Text Render > thaanaTextRender.php
<?php

// {{{ Thaana Text Render

/**
 * Renders given Thaana text as an image, with configuration options for font, font size and color.
 *
 * This class currently provides the following functions:
 * 
 * render()
 * renderImage()
 * setFontPath()
 * setFont()
 * setFontSize()
 * setTextColor()
 * setTextLineSpacing()
 * setBgColor()
 * setShadow()
 *
 * Simple usage:
 * include('thaanaTextRender.php');
 * $ttr = new ThaanaTextRender('./fonts/', 'a_waheed', 18, 'white', 0, 50, 'rgb(0,0,0)', 127, 2, '#555555', 50);
 * $ttr->renderImage('swaincsc', 100, 50, 'output.png', 'png')
 *
 *
 * @author Jawish Hameed
 * @link http://www.jawish.org/
 * @copyright  2011 Jawish Hameed
 * @license http://www.opensource.org/licenses/mit-license.php MIT License
 * @version Release: 1.0
 */

class ThaanaTextRender {
	
	// {{{ properties
	
	private $fontPath = './';
	private $fontFile;
	private $fontSize = 12;
	private $textColor = array('r' => 0, 'g' => 0, 'b' => 0);
	private $textAlpha = 0;
	private $textLineSpacing = 0;
	private $bgColor = array('r' => 255, 'g' => 255, 'b' => 255);
	private $bgAlpha = 0;
	private $bgTransparent = true;
	private $shadowOffset = false;
	private $shadowColor = '#EBEBEB';
	private $shadowAlpha = 0;
	private $width;
	
	// }}}
	
	
	// {{{ __construct()
	
	/**
	 *
	 *
	 */
	public function __construct($fontPath=NULL, $fontName=NULL, $fontSize=NULL, $textColor=NULL, $textAlpha=NULL, $textLineSpacing=NULL, $bgColor=NULL, $bgAlpha=NULL, $shadowOffset=NULL, $shadowColor=NULL, $shadowAlpha=NULL)
	{
		// Initialize with specified defaults:
		if (!empty($fontPath)) $this->setFontPath($fontPath);
		if (!empty($fontName)) $this->setFont($fontName);
		if (!empty($fontSize)) $this->setFontSize($fontSize);
		if (!empty($textColor)) $this->setTextColor($textColor, $textAlpha);
		if (!empty($textLineSpacing)) $this->setTextLineSpacing($textLineSpacing);
		if (!empty($bgColor)) $this->setBgColor($bgColor, $bgAlpha);
		if (!empty($shadowOffset)) $this->setShadow($shadowOffset, $shadowColor, $shadowAlpha);
	}
	
	// }}}
	
	
	// {{{ render()
	
	/**
	 * Render the given ASCII Thaana text and return image handle
	 *
	 * @param string $text			Text to render in Dhivehi as ASCII Thaana
	 * @param integer $width		Width of the rendered image
	 * @param integer $linespacing	Line spacing
	 * @return string				Image identifier handle
	 *
	 * @access public
	 */
	public function render($text, $width=NULL)
	{	
		try
		{
			// Word wrap text
			$lines = $this->wordWrap($text, $width);
			
			// Set linespacing to 1x if is not specified
			$linespacing = ($this->textLineSpacing > 0) ? $this->textLineSpacing : $lines['maxheight'];
			
			// Calculate text width and height
			$width = max($width, $lines['maxwidth']);
			$height = $linespacing * count($lines['text']);
			
			// Create image
			$im = imagecreatetruecolor($width, $height);
			
			// Setup alpha channel handling
			imagesavealpha($im, true);
			imagealphablending($im, true);
			
			// Allocate required colors
			$bgColor = imagecolorallocatealpha($im, $this->bgColor['r'], $this->bgColor['g'], $this->bgColor['b'], $this->bgAlpha);
			$fontColor = imagecolorallocatealpha($im, $this->textColor['r'], $this->textColor['g'], $this->textColor['b'], $this->textAlpha);
			
			// Set shadow color if shadow in use
			if (is_numeric($this->shadowOffset))
			{
				// Allocate shadow color
				$shadowColor = imagecolorallocatealpha($im, $this->shadowColor['r'], $this->shadowColor['g'], $this->shadowColor['b'], $this->shadowAlpha);
			}
			
			// Set background color
			imagefill($im, 0, 0, $bgColor);
			
			// Process the lines
			foreach ($lines['text'] as $lineno => $line)
			{
				// Reverse line
				$line = strrev($line);
				
				// Calculate bounding box and line width without the new word
				$bbox = imagettfbbox($this->fontSize, 0, $this->fontFile, $line);
				
				// Calculate X axis offset
				$xpos = ($width - abs($bbox[2] - $bbox[0])) - abs($bbox[0]);
				
				// Calculate Y axis offset
				$ypos = ($linespacing * $lineno) + abs($bbox[7]);
				
				// Render text shadow
				if ($this->shadowOffset > 0)
				{
					imagettftext($im, $this->fontSize, 0, $xpos + $this->shadowOffset, 
								 $ypos + $this->shadowOffset, $shadowColor, $this->fontFile, $line
								 );
				}
				
				// Render text
				imagettftext($im, $this->fontSize, 0, $xpos, $ypos, $fontColor, $this->fontFile, $line);
			}
		
		}
		catch (Exception $e)
		{
			// An error had occured:
			
			// Create a 1x1 pixel image
			$im = imagecreatetruecolor(1, 1);
		}
		
		// Return rendered image handle
		return $im;
	}
	
	// }}}
	
	
	// {{{ renderImage()
	
	/**
	 * Render the given text and output directly or save
	 *
	 * @param string $text			Text string to render
	 * @param integer $width		Width of the rendered image
	 * @param string $filename		Filename to save the rendered image as. Set to NULL to output directly.
	 * @param string $imagetype		Image type. Can be 'png', 'jpg', 'jpeg' or 'gif'
	 * @return string				Image identifier handle
	 *
	 * @access public
	 */
	public function renderImage($text, $width=NULL, $filename=NULL, $imagetype = 'png')
	{
		// Render and return image handle
		$im = $this->render($text, $width);
		
		// Select output image type
		switch ($imagetype)
		{
			case 'png':
				// Render as png
				header("Content-type: image/png");
				imagepng($im, $filename);
				break;
			
			case 'jpg':
			case 'jpeg':
				// Render as jpg
				header("Content-type: image/jpeg");
				imagejpeg($im, $filename);
				break;
				
			case 'gif':
				// Render as gif
				header("Content-type: image/gif");
				imagegif($im, $filename);
				break;
		}
	}
	
	// }}}
	
	
	// {{{ wordWrap()
	
	/**
	 * Word wrap the text at the given width boundary
	 * Returns the wrapped text as an array of lines.
	 * Returns max line width and max line height details
	 *
	 * @param string $text		Text to word wrap
	 * @param integer $width	Width boundary to word wrap
	 * @return array			Word wrapped line data as an array with elements [text, linewidth, lineheight]
	 *
	 * @access private
	 */
	private function wordWrap($text, $width=NULL)
	{
		// Check if wrapping is necessary
		if (empty($width))
		{
			// No width set -> no wrapping required
			return explode("\r\n", $text);
		}
		
		// Initialize variables for line data
		$lines = array();
		$lineno = -1;
		$maxlinewidth = 0;
		$maxlineheight = 0;
		
		// Get paragraphs
		$text = explode("\n", $text);
		
		// Loop through paragraphs
		for ($x = 0; $x < count($text); $x++)
		{
			
			// Convert the text to an array
			$word = strtok($text[$x], ' ');
						
			// Begin a new line
			$lines[++$lineno] = '';
			
			// Loop through words
			while ($word !== false)
			{
				
				// Calculate bounding box for the current line + current word
				$bbox = imagettfbbox($this->fontSize, 0, $this->fontFile, $lines[$lineno] . $word . ' ');
				
				// Calculate line width and height
				$linewidth = abs($bbox[2] - $bbox[0]);
				$lineheight = abs($bbox[7] - $bbox[1]);
				
				// Check if line + word exceeds max width allowed
				if ($linewidth > $width)
				{
					// Width exceeds:
					
					// Start a new line and add current word to it
					$lines[++$lineno] = $word . ' ';
					
				}
				else
				{
					// Width ok:
					
					// Add word to current line
					$lines[$lineno] .= $word . ' ';
					
					// Store the line width/height if largest
					if ($linewidth > $maxlinewidth) $maxlinewidth = $linewidth;
					if ($lineheight > $maxlineheight) $maxlineheight = $lineheight;
				}
				
				// Get next word
				$word = strtok(' ');
			}
		}
		
		// Return the wordwrapped text
		return array('text' => $lines, 'maxwidth' => $maxlinewidth, 'maxheight' => $maxlineheight);
	}
	
	// }}}
	
	
	// {{{ setFont()
	
	/**
	 * Set the name of the font to use by checking a given list of fonts for a useable font.
	 * Falls back to the default if no font in the list is found.
	 * Expects fonts to be in the specified font path with lowercase filenames and named as given in the font list.
	 *
	 * @param string $fontNames		HTML/CSS font names list
	 * @param string $default		Name of font to default to in case of failure
	 * @return boolean 				True if font set successfully, false otherwise
	 *
	 * @access public
	 */
	public function setFont($fontNames, $default=NULL)
	{
		// Get the list of fonts specified
		$fontNames = explode(',', $fontNames);
		
		// Add the default font as the last font to check
		if ($default != NULL) array_push($fontNames, $default);
		
		// Loop through the specified list to find one that can be used
		foreach ($fontNames as $fontName)
		{
			// Cleanup font name by removing extra whitespace and quotes
			$fontName = str_replace(array('\'', '"'), '', strtolower(trim($fontName)));
			
			// Check if the given font exists in the fonts store
			if (file_exists($this->fontPath . $fontName . '.ttf'))
			{
				// Given font exists:
				
				// Useable font found, set it for use
				$this->fontFile = $this->fontPath . $fontName . '.ttf';
				
				return true;
			}
		}
		
		// No useable font found
		return false;
	}
	
	// }}}
	
	
	// {{{ setFontSize()
	
	/**
	 * Set font size
	 *
	 * @param integer $size		Font size to use
	 * @return boolean			True if successfully set, false otherwise
	 *
	 * @access public
	 */
	public function setFontSize($size)
	{
		// Check if font size is valid
		if (intval($size) > 0)
		{
			// Font size valid
			
			// Save font size
			$this->fontSize = intval($size);
			
			return true;
		}
			
		return false;
	}
	
	// }}}
	
	
	// {{{ setTextColor()
	
	/**
	 * Set text color
	 *
	 * @param string $color		Text color. Can be any HTML/CSS color spec
	 * @param integer $alpha	Alpha value [0-127] for transparency
	 *
	 * @access public
	 */
	public function setTextColor($color, $alpha=NULL)
	{
		// Set text color
		$this->textColor = $this->parseColor($color);
		
		// Set text alpha
		if (!empty($alpha)) $this->textAlpha = intval($alpha);
	}
	
	// }}}
	
	
	/**
	 * Set the line spacing for the text
	 *
	 * @param integer $spacing	Line spacing in pixels
	 *
	 * @access public
	 */
	// {{{ setTextLineSpacing()
	public function setTextLineSpacing($spacing)
	{
		if (!empty($spacing)) $this->textLineSpacing = intval($spacing);
	}
	
	// }}}
	
	
	// {{{ setFontPath()
	
	/**
	 * Set the path to where the TTF font files are stored
	 *
	 * @param string $path		Path to font files
	 * @return boolean			True if font path exists, false if not.
	 *
	 * @access public
	 */
	public function setFontPath($path)
	{
		// Check if the path exists
		if (file_exists($path))
		{
			// Path found:
			
			// Set font path
			$this->fontPath = $path;
			
			return true;
		}
			
		return false;
	}
	
	// }}}
	
	
	// {{{ setBgColor()
	
	/**
	 * Set background color
	 *
	 * @param string $color		HTML/CSS background spec
	 * @param integer $alpha	Alpha value [0-127] for transparency 
	 *
	 * @access public
	 */
	public function setBgColor($color, $alpha=NULL)
	{
		// Set bg color
		$this->bgColor = $this->parseColor($color);
		
		// Set bg alpha
		if (!empty($alpha)) $this->bgAlpha = intval($alpha);
	}
	
	// }}}
	
	
	// {{{ setShadow()
	
	/**
	 * Set shadow
	 *
	 * @param integer $offset		Shadow offset
	 * @param string $color			Color as any HTML/CSS color spec
	 * @param integer $alpha		Alpha value [0-127] for transparency
	 *
	 * @access public
	 */
	public function setShadow($offset, $color, $alpha=NULL)
	{
		// Set shadow offset
		$this->shadowOffset = intval($offset);
		
		// Set shadow color
		$this->shadowColor = $this->parseColor($color);
		
		// Set shadow alpha
		if (!empty($alpha)) $this->shadowAlpha = intval($alpha);
	}
	
	// }}}
	
	
	// {{{ parseColor()
	
	/**
	 * Parse a string for HTML/CSS color and return RGB
	 *
	 * @param string $color     Containing color specification as RGB, hex or named colors as per HTML/CSS
	 * @return array 			RGB color components 'r', 'g', 'b'
	 *
	 * @access private
	 */
	private function parseColor($color)
	{
		// Which color format?
		if (substr($color, 0, 1) == '#')
		{
			// Hex:
			
			// Extract the RGB components
			$int = hexdec(substr($color, 1));
			return array('r' => 0xFF & ($int >> 0x10), 'g' => 0xFF & ($int >> 0x8), 'b' => 0xFF & $int);
		}
		elseif (substr($color, 0, 3) == 'rgb')
		{
			// RGB:
			
			// Extract RGB components
			list($r, $g, $b) = sscanf($color, 'rgb(%d,%d,%d)');
			
			// Return the RGB components
			return array('r' => $r, 'g' => $g, 'b' => $b);
		}
		else
		{
			// Named or other:
			
			// W3C listed named colors required for validation
			$names = array ('aqua' => '#00FFFF', 'black' => '#000000',
							'blue' => '#0000FF', 'fuchsia' => '#FF00FF', 
							'gray' => '#808080', 'green' => '#008000', 
							'lime' => '#00FF00', 'maroon' => '#800000', 
							'navy' => '#000080', 'olive' => '#808000', 
							'purple' => '#800080', 'red' => '#ff0000', 
							'silver' => '#C0C0C0', 'teal' => '#008080', 
							'white' => '#FFFFFF', 'yellow' => '#FFFF00'
							);
			
			// Check if named color is defined
			if (isset($names[strtolower($color)]))
			{
				// Named color defined:
				
				// Recursive call to get the rgb components of the named color
				return $this->parseColor($names[strtolower($color)]);
			}
		}
		
		return array('r' => 0, 'g' => 0, 'b' => 0);
	}
	
	// }}}	
}
?>
Return current item: Thaana Text Render