Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/*******************************************************************************
3
 * Utility to generate font definition files                                    *
4
 * Version: 1.13                                                                *
5
 * Date:    2004-12-31                                                          *
6
 *******************************************************************************/
7
 
8
function ReadMap($enc)
9
{
10
  //Read a map file
11
  $file=dirname(__FILE__).'/'.strtolower($enc).'.map';
12
  $a=file($file);
13
  if(empty($a))
14
    die('<B>Error:</B> encoding not found: '.$enc);
15
  $cc2gn=array();
16
  foreach($a as $l)
17
    {
18
      if($l{0}=='!')
19
        {
20
          $e=preg_split('/[ \\t]+/',rtrim($l));
21
          $cc=hexdec(substr($e[0],1));
22
          $gn=$e[2];
23
          $cc2gn[$cc]=$gn;
24
        }
25
    }
26
  for($i=0;$i<=255;$i++)
27
    {
28
      if(!isset($cc2gn[$i]))
29
        $cc2gn[$i]='.notdef';
30
    }
31
  return $cc2gn;
32
}
33
 
34
function ReadAFM($file,&$map)
35
{
36
  //Read a font metric file
37
  $a=file($file);
38
  if(empty($a))
39
    die('File not found');
40
  $widths=array();
41
  $fm=array();
42
  $fix=array('Edot'=>'Edotaccent','edot'=>'edotaccent','Idot'=>'Idotaccent','Zdot'=>'Zdotaccent','zdot'=>'zdotaccent',
43
             'Odblacute'=>'Ohungarumlaut','odblacute'=>'ohungarumlaut','Udblacute'=>'Uhungarumlaut','udblacute'=>'uhungarumlaut',
44
             'Gcedilla'=>'Gcommaaccent','gcedilla'=>'gcommaaccent','Kcedilla'=>'Kcommaaccent','kcedilla'=>'kcommaaccent',
45
             'Lcedilla'=>'Lcommaaccent','lcedilla'=>'lcommaaccent','Ncedilla'=>'Ncommaaccent','ncedilla'=>'ncommaaccent',
46
             'Rcedilla'=>'Rcommaaccent','rcedilla'=>'rcommaaccent','Scedilla'=>'Scommaaccent','scedilla'=>'scommaaccent',
47
             'Tcedilla'=>'Tcommaaccent','tcedilla'=>'tcommaaccent','Dslash'=>'Dcroat','dslash'=>'dcroat','Dmacron'=>'Dcroat','dmacron'=>'dcroat',
48
             'combininggraveaccent'=>'gravecomb','combininghookabove'=>'hookabovecomb','combiningtildeaccent'=>'tildecomb',
49
             'combiningacuteaccent'=>'acutecomb','combiningdotbelow'=>'dotbelowcomb','dongsign'=>'dong');
50
  foreach($a as $l)
51
    {
52
      $e=explode(' ',rtrim($l));
53
      if(count($e)<2)
54
        continue;
55
      $code=$e[0];
56
      $param=$e[1];
57
      if($code=='C')
58
        {
59
          //Character metrics
60
          $cc=(int)$e[1];
61
          $w=$e[4];
62
          $gn=$e[7];
63
          if(substr($gn,-4)=='20AC')
64
            $gn='Euro';
65
          if(isset($fix[$gn]))
66
            {
67
              //Fix incorrect glyph name
68
              foreach($map as $c=>$n)
69
                {
70
                  if($n==$fix[$gn])
71
                    $map[$c]=$gn;
72
                }
73
            }
74
          if(empty($map))
75
            {
76
              //Symbolic font: use built-in encoding
77
              $widths[$cc]=$w;
78
            }
79
          else
80
            {
81
              $widths[$gn]=$w;
82
              if($gn=='X')
83
                $fm['CapXHeight']=$e[13];
84
            }
85
          if($gn=='.notdef')
86
            $fm['MissingWidth']=$w;
87
        }
88
      elseif($code=='FontName')
89
        $fm['FontName']=$param;
90
      elseif($code=='Weight')
91
        $fm['Weight']=$param;
92
      elseif($code=='ItalicAngle')
93
        $fm['ItalicAngle']=(double)$param;
94
      elseif($code=='Ascender')
95
        $fm['Ascender']=(int)$param;
96
      elseif($code=='Descender')
97
        $fm['Descender']=(int)$param;
98
      elseif($code=='UnderlineThickness')
99
        $fm['UnderlineThickness']=(int)$param;
100
      elseif($code=='UnderlinePosition')
101
        $fm['UnderlinePosition']=(int)$param;
102
      elseif($code=='IsFixedPitch')
103
        $fm['IsFixedPitch']=($param=='true');
104
      elseif($code=='FontBBox')
105
        $fm['FontBBox']=array($e[1],$e[2],$e[3],$e[4]);
106
      elseif($code=='CapHeight')
107
        $fm['CapHeight']=(int)$param;
108
      elseif($code=='StdVW')
109
        $fm['StdVW']=(int)$param;
110
    }
111
  if(!isset($fm['FontName']))
112
    die('FontName not found');
113
  if(!empty($map))
114
    {
115
      if(!isset($widths['.notdef']))
116
        $widths['.notdef']=600;
117
      if(!isset($widths['Delta']) and isset($widths['increment']))
118
        $widths['Delta']=$widths['increment'];
119
      //Order widths according to map
120
      for($i=0;$i<=255;$i++)
121
        {
122
          if(!isset($widths[$map[$i]]))
123
            {
124
              echo '<B>Warning:</B> character '.$map[$i].' is missing<BR>';
125
              $widths[$i]=$widths['.notdef'];
126
            }
127
          else
128
            $widths[$i]=$widths[$map[$i]];
129
        }
130
    }
131
  $fm['Widths']=$widths;
132
  return $fm;
133
}
134
 
135
function MakeFontDescriptor($fm,$symbolic)
136
{
137
  //Ascent
138
  $asc=(isset($fm['Ascender']) ? $fm['Ascender'] : 1000);
139
  $fd="array('Ascent'=>".$asc;
140
  //Descent
141
  $desc=(isset($fm['Descender']) ? $fm['Descender'] : -200);
142
  $fd.=",'Descent'=>".$desc;
143
  //CapHeight
144
  if(isset($fm['CapHeight']))
145
    $ch=$fm['CapHeight'];
146
  elseif(isset($fm['CapXHeight']))
147
    $ch=$fm['CapXHeight'];
148
  else
149
    $ch=$asc;
150
  $fd.=",'CapHeight'=>".$ch;
151
  //Flags
152
  $flags=0;
153
  if(isset($fm['IsFixedPitch']) and $fm['IsFixedPitch'])
154
    $flags+=1<<0;
155
  if($symbolic)
156
    $flags+=1<<2;
157
  if(!$symbolic)
158
    $flags+=1<<5;
159
  if(isset($fm['ItalicAngle']) and $fm['ItalicAngle']!=0)
160
    $flags+=1<<6;
161
  $fd.=",'Flags'=>".$flags;
162
  //FontBBox
163
  if(isset($fm['FontBBox']))
164
    $fbb=$fm['FontBBox'];
165
  else
166
    $fbb=array(0,$des-100,1000,$asc+100);
167
  $fd.=",'FontBBox'=>'[".$fbb[0].' '.$fbb[1].' '.$fbb[2].' '.$fbb[3]."]'";
168
  //ItalicAngle
169
  $ia=(isset($fm['ItalicAngle']) ? $fm['ItalicAngle'] : 0);
170
  $fd.=",'ItalicAngle'=>".$ia;
171
  //StemV
172
  if(isset($fm['StdVW']))
173
    $stemv=$fm['StdVW'];
174
  elseif(isset($fm['Weight']) and eregi('(bold|black)',$fm['Weight']))
175
    $stemv=120;
176
  else
177
    $stemv=70;
178
  $fd.=",'StemV'=>".$stemv;
179
  //MissingWidth
180
  if(isset($fm['MissingWidth']))
181
    $fd.=",'MissingWidth'=>".$fm['MissingWidth'];
182
  $fd.=')';
183
  return $fd;
184
}
185
 
186
function MakeWidthArray($fm)
187
{
188
  //Make character width array
189
  $s="array(\n\t";
190
  $cw=$fm['Widths'];
191
  for($i=0;$i<=255;$i++)
192
    {
193
      if(chr($i)=="'")
194
        $s.="'\\''";
195
      elseif(chr($i)=="\\")
196
        $s.="'\\\\'";
197
      elseif($i>=32 and $i<=126)
198
        $s.="'".chr($i)."'";
199
      else
200
        $s.="chr($i)";
201
      $s.='=>'.$fm['Widths'][$i];
202
      if($i<255)
203
        $s.=',';
204
      if(($i+1)%22==0)
205
        $s.="\n\t";
206
    }
207
  $s.=')';
208
  return $s;
209
}
210
 
211
function MakeFontEncoding($map)
212
{
213
  //Build differences from reference encoding
214
  $ref=ReadMap('cp1252');
215
  $s='';
216
  $last=0;
217
  for($i=32;$i<=255;$i++)
218
    {
219
      if($map[$i]!=$ref[$i])
220
        {
221
          if($i!=$last+1)
222
            $s.=$i.' ';
223
          $last=$i;
224
          $s.='/'.$map[$i].' ';
225
        }
226
    }
227
  return rtrim($s);
228
}
229
 
230
function SaveToFile($file,$s,$mode='t')
231
{
232
  $f=fopen($file,'w'.$mode);
233
  if(!$f)
234
    die('Can\'t write to file '.$file);
235
  fwrite($f,$s,strlen($s));
236
  fclose($f);
237
}
238
 
239
function ReadShort($f)
240
{
241
  $a=unpack('n1n',fread($f,2));
242
  return $a['n'];
243
}
244
 
245
function ReadLong($f)
246
{
247
  $a=unpack('N1N',fread($f,4));
248
  return $a['N'];
249
}
250
 
251
function CheckTTF($file)
252
{
253
  //Check if font license allows embedding
254
  $f=fopen($file,'rb');
255
  if(!$f)
256
    die('<B>Error:</B> Can\'t open '.$file);
257
  //Extract number of tables
258
  fseek($f,4,SEEK_CUR);
259
  $nb=ReadShort($f);
260
  fseek($f,6,SEEK_CUR);
261
  //Seek OS/2 table
262
  $found=false;
263
  for($i=0;$i<$nb;$i++)
264
    {
265
      if(fread($f,4)=='OS/2')
266
        {
267
          $found=true;
268
          break;
269
        }
270
      fseek($f,12,SEEK_CUR);
271
    }
272
  if(!$found)
273
    {
274
      fclose($f);
275
      return;
276
    }
277
  fseek($f,4,SEEK_CUR);
278
  $offset=ReadLong($f);
279
  fseek($f,$offset,SEEK_SET);
280
  //Extract fsType flags
281
  fseek($f,8,SEEK_CUR);
282
  $fsType=ReadShort($f);
283
  $rl=($fsType & 0x02)!=0;
284
  $pp=($fsType & 0x04)!=0;
285
  $e=($fsType & 0x08)!=0;
286
  fclose($f);
287
  if($rl and !$pp and !$e)
288
    echo '<B>Warning:</B> font license does not allow embedding';
289
}
290
 
291
/*******************************************************************************
292
 * $fontfile : chemin du fichier TTF (ou chaîne vide si pas d'incorporation)    *
293
 * $afmfile :  chemin du fichier AFM                                            *
294
 * $enc :      encodage (ou chaîne vide si la police est symbolique)            *
295
 * $patch :    patch optionnel pour l'encodage                                  *
296
 * $type :     type de la police si $fontfile est vide                          *
297
 *******************************************************************************/
298
function MakeFont($fontfile,$afmfile,$destdir,$destfile,$enc='cp1252',$patch=array(),$type='TrueType')
299
{
300
  //Generate a font definition file
301
  set_magic_quotes_runtime(0);
302
  ini_set('auto_detect_line_endings','1');
303
  if($enc)
304
    {
305
      $map=ReadMap($enc);
306
      foreach($patch as $cc=>$gn)
307
        $map[$cc]=$gn;
308
    }
309
  else
310
    $map=array();
311
  if(!file_exists($afmfile))
312
    die('<B>Error:</B> AFM file not found: '.$afmfile);
313
  $fm=ReadAFM($afmfile,$map);
314
  if($enc)
315
    $diff=MakeFontEncoding($map);
316
  else
317
    $diff='';
318
  $fd=MakeFontDescriptor($fm,empty($map));
319
  //Find font type
320
  if($fontfile)
321
    {
322
      $ext=strtolower(substr($fontfile,-3));
323
      if($ext=='ttf')
324
        $type='TrueType';
325
      elseif($ext=='pfb')
326
        $type='Type1';
327
      else
328
        die('<B>Error:</B> unrecognized font file extension: '.$ext);
329
    }
330
  else
331
    {
332
      if($type!='TrueType' and $type!='Type1')
333
        die('<B>Error:</B> incorrect font type: '.$type);
334
    }
335
  //Start generation
336
  $s='<?php'."\n";
337
  $s.='$type=\''.$type."';\n";
338
  $s.='$name=\''.$fm['FontName']."';\n";
339
  $s.='$desc='.$fd.";\n";
340
  if(!isset($fm['UnderlinePosition']))
341
    $fm['UnderlinePosition']=-100;
342
  if(!isset($fm['UnderlineThickness']))
343
    $fm['UnderlineThickness']=50;
344
  $s.='$up='.$fm['UnderlinePosition'].";\n";
345
  $s.='$ut='.$fm['UnderlineThickness'].";\n";
346
  $w=MakeWidthArray($fm);
347
  $s.='$cw='.$w.";\n";
348
  $s.='$enc=\''.$enc."';\n";
349
  $s.='$diff=\''.$diff."';\n";
350
  $basename=substr(basename($afmfile),0,-4);
351
  if($fontfile)
352
    {
353
      //Embedded font
354
      if(!file_exists($fontfile))
355
        die('<B>Error:</B> font file not found: '.$fontfile);
356
      if($type=='TrueType')
357
        CheckTTF($fontfile);
358
      $f=fopen($fontfile,'rb');
359
      if(!$f)
360
        die('<B>Error:</B> Can\'t open '.$fontfile);
361
      $file=fread($f,filesize($fontfile));
362
      fclose($f);
363
      if($type=='Type1')
364
        {
365
          //Find first two sections and discard third one
366
          $header=(ord($file{0})==128);
367
          if($header)
368
            {
369
              //Strip first binary header
370
              $file=substr($file,6);
371
            }
372
          $pos=strpos($file,'eexec');
373
          if(!$pos)
374
            die('<B>Error:</B> font file does not seem to be valid Type1');
375
          $size1=$pos+6;
376
          if($header and ord($file{$size1})==128)
377
            {
378
              //Strip second binary header
379
              $file=substr($file,0,$size1).substr($file,$size1+6);
380
            }
381
          $pos=strpos($file,'00000000');
382
          if(!$pos)
383
            die('<B>Error:</B> font file does not seem to be valid Type1');
384
          $size2=$pos-$size1;
385
          $file=substr($file,0,$size1+$size2);
386
        }
387
      if(function_exists('gzcompress'))
388
        {
389
          $cmp=$basename.'.z';
390
          SaveToFile($destdir.$cmp,gzcompress($file),'b');
391
          $s.='$file=\''.$cmp."';\n";
392
          echo 'Font file compressed ('.$cmp.')<BR>';
393
        }
394
      else
395
        {
396
          $s.='$file=\''.basename($fontfile)."';\n";
397
          echo '<B>Notice:</B> font file could not be compressed (zlib extension not available)<BR>';
398
        }
399
      if($type=='Type1')
400
        {
401
          $s.='$size1='.$size1.";\n";
402
          $s.='$size2='.$size2.";\n";
403
        }
404
      else
405
        $s.='$originalsize='.filesize($fontfile).";\n";
406
    }
407
  else
408
    {
409
      //Not embedded font
410
      $s.='$file='."'';\n";
411
    }
412
  $s.="?>\n";
413
  SaveToFile($destdir.$destfile,$s);
414
  echo 'Font definition file generated ('.$basename.'.php'.')<BR>';
415
}
416
?>