Zend_Pdf: align drawn text on right or center it horizontally

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.

sources

6 Comments: Trackback URL | Comments RSS

  1. jcerdan Says:

    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!

  2. tjunicho Says:

    doesnt seem to work for JAPANESE charcters.

    is it relevant to multi-bites?

  3. Greg Says:

    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!

    }

  4. max4ever Says:

    Thanks for the getTextWidth function :D

  5. MaxFor222 Says:

    :) good job, thanx ;)

  6. Jamie Saunders Says:

    Great, plugged this into Magento’s PDF functionality (built on the Zend Framework), and it work first time. Thanks!

Post a Comment

Your email is never published nor shared. You're allow to say what you want...

Powered by sweet Captcha