Menu

#996 getCharBBox($char) returns incorrect results for TTF glyphs without outlines

v1.0_(example)
closed
nobody
None
1
2014-11-08
2014-11-07
Jim Hanlon
No

TCPDF version 6.0.97 getCharBBox($char) returns incorrect results for TTF glyphs without outlines.

The crux of the problem is that the font parsing code assumes that the 'loca' table netry for a glyph always points to an entry in the 'glyf' table. That's only true when the glyph has an outline (has splines or references). If the glyph doesn't have any outline then there will not be any entry in the 'glyf' table. When the 'n'th glyph has no outline then 'loca[n] = loca[n+1]' (i.e. glyph 'n' doesn't occupy any space in the glyf table. Most spacing characters, control codes and the like will be like this.

The current parsing of the 'loca' table will end up "assigning" glyf data for the next outline to preceding glyphs that have no outline. That, in turn, leads to getCharBBox($char) returnsing a bounding box for a glyph with no outlines -- which is clearly nonsense.

The attached patch proposes a fix for this. To preserve the semantics that getCharBBox($char) returns FALSE for character codes that aren't defined in the font, the patch returns array(0, 0, 0, 0) as the bounding box for glyphs without outlines. While not technically accurate, it at least has the property that the bounding box width and height are both zero.

diff -rupN -t '--tabsize=4' tcpdf.6_0_97/tcpdf_fonts.php tcpdf.6_0_97.fixed/tcpdf_fonts.php
--- tcpdf.6_0_97/tcpdf_fonts.php    2014-11-07 08:30:41.279906919 -0600
+++ tcpdf.6_0_97.fixed/tcpdf_fonts.php  2014-11-07 08:34:08.651895847 -0600
@@ -435,6 +435,10 @@ class TCPDF_FONTS {
                 $tot_num_glyphs = floor($table['loca']['length'] / 2); // numGlyphs + 1
                 for ($i = 0; $i < $tot_num_glyphs; ++$i) {
                     $indexToLoc[$i] = TCPDF_STATIC::_getUSHORT($font, $offset) * 2;
+                    if (isset($indexToLoc[$i-1]) && ($indexToLoc[$i] == $indexToLoc[$i-1])) {
+                        // The last glyph didn't have an outline
+                        unset($indexToLoc[$i-1]);
+                    }
                     $offset += 2;
                 }
             } else {
@@ -442,6 +446,10 @@ class TCPDF_FONTS {
                 $tot_num_glyphs = floor($table['loca']['length'] / 4); // numGlyphs + 1
                 for ($i = 0; $i < $tot_num_glyphs; ++$i) {
                     $indexToLoc[$i] = TCPDF_STATIC::_getULONG($font, $offset);
+                    if (isset($indexToLoc[$i-1]) && ($indexToLoc[$i] == $indexToLoc[$i-1])) {
+                        // The last glyph didn't have an outline
+                        unset($indexToLoc[$i-1]);
+                    }
                     $offset += 4;
                 }
             }
diff -rupN -t '--tabsize=4' tcpdf.6_0_97/tcpdf.php tcpdf.6_0_97.fixed/tcpdf.php
--- tcpdf.6_0_97/tcpdf.php  2014-11-07 08:35:12.167935453 -0600
+++ tcpdf.6_0_97.fixed/tcpdf.php    2014-11-07 08:42:54.867950751 -0600
@@ -4580,8 +4580,14 @@ class TCPDF {
      * @since 5.9.186 (2012-09-13)
      */
     public function getCharBBox($char) {
-        if (isset($this->CurrentFont['cbbox'][$char])) {
-            return array_map(array($this,'getAbsFontMeasure'), $this->CurrentFont['cbbox'][intval($char)]);
+        $c = intval($char);
+        if (isset($this->CurrentFont['cw'][$c])) {
+            // Glyph is defined ... use zero width & height for glyphs without outlines
+            $result = array(0,0,0,0);
+            if (isset($this->CurrentFont['cbbox'][$c])) {
+                $result = $this->CurrentFont['cbbox'][$c];
+            }
+            return array_map(array($this,'getAbsFontMeasure'), $result);
         }
         return false;
     }

Discussion

  • Nicola Asuni

    Nicola Asuni - 2014-11-08
    • status: open --> closed
     
  • Nicola Asuni

    Nicola Asuni - 2014-11-08

    OK. Fixed in TCPDF 6.0.098.
    Thank you for reporting this issue.

     

Log in to post a comment.