ascender; } function descender() { return $this->descender; } function error_message() { return $this->error_message; } function Font() {} function linethrough_position() { return $this->bbox[3]*0.25; } function name() { return $this->name; } function overline_position() { return $this->bbox[3]*0.8; } function points($fontsize, $dimension) { return $dimension * $fontsize / 1000; } function stringwidth($string) { $width = 0; $length = strlen($string); for ($i=0; $i<$length; $i++) { $width += $this->char_widths[$string{$i}]; }; return $width; } function underline_position() { return $this->underline_position; } function underline_thickness() { return $this->underline_thickness; } } class FontTrueType extends Font { function create($fontfile, $encoding) { $font = new FontTrueType(); $font->_read(TTF_FONTS_REPOSITORY.$fontfile, $encoding); return $font; } /** * TODO: cache results; replace makefont with this utility */ function _read($file, $encoding) { error_log(sprintf("Parsing font file file %s for encoding %s", $file, $encoding)); $font = new OpenTypeFile(); $font->open($file); $hhea = $font->getTable('hhea'); $head = $font->getTable('head'); $hmtx = $font->getTable('hmtx'); $post = $font->getTable('post'); $cmap = $font->getTable('cmap'); $subtable = $cmap->findSubtable(OT_CMAP_PLATFORM_WINDOWS, OT_CMAP_PLATFORM_WINDOWS_UNICODE); /** * Read character widths for selected encoding */ $widths = array(); $manager = ManagerEncoding::get(); $map = $manager->get_encoding_vector($encoding); foreach ($map as $code => $ucs2) { $glyphIndex = $subtable->lookup($ucs2); if (!is_null($glyphIndex)) { $widths[$code] = floor($hmtx->_hMetrics[$glyphIndex]['advanceWidth']*1000/$head->_unitsPerEm); } else { $widths[$code] = DEFAULT_CHAR_WIDTH; }; }; // Fill unknown characters with the default char width for ($i=0; $i<256; $i++) { if (!isset($widths[chr($i)])) { $widths[chr($i)] = DEFAULT_CHAR_WIDTH; }; }; $this->ascender = floor($hhea->_ascender*1000/$head->_unitsPerEm); $this->descender = floor($hhea->_descender*1000/$head->_unitsPerEm); $this->bbox = array($head->_xMin*1000/$head->_unitsPerEm, $head->_yMin*1000/$head->_unitsPerEm, $head->_xMax*1000/$head->_unitsPerEm, $head->_yMax*1000/$head->_unitsPerEm); $this->underline_position = floor($post->_underlinePosition*1000/$head->_unitsPerEm); $this->underline_thickness = floor($post->_underlineThickness*1000/$head->_unitsPerEm); $this->char_widths = $widths; $font->close(); } } // Note that ALL font dimensions are measured in 1/1000 of font size units; // class FontType1 extends Font { function &create($typeface, $encoding, $font_resolver, &$error_message) { $font = new FontType1(); $font->underline_position = 0; $font->underline_thickness = 0; $font->ascender; $font->descender; $font->char_widths = array(); $font->bbox = array(); global $g_last_assigned_font_id; $g_last_assigned_font_id++; $font->name = "font".$g_last_assigned_font_id; // Get and load the metrics file $afm = $font_resolver->get_afm_mapping($typeface); if (!$font->_parse_afm($afm, $typeface, $encoding)) { $error_message = $font->error_message(); $dummy = null; return $dummy; }; return $font; } // Parse the AFM metric file; keep only sized of glyphs present in the chosen encoding function _parse_afm($afm, $typeface, $encoding) { global $g_manager_encodings; $encoding_data = $g_manager_encodings->get_glyph_to_code_mapping($encoding); $filename = TYPE1_FONTS_REPOSITORY.$afm.".afm"; $file = @fopen($filename, 'r'); if (!$file) { $_filename = $filename; $_typeface = $typeface; ob_start(); include(HTML2PS_DIR.'templates/error._missing_afm.tpl'); $this->error_message = ob_get_contents(); ob_end_clean(); error_log(sprintf("Missing font metrics file: %s",$filename)); return false; }; while ($line = fgets($file)) { if (preg_match("/C\s-?\d+\s;\sWX\s(\d+)\s;\sN\s(\S+)\s;/",$line,$matches)) { $glyph_width = $matches[1]; $glyph_name = $matches[2]; // This line is a character width definition if (isset($encoding_data[$glyph_name])) { foreach ($encoding_data[$glyph_name] as $c) { $this->char_widths[$c] = $glyph_width; }; }; } elseif (preg_match("/UnderlinePosition ([\d-]+)/",$line,$matches)) { // This line is an underline position line $this->underline_position = $matches[1]; } elseif (preg_match("/UnderlineThickness ([\d-]+)/",$line,$matches)) { // This line is an underline thickness line $this->underline_thickness = $matches[1]; } elseif (preg_match("/Ascender ([\d-]+)/",$line,$matches)) { // This line is an ascender line $this->ascender = $matches[1]; } elseif (preg_match("/Descender ([\d-]+)/",$line,$matches)) { // This line is an descender line $this->descender = $matches[1]; } elseif (preg_match("/FontBBox ([\d-]+) ([\d-]+) ([\d-]+) ([\d-]+)/",$line,$matches)) { // This line is an font BBox line $this->bbox = array($matches[1], $matches[2], $matches[3], $matches[4]); }; }; fclose($file); // Fill unknown characters with the default char width for ($i=0; $i<256; $i++) { if (!isset($this->char_widths[chr($i)])) { $this->char_widths[chr($i)] = DEFAULT_CHAR_WIDTH; }; }; return true; } } ?>