public function Visualize($table_data, $font_size)
 {
     $ww_table = $this->wordWrapTable($table_data, $font_size, true);
     $rows = count($ww_table);
     $cols = array_keys($ww_table[0]);
     $col_size = array();
     if ($this->encoding->useMB()) {
         $plus = mb_convert_encoding("+", $this->encoding->getEncodingType());
         $newline = mb_convert_encoding("\n", $this->encoding->getEncodingType());
         $dash = mb_convert_encoding("-", $this->encoding->getEncodingType());
         $space = mb_convert_encoding(" ", $this->encoding->getEncodingType());
         $vert = mb_convert_encoding('|', $this->encoding->getEncodingType());
         $out = mb_convert_encoding("", $this->encoding->getEncodingType());
     } else {
         $plus = "+";
         $newline = "\n";
         $dash = "-";
         $space = " ";
         $vert = '|';
         $out = "";
     }
     $lengths = array();
     for ($r = 0; $r < $rows; $r++) {
         $lengths[$r] = array();
     }
     foreach ($cols as $col) {
         $max = 0;
         for ($r = 0; $r < $rows; $r++) {
             $z = count($ww_table[$r][$col]);
             for ($i = 0; $i < $z; $i++) {
                 $line = $ww_table[$r][$col][$i];
                 if ($this->encoding->useMB()) {
                     $w = mb_strlen($line, $this->encoding->getEncodingType());
                 } else {
                     $w = strlen($line);
                 }
                 $lengths[$r][$col][$i] = $w;
                 if ($w > $max) {
                     $max = $w;
                 }
             }
         }
         $col_size[$col] = $max;
     }
     //now do the display
     for ($r = 0; $r < $rows; $r++) {
         foreach ($cols as $col) {
             $out .= $plus;
             for ($j = 0; $j < $col_size[$col]; $j++) {
                 $out .= $dash;
             }
         }
         $out .= $plus . $newline;
         $z = count($ww_table[$r][$cols[0]]);
         for ($i = 0; $i < $z; $i++) {
             foreach ($cols as $col) {
                 $out .= $vert . $ww_table[$r][$col][$i];
                 for ($j = $lengths[$r][$col][$i]; $j < $col_size[$col]; $j++) {
                     $out .= $space;
                 }
             }
             $out .= $vert . $newline;
         }
     }
     foreach ($cols as $col) {
         $out .= $plus;
         for ($j = 0; $j < $col_size[$col]; $j++) {
             $out .= $dash;
         }
     }
     $out .= $plus . $newline;
     return $out;
 }
Example #2
0
 /**
  *  Get the  parts of a word which breaks along hyphenation points or any non-letter.
  * @param string $word the word we wish to break up
  * @param bool $supress true (default)to suppress hyphenation points at the beginning/end of a word.
  *  @returns an  the associative array has 
  *  a string 'Subword' which tells what the subword is, the int 'Offset' tells where the subword started,
  *  the int 'Length' the length of the subword, and the boolean 'IsLetter' which tells us if the 
  *  subword is a composed of letters (by the Unicode convention) or not.
  */
 public function getWordParts($word, $supress = true)
 {
     $word_parts = array();
     $mb_encoding = $this->enc->getEncodingType();
     $use_mb = $this->enc->useMB();
     mb_regex_encoding($mb_encoding);
     if ($use_mb) {
         $word_len = mb_strlen($word, $mb_encoding);
     } else {
         $word_len = strlen($word);
     }
     if ($mb_encoding != 'UTF-8') {
         if ($mb_encoding) {
             $utf8_word = mb_convert_encoding($word, 'UTF-8', $mb_encoding);
         } else {
             $utf8_word = mb_convert_encoding($word, 'UTF-8');
         }
     } else {
         $utf8_word = $word;
     }
     $i = 0;
     $prev_i = 0;
     $c = '';
     do {
         $sub_word_len = 0;
         $is_letter = true;
         while ($i < $word_len && $is_letter) {
             $c = mb_substr($utf8_word, 0, 1, 'UTF-8');
             //get the first character
             $utf8_word = mb_substr($utf8_word, 1);
             //delete the first character
             if (!preg_match('/^\\p{L}/', $c)) {
                 //the character is not a letter
                 $is_letter = false;
             }
             $sub_word_len++;
             $i++;
         }
         if (!$is_letter) {
             //the last character we read was a non-letter
             $sub_word_len--;
         }
         if ($use_mb) {
             $subword = mb_substr($word, $prev_i, $sub_word_len, $mb_encoding);
         } else {
             $subword = substr($word, $prev_i, $sub_word_len);
         }
         if ($sub_word_len > 0) {
             //get the hyphenation points for the word.
             $hp = $this->HyphenateWord($subword, $mb_encoding, $supress);
             $num_hp = count($hp);
             if ($use_mb) {
                 for ($k = 0; $k < $num_hp - 1; $k++) {
                     $word_parts[] = array('Offset' => $prev_i + $hp[$k], 'Length' => $hp[$k + 1] - $hp[$k], 'Subword' => mb_substr($subword, $hp[$k], $hp[$k + 1] - $hp[$k], $mb_encoding), 'IsLetter' => True);
                 }
                 $word_parts[] = array('Offset' => $prev_i + $hp[$num_hp - 1], 'Length' => $sub_word_len - $hp[$num_hp - 1], 'Subword' => mb_substr($subword, $hp[$num_hp - 1], $sub_word_len - $hp[$num_hp - 1], $mb_encoding), 'IsLetter' => True);
             } else {
                 for ($k = 0; $k < $num_hp - 1; $k++) {
                     $word_parts[] = array('Offset' => $prev_i + $hp[$k], 'Length' => $hp[$k + 1] - $hp[$k], 'Subword' => substr($subword, $hp[$k], $hp[$k + 1] - $hp[$k]), 'IsLetter' => True);
                 }
                 $word_parts[] = array('Offset' => $i + $hp[$num_hp - 1], 'Length' => $sub_word_len - $hp[$num_hp - 1], 'Subword' => substr($subword, $hp[$num_hp - 1]), 'IsLetter' => True);
             }
         }
         if (!$is_letter) {
             $word_parts[] = array('Offset' => $i, 'Length' => 1, 'Subword' => $c, 'IsLetter' => False);
         }
         $prev_i = $i;
     } while ($i < $word_len);
     return $word_parts;
 }
Example #3
0
 /**
  * Get the I2CE_Encoding according to one of the standard adobe encodings
  */
 protected function getAdobeStandardEncoding($encoding)
 {
     if (isset($this->adobe_standard_encondings[$encoding])) {
         return;
     }
     $enc = new I2CE_Encoding($encoding);
     if (!isset($this->glyph_list)) {
         $this->loadGlyphList();
     }
     $a = $this->load_file('PDF_CORE', $encoding . '.list');
     foreach ($a as $l) {
         $l = trim($l);
         $e = explode(" ", rtrim($l));
         $cc = (int) $e[0];
         $gn = $e[1];
         $cps = $this->glyph_list[$gn];
         if (count($cps) == 1) {
             //a adobe glyphname may be associated to several unicode codepoints (e.g. lamedholam)
             //if this is the case, we ignore it.
             $enc->setGlyphname($cps[0], $gn);
             $enc->setCharacterCode($cps[0], $cc);
         }
     }
     $this->adobe_standard_encodings[$encoding] = $enc;
     return $enc;
 }
 /**
  *  Load the font metrics from an afm  file
  *  (Some of this code was stolen from makefont.php)
  *  @param I2CE_Encoding $encoding -- the character encoding  used in the file
  *  @param string $afmfile
  *  Caution:  Units for these files are 1/1000 of a point where a point is 1/72 of an inch
  */
 protected function loadFontMetricFromAFM($encoding, $afmfile)
 {
     $prev_dir = $this->getDirection();
     $sub = mb_substitute_character();
     mb_substitute_character("none");
     //Read a font metric file
     $found_afmfile = I2CE::getFileSearch()->search('AFM_PATH', $afmfile);
     if (!$found_afmfile) {
         die('Error: AFM file not found: ' . $afmfile);
     } else {
         $afmfile = $found_afmfile;
     }
     $a = file($found_afmfile);
     if (empty($a)) {
         die('File empty' . $afmfile);
     }
     $this->setGlobal();
     //global information is the default
     $this->setLinegap(0);
     //no line gap information is present in a AFM file
     $mode = 0;
     /**
      * Modes are 0: header or wirting direction
      * 10: Character metrics
      * 20: Kerning
      * 21: Kerning Tracking
      * 21: Kerning Pairs 
      * 30: Composites
      */
     foreach ($a as $l) {
         $e = explode(' ', rtrim($l));
         $code = $e[0];
         switch ($mode) {
             case 10:
                 //character metrics
                 $vals = array();
                 unset($cc);
                 unset($gn);
                 switch ($code) {
                     case 'EndCharacterMetrics':
                     case 'EndCharMetrics':
                         $mode = 0;
                         continue 2;
                         //break out of the switch($mode)
                     //break out of the switch($mode)
                     case 'C':
                         $cc = (int) $e[1];
                         break;
                     case 'CH':
                         $cc = hexdec($e[1]);
                         break;
                 }
                 if (!isset($cc)) {
                     break;
                 }
                 $i = 3;
                 while ($i < count($e)) {
                     $subcode = $e[$i];
                     switch ($subcode) {
                         case 'WX':
                         case 'W0X':
                         case 'W1X':
                         case 'WY':
                         case 'W0Y':
                         case 'W1Y':
                             //widths and heights
                             $vals[$subcode] = (double) $e[$i + 1];
                             $i = $i + 2;
                             break;
                         case 'W':
                         case 'W0':
                         case 'W1':
                         case 'VV':
                             //widths and heights
                             $vals[$subcode] = array((double) $e[$i + 1], (double) $e[$i + 2]);
                             $i = $i + 3;
                             break;
                         case 'N':
                             //postscript glyph name
                             $gn = $e[$i + 1];
                             $i = $i + 2;
                             break;
                         case 'B':
                             //bounding box
                             $vals[$subcode] = array((double) $e[$i + 1], (double) $e[$i + 2], (double) $e[$i + 3], (double) $e[$i + 4]);
                             $i = $i + 5;
                             break;
                         case 'L':
                             //Ligature sequence -- may have more than one
                             if (!isset($vals['L'])) {
                                 $vals['L'] = array();
                             }
                             $vals['L'][] = array($e[$i + 1], $e[$i + 2]);
                             $i = $i + 3;
                             $i++;
                             break;
                         default:
                             $i++;
                             break;
                     }
                 }
                 unset($uc);
                 if ($cc < 0) {
                     //not a valid character code
                     if ($gn !== null) {
                         //try to get the unicode code point of the glyphname based on our encoding
                         $uc = $encoding->UnicodeFromGlyphname($gn);
                         if ($uc === null) {
                             //we failed
                             //try to get a unicode code point from the glyphname
                             if (preg_match('/^uni([0-9A-F]{4})$/', $gn, $ucs)) {
                                 //we have a unicode codepoint
                                 $uc = $ucs[1];
                             }
                         }
                     }
                 } else {
                     //we have a valid character code
                     $uc = $encoding->UnicodeFromCharactercode($cc);
                     if ($gn !== null) {
                         $this->gn2cc[$gn] = $cc;
                     }
                 }
                 if ($uc !== null && $uc <= 0xffff && $uc >= 0 && $uc !== 0xfffd) {
                     //replacement character
                     $uc = I2CE_UTF8::cp_to_code($uc);
                     //convert to UTF8
                     $cc = mb_convert_encoding($uc, $this->getEncoding()->getEncodingType(), 'UTF-8');
                     if ($this->getEncoding()->useMB()) {
                         if (mb_strlen($cc, $this->getEncoding()->getEncodingType()) === 0) {
                             $cc = -1;
                         }
                     } else {
                         if (strlen($cc) === 0) {
                             $cc = -1;
                         }
                     }
                 } else {
                     $cc = -1;
                 }
                 foreach (array('WX', 'W0X') as $key) {
                     if (array_key_exists($key, $vals) && $vals[$key] !== null) {
                         $this->setDirection('H');
                         if ($cc !== -1) {
                             $this->setCharacterWidth($cc, $vals[$key]);
                         }
                         if ($gn !== null) {
                             $this->setCharacterWidth($gn, $vals[$key]);
                         }
                     }
                 }
                 if (array_key_exists('W1X', $vals) && $vals['W1X'] !== null) {
                     $this->setDirection('V');
                     if ($cc !== -1) {
                         $this->setCharacterWidth($cc, $vals['W1X']);
                     }
                     if (null !== $gn) {
                         $this->setCharacterWidth($gn, $vals['W1X']);
                     }
                 }
                 foreach (array('WY', 'W0Y') as $key) {
                     if (array_key_exists($key, $vals) && null !== $vals[$key]) {
                         $this->setDirection('H');
                         if ($cc !== -1) {
                             $this->setCharacterHeight($cc, $vals[$key]);
                         }
                         if (null !== $gn) {
                             $this->setCharacterHeight($gn, $vals[$key]);
                         }
                     }
                 }
                 if (array_key_exists('W1Y', $vals) && null !== $vals['W1Y']) {
                     $this->setDirection('V');
                     if ($cc !== -1) {
                         $this->setCharacterHeight($cc, $vals['W1Y']);
                     }
                     if (null !== $gn) {
                         $this->setCharacterHeight($gn, $vals['W1Y']);
                     }
                 }
                 foreach (array('W', 'W0') as $key) {
                     $this->setDirection('H');
                     if (array_key_exists($key, $vals) && null !== $vals[$key]) {
                         if ($cc !== -1) {
                             $this->setCharacterWidth($cc, $vals[$key]);
                             $this->setCharacterHeight($cc, $vals[$key]);
                         }
                         if (null !== $gn) {
                             $this->setCharacterWidth($gn, $vals[$key]);
                             $this->setCharacterHeight($gn, $vals[$key]);
                         }
                     }
                 }
                 if (array_key_exists('W1', $vals) && null !== $vals['W1']) {
                     $this->setDirection('V');
                     if ($cc !== -1) {
                         $this->setCharacterWidth($cc, $vals[$key]);
                         $this->setCharacterHeight($cc, $vals[$key]);
                     }
                     if (null !== $gn) {
                         $this->setCharacterWidth($gn, $vals[$key]);
                         $this->setCharacterHeight($gn, $vals[$key]);
                     }
                 }
                 foreach (array('VVector' => 'VV', 'BoundingBox' => 'B', 'Ligature' => 'L') as $name => $key) {
                     $this->setGlobal();
                     if (array_key_exists($key, $vals) && null !== $vals[$key]) {
                         if ($cc !== -1) {
                             $this->setCharacterInfo($cc, $name, $vals[$key]);
                         }
                         if (null !== $gn) {
                             $this->setCharacterInfo($gn, $name, $vals[$key]);
                         }
                     }
                 }
                 break;
             case 20:
                 //kerning
                 switch ($code) {
                     case 'EndKernData':
                         $mode = 0;
                         break;
                     case 'StartTrackKern':
                         $mode = 21;
                         break;
                     case 'StartKernPairs':
                     case 'StartKernPairs0':
                         $this->setDirection('H');
                         $mode = 22;
                         break;
                     case 'StartKernPairs1':
                         $this->setDirection('V');
                         $mode = 22;
                         break;
                 }
                 break;
             case 21:
                 //kerning tracking
                 switch ($code) {
                     case 'EndTrackKern':
                         $mode = 20;
                         break;
                     case '':
                         break;
                 }
                 break;
             case 22:
                 //kerning pairs
                 switch ($code) {
                     case 'EndKernPairs':
                         $mode = 21;
                         break;
                     case 'KP':
                         //kerning pairs are given by glyph name
                         $this->setDirection('H');
                         $this->setKerningByPair($e[1], $e[2], (double) $e[3]);
                         $this->setDirection('V');
                         $this->setKerningByPair($e[1], $e[2], (double) $e[4]);
                         //get the corresponding character codes and insert into the table
                         $this->setGlobal();
                         $cc1 = $this->getEncoding()->getCodeFromGlyphname($e[1]);
                         $cc2 = $this->getEncoding()->getCodeFromGlyphname($e[2]);
                         if ($cc1 !== -1 && $cc2 !== -1) {
                             $this->setDirection('H');
                             $this->setKerningByPair($cc1, $cc2, (double) $e[3]);
                             $this->setDirection('V');
                             $this->setKerningByPair($cc1, $cc2, (double) $e[4]);
                         }
                         break;
                     case 'KPH':
                         //not sure what is best to do here.
                         $ch1 = ltrim(rtrim($e[1], '>'), '<');
                         $ch2 = ltrim(rtrim($e[1], '>'), '<');
                         $this->setDirection('H');
                         $this->setKerningByPair($ch1, $ch2, (double) $e[3]);
                         $this->setDirection('V');
                         $this->setKerningByPair($ch1, $ch2, (double) $e[4]);
                         break;
                     case 'KPX':
                         $this->setDirection('H');
                         $this->setKerningByPair($e[1], $e[2], (double) $e[3]);
                         if (!array_key_exists($e[1], $this->gn2cc) || !array_key_exists($e[2], $this->gn2cc)) {
                             break;
                         }
                         $cc1 = $this->gn2cc[$e[1]];
                         $cc2 = $this->gn2cc[$e[2]];
                         if ($cc1 !== -1 && $cc2 !== -1) {
                             $this->setKerningByPair($cc1, $cc2, (double) $e[3]);
                         }
                         break;
                     case 'KPY':
                         $this->setDirection('V');
                         $this->setKerningByPair($e[1], $e[2], (double) $e[3]);
                         if (!array_key_exists($e[1], $this->gn2cc) || !array_key_exists($e[2], $this->gn2cc)) {
                             break;
                         }
                         $cc1 = $this->gn2cc[$e[1]];
                         $cc2 = $this->gn2cc[$e[2]];
                         if ($cc1 !== -1 && $cc2 !== -1) {
                             $this->setKerningByPair($cc1, $cc2, (double) $e[3]);
                         }
                         break;
                 }
                 break;
             case 30:
                 //composites
                 switch ($code) {
                     case 'EndComposites':
                         $mode = 0;
                         break;
                 }
                 break;
             default:
                 //header/global information or writing direction
                 switch ($code) {
                     case 'BeginCharacterMetrics':
                     case 'StartCharMetrics':
                         $mode = 10;
                         break;
                     case 'BeginKernData':
                     case 'StartKernData':
                         $mode = 20;
                         break;
                     case 'BeginComposites':
                     case 'StartComposites':
                         $mode = 03;
                         break;
                     case 'StartDirection':
                         //does not have to exist in which case we are in direction 0
                         if ($e[1] == '1') {
                             $this->setDirection('V');
                         } else {
                             $this->setDirection('H');
                         }
                         break;
                     case 'EndDirection':
                         $this->setGlobal();
                         break;
                     case 'CharWidth':
                         $dir = $this->getDirection();
                         //this is not global information
                         if ($dir === -1) {
                             // however the keyword StartDirection is optional
                             $this->setDirection('H');
                         }
                         $this->setFixedWidth(true);
                         $this->setFixedWidthSize((double) $e[1]);
                         $this->setFixedHeightSize((double) $e[2]);
                         $this->setDirection($dir);
                         break;
                     case 'UnderlinePosition':
                     case 'UnderlineThickness':
                     case 'ItalicAngle':
                         $dir = $this->getDirection();
                         //this is not global information
                         if ($dir === -1) {
                             // however the keyword StartDirection is optional
                             $this->setDirection('H');
                         }
                         $this->setFontCharacteristic($code, $e[1]);
                         $this->setDirection($dir);
                         break;
                     case 'IsFixedPitch':
                         $isfixed = strpos(strtolower($e[1]), 'true') === 0;
                         $dir = $this->getDirection();
                         //this is not global information
                         if ($dir === -1) {
                             // however the keyword StartDirection is optional
                             $this->setDirection('H');
                         }
                         $this->setFixedWidth($isfixed);
                         $this->setDirection($dir);
                         break;
                     case 'isFixedV':
                     case 'isBaseFont':
                         $this->setGlobal();
                         $this->setFontCharacteristic($code, strpos(strtolower($e[1]), 'true'));
                         break;
                     case 'MappingScheme':
                     case 'EscCar':
                     case 'Characters':
                         $this->setGlobal();
                         $this->setFontCharacteristic($code, (int) $e[1]);
                         break;
                     case 'Notice':
                     case 'Comment':
                         $this->setGlobal();
                         $val = $this->getFontCharacteristic($code);
                         if ($val === null) {
                             $val = "";
                         }
                         $this->setFontCharacteristic($code, $val . substr($l, strlen($code) + 1));
                         break;
                     case 'CapHeight':
                     case 'XHeight':
                         $this->setGlobal();
                         $this->setFontCharacteristic($code, (double) $e[1]);
                         break;
                     case 'Ascender':
                         $this->setGlobal();
                         $this->setAscender((double) $e[1]);
                         break;
                     case 'Descender':
                         $this->setGlobal();
                         $this->setDescender((double) $e[1]);
                         break;
                     case 'VVector':
                         $this->setGlobal();
                         $this->setFontCharacteristic($code, array((double) $e[1], (double) $e[2]));
                     case 'FontBBox':
                         $this->setGlobal();
                         $this->setBoundingBox(array((double) $e[1], (double) $e[2], (double) $e[3], (double) $e[4]));
                         break;
                     default:
                         //the rest are strings for global font information
                         $this->setGlobal();
                         $this->setFontCharacteristic($code, $e[1]);
                         break;
                 }
                 break;
         }
     }
     //normalize a few values.
     $this->setGlobal();
     $asc = $this->getAscender();
     if ($asc == 0) {
         $d = mb_convert_encoding('d', $this->getEncoding()->getEncodingType(), 'ASCII');
         $ht = $this->getCharacterHeight($d);
         if ($ht != 0) {
             $this->setAscender($ht);
         } else {
             $this->setDirection('H');
             $ht = $this->getCharacterHeight($d);
             if ($ht != 0) {
                 $this->setAscender($ht);
             } else {
                 $this->setGlobal();
                 $bbox = $this->getBoundingBox();
                 $this->setAscender($bbox[3]);
             }
         }
     }
     $this->setGlobal();
     $dsc = $this->getAscender();
     if ($dsc == 0) {
         $p = mb_convert_encoding('p', $this->getEncoding()->getEncodingType(), 'ASCII');
         $bbox = $this->getCharacterInfo($p, 'BoundingBox');
         if (!$bbox == null) {
             $this->setDescender($bbox[1]);
         } else {
             $this->setDirection('H');
             $bbox = $this->getCharacterInfo($p, 'BoundingBox');
             if (!$bbox == null) {
                 $this->setDescender($bbox[1]);
             } else {
                 $this->setGlobal();
                 $bbox = $this->getBoundingBox();
                 $this->setDescender($bbox[1]);
             }
         }
     }
     $this->setDirection($prev_dir);
     mb_substitute_character($sub);
 }