275 $this->sFamilyClass = 0;
276 $this->sFamilySubClass = 0;
281 die(
"Unknown name table format ".$format);
283 $string_data_offset = $name_offset + $this->
read_ushort();
284 $names =
array(1=>
'',2=>
'',3=>
'',4=>
'',6=>
'');
285 $K = array_keys($names);
286 $nameCount =
count($names);
287 for (
$i=0;
$i<$numRecords;
$i++) {
294 if (!in_array($nameId,$K))
continue;
296 if ($platformId == 3 && $encodingId == 1 && $languageId == 0x409) {
298 $this->
seek($string_data_offset + $offset);
299 if ($length % 2 != 0)
300 die(
"PostScript name is UTF-16BE string of odd length");
303 while ($length > 0) {
311 else if ($platformId == 1 && $encodingId == 0 && $languageId == 0) {
313 $N = $this->
get_chunk($string_data_offset + $offset, $length);
317 if ($N && $names[$nameId]==
'') {
318 $names[$nameId] = $N;
320 if ($nameCount==0)
break;
326 $psName = preg_replace(
'/ /',
'-',$names[4]);
328 $psName = preg_replace(
'/ /',
'-',$names[1]);
332 die(
"Could not find PostScript font name");
333 $this->name = $psName;
334 if ($names[1]) { $this->familyName = $names[1]; }
else { $this->familyName = $psName; }
335 if ($names[2]) { $this->styleName = $names[2]; }
else { $this->styleName =
'Regular'; }
336 if ($names[4]) { $this->fullName = $names[4]; }
else { $this->fullName = $psName; }
337 if ($names[3]) { $this->uniqueFontID = $names[3]; }
else { $this->uniqueFontID = $psName; }
338 if ($names[6]) { $this->fullName = $names[6]; }
352 $this->bbox =
array(($xMin*$scale), ($yMin*$scale), ($xMax*$scale), ($yMax*$scale));
356 if ($glyphDataFormat != 0)
357 die(
'Unknown glyph data format '.$glyphDataFormat);
363 if (isset($this->tables[
"hhea"])) {
368 $this->ascent = ($hheaAscender *$scale);
369 $this->descent = ($hheaDescender *$scale);
375 if (isset($this->tables[
"OS/2"])) {
382 if ($fsType == 0x0002 || ($fsType & 0x0300) != 0) {
383 die(
'ERROR - Font file '.$this->filename.
' cannot be embedded due to copyright restrictions.');
384 $this->restrictedUse =
true;
388 $this->sFamilyClass = ($sF >> 8);
389 $this->sFamilySubClass = ($sF & 0xFF);
391 $panose = fread($this->fh,10);
395 if (!$this->ascent) $this->ascent = ($sTypoAscender*$scale);
396 if (!$this->descent) $this->descent = ($sTypoDescender*$scale);
400 $this->capHeight = ($sCapHeight*$scale);
407 $usWeightClass = 500;
408 if (!$this->ascent) $this->ascent = ($yMax*$scale);
409 if (!$this->descent) $this->descent = ($yMin*$scale);
412 $this->stemV = 50 + intval(pow(($usWeightClass / 65.0),2));
420 $this->underlinePosition = $this->
read_short() * $scale;
421 $this->underlineThickness = $this->
read_short() * $scale;
426 if ($this->italicAngle!= 0)
427 $this->flags = $this->flags | 64;
428 if ($usWeightClass >= 600)
429 $this->flags = $this->flags | 262144;
431 $this->flags = $this->flags | 1;
439 if ($metricDataFormat != 0)
440 die(
'Unknown horizontal metric data format '.$metricDataFormat);
442 if ($numberOfHMetrics == 0)
443 die(
'Number of horizontal metrics is 0');
459 $unicode_cmap_offset = 0;
460 for (
$i=0;
$i<$cmapTableCount;
$i++) {
465 if (($platformID == 3 && $encodingID == 1) || $platformID == 0) {
466 $format = $this->
get_ushort($cmap_offset + $offset);
468 if (!$unicode_cmap_offset) $unicode_cmap_offset = $cmap_offset + $offset;
472 $this->
seek($save_pos );
474 if (!$unicode_cmap_offset)
475 die(
'Font ('.$this->filename .
') does not have cmap for Unicode (platform 3, encoding 1, format 4, or platform 0, any encoding, format 4)');
478 $glyphToChar =
array();
485 $this->
getHMTX($numberOfHMetrics, $numGlyphs, $glyphToChar, $scale);
495 $this->filename = $file;
496 $this->fh = fopen($file ,
'rb') or
die(
'Can\'t open file ' . $file);
498 $this->charWidths =
'';
499 $this->glyphPos =
array();
500 $this->charToGlyph =
array();
501 $this->tables =
array();
502 $this->otables =
array();
524 $orignHmetrics = $numberOfHMetrics = $this->
read_ushort();
540 $unicode_cmap_offset = 0;
541 for (
$i=0;
$i<$cmapTableCount;
$i++) {
546 if (($platformID == 3 && $encodingID == 1) || $platformID == 0) {
547 $format = $this->
get_ushort($cmap_offset + $offset);
549 $unicode_cmap_offset = $cmap_offset + $offset;
553 $this->
seek($save_pos );
556 if (!$unicode_cmap_offset)
557 die(
'Font ('.$this->filename .
') does not have cmap for Unicode (platform 3, encoding 1, format 4, or platform 0, any encoding, format 4)');
560 $glyphToChar =
array();
570 $this->
getHMTX($numberOfHMetrics, $numGlyphs, $glyphToChar, $scale);
575 $this->
getLOCA($indexToLocFormat, $numGlyphs);
577 $subsetglyphs =
array(0=>0);
578 $subsetCharToGlyph =
array();
579 foreach($subset AS
$code) {
580 if (isset($this->charToGlyph[
$code])) {
581 $subsetglyphs[$this->charToGlyph[
$code]] =
$code;
582 $subsetCharToGlyph[
$code] = $this->charToGlyph[
$code];
585 $this->maxUni = max($this->maxUni,
$code);
591 ksort($subsetglyphs);
593 $fsLastCharIndex = 0;
594 foreach($subsetglyphs AS $originalGlyphIdx => $uni) {
595 $fsLastCharIndex = max($fsLastCharIndex , $uni);
596 $glyphSet[$originalGlyphIdx] =
$n;
600 ksort($subsetCharToGlyph);
601 foreach($subsetCharToGlyph AS $uni => $originalGlyphIdx) {
602 $codeToGlyph[$uni] = $glyphSet[$originalGlyphIdx] ;
604 $this->codeToGlyph = $codeToGlyph;
606 ksort($subsetglyphs);
607 foreach($subsetglyphs AS $originalGlyphIdx => $uni) {
611 $numGlyphs = $numberOfHMetrics =
count($subsetglyphs );
614 $tags =
array (
'name');
615 foreach($tags AS $tag) { $this->
add($tag, $this->
get_table($tag)); }
616 $tags =
array (
'cvt ',
'fpgm',
'prep',
'gasp');
617 foreach($tags AS $tag) {
618 if (isset($this->tables[$tag])) { $this->
add($tag, $this->
get_table($tag)); }
623 $post =
"\x00\x03\x00\x00" . mb_substr($opost,4,12,
'8bit') .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
628 unset($codeToGlyph[0]);
635 foreach ($codeToGlyph as $cid => $glidx) {
636 if ($cid == ($prevcid + 1) && $glidx == ($prevglidx + 1)) {
637 $range[$rangeid][] = $glidx;
641 $range[$rangeid] =
array();
642 $range[$rangeid][] = $glidx;
649 $segCount =
count($range) + 1;
658 $length = 16 + (8*$segCount ) + ($numGlyphs+1);
669 foreach($range AS
$start=>$subrange) {
677 foreach($range AS
$start=>$subrange) {
682 foreach($range AS
$start=>$subrange) {
683 $idDelta = -(
$start-$subrange[0]);
689 foreach($range AS $subrange) {
694 foreach($range AS $subrange) {
695 foreach($subrange AS $glidx) {
701 foreach($cmap AS $cm) { $cmapstr .= pack(
"n",$cm); }
702 $this->
add(
'cmap', $cmapstr);
706 list($glyfOffset,$glyfLength) = $this->
get_table_pos(
'glyf');
707 if ($glyfLength < $this->maxStrLenRead) {
720 $advanceWidthMax = 0;
721 $minLeftSideBearing = 0;
722 $minRightSideBearing = 0;
726 $maxComponentPoints = 0;
727 $maxComponentContours = 0;
728 $maxComponentElements = 0;
729 $maxComponentDepth = 0;
730 $this->glyphdata =
array();
732 foreach($subsetglyphs AS $originalGlyphIdx => $uni) {
734 $hm = $this->
getHMetric($orignHmetrics, $originalGlyphIdx);
738 $glyphPos = $this->glyphPos[$originalGlyphIdx];
739 $glyphLen = $this->glyphPos[$originalGlyphIdx + 1] -
$glyphPos;
740 if ($glyfLength < $this->maxStrLenRead) {
749 $up = unpack(
"n", mb_substr(
$data,0,2,
'8bit'));
752 if ($glyphLen > 2 && ($up[1] & (1 << 15)) ) {
755 $nComponentElements = 0;
757 $nComponentElements += 1;
758 $up = unpack(
"n", mb_substr(
$data,$pos_in_glyph,2,
'8bit'));
760 $up = unpack(
"n", mb_substr(
$data,$pos_in_glyph+2,2,
'8bit'));
762 $this->glyphdata[$originalGlyphIdx][
'compGlyphs'][] = $glyphIdx;
766 else { $pos_in_glyph += 2; }
771 $maxComponentElements = max($maxComponentElements, $nComponentElements);
777 $padding = 4 - ($pos % 4);
778 $glyf .= str_repeat(
"\0",$padding);
784 $this->
add(
'glyf', $glyf);
787 $this->
add(
'hmtx', $hmtxstr);
791 if ((($pos + 1) >> 1) > 0xFFFF) {
792 $indexToLocFormat = 1;
793 foreach($offsets AS $offset) { $locastr .= pack(
"N",$offset); }
796 $indexToLocFormat = 0;
797 foreach($offsets AS $offset) { $locastr .= pack(
"n",($offset/2)); }
799 $this->
add(
'loca', $locastr);
803 $head = $this->
_set_ushort($head, 50, $indexToLocFormat);
804 $this->
add(
'head', $head);
809 $hhea = $this->
_set_ushort($hhea, 34, $numberOfHMetrics);
810 $this->
add(
'hhea', $hhea);
815 $this->
add(
'maxp', $maxp);
820 $this->
add(
'OS/2', $os2 );
832 function getGlyphData($originalGlyphIdx, &$maxdepth, &$depth, &$points, &$contours) {
834 $maxdepth = max($maxdepth, $depth);
835 if (
count($this->glyphdata[$originalGlyphIdx][
'compGlyphs'])) {
836 foreach($this->glyphdata[$originalGlyphIdx][
'compGlyphs'] AS $glyphIdx) {
837 $this->
getGlyphData($glyphIdx, $maxdepth, $depth, $points, $contours);
840 else if (($this->glyphdata[$originalGlyphIdx][
'nContours'] > 0) && $depth > 0) {
841 $contours += $this->glyphdata[$originalGlyphIdx][
'nContours'];
842 $points += $this->glyphdata[$originalGlyphIdx][
'nPoints'];
887 function getHMTX($numberOfHMetrics, $numGlyphs, &$glyphToChar, $scale) {
890 $this->charWidths = str_pad(
'', 256*256*2,
"\x00");
892 if (($numberOfHMetrics*4) < $this->maxStrLenRead) {
897 for( $glyph=0; $glyph<$numberOfHMetrics; $glyph++) {
899 if (($numberOfHMetrics*4) < $this->maxStrLenRead) {
900 $aw =
$arr[($glyph*2)+1];
906 if (isset($glyphToChar[$glyph]) || $glyph == 0) {
908 if ($aw >= (1 << 15) ) { $aw = 0; }
911 $this->defaultWidth = $scale*$aw;
914 foreach($glyphToChar[$glyph] AS $char) {
915 if ($char != 0 && $char != 65535) {
916 $w = intval(round($scale*$aw));
917 if ($w == 0) { $w = 65535; }
918 if ($char < 196608) {
919 $this->charWidths[$char*2] = chr($w >> 8);
920 $this->charWidths[$char*2 + 1] = chr($w & 0xFF);
929 $diff = $numGlyphs-$numberOfHMetrics;
930 for( $pos=0; $pos<$diff; $pos++) {
931 $glyph = $pos + $numberOfHMetrics;
932 if (isset($glyphToChar[$glyph])) {
933 foreach($glyphToChar[$glyph] AS $char) {
934 if ($char != 0 && $char != 65535) {
935 $w = intval(round($scale*$aw));
936 if ($w == 0) { $w = 65535; }
937 if ($char < 196608) {
938 $this->charWidths[$char*2] = chr($w >> 8);
939 $this->charWidths[$char*2 + 1] = chr($w & 0xFF);
948 $this->charWidths[0] = chr($nCharWidths >> 8);
949 $this->charWidths[1] = chr($nCharWidths & 0xFF);
991 $this->maxUniChar = 0;
992 $this->
seek($unicode_cmap_offset + 2);
994 $limit = $unicode_cmap_offset + $length;
1002 $startCount =
array();
1007 $idRangeOffset =
array();
1010 for (
$n=0;
$n<$segCount;
$n++) {
1011 $endpoint = ($endCount[
$n] + 1);
1012 for ($unichar=$startCount[
$n];$unichar<$endpoint;$unichar++) {
1013 if ($idRangeOffset[
$n] == 0)
1014 $glyph = ($unichar + $idDelta[
$n]) & 0xFFFF;
1016 $offset = ($unichar - $startCount[
$n]) * 2 + $idRangeOffset[
$n];
1017 $offset = $idRangeOffset_start + 2 *
$n + $offset;
1018 if ($offset >= $limit)
1023 $glyph = ($glyph + $idDelta[
$n]) & 0xFFFF;
1027 if ($unichar < 196608) { $this->maxUniChar = max($unichar,$this->maxUniChar); }
1028 $glyphToChar[$glyph][] = $unichar;