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
*                                                                              *
5
* Version: 1.2                                                                 *
6
* Date:    2011-06-18                                                          *
7
* Author:  Olivier PLATHEY                                                     *
8
*******************************************************************************/
9
 
10
require('ttfparser.php');
11
 
12
function Message($txt, $severity='')
13
{
14
	if(PHP_SAPI=='cli')
15
	{
16
		if($severity)
17
			echo "$severity: ";
18
		echo "$txt\n";
19
	}
20
	else
21
	{
22
		if($severity)
23
			echo "<b>$severity</b>: ";
24
		echo "$txt<br>";
25
	}
26
}
27
 
28
function Notice($txt)
29
{
30
	Message($txt, 'Notice');
31
}
32
 
33
function Warning($txt)
34
{
35
	Message($txt, 'Warning');
36
}
37
 
38
function Error($txt)
39
{
40
	Message($txt, 'Error');
41
	exit;
42
}
43
 
44
function LoadMap($enc)
45
{
46
	$file = dirname(__FILE__).'/'.strtolower($enc).'.map';
47
	$a = file($file);
48
	if(empty($a))
49
		Error('Encoding not found: '.$enc);
50
	$map = array_fill(0, 256, array('uv'=>-1, 'name'=>'.notdef'));
51
	foreach($a as $line)
52
	{
53
		$e = explode(' ', rtrim($line));
54
		$c = hexdec(substr($e[0],1));
55
		$uv = hexdec(substr($e[1],2));
56
		$name = $e[2];
57
		$map[$c] = array('uv'=>$uv, 'name'=>$name);
58
	}
59
	return $map;
60
}
61
 
62
function GetInfoFromTrueType($file, $embed, $map)
63
{
64
	// Return informations from a TrueType font
65
	$ttf = new TTFParser();
66
	$ttf->Parse($file);
67
	if($embed)
68
	{
69
		if(!$ttf->Embeddable)
70
			Error('Font license does not allow embedding');
71
		$info['Data'] = file_get_contents($file);
72
		$info['OriginalSize'] = filesize($file);
73
	}
74
	$k = 1000/$ttf->unitsPerEm;
75
	$info['FontName'] = $ttf->postScriptName;
76
	$info['Bold'] = $ttf->Bold;
77
	$info['ItalicAngle'] = $ttf->italicAngle;
78
	$info['IsFixedPitch'] = $ttf->isFixedPitch;
79
	$info['Ascender'] = round($k*$ttf->typoAscender);
80
	$info['Descender'] = round($k*$ttf->typoDescender);
81
	$info['UnderlineThickness'] = round($k*$ttf->underlineThickness);
82
	$info['UnderlinePosition'] = round($k*$ttf->underlinePosition);
83
	$info['FontBBox'] = array(round($k*$ttf->xMin), round($k*$ttf->yMin), round($k*$ttf->xMax), round($k*$ttf->yMax));
84
	$info['CapHeight'] = round($k*$ttf->capHeight);
85
	$info['MissingWidth'] = round($k*$ttf->widths[0]);
86
	$widths = array_fill(0, 256, $info['MissingWidth']);
87
	for($c=0;$c<=255;$c++)
88
	{
89
		if($map[$c]['name']!='.notdef')
90
		{
91
			$uv = $map[$c]['uv'];
92
			if(isset($ttf->chars[$uv]))
93
			{
94
				$w = $ttf->widths[$ttf->chars[$uv]];
95
				$widths[$c] = round($k*$w);
96
			}
97
			else
98
				Warning('Character '.$map[$c]['name'].' is missing');
99
		}
100
	}
101
	$info['Widths'] = $widths;
102
	return $info;
103
}
104
 
105
function GetInfoFromType1($file, $embed, $map)
106
{
107
	// Return informations from a Type1 font
108
	if($embed)
109
	{
110
		$f = fopen($file, 'rb');
111
		if(!$f)
112
			Error('Can\'t open font file');
113
		// Read first segment
114
		$a = unpack('Cmarker/Ctype/Vsize', fread($f,6));
115
		if($a['marker']!=128)
116
			Error('Font file is not a valid binary Type1');
117
		$size1 = $a['size'];
118
		$data = fread($f, $size1);
119
		// Read second segment
120
		$a = unpack('Cmarker/Ctype/Vsize', fread($f,6));
121
		if($a['marker']!=128)
122
			Error('Font file is not a valid binary Type1');
123
		$size2 = $a['size'];
124
		$data .= fread($f, $size2);
125
		fclose($f);
126
		$info['Data'] = $data;
127
		$info['Size1'] = $size1;
128
		$info['Size2'] = $size2;
129
	}
130
 
131
	$afm = substr($file, 0, -3).'afm';
132
	if(!file_exists($afm))
133
		Error('AFM font file not found: '.$afm);
134
	$a = file($afm);
135
	if(empty($a))
136
		Error('AFM file empty or not readable');
137
	foreach($a as $line)
138
	{
139
		$e = explode(' ', rtrim($line));
140
		if(count($e)<2)
141
			continue;
142
		$entry = $e[0];
143
		if($entry=='C')
144
		{
145
			$w = $e[4];
146
			$name = $e[7];
147
			$cw[$name] = $w;
148
		}
149
		elseif($entry=='FontName')
150
			$info['FontName'] = $e[1];
151
		elseif($entry=='Weight')
152
			$info['Weight'] = $e[1];
153
		elseif($entry=='ItalicAngle')
154
			$info['ItalicAngle'] = (int)$e[1];
155
		elseif($entry=='Ascender')
156
			$info['Ascender'] = (int)$e[1];
157
		elseif($entry=='Descender')
158
			$info['Descender'] = (int)$e[1];
159
		elseif($entry=='UnderlineThickness')
160
			$info['UnderlineThickness'] = (int)$e[1];
161
		elseif($entry=='UnderlinePosition')
162
			$info['UnderlinePosition'] = (int)$e[1];
163
		elseif($entry=='IsFixedPitch')
164
			$info['IsFixedPitch'] = ($e[1]=='true');
165
		elseif($entry=='FontBBox')
166
			$info['FontBBox'] = array((int)$e[1], (int)$e[2], (int)$e[3], (int)$e[4]);
167
		elseif($entry=='CapHeight')
168
			$info['CapHeight'] = (int)$e[1];
169
		elseif($entry=='StdVW')
170
			$info['StdVW'] = (int)$e[1];
171
	}
172
 
173
	if(!isset($info['FontName']))
174
		Error('FontName missing in AFM file');
175
	$info['Bold'] = isset($info['Weight']) && preg_match('/bold|black/i', $info['Weight']);
176
	if(isset($cw['.notdef']))
177
		$info['MissingWidth'] = $cw['.notdef'];
178
	else
179
		$info['MissingWidth'] = 0;
180
	$widths = array_fill(0, 256, $info['MissingWidth']);
181
	for($c=0;$c<=255;$c++)
182
	{
183
		$name = $map[$c]['name'];
184
		if($name!='.notdef')
185
		{
186
			if(isset($cw[$name]))
187
				$widths[$c] = $cw[$name];
188
			else
189
				Warning('Character '.$name.' is missing');
190
		}
191
	}
192
	$info['Widths'] = $widths;
193
	return $info;
194
}
195
 
196
function MakeFontDescriptor($info)
197
{
198
	// Ascent
199
	$fd = "array('Ascent'=>".$info['Ascender'];
200
	// Descent
201
	$fd .= ",'Descent'=>".$info['Descender'];
202
	// CapHeight
203
	if(!empty($info['CapHeight']))
204
		$fd .= ",'CapHeight'=>".$info['CapHeight'];
205
	else
206
		$fd .= ",'CapHeight'=>".$info['Ascender'];
207
	// Flags
208
	$flags = 0;
209
	if($info['IsFixedPitch'])
210
		$flags += 1<<0;
211
	$flags += 1<<5;
212
	if($info['ItalicAngle']!=0)
213
		$flags += 1<<6;
214
	$fd .= ",'Flags'=>".$flags;
215
	// FontBBox
216
	$fbb = $info['FontBBox'];
217
	$fd .= ",'FontBBox'=>'[".$fbb[0].' '.$fbb[1].' '.$fbb[2].' '.$fbb[3]."]'";
218
	// ItalicAngle
219
	$fd .= ",'ItalicAngle'=>".$info['ItalicAngle'];
220
	// StemV
221
	if(isset($info['StdVW']))
222
		$stemv = $info['StdVW'];
223
	elseif($info['Bold'])
224
		$stemv = 120;
225
	else
226
		$stemv = 70;
227
	$fd .= ",'StemV'=>".$stemv;
228
	// MissingWidth
229
	$fd .= ",'MissingWidth'=>".$info['MissingWidth'].')';
230
	return $fd;
231
}
232
 
233
function MakeWidthArray($widths)
234
{
235
	$s = "array(\n\t";
236
	for($c=0;$c<=255;$c++)
237
	{
238
		if(chr($c)=="'")
239
			$s .= "'\\''";
240
		elseif(chr($c)=="\\")
241
			$s .= "'\\\\'";
242
		elseif($c>=32 && $c<=126)
243
			$s .= "'".chr($c)."'";
244
		else
245
			$s .= "chr($c)";
246
		$s .= '=>'.$widths[$c];
247
		if($c<255)
248
			$s .= ',';
249
		if(($c+1)%22==0)
250
			$s .= "\n\t";
251
	}
252
	$s .= ')';
253
	return $s;
254
}
255
 
256
function MakeFontEncoding($map)
257
{
258
	// Build differences from reference encoding
259
	$ref = LoadMap('cp1252');
260
	$s = '';
261
	$last = 0;
262
	for($c=32;$c<=255;$c++)
263
	{
264
		if($map[$c]['name']!=$ref[$c]['name'])
265
		{
266
			if($c!=$last+1)
267
				$s .= $c.' ';
268
			$last = $c;
269
			$s .= '/'.$map[$c]['name'].' ';
270
		}
271
	}
272
	return rtrim($s);
273
}
274
 
275
function SaveToFile($file, $s, $mode)
276
{
277
	$f = fopen($file, 'w'.$mode);
278
	if(!$f)
279
		Error('Can\'t write to file '.$file);
280
	fwrite($f, $s, strlen($s));
281
	fclose($f);
282
}
283
 
284
function MakeDefinitionFile($file, $type, $enc, $embed, $map, $info)
285
{
286
	$s = "<?php\n";
287
	$s .= '$type = \''.$type."';\n";
288
	$s .= '$name = \''.$info['FontName']."';\n";
289
	$s .= '$desc = '.MakeFontDescriptor($info).";\n";
290
	$s .= '$up = '.$info['UnderlinePosition'].";\n";
291
	$s .= '$ut = '.$info['UnderlineThickness'].";\n";
292
	$s .= '$cw = '.MakeWidthArray($info['Widths']).";\n";
293
	$s .= '$enc = \''.$enc."';\n";
294
	$diff = MakeFontEncoding($map);
295
	if($diff)
296
		$s .= '$diff = \''.$diff."';\n";
297
	if($embed)
298
	{
299
		$s .= '$file = \''.$info['File']."';\n";
300
		if($type=='Type1')
301
		{
302
			$s .= '$size1 = '.$info['Size1'].";\n";
303
			$s .= '$size2 = '.$info['Size2'].";\n";
304
		}
305
		else
306
			$s .= '$originalsize = '.$info['OriginalSize'].";\n";
307
	}
308
	$s .= "?>\n";
309
	SaveToFile($file, $s, 't');
310
}
311
 
312
function MakeFont($fontfile, $enc='cp1252', $embed=true)
313
{
314
	// Generate a font definition file
315
	if(get_magic_quotes_runtime())
316
		@set_magic_quotes_runtime(0);
317
	ini_set('auto_detect_line_endings', '1');
318
 
319
	if(!file_exists($fontfile))
320
		Error('Font file not found: '.$fontfile);
321
	$ext = strtolower(substr($fontfile,-3));
322
	if($ext=='ttf' || $ext=='otf')
323
		$type = 'TrueType';
324
	elseif($ext=='pfb')
325
		$type = 'Type1';
326
	else
327
		Error('Unrecognized font file extension: '.$ext);
328
 
329
	$map = LoadMap($enc);
330
 
331
	if($type=='TrueType')
332
		$info = GetInfoFromTrueType($fontfile, $embed, $map);
333
	else
334
		$info = GetInfoFromType1($fontfile, $embed, $map);
335
 
336
	$basename = substr(basename($fontfile), 0, -4);
337
	if($embed)
338
	{
339
		if(function_exists('gzcompress'))
340
		{
341
			$file = $basename.'.z';
342
			SaveToFile($file, gzcompress($info['Data']), 'b');
343
			$info['File'] = $file;
344
			Message('Font file compressed: '.$file);
345
		}
346
		else
347
		{
348
			$info['File'] = basename($fontfile);
349
			Notice('Font file could not be compressed (zlib extension not available)');
350
		}
351
	}
352
 
353
	MakeDefinitionFile($basename.'.php', $type, $enc, $embed, $map, $info);
354
	Message('Font definition file generated: '.$basename.'.php');
355
}
356
 
357
if(PHP_SAPI=='cli')
358
{
359
	// Command-line interface
360
	if($argc==1)
361
		die("Usage: php makefont.php fontfile [enc] [embed]\n");
362
	$fontfile = $argv[1];
363
	if($argc>=3)
364
		$enc = $argv[2];
365
	else
366
		$enc = 'cp1252';
367
	if($argc>=4)
368
		$embed = ($argv[3]=='true' || $argv[3]=='1');
369
	else
370
		$embed = true;
371
	MakeFont($fontfile, $enc, $embed);
372
}
373
?>