Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
/*******************************************************************************
3
* Utility to generate font definition files                                    *
4
*                                                                              *
5
* Version: 1.31                                                                *
6
* Date:    2019-12-07                                                          *
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, $subset, $map)
63
{
64
	// Return information from a TrueType font
65
	try
66
	{
67
		$ttf = new TTFParser($file);
68
		$ttf->Parse();
69
	}
70
	catch(Exception $e)
71
	{
72
		Error($e->getMessage());
73
	}
74
	if($embed)
75
	{
76
		if(!$ttf->embeddable)
77
			Error('Font license does not allow embedding');
78
		if($subset)
79
		{
80
			$chars = array();
81
			foreach($map as $v)
82
			{
83
				if($v['name']!='.notdef')
84
					$chars[] = $v['uv'];
85
			}
86
			$ttf->Subset($chars);
87
			$info['Data'] = $ttf->Build();
88
		}
89
		else
90
			$info['Data'] = file_get_contents($file);
91
		$info['OriginalSize'] = strlen($info['Data']);
92
	}
93
	$k = 1000/$ttf->unitsPerEm;
94
	$info['FontName'] = $ttf->postScriptName;
95
	$info['Bold'] = $ttf->bold;
96
	$info['ItalicAngle'] = $ttf->italicAngle;
97
	$info['IsFixedPitch'] = $ttf->isFixedPitch;
98
	$info['Ascender'] = round($k*$ttf->typoAscender);
99
	$info['Descender'] = round($k*$ttf->typoDescender);
100
	$info['UnderlineThickness'] = round($k*$ttf->underlineThickness);
101
	$info['UnderlinePosition'] = round($k*$ttf->underlinePosition);
102
	$info['FontBBox'] = array(round($k*$ttf->xMin), round($k*$ttf->yMin), round($k*$ttf->xMax), round($k*$ttf->yMax));
103
	$info['CapHeight'] = round($k*$ttf->capHeight);
104
	$info['MissingWidth'] = round($k*$ttf->glyphs[0]['w']);
105
	$widths = array_fill(0, 256, $info['MissingWidth']);
106
	foreach($map as $c=>$v)
107
	{
108
		if($v['name']!='.notdef')
109
		{
110
			if(isset($ttf->chars[$v['uv']]))
111
			{
112
				$id = $ttf->chars[$v['uv']];
113
				$w = $ttf->glyphs[$id]['w'];
114
				$widths[$c] = round($k*$w);
115
			}
116
			else
117
				Warning('Character '.$v['name'].' is missing');
118
		}
119
	}
120
	$info['Widths'] = $widths;
121
	return $info;
122
}
123
 
124
function GetInfoFromType1($file, $embed, $map)
125
{
126
	// Return information from a Type1 font
127
	if($embed)
128
	{
129
		$f = fopen($file, 'rb');
130
		if(!$f)
131
			Error('Can\'t open font file');
132
		// Read first segment
133
		$a = unpack('Cmarker/Ctype/Vsize', fread($f,6));
134
		if($a['marker']!=128)
135
			Error('Font file is not a valid binary Type1');
136
		$size1 = $a['size'];
137
		$data = fread($f, $size1);
138
		// Read second segment
139
		$a = unpack('Cmarker/Ctype/Vsize', fread($f,6));
140
		if($a['marker']!=128)
141
			Error('Font file is not a valid binary Type1');
142
		$size2 = $a['size'];
143
		$data .= fread($f, $size2);
144
		fclose($f);
145
		$info['Data'] = $data;
146
		$info['Size1'] = $size1;
147
		$info['Size2'] = $size2;
148
	}
149
 
150
	$afm = substr($file, 0, -3).'afm';
151
	if(!file_exists($afm))
152
		Error('AFM font file not found: '.$afm);
153
	$a = file($afm);
154
	if(empty($a))
155
		Error('AFM file empty or not readable');
156
	foreach($a as $line)
157
	{
158
		$e = explode(' ', rtrim($line));
159
		if(count($e)<2)
160
			continue;
161
		$entry = $e[0];
162
		if($entry=='C')
163
		{
164
			$w = $e[4];
165
			$name = $e[7];
166
			$cw[$name] = $w;
167
		}
168
		elseif($entry=='FontName')
169
			$info['FontName'] = $e[1];
170
		elseif($entry=='Weight')
171
			$info['Weight'] = $e[1];
172
		elseif($entry=='ItalicAngle')
173
			$info['ItalicAngle'] = (int)$e[1];
174
		elseif($entry=='Ascender')
175
			$info['Ascender'] = (int)$e[1];
176
		elseif($entry=='Descender')
177
			$info['Descender'] = (int)$e[1];
178
		elseif($entry=='UnderlineThickness')
179
			$info['UnderlineThickness'] = (int)$e[1];
180
		elseif($entry=='UnderlinePosition')
181
			$info['UnderlinePosition'] = (int)$e[1];
182
		elseif($entry=='IsFixedPitch')
183
			$info['IsFixedPitch'] = ($e[1]=='true');
184
		elseif($entry=='FontBBox')
185
			$info['FontBBox'] = array((int)$e[1], (int)$e[2], (int)$e[3], (int)$e[4]);
186
		elseif($entry=='CapHeight')
187
			$info['CapHeight'] = (int)$e[1];
188
		elseif($entry=='StdVW')
189
			$info['StdVW'] = (int)$e[1];
190
	}
191
 
192
	if(!isset($info['FontName']))
193
		Error('FontName missing in AFM file');
194
	if(!isset($info['Ascender']))
195
		$info['Ascender'] = $info['FontBBox'][3];
196
	if(!isset($info['Descender']))
197
		$info['Descender'] = $info['FontBBox'][1];
198
	$info['Bold'] = isset($info['Weight']) && preg_match('/bold|black/i', $info['Weight']);
199
	if(isset($cw['.notdef']))
200
		$info['MissingWidth'] = $cw['.notdef'];
201
	else
202
		$info['MissingWidth'] = 0;
203
	$widths = array_fill(0, 256, $info['MissingWidth']);
204
	foreach($map as $c=>$v)
205
	{
206
		if($v['name']!='.notdef')
207
		{
208
			if(isset($cw[$v['name']]))
209
				$widths[$c] = $cw[$v['name']];
210
			else
211
				Warning('Character '.$v['name'].' is missing');
212
		}
213
	}
214
	$info['Widths'] = $widths;
215
	return $info;
216
}
217
 
218
function MakeFontDescriptor($info)
219
{
220
	// Ascent
221
	$fd = "array('Ascent'=>".$info['Ascender'];
222
	// Descent
223
	$fd .= ",'Descent'=>".$info['Descender'];
224
	// CapHeight
225
	if(!empty($info['CapHeight']))
226
		$fd .= ",'CapHeight'=>".$info['CapHeight'];
227
	else
228
		$fd .= ",'CapHeight'=>".$info['Ascender'];
229
	// Flags
230
	$flags = 0;
231
	if($info['IsFixedPitch'])
232
		$flags += 1<<0;
233
	$flags += 1<<5;
234
	if($info['ItalicAngle']!=0)
235
		$flags += 1<<6;
236
	$fd .= ",'Flags'=>".$flags;
237
	// FontBBox
238
	$fbb = $info['FontBBox'];
239
	$fd .= ",'FontBBox'=>'[".$fbb[0].' '.$fbb[1].' '.$fbb[2].' '.$fbb[3]."]'";
240
	// ItalicAngle
241
	$fd .= ",'ItalicAngle'=>".$info['ItalicAngle'];
242
	// StemV
243
	if(isset($info['StdVW']))
244
		$stemv = $info['StdVW'];
245
	elseif($info['Bold'])
246
		$stemv = 120;
247
	else
248
		$stemv = 70;
249
	$fd .= ",'StemV'=>".$stemv;
250
	// MissingWidth
251
	$fd .= ",'MissingWidth'=>".$info['MissingWidth'].')';
252
	return $fd;
253
}
254
 
255
function MakeWidthArray($widths)
256
{
257
	$s = "array(\n\t";
258
	for($c=0;$c<=255;$c++)
259
	{
260
		if(chr($c)=="'")
261
			$s .= "'\\''";
262
		elseif(chr($c)=="\\")
263
			$s .= "'\\\\'";
264
		elseif($c>=32 && $c<=126)
265
			$s .= "'".chr($c)."'";
266
		else
267
			$s .= "chr($c)";
268
		$s .= '=>'.$widths[$c];
269
		if($c<255)
270
			$s .= ',';
271
		if(($c+1)%22==0)
272
			$s .= "\n\t";
273
	}
274
	$s .= ')';
275
	return $s;
276
}
277
 
278
function MakeFontEncoding($map)
279
{
280
	// Build differences from reference encoding
281
	$ref = LoadMap('cp1252');
282
	$s = '';
283
	$last = 0;
284
	for($c=32;$c<=255;$c++)
285
	{
286
		if($map[$c]['name']!=$ref[$c]['name'])
287
		{
288
			if($c!=$last+1)
289
				$s .= $c.' ';
290
			$last = $c;
291
			$s .= '/'.$map[$c]['name'].' ';
292
		}
293
	}
294
	return rtrim($s);
295
}
296
 
297
function MakeUnicodeArray($map)
298
{
299
	// Build mapping to Unicode values
300
	$ranges = array();
301
	foreach($map as $c=>$v)
302
	{
303
		$uv = $v['uv'];
304
		if($uv!=-1)
305
		{
306
			if(isset($range))
307
			{
308
				if($c==$range[1]+1 && $uv==$range[3]+1)
309
				{
310
					$range[1]++;
311
					$range[3]++;
312
				}
313
				else
314
				{
315
					$ranges[] = $range;
316
					$range = array($c, $c, $uv, $uv);
317
				}
318
			}
319
			else
320
				$range = array($c, $c, $uv, $uv);
321
		}
322
	}
323
	$ranges[] = $range;
324
 
325
	foreach($ranges as $range)
326
	{
327
		if(isset($s))
328
			$s .= ',';
329
		else
330
			$s = 'array(';
331
		$s .= $range[0].'=>';
332
		$nb = $range[1]-$range[0]+1;
333
		if($nb>1)
334
			$s .= 'array('.$range[2].','.$nb.')';
335
		else
336
			$s .= $range[2];
337
	}
338
	$s .= ')';
339
	return $s;
340
}
341
 
342
function SaveToFile($file, $s, $mode)
343
{
344
	$f = fopen($file, 'w'.$mode);
345
	if(!$f)
346
		Error('Can\'t write to file '.$file);
347
	fwrite($f, $s);
348
	fclose($f);
349
}
350
 
351
function MakeDefinitionFile($file, $type, $enc, $embed, $subset, $map, $info)
352
{
353
	$s = "<?php\n";
354
	$s .= '$type = \''.$type."';\n";
355
	$s .= '$name = \''.$info['FontName']."';\n";
356
	$s .= '$desc = '.MakeFontDescriptor($info).";\n";
357
	$s .= '$up = '.$info['UnderlinePosition'].";\n";
358
	$s .= '$ut = '.$info['UnderlineThickness'].";\n";
359
	$s .= '$cw = '.MakeWidthArray($info['Widths']).";\n";
360
	$s .= '$enc = \''.$enc."';\n";
361
	$diff = MakeFontEncoding($map);
362
	if($diff)
363
		$s .= '$diff = \''.$diff."';\n";
364
	$s .= '$uv = '.MakeUnicodeArray($map).";\n";
365
	if($embed)
366
	{
367
		$s .= '$file = \''.$info['File']."';\n";
368
		if($type=='Type1')
369
		{
370
			$s .= '$size1 = '.$info['Size1'].";\n";
371
			$s .= '$size2 = '.$info['Size2'].";\n";
372
		}
373
		else
374
		{
375
			$s .= '$originalsize = '.$info['OriginalSize'].";\n";
376
			if($subset)
377
				$s .= "\$subsetted = true;\n";
378
		}
379
	}
380
	$s .= "?>\n";
381
	SaveToFile($file, $s, 't');
382
}
383
 
384
function MakeFont($fontfile, $enc='cp1252', $embed=true, $subset=true)
385
{
386
	// Generate a font definition file
387
	if(!file_exists($fontfile))
388
		Error('Font file not found: '.$fontfile);
389
	$ext = strtolower(substr($fontfile,-3));
390
	if($ext=='ttf' || $ext=='otf')
391
		$type = 'TrueType';
392
	elseif($ext=='pfb')
393
		$type = 'Type1';
394
	else
395
		Error('Unrecognized font file extension: '.$ext);
396
 
397
	$map = LoadMap($enc);
398
 
399
	if($type=='TrueType')
400
		$info = GetInfoFromTrueType($fontfile, $embed, $subset, $map);
401
	else
402
		$info = GetInfoFromType1($fontfile, $embed, $map);
403
 
404
	$basename = substr(basename($fontfile), 0, -4);
405
	if($embed)
406
	{
407
		if(function_exists('gzcompress'))
408
		{
409
			$file = $basename.'.z';
410
			SaveToFile($file, gzcompress($info['Data']), 'b');
411
			$info['File'] = $file;
412
			Message('Font file compressed: '.$file);
413
		}
414
		else
415
		{
416
			$info['File'] = basename($fontfile);
417
			$subset = false;
418
			Notice('Font file could not be compressed (zlib extension not available)');
419
		}
420
	}
421
 
422
	MakeDefinitionFile($basename.'.php', $type, $enc, $embed, $subset, $map, $info);
423
	Message('Font definition file generated: '.$basename.'.php');
424
}
425
 
426
if(PHP_SAPI=='cli')
427
{
428
	// Command-line interface
429
	ini_set('log_errors', '0');
430
	if($argc==1)
431
		die("Usage: php makefont.php fontfile [encoding] [embed] [subset]\n");
432
	$fontfile = $argv[1];
433
	if($argc>=3)
434
		$enc = $argv[2];
435
	else
436
		$enc = 'cp1252';
437
	if($argc>=4)
438
		$embed = ($argv[3]=='true' || $argv[3]=='1');
439
	else
440
		$embed = true;
441
	if($argc>=5)
442
		$subset = ($argv[4]=='true' || $argv[4]=='1');
443
	else
444
		$subset = true;
445
	MakeFont($fontfile, $enc, $embed, $subset);
446
}
447
?>