Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
 
3
$GLOBALS['g_last_assigned_font_id'] = 0;
4
 
5
class Font {
6
  var $underline_position;
7
  var $underline_thickness;
8
  var $ascender;
9
  var $descender;
10
  var $char_widths;
11
  var $bbox;
12
 
13
  function ascender() {
14
    return $this->ascender;
15
  }
16
 
17
  function descender() {
18
    return $this->descender;
19
  }
20
 
21
  function error_message() {
22
    return $this->error_message;
23
  }
24
 
25
  function Font() {}
26
 
27
  function linethrough_position() {
28
    return $this->bbox[3]*0.25;
29
  }
30
 
31
  function name() {
32
    return $this->name;
33
  }
34
 
35
  function overline_position() {
36
    return $this->bbox[3]*0.8;
37
  }
38
 
39
  function points($fontsize, $dimension) {
40
    return $dimension * $fontsize / 1000;
41
  }
42
 
43
  function stringwidth($string) {
44
    $width = 0;
45
 
46
    $length = strlen($string);
47
    for ($i=0; $i<$length; $i++) {
48
      $width += $this->char_widths[$string{$i}];
49
    };
50
 
51
    return $width;
52
  }
53
 
54
  function underline_position() {
55
    return $this->underline_position;
56
  }
57
 
58
  function underline_thickness() {
59
    return $this->underline_thickness;
60
  }
61
}
62
 
63
class FontTrueType extends Font {
64
  function create($fontfile, $encoding) {
65
    $font = new FontTrueType();
66
    $font->_read(TTF_FONTS_REPOSITORY.$fontfile, $encoding);
67
    return $font;
68
  }
69
 
70
  /**
71
   * TODO: cache results; replace makefont with this utility
72
   */
73
  function _read($file, $encoding) {
74
    error_log(sprintf("Parsing font file file %s for encoding %s", $file, $encoding));
75
 
76
    $font = new OpenTypeFile();
77
    $font->open($file);
78
    $hhea = $font->getTable('hhea');
79
    $head = $font->getTable('head');
80
    $hmtx = $font->getTable('hmtx');
81
    $post = $font->getTable('post');
82
    $cmap = $font->getTable('cmap');
83
    $subtable = $cmap->findSubtable(OT_CMAP_PLATFORM_WINDOWS,
84
                                    OT_CMAP_PLATFORM_WINDOWS_UNICODE);
85
 
86
    /**
87
     * Read character widths for selected encoding
88
     */
89
    $widths = array();
90
    $manager = ManagerEncoding::get();
91
    $map = $manager->get_encoding_vector($encoding);
92
    foreach ($map as $code => $ucs2) {
93
      $glyphIndex = $subtable->lookup($ucs2);
94
      if (!is_null($glyphIndex)) {
95
        $widths[$code] = floor($hmtx->_hMetrics[$glyphIndex]['advanceWidth']*1000/$head->_unitsPerEm);
96
      } else {
97
        $widths[$code] = DEFAULT_CHAR_WIDTH;
98
      };
99
    };
100
 
101
    // Fill unknown characters with the default char width
102
    for ($i=0; $i<256; $i++) {
103
      if (!isset($widths[chr($i)])) {
104
        $widths[chr($i)] = DEFAULT_CHAR_WIDTH;
105
      };
106
    };
107
 
108
    $this->ascender            = floor($hhea->_ascender*1000/$head->_unitsPerEm);
109
    $this->descender           = floor($hhea->_descender*1000/$head->_unitsPerEm);
110
    $this->bbox                = array($head->_xMin*1000/$head->_unitsPerEm,
111
                                       $head->_yMin*1000/$head->_unitsPerEm,
112
                                       $head->_xMax*1000/$head->_unitsPerEm,
113
                                       $head->_yMax*1000/$head->_unitsPerEm);
114
    $this->underline_position  = floor($post->_underlinePosition*1000/$head->_unitsPerEm);
115
    $this->underline_thickness = floor($post->_underlineThickness*1000/$head->_unitsPerEm);
116
    $this->char_widths         = $widths;
117
 
118
    $font->close();
119
  }
120
}
121
 
122
// Note that ALL font dimensions are measured in 1/1000 of font size units;
123
//
124
class FontType1 extends Font {
125
  function &create($typeface, $encoding, $font_resolver, &$error_message) {
126
    $font = new FontType1();
127
 
128
    $font->underline_position = 0;
129
    $font->underline_thickness = 0;
130
    $font->ascender;
131
    $font->descender;
132
    $font->char_widths = array();
133
    $font->bbox = array();
134
 
135
    global $g_last_assigned_font_id;
136
    $g_last_assigned_font_id++;
137
 
138
    $font->name = "font".$g_last_assigned_font_id;
139
 
140
    // Get and load the metrics file
141
    $afm = $font_resolver->get_afm_mapping($typeface);
142
 
143
    if (!$font->_parse_afm($afm, $typeface, $encoding)) {
144
      $error_message = $font->error_message();
145
      $dummy = null;
146
      return $dummy;
147
    };
148
 
149
    return $font;
150
  }
151
 
152
  // Parse the AFM metric file; keep only sized of glyphs present in the chosen encoding
153
  function _parse_afm($afm, $typeface, $encoding) {
154
    global $g_manager_encodings;
155
    $encoding_data = $g_manager_encodings->get_glyph_to_code_mapping($encoding);
156
 
157
    $filename = TYPE1_FONTS_REPOSITORY.$afm.".afm";
158
 
159
    $file = @fopen($filename, 'r');
160
    if (!$file) {
161
      $_filename = $filename;
162
      $_typeface = $typeface;
163
 
164
      ob_start();
165
      include(HTML2PS_DIR.'templates/error._missing_afm.tpl');
166
      $this->error_message = ob_get_contents();
167
      ob_end_clean();
168
 
169
      error_log(sprintf("Missing font metrics file: %s",$filename));
170
      return false;
171
    };
172
 
173
    while ($line = fgets($file)) {
174
      if (preg_match("/C\s-?\d+\s;\sWX\s(\d+)\s;\sN\s(\S+)\s;/",$line,$matches)) {
175
        $glyph_width = $matches[1];
176
        $glyph_name  = $matches[2];
177
 
178
        // This line is a character width definition
179
        if (isset($encoding_data[$glyph_name])) {
180
          foreach ($encoding_data[$glyph_name] as $c) {
181
            $this->char_widths[$c] = $glyph_width;
182
          };
183
        };
184
 
185
      } elseif (preg_match("/UnderlinePosition ([\d-]+)/",$line,$matches)) {
186
        // This line is an underline position line
187
        $this->underline_position = $matches[1];
188
 
189
      } elseif (preg_match("/UnderlineThickness ([\d-]+)/",$line,$matches)) {
190
        // This line is an underline thickness line
191
        $this->underline_thickness = $matches[1];
192
 
193
      } elseif (preg_match("/Ascender ([\d-]+)/",$line,$matches)) {
194
        // This line is an ascender line
195
        $this->ascender = $matches[1];
196
 
197
      } elseif (preg_match("/Descender ([\d-]+)/",$line,$matches)) {
198
        // This line is an descender line
199
        $this->descender = $matches[1];
200
 
201
      } elseif (preg_match("/FontBBox ([\d-]+) ([\d-]+) ([\d-]+) ([\d-]+)/",$line,$matches)) {
202
        // This line is an font BBox line
203
        $this->bbox = array($matches[1], $matches[2], $matches[3], $matches[4]);
204
      };
205
    };
206
 
207
    fclose($file);
208
 
209
    // Fill unknown characters with the default char width
210
    for ($i=0; $i<256; $i++) {
211
      if (!isset($this->char_widths[chr($i)])) {
212
        $this->char_widths[chr($i)] = DEFAULT_CHAR_WIDTH;
213
      };
214
    };
215
 
216
    return true;
217
  }
218
}
219
?>