Below is the code I used to align drawn text on the right or center it within provided width.
As stated in http://framework.zend.com/issues/browse/ZF-7144, use of Zend_Pdf_Page subclass is not easy on ZF 1.8.4 => I subclassed Zend_Pdf and implemented within this class instead.
Below code relies on function to find out width of text to be generated (see Zend_Pdf: find out width of text to be drawn) and also incorporates small code improvement to handle multi-line text (see Zend_Pdf: draw multi-line text).
Here it is:
<?php
require_once 'Zend/Pdf.php';
/**
* Represent an order/bill pdf
*/
class Library_Pdf_Base extends Zend_Pdf
{
/**
* Align text at left of provided coordinates
*/
const TEXT_ALIGN_LEFT = 'left';
/**
* Align text at right of provided coordinates
*/
const TEXT_ALIGN_RIGHT = 'right';
/**
* Center-text horizontally within provided coordinates
*/
const TEXT_ALIGN_CENTER = 'center';
/**
* Extension of basic draw-text function to allow it to vertically center text
*
* @param Zend_Pdf_Page $page
* @param string $text
* @param int $x1
* @param int $y1
* @param int $x2
* @param int $position
* @param string $encoding
* @return self
*/
public function drawText(Zend_Pdf_Page $page, $text, $x1, $y1, $x2 = null, $position = self::TEXT_ALIGN_LEFT, $encoding = null)
{
$bottom = $y1; // could do the same for vertical-centering
switch ($position) {
case self::TEXT_ALIGN_LEFT:
$left = $x1;
break;
case self::TEXT_ALIGN_RIGHT:
$text_width = $this->getTextWidth($text, $page->getFont(), $page->getFontSize());
$left = $x1 - $text_width;
break;
case self::TEXT_ALIGN_CENTER:
if (null === $x2) {
throw new Exception("Cannot center text horizontally, x2 is not provided");
}
$text_width = $this->getTextWidth($text, $page->getFont(), $page->getFontSize());
$box_width = $x2 - $x1;
$left = $x1 + ($box_width - $text_width) / 2;
break;
default:
throw new Exception("Invalid position value \"$position\"");
}
// display multi-line text
foreach (explode(PHP_EOL, $text) as $i => $line) {
$page->drawText($line, $left, $bottom - $i * $page->getFontSize(), $encoding);
}
return $this;
}
/**
* Return length of generated string in points
*
* @param string $string
* @param Zend_Pdf_Resource_Font $font
* @param int $font_size
* @return double
*/
public function getTextWidth($text, Zend_Pdf_Resource_Font $font, $font_size)
{
$drawing_text = iconv('', 'UTF-16BE', $text);
$characters = array();
for ($i = 0; $i < strlen($drawing_text); $i++) {
$characters[] = (ord($drawing_text[$i++]) << 8) | ord ($drawing_text[$i]);
}
$glyphs = $font->glyphNumbersForCharacters($characters);
$widths = $font->widthsForGlyphs($glyphs);
$text_width = (array_sum($widths) / $font->getUnitsPerEm()) * $font_size;
return $text_width;
}
}
So far it worked real great for him, I hope some folks will find it useful to and improve it.
6 Comments: Trackback URL | Comments RSS
March 19th, 2010 at 2:59 pm
Very very useful! thanks!
I replaced last lines of drawText() by this:
// display multi-line text
foreach (explode(PHP_EOL, $text) as $i => $line) {
$page->drawText($line, $left, $bottom – $i * $page->getFontSize(), $encoding);
$height = $bottom – $i * $page->getFontSize();
}
return $height;
Like this, this function returns the $height position if you need to write just below!
October 13th, 2010 at 10:50 am
doesnt seem to work for JAPANESE charcters.
is it relevant to multi-bites?
March 24th, 2011 at 11:15 am
Good thing, thanks.
therefore, you inctroduced an interface break : the $x2 and $position parameters should be placed after the $encoding parameter, as shown here, nothing seems to break, but it does :
// In your app code :
$obj = new Library_Pdf_Base();
// later, in a Zend Framework standard class :
if ($obj instanceof Zend_Pdf) {
$obj->drawText($page, ‘Hello World!’, 35, 100, ‘UTF-8′) // Break!
…
}
June 13th, 2011 at 5:47 pm
Thanks for the getTextWidth function
January 23rd, 2012 at 2:44 pm
March 11th, 2012 at 9:16 pm
Great, plugged this into Magento’s PDF functionality (built on the Zend Framework), and it work first time. Thanks!