Project

General

Profile

Statistics
| Branch: | Revision:

colonymech / docs / www / colonyscout / internal / includes / font / makefont / makefont.php @ f59acf11

History | View | Annotate | Download (10.4 KB)

1
<?php
2
/*******************************************************************************
3
* Utility to generate font definition files                                    *
4
*                                                                              *
5
* Version: 1.14                                                                *
6
* Date:    2008-08-03                                                          *
7
* Author:  Olivier PLATHEY                                                     *
8
*******************************************************************************/
9

    
10
function ReadMap($enc)
11
{
12
        //Read a map file
13
        $file=dirname(__FILE__).'/'.strtolower($enc).'.map';
14
        $a=file($file);
15
        if(empty($a))
16
                die('<b>Error:</b> encoding not found: '.$enc);
17
        $cc2gn=array();
18
        foreach($a as $l)
19
        {
20
                if($l[0]=='!')
21
                {
22
                        $e=preg_split('/[ \\t]+/',rtrim($l));
23
                        $cc=hexdec(substr($e[0],1));
24
                        $gn=$e[2];
25
                        $cc2gn[$cc]=$gn;
26
                }
27
        }
28
        for($i=0;$i<=255;$i++)
29
        {
30
                if(!isset($cc2gn[$i]))
31
                        $cc2gn[$i]='.notdef';
32
        }
33
        return $cc2gn;
34
}
35

    
36
function ReadAFM($file, &$map)
37
{
38
        //Read a font metric file
39
        $a=file($file);
40
        if(empty($a))
41
                die('File not found');
42
        $widths=array();
43
        $fm=array();
44
        $fix=array('Edot'=>'Edotaccent','edot'=>'edotaccent','Idot'=>'Idotaccent','Zdot'=>'Zdotaccent','zdot'=>'zdotaccent',
45
                'Odblacute'=>'Ohungarumlaut','odblacute'=>'ohungarumlaut','Udblacute'=>'Uhungarumlaut','udblacute'=>'uhungarumlaut',
46
                'Gcedilla'=>'Gcommaaccent','gcedilla'=>'gcommaaccent','Kcedilla'=>'Kcommaaccent','kcedilla'=>'kcommaaccent',
47
                'Lcedilla'=>'Lcommaaccent','lcedilla'=>'lcommaaccent','Ncedilla'=>'Ncommaaccent','ncedilla'=>'ncommaaccent',
48
                'Rcedilla'=>'Rcommaaccent','rcedilla'=>'rcommaaccent','Scedilla'=>'Scommaaccent','scedilla'=>'scommaaccent',
49
                'Tcedilla'=>'Tcommaaccent','tcedilla'=>'tcommaaccent','Dslash'=>'Dcroat','dslash'=>'dcroat','Dmacron'=>'Dcroat','dmacron'=>'dcroat',
50
                'combininggraveaccent'=>'gravecomb','combininghookabove'=>'hookabovecomb','combiningtildeaccent'=>'tildecomb',
51
                'combiningacuteaccent'=>'acutecomb','combiningdotbelow'=>'dotbelowcomb','dongsign'=>'dong');
52
        foreach($a as $l)
53
        {
54
                $e=explode(' ',rtrim($l));
55
                if(count($e)<2)
56
                        continue;
57
                $code=$e[0];
58
                $param=$e[1];
59
                if($code=='C')
60
                {
61
                        //Character metrics
62
                        $cc=(int)$e[1];
63
                        $w=$e[4];
64
                        $gn=$e[7];
65
                        if(substr($gn,-4)=='20AC')
66
                                $gn='Euro';
67
                        if(isset($fix[$gn]))
68
                        {
69
                                //Fix incorrect glyph name
70
                                foreach($map as $c=>$n)
71
                                {
72
                                        if($n==$fix[$gn])
73
                                                $map[$c]=$gn;
74
                                }
75
                        }
76
                        if(empty($map))
77
                        {
78
                                //Symbolic font: use built-in encoding
79
                                $widths[$cc]=$w;
80
                        }
81
                        else
82
                        {
83
                                $widths[$gn]=$w;
84
                                if($gn=='X')
85
                                        $fm['CapXHeight']=$e[13];
86
                        }
87
                        if($gn=='.notdef')
88
                                $fm['MissingWidth']=$w;
89
                }
90
                elseif($code=='FontName')
91
                        $fm['FontName']=$param;
92
                elseif($code=='Weight')
93
                        $fm['Weight']=$param;
94
                elseif($code=='ItalicAngle')
95
                        $fm['ItalicAngle']=(double)$param;
96
                elseif($code=='Ascender')
97
                        $fm['Ascender']=(int)$param;
98
                elseif($code=='Descender')
99
                        $fm['Descender']=(int)$param;
100
                elseif($code=='UnderlineThickness')
101
                        $fm['UnderlineThickness']=(int)$param;
102
                elseif($code=='UnderlinePosition')
103
                        $fm['UnderlinePosition']=(int)$param;
104
                elseif($code=='IsFixedPitch')
105
                        $fm['IsFixedPitch']=($param=='true');
106
                elseif($code=='FontBBox')
107
                        $fm['FontBBox']=array($e[1],$e[2],$e[3],$e[4]);
108
                elseif($code=='CapHeight')
109
                        $fm['CapHeight']=(int)$param;
110
                elseif($code=='StdVW')
111
                        $fm['StdVW']=(int)$param;
112
        }
113
        if(!isset($fm['FontName']))
114
                die('FontName not found');
115
        if(!empty($map))
116
        {
117
                if(!isset($widths['.notdef']))
118
                        $widths['.notdef']=600;
119
                if(!isset($widths['Delta']) && isset($widths['increment']))
120
                        $widths['Delta']=$widths['increment'];
121
                //Order widths according to map
122
                for($i=0;$i<=255;$i++)
123
                {
124
                        if(!isset($widths[$map[$i]]))
125
                        {
126
                                echo '<b>Warning:</b> character '.$map[$i].' is missing<br>';
127
                                $widths[$i]=$widths['.notdef'];
128
                        }
129
                        else
130
                                $widths[$i]=$widths[$map[$i]];
131
                }
132
        }
133
        $fm['Widths']=$widths;
134
        return $fm;
135
}
136

    
137
function MakeFontDescriptor($fm, $symbolic)
138
{
139
        //Ascent
140
        $asc=(isset($fm['Ascender']) ? $fm['Ascender'] : 1000);
141
        $fd="array('Ascent'=>".$asc;
142
        //Descent
143
        $desc=(isset($fm['Descender']) ? $fm['Descender'] : -200);
144
        $fd.=",'Descent'=>".$desc;
145
        //CapHeight
146
        if(isset($fm['CapHeight']))
147
                $ch=$fm['CapHeight'];
148
        elseif(isset($fm['CapXHeight']))
149
                $ch=$fm['CapXHeight'];
150
        else
151
                $ch=$asc;
152
        $fd.=",'CapHeight'=>".$ch;
153
        //Flags
154
        $flags=0;
155
        if(isset($fm['IsFixedPitch']) && $fm['IsFixedPitch'])
156
                $flags+=1<<0;
157
        if($symbolic)
158
                $flags+=1<<2;
159
        if(!$symbolic)
160
                $flags+=1<<5;
161
        if(isset($fm['ItalicAngle']) && $fm['ItalicAngle']!=0)
162
                $flags+=1<<6;
163
        $fd.=",'Flags'=>".$flags;
164
        //FontBBox
165
        if(isset($fm['FontBBox']))
166
                $fbb=$fm['FontBBox'];
167
        else
168
                $fbb=array(0,$desc-100,1000,$asc+100);
169
        $fd.=",'FontBBox'=>'[".$fbb[0].' '.$fbb[1].' '.$fbb[2].' '.$fbb[3]."]'";
170
        //ItalicAngle
171
        $ia=(isset($fm['ItalicAngle']) ? $fm['ItalicAngle'] : 0);
172
        $fd.=",'ItalicAngle'=>".$ia;
173
        //StemV
174
        if(isset($fm['StdVW']))
175
                $stemv=$fm['StdVW'];
176
        elseif(isset($fm['Weight']) && preg_match('/bold|black/i',$fm['Weight']))
177
                $stemv=120;
178
        else
179
                $stemv=70;
180
        $fd.=",'StemV'=>".$stemv;
181
        //MissingWidth
182
        if(isset($fm['MissingWidth']))
183
                $fd.=",'MissingWidth'=>".$fm['MissingWidth'];
184
        $fd.=')';
185
        return $fd;
186
}
187

    
188
function MakeWidthArray($fm)
189
{
190
        //Make character width array
191
        $s="array(\n\t";
192
        $cw=$fm['Widths'];
193
        for($i=0;$i<=255;$i++)
194
        {
195
                if(chr($i)=="'")
196
                        $s.="'\\''";
197
                elseif(chr($i)=="\\")
198
                        $s.="'\\\\'";
199
                elseif($i>=32 && $i<=126)
200
                        $s.="'".chr($i)."'";
201
                else
202
                        $s.="chr($i)";
203
                $s.='=>'.$fm['Widths'][$i];
204
                if($i<255)
205
                        $s.=',';
206
                if(($i+1)%22==0)
207
                        $s.="\n\t";
208
        }
209
        $s.=')';
210
        return $s;
211
}
212

    
213
function MakeFontEncoding($map)
214
{
215
        //Build differences from reference encoding
216
        $ref=ReadMap('cp1252');
217
        $s='';
218
        $last=0;
219
        for($i=32;$i<=255;$i++)
220
        {
221
                if($map[$i]!=$ref[$i])
222
                {
223
                        if($i!=$last+1)
224
                                $s.=$i.' ';
225
                        $last=$i;
226
                        $s.='/'.$map[$i].' ';
227
                }
228
        }
229
        return rtrim($s);
230
}
231

    
232
function SaveToFile($file, $s, $mode)
233
{
234
        $f=fopen($file,'w'.$mode);
235
        if(!$f)
236
                die('Can\'t write to file '.$file);
237
        fwrite($f,$s,strlen($s));
238
        fclose($f);
239
}
240

    
241
function ReadShort($f)
242
{
243
        $a=unpack('n1n',fread($f,2));
244
        return $a['n'];
245
}
246

    
247
function ReadLong($f)
248
{
249
        $a=unpack('N1N',fread($f,4));
250
        return $a['N'];
251
}
252

    
253
function CheckTTF($file)
254
{
255
        //Check if font license allows embedding
256
        $f=fopen($file,'rb');
257
        if(!$f)
258
                die('<b>Error:</b> Can\'t open '.$file);
259
        //Extract number of tables
260
        fseek($f,4,SEEK_CUR);
261
        $nb=ReadShort($f);
262
        fseek($f,6,SEEK_CUR);
263
        //Seek OS/2 table
264
        $found=false;
265
        for($i=0;$i<$nb;$i++)
266
        {
267
                if(fread($f,4)=='OS/2')
268
                {
269
                        $found=true;
270
                        break;
271
                }
272
                fseek($f,12,SEEK_CUR);
273
        }
274
        if(!$found)
275
        {
276
                fclose($f);
277
                return;
278
        }
279
        fseek($f,4,SEEK_CUR);
280
        $offset=ReadLong($f);
281
        fseek($f,$offset,SEEK_SET);
282
        //Extract fsType flags
283
        fseek($f,8,SEEK_CUR);
284
        $fsType=ReadShort($f);
285
        $rl=($fsType & 0x02)!=0;
286
        $pp=($fsType & 0x04)!=0;
287
        $e=($fsType & 0x08)!=0;
288
        fclose($f);
289
        if($rl && !$pp && !$e)
290
                echo '<b>Warning:</b> font license does not allow embedding';
291
}
292

    
293
/*******************************************************************************
294
* fontfile: path to TTF file (or empty string if not to be embedded)           *
295
* afmfile:  path to AFM file                                                   *
296
* enc:      font encoding (or empty string for symbolic fonts)                 *
297
* patch:    optional patch for encoding                                        *
298
* type:     font type if fontfile is empty                                     *
299
*******************************************************************************/
300
function MakeFont($fontfile, $afmfile, $enc='cp1252', $patch=array(), $type='TrueType')
301
{
302
        //Generate a font definition file
303
        if(get_magic_quotes_runtime())
304
                @set_magic_quotes_runtime(0);
305
        ini_set('auto_detect_line_endings','1');
306
        if($enc)
307
        {
308
                $map=ReadMap($enc);
309
                foreach($patch as $cc=>$gn)
310
                        $map[$cc]=$gn;
311
        }
312
        else
313
                $map=array();
314
        if(!file_exists($afmfile))
315
                die('<b>Error:</b> AFM file not found: '.$afmfile);
316
        $fm=ReadAFM($afmfile,$map);
317
        if($enc)
318
                $diff=MakeFontEncoding($map);
319
        else
320
                $diff='';
321
        $fd=MakeFontDescriptor($fm,empty($map));
322
        //Find font type
323
        if($fontfile)
324
        {
325
                $ext=strtolower(substr($fontfile,-3));
326
                if($ext=='ttf')
327
                        $type='TrueType';
328
                elseif($ext=='pfb')
329
                        $type='Type1';
330
                else
331
                        die('<b>Error:</b> unrecognized font file extension: '.$ext);
332
        }
333
        else
334
        {
335
                if($type!='TrueType' && $type!='Type1')
336
                        die('<b>Error:</b> incorrect font type: '.$type);
337
        }
338
        //Start generation
339
        $s='<?php'."\n";
340
        $s.='$type=\''.$type."';\n";
341
        $s.='$name=\''.$fm['FontName']."';\n";
342
        $s.='$desc='.$fd.";\n";
343
        if(!isset($fm['UnderlinePosition']))
344
                $fm['UnderlinePosition']=-100;
345
        if(!isset($fm['UnderlineThickness']))
346
                $fm['UnderlineThickness']=50;
347
        $s.='$up='.$fm['UnderlinePosition'].";\n";
348
        $s.='$ut='.$fm['UnderlineThickness'].";\n";
349
        $w=MakeWidthArray($fm);
350
        $s.='$cw='.$w.";\n";
351
        $s.='$enc=\''.$enc."';\n";
352
        $s.='$diff=\''.$diff."';\n";
353
        $basename=substr(basename($afmfile),0,-4);
354
        if($fontfile)
355
        {
356
                //Embedded font
357
                if(!file_exists($fontfile))
358
                        die('<b>Error:</b> font file not found: '.$fontfile);
359
                if($type=='TrueType')
360
                        CheckTTF($fontfile);
361
                $f=fopen($fontfile,'rb');
362
                if(!$f)
363
                        die('<b>Error:</b> Can\'t open '.$fontfile);
364
                $file=fread($f,filesize($fontfile));
365
                fclose($f);
366
                if($type=='Type1')
367
                {
368
                        //Find first two sections and discard third one
369
                        $header=(ord($file[0])==128);
370
                        if($header)
371
                        {
372
                                //Strip first binary header
373
                                $file=substr($file,6);
374
                        }
375
                        $pos=strpos($file,'eexec');
376
                        if(!$pos)
377
                                die('<b>Error:</b> font file does not seem to be valid Type1');
378
                        $size1=$pos+6;
379
                        if($header && ord($file[$size1])==128)
380
                        {
381
                                //Strip second binary header
382
                                $file=substr($file,0,$size1).substr($file,$size1+6);
383
                        }
384
                        $pos=strpos($file,'00000000');
385
                        if(!$pos)
386
                                die('<b>Error:</b> font file does not seem to be valid Type1');
387
                        $size2=$pos-$size1;
388
                        $file=substr($file,0,$size1+$size2);
389
                }
390
                if(function_exists('gzcompress'))
391
                {
392
                        $cmp=$basename.'.z';
393
                        SaveToFile($cmp,gzcompress($file),'b');
394
                        $s.='$file=\''.$cmp."';\n";
395
                        echo 'Font file compressed ('.$cmp.')<br>';
396
                }
397
                else
398
                {
399
                        $s.='$file=\''.basename($fontfile)."';\n";
400
                        echo '<b>Notice:</b> font file could not be compressed (zlib extension not available)<br>';
401
                }
402
                if($type=='Type1')
403
                {
404
                        $s.='$size1='.$size1.";\n";
405
                        $s.='$size2='.$size2.";\n";
406
                }
407
                else
408
                        $s.='$originalsize='.filesize($fontfile).";\n";
409
        }
410
        else
411
        {
412
                //Not embedded font
413
                $s.='$file='."'';\n";
414
        }
415
        $s.="?>\n";
416
        SaveToFile($basename.'.php',$s,'t');
417
        echo 'Font definition file generated ('.$basename.'.php'.')<br>';
418
}
419
?>