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) {
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) {
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) {
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) {
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');
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" . substr($opost,4,12) .
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
624 $this->
add(
'post', $post);
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) {
670 $endCode =
$start + (count($subrange)-1);
677 foreach($range AS
$start=>$subrange) {
682 foreach($range AS
$start=>$subrange) {
683 $idDelta = -(
$start-$subrange[0]);
684 $n += count($subrange);
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", substr(
$data,0,2));
752 if ($glyphLen > 2 && (
$up[1] & (1 << 15)) ) {
755 $nComponentElements = 0;
757 $nComponentElements += 1;
758 $up = unpack(
"n", substr(
$data,$pos_in_glyph,2));
760 $up = unpack(
"n", substr(
$data,$pos_in_glyph+2,2));
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;
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'];
851 $glyphPos = $this->glyphPos[$originalGlyphIdx];
852 $glyphLen = $this->glyphPos[$originalGlyphIdx + 1] -
$glyphPos;
858 if ($numberOfContours < 0) {
864 if (!isset($glyphSet[$glyphIdx])) {
865 $glyphSet[$glyphIdx] = count($subsetglyphs);
866 $subsetglyphs[$glyphIdx] =
true;
868 $savepos = ftell($this->fh);
870 $this->
seek($savepos);
887 function getHMTX($numberOfHMetrics, $numGlyphs, &$glyphToChar, $scale) {
890 $this->charWidths = str_pad(
'', 256*256*2,
"\x00");
892 if (($numberOfHMetrics*4) < $this->maxStrLenRead) {
894 $arr = unpack(
"n*",
$data);
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);
928 $arr = unpack(
"n*",
$data);
929 $diff = $numGlyphs-$numberOfHMetrics;
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];
1023 $glyph = ($glyph + $idDelta[
$n]) & 0xFFFF;
1027 if ($unichar < 196608) { $this->maxUniChar = max($unichar,$this->maxUniChar); }
1028 $glyphToChar[$glyph][] = $unichar;