1 # -*- encoding: utf-8 -*-
4 # Copyright (C) 2006-2011 Jörg Lehmann <joergl@users.sourceforge.net>
5 # Copyright (C) 2007-2011 André Wobst <wobsta@users.sourceforge.net>
7 # This file is part of PyX (http://pyx.sourceforge.net/).
9 # PyX is free software; you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation; either version 2 of the License, or
12 # (at your option) any later version.
14 # PyX is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with PyX; if not, write to the Free Software
21 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
26 unicodestring
= {u
" ": "space",
122 u
"\xa1": "exclamdown",
127 u
"\xa6": "brokenbar",
130 u
"\xa9": "copyright",
131 u
"\xaa": "ordfeminine",
132 u
"\xab": "guillemotleft",
133 u
"\xac": "logicalnot",
135 u
"\xae": "registered",
138 u
"\xb1": "plusminus",
140 u
"\xb6": "paragraph",
141 u
"\xb7": "periodcentered",
143 u
"\xba": "ordmasculine",
144 u
"\xbb": "guillemotright",
145 u
"\xbc": "onequarter",
147 u
"\xbe": "threequarters",
148 u
"\xbf": "questiondown",
151 u
"\xc2": "Acircumflex",
153 u
"\xc4": "Adieresis",
159 u
"\xca": "Ecircumflex",
160 u
"\xcb": "Edieresis",
163 u
"\xce": "Icircumflex",
164 u
"\xcf": "Idieresis",
169 u
"\xd4": "Ocircumflex",
171 u
"\xd6": "Odieresis",
176 u
"\xdb": "Ucircumflex",
177 u
"\xdc": "Udieresis",
180 u
"\xdf": "germandbls",
183 u
"\xe2": "acircumflex",
185 u
"\xe4": "adieresis",
191 u
"\xea": "ecircumflex",
192 u
"\xeb": "edieresis",
195 u
"\xee": "icircumflex",
196 u
"\xef": "idieresis",
201 u
"\xf4": "ocircumflex",
203 u
"\xf6": "odieresis",
208 u
"\xfb": "ucircumflex",
209 u
"\xfc": "udieresis",
212 u
"\xff": "ydieresis",
213 u
"\u0100": "Amacron",
214 u
"\u0101": "amacron",
217 u
"\u0104": "Aogonek",
218 u
"\u0105": "aogonek",
221 u
"\u0108": "Ccircumflex",
222 u
"\u0109": "ccircumflex",
223 u
"\u010a": "Cdotaccent",
224 u
"\u010b": "cdotaccent",
231 u
"\u0112": "Emacron",
232 u
"\u0113": "emacron",
235 u
"\u0116": "Edotaccent",
236 u
"\u0117": "edotaccent",
237 u
"\u0118": "Eogonek",
238 u
"\u0119": "eogonek",
241 u
"\u011c": "Gcircumflex",
242 u
"\u011d": "gcircumflex",
245 u
"\u0120": "Gdotaccent",
246 u
"\u0121": "gdotaccent",
247 u
"\u0122": "Gcommaaccent",
248 u
"\u0123": "gcommaaccent",
249 u
"\u0124": "Hcircumflex",
250 u
"\u0125": "hcircumflex",
255 u
"\u012a": "Imacron",
256 u
"\u012b": "imacron",
259 u
"\u012e": "Iogonek",
260 u
"\u012f": "iogonek",
261 u
"\u0130": "Idotaccent",
262 u
"\u0131": "dotlessi",
265 u
"\u0134": "Jcircumflex",
266 u
"\u0135": "jcircumflex",
267 u
"\u0136": "Kcommaaccent",
268 u
"\u0137": "kcommaaccent",
269 u
"\u0138": "kgreenlandic",
272 u
"\u013b": "Lcommaaccent",
273 u
"\u013c": "lcommaaccent",
282 u
"\u0145": "Ncommaaccent",
283 u
"\u0146": "ncommaaccent",
286 u
"\u0149": "napostrophe",
289 u
"\u014c": "Omacron",
290 u
"\u014d": "omacron",
293 u
"\u0150": "Ohungarumlaut",
294 u
"\u0151": "ohungarumlaut",
299 u
"\u0156": "Rcommaaccent",
300 u
"\u0157": "rcommaaccent",
305 u
"\u015c": "Scircumflex",
306 u
"\u015d": "scircumflex",
307 u
"\u015e": "Scedilla",
308 u
"\u015f": "scedilla",
311 u
"\u0162": "Tcommaaccent",
312 u
"\u0163": "tcommaaccent",
319 u
"\u016a": "Umacron",
320 u
"\u016b": "umacron",
325 u
"\u0170": "Uhungarumlaut",
326 u
"\u0171": "uhungarumlaut",
327 u
"\u0172": "Uogonek",
328 u
"\u0173": "uogonek",
329 u
"\u0174": "Wcircumflex",
330 u
"\u0175": "wcircumflex",
331 u
"\u0176": "Ycircumflex",
332 u
"\u0177": "ycircumflex",
333 u
"\u0178": "Ydieresis",
336 u
"\u017b": "Zdotaccent",
337 u
"\u017c": "zdotaccent",
348 u
"\u01fa": "Aringacute",
349 u
"\u01fb": "aringacute",
350 u
"\u01fc": "AEacute",
351 u
"\u01fd": "aeacute",
352 u
"\u01fe": "Oslashacute",
353 u
"\u01ff": "oslashacute",
354 u
"\u0218": "Scommaaccent",
355 u
"\u0219": "scommaaccent",
356 u
"\u02bc": "afii57929",
357 u
"\u02bd": "afii64937",
358 u
"\u02c6": "circumflex",
362 u
"\u02d9": "dotaccent",
366 u
"\u02dd": "hungarumlaut",
367 u
"\u0300": "gravecomb",
368 u
"\u0301": "acutecomb",
369 u
"\u0303": "tildecomb",
370 u
"\u0309": "hookabovecomb",
371 u
"\u0323": "dotbelowcomb",
373 u
"\u0385": "dieresistonos",
374 u
"\u0386": "Alphatonos",
375 u
"\u0387": "anoteleia",
376 u
"\u0388": "Epsilontonos",
377 u
"\u0389": "Etatonos",
378 u
"\u038a": "Iotatonos",
379 u
"\u038c": "Omicrontonos",
380 u
"\u038e": "Upsilontonos",
381 u
"\u038f": "Omegatonos",
382 u
"\u0390": "iotadieresistonos",
387 u
"\u0395": "Epsilon",
397 u
"\u039f": "Omicron",
402 u
"\u03a5": "Upsilon",
407 u
"\u03aa": "Iotadieresis",
408 u
"\u03ab": "Upsilondieresis",
409 u
"\u03ac": "alphatonos",
410 u
"\u03ad": "epsilontonos",
411 u
"\u03ae": "etatonos",
412 u
"\u03af": "iotatonos",
413 u
"\u03b0": "upsilondieresistonos",
418 u
"\u03b5": "epsilon",
428 u
"\u03bf": "omicron",
434 u
"\u03c5": "upsilon",
439 u
"\u03ca": "iotadieresis",
440 u
"\u03cb": "upsilondieresis",
441 u
"\u03cc": "omicrontonos",
442 u
"\u03cd": "upsilontonos",
443 u
"\u03ce": "omegatonos",
445 u
"\u03d2": "Upsilon1",
448 u
"\u0401": "afii10023",
449 u
"\u0402": "afii10051",
450 u
"\u0403": "afii10052",
451 u
"\u0404": "afii10053",
452 u
"\u0405": "afii10054",
453 u
"\u0406": "afii10055",
454 u
"\u0407": "afii10056",
455 u
"\u0408": "afii10057",
456 u
"\u0409": "afii10058",
457 u
"\u040a": "afii10059",
458 u
"\u040b": "afii10060",
459 u
"\u040c": "afii10061",
460 u
"\u040e": "afii10062",
461 u
"\u040f": "afii10145",
462 u
"\u0410": "afii10017",
463 u
"\u0411": "afii10018",
464 u
"\u0412": "afii10019",
465 u
"\u0413": "afii10020",
466 u
"\u0414": "afii10021",
467 u
"\u0415": "afii10022",
468 u
"\u0416": "afii10024",
469 u
"\u0417": "afii10025",
470 u
"\u0418": "afii10026",
471 u
"\u0419": "afii10027",
472 u
"\u041a": "afii10028",
473 u
"\u041b": "afii10029",
474 u
"\u041c": "afii10030",
475 u
"\u041d": "afii10031",
476 u
"\u041e": "afii10032",
477 u
"\u041f": "afii10033",
478 u
"\u0420": "afii10034",
479 u
"\u0421": "afii10035",
480 u
"\u0422": "afii10036",
481 u
"\u0423": "afii10037",
482 u
"\u0424": "afii10038",
483 u
"\u0425": "afii10039",
484 u
"\u0426": "afii10040",
485 u
"\u0427": "afii10041",
486 u
"\u0428": "afii10042",
487 u
"\u0429": "afii10043",
488 u
"\u042a": "afii10044",
489 u
"\u042b": "afii10045",
490 u
"\u042c": "afii10046",
491 u
"\u042d": "afii10047",
492 u
"\u042e": "afii10048",
493 u
"\u042f": "afii10049",
494 u
"\u0430": "afii10065",
495 u
"\u0431": "afii10066",
496 u
"\u0432": "afii10067",
497 u
"\u0433": "afii10068",
498 u
"\u0434": "afii10069",
499 u
"\u0435": "afii10070",
500 u
"\u0436": "afii10072",
501 u
"\u0437": "afii10073",
502 u
"\u0438": "afii10074",
503 u
"\u0439": "afii10075",
504 u
"\u043a": "afii10076",
505 u
"\u043b": "afii10077",
506 u
"\u043c": "afii10078",
507 u
"\u043d": "afii10079",
508 u
"\u043e": "afii10080",
509 u
"\u043f": "afii10081",
510 u
"\u0440": "afii10082",
511 u
"\u0441": "afii10083",
512 u
"\u0442": "afii10084",
513 u
"\u0443": "afii10085",
514 u
"\u0444": "afii10086",
515 u
"\u0445": "afii10087",
516 u
"\u0446": "afii10088",
517 u
"\u0447": "afii10089",
518 u
"\u0448": "afii10090",
519 u
"\u0449": "afii10091",
520 u
"\u044a": "afii10092",
521 u
"\u044b": "afii10093",
522 u
"\u044c": "afii10094",
523 u
"\u044d": "afii10095",
524 u
"\u044e": "afii10096",
525 u
"\u044f": "afii10097",
526 u
"\u0451": "afii10071",
527 u
"\u0452": "afii10099",
528 u
"\u0453": "afii10100",
529 u
"\u0454": "afii10101",
530 u
"\u0455": "afii10102",
531 u
"\u0456": "afii10103",
532 u
"\u0457": "afii10104",
533 u
"\u0458": "afii10105",
534 u
"\u0459": "afii10106",
535 u
"\u045a": "afii10107",
536 u
"\u045b": "afii10108",
537 u
"\u045c": "afii10109",
538 u
"\u045e": "afii10110",
539 u
"\u045f": "afii10193",
540 u
"\u0462": "afii10146",
541 u
"\u0463": "afii10194",
542 u
"\u0472": "afii10147",
543 u
"\u0473": "afii10195",
544 u
"\u0474": "afii10148",
545 u
"\u0475": "afii10196",
546 u
"\u0490": "afii10050",
547 u
"\u0491": "afii10098",
548 u
"\u04d9": "afii10846",
549 u
"\u05b0": "afii57799",
550 u
"\u05b1": "afii57801",
551 u
"\u05b2": "afii57800",
552 u
"\u05b3": "afii57802",
553 u
"\u05b4": "afii57793",
554 u
"\u05b5": "afii57794",
555 u
"\u05b6": "afii57795",
556 u
"\u05b7": "afii57798",
557 u
"\u05b8": "afii57797",
558 u
"\u05b9": "afii57806",
559 u
"\u05bb": "afii57796",
560 u
"\u05bc": "afii57807",
561 u
"\u05bd": "afii57839",
562 u
"\u05be": "afii57645",
563 u
"\u05bf": "afii57841",
564 u
"\u05c0": "afii57842",
565 u
"\u05c1": "afii57804",
566 u
"\u05c2": "afii57803",
567 u
"\u05c3": "afii57658",
568 u
"\u05d0": "afii57664",
569 u
"\u05d1": "afii57665",
570 u
"\u05d2": "afii57666",
571 u
"\u05d3": "afii57667",
572 u
"\u05d4": "afii57668",
573 u
"\u05d5": "afii57669",
574 u
"\u05d6": "afii57670",
575 u
"\u05d7": "afii57671",
576 u
"\u05d8": "afii57672",
577 u
"\u05d9": "afii57673",
578 u
"\u05da": "afii57674",
579 u
"\u05db": "afii57675",
580 u
"\u05dc": "afii57676",
581 u
"\u05dd": "afii57677",
582 u
"\u05de": "afii57678",
583 u
"\u05df": "afii57679",
584 u
"\u05e0": "afii57680",
585 u
"\u05e1": "afii57681",
586 u
"\u05e2": "afii57682",
587 u
"\u05e3": "afii57683",
588 u
"\u05e4": "afii57684",
589 u
"\u05e5": "afii57685",
590 u
"\u05e6": "afii57686",
591 u
"\u05e7": "afii57687",
592 u
"\u05e8": "afii57688",
593 u
"\u05e9": "afii57689",
594 u
"\u05ea": "afii57690",
595 u
"\u05f0": "afii57716",
596 u
"\u05f1": "afii57717",
597 u
"\u05f2": "afii57718",
598 u
"\u060c": "afii57388",
599 u
"\u061b": "afii57403",
600 u
"\u061f": "afii57407",
601 u
"\u0621": "afii57409",
602 u
"\u0622": "afii57410",
603 u
"\u0623": "afii57411",
604 u
"\u0624": "afii57412",
605 u
"\u0625": "afii57413",
606 u
"\u0626": "afii57414",
607 u
"\u0627": "afii57415",
608 u
"\u0628": "afii57416",
609 u
"\u0629": "afii57417",
610 u
"\u062a": "afii57418",
611 u
"\u062b": "afii57419",
612 u
"\u062c": "afii57420",
613 u
"\u062d": "afii57421",
614 u
"\u062e": "afii57422",
615 u
"\u062f": "afii57423",
616 u
"\u0630": "afii57424",
617 u
"\u0631": "afii57425",
618 u
"\u0632": "afii57426",
619 u
"\u0633": "afii57427",
620 u
"\u0634": "afii57428",
621 u
"\u0635": "afii57429",
622 u
"\u0636": "afii57430",
623 u
"\u0637": "afii57431",
624 u
"\u0638": "afii57432",
625 u
"\u0639": "afii57433",
626 u
"\u063a": "afii57434",
627 u
"\u0640": "afii57440",
628 u
"\u0641": "afii57441",
629 u
"\u0642": "afii57442",
630 u
"\u0643": "afii57443",
631 u
"\u0644": "afii57444",
632 u
"\u0645": "afii57445",
633 u
"\u0646": "afii57446",
634 u
"\u0647": "afii57470",
635 u
"\u0648": "afii57448",
636 u
"\u0649": "afii57449",
637 u
"\u064a": "afii57450",
638 u
"\u064b": "afii57451",
639 u
"\u064c": "afii57452",
640 u
"\u064d": "afii57453",
641 u
"\u064e": "afii57454",
642 u
"\u064f": "afii57455",
643 u
"\u0650": "afii57456",
644 u
"\u0651": "afii57457",
645 u
"\u0652": "afii57458",
646 u
"\u0660": "afii57392",
647 u
"\u0661": "afii57393",
648 u
"\u0662": "afii57394",
649 u
"\u0663": "afii57395",
650 u
"\u0664": "afii57396",
651 u
"\u0665": "afii57397",
652 u
"\u0666": "afii57398",
653 u
"\u0667": "afii57399",
654 u
"\u0668": "afii57400",
655 u
"\u0669": "afii57401",
656 u
"\u066a": "afii57381",
657 u
"\u066d": "afii63167",
658 u
"\u0679": "afii57511",
659 u
"\u067e": "afii57506",
660 u
"\u0686": "afii57507",
661 u
"\u0688": "afii57512",
662 u
"\u0691": "afii57513",
663 u
"\u0698": "afii57508",
664 u
"\u06a4": "afii57505",
665 u
"\u06af": "afii57509",
666 u
"\u06ba": "afii57514",
667 u
"\u06d2": "afii57519",
668 u
"\u06d5": "afii57534",
673 u
"\u1e84": "Wdieresis",
674 u
"\u1e85": "wdieresis",
677 u
"\u200c": "afii61664",
678 u
"\u200d": "afii301",
679 u
"\u200e": "afii299",
680 u
"\u200f": "afii300",
681 u
"\u2012": "figuredash",
684 u
"\u2015": "afii00208",
685 u
"\u2017": "underscoredbl",
686 u
"\u2018": "quoteleft",
687 u
"\u2019": "quoteright",
688 u
"\u201a": "quotesinglbase",
689 u
"\u201b": "quotereversed",
690 u
"\u201c": "quotedblleft",
691 u
"\u201d": "quotedblright",
692 u
"\u201e": "quotedblbase",
694 u
"\u2021": "daggerdbl",
696 u
"\u2024": "onedotenleader",
697 u
"\u2025": "twodotenleader",
698 u
"\u2026": "ellipsis",
699 u
"\u202c": "afii61573",
700 u
"\u202d": "afii61574",
701 u
"\u202e": "afii61575",
702 u
"\u2030": "perthousand",
705 u
"\u2039": "guilsinglleft",
706 u
"\u203a": "guilsinglright",
707 u
"\u203c": "exclamdbl",
708 u
"\u2044": "fraction",
709 u
"\u20a1": "colonmonetary",
713 u
"\u20aa": "afii57636",
716 u
"\u2105": "afii61248",
717 u
"\u2111": "Ifraktur",
718 u
"\u2113": "afii61289",
719 u
"\u2116": "afii61352",
720 u
"\u2118": "weierstrass",
721 u
"\u211c": "Rfraktur",
722 u
"\u211e": "prescription",
723 u
"\u2122": "trademark",
724 u
"\u212e": "estimated",
726 u
"\u2153": "onethird",
727 u
"\u2154": "twothirds",
728 u
"\u215b": "oneeighth",
729 u
"\u215c": "threeeighths",
730 u
"\u215d": "fiveeighths",
731 u
"\u215e": "seveneighths",
732 u
"\u2190": "arrowleft",
733 u
"\u2191": "arrowup",
734 u
"\u2192": "arrowright",
735 u
"\u2193": "arrowdown",
736 u
"\u2194": "arrowboth",
737 u
"\u2195": "arrowupdn",
738 u
"\u21a8": "arrowupdnbse",
739 u
"\u21b5": "carriagereturn",
740 u
"\u21d0": "arrowdblleft",
741 u
"\u21d1": "arrowdblup",
742 u
"\u21d2": "arrowdblright",
743 u
"\u21d3": "arrowdbldown",
744 u
"\u21d4": "arrowdblboth",
745 u
"\u2200": "universal",
746 u
"\u2202": "partialdiff",
747 u
"\u2203": "existential",
748 u
"\u2205": "emptyset",
749 u
"\u2207": "gradient",
750 u
"\u2208": "element",
751 u
"\u2209": "notelement",
752 u
"\u220b": "suchthat",
753 u
"\u220f": "product",
754 u
"\u2211": "summation",
756 u
"\u2215": "fraction",
757 u
"\u2217": "asteriskmath",
758 u
"\u2219": "periodcentered",
759 u
"\u221a": "radical",
760 u
"\u221d": "proportional",
761 u
"\u221e": "infinity",
762 u
"\u221f": "orthogonal",
764 u
"\u2227": "logicaland",
765 u
"\u2228": "logicalor",
766 u
"\u2229": "intersection",
768 u
"\u222b": "integral",
769 u
"\u2234": "therefore",
770 u
"\u223c": "similar",
771 u
"\u2245": "congruent",
772 u
"\u2248": "approxequal",
773 u
"\u2260": "notequal",
774 u
"\u2261": "equivalence",
775 u
"\u2264": "lessequal",
776 u
"\u2265": "greaterequal",
777 u
"\u2282": "propersubset",
778 u
"\u2283": "propersuperset",
779 u
"\u2284": "notsubset",
780 u
"\u2286": "reflexsubset",
781 u
"\u2287": "reflexsuperset",
782 u
"\u2295": "circleplus",
783 u
"\u2297": "circlemultiply",
784 u
"\u22a5": "perpendicular",
785 u
"\u22c5": "dotmath",
787 u
"\u2310": "revlogicalnot",
788 u
"\u2320": "integraltp",
789 u
"\u2321": "integralbt",
790 u
"\u2329": "angleleft",
791 u
"\u232a": "angleright",
792 u
"\u2500": "SF100000",
793 u
"\u2502": "SF110000",
794 u
"\u250c": "SF010000",
795 u
"\u2510": "SF030000",
796 u
"\u2514": "SF020000",
797 u
"\u2518": "SF040000",
798 u
"\u251c": "SF080000",
799 u
"\u2524": "SF090000",
800 u
"\u252c": "SF060000",
801 u
"\u2534": "SF070000",
802 u
"\u253c": "SF050000",
803 u
"\u2550": "SF430000",
804 u
"\u2551": "SF240000",
805 u
"\u2552": "SF510000",
806 u
"\u2553": "SF520000",
807 u
"\u2554": "SF390000",
808 u
"\u2555": "SF220000",
809 u
"\u2556": "SF210000",
810 u
"\u2557": "SF250000",
811 u
"\u2558": "SF500000",
812 u
"\u2559": "SF490000",
813 u
"\u255a": "SF380000",
814 u
"\u255b": "SF280000",
815 u
"\u255c": "SF270000",
816 u
"\u255d": "SF260000",
817 u
"\u255e": "SF360000",
818 u
"\u255f": "SF370000",
819 u
"\u2560": "SF420000",
820 u
"\u2561": "SF190000",
821 u
"\u2562": "SF200000",
822 u
"\u2563": "SF230000",
823 u
"\u2564": "SF470000",
824 u
"\u2565": "SF480000",
825 u
"\u2566": "SF410000",
826 u
"\u2567": "SF450000",
827 u
"\u2568": "SF460000",
828 u
"\u2569": "SF400000",
829 u
"\u256a": "SF540000",
830 u
"\u256b": "SF530000",
831 u
"\u256c": "SF440000",
832 u
"\u2580": "upblock",
833 u
"\u2584": "dnblock",
835 u
"\u258c": "lfblock",
836 u
"\u2590": "rtblock",
837 u
"\u2591": "ltshade",
839 u
"\u2593": "dkshade",
840 u
"\u25a0": "filledbox",
844 u
"\u25ac": "filledrect",
845 u
"\u25b2": "triagup",
846 u
"\u25ba": "triagrt",
847 u
"\u25bc": "triagdn",
848 u
"\u25c4": "triaglf",
849 u
"\u25ca": "lozenge",
852 u
"\u25d8": "invbullet",
853 u
"\u25d9": "invcircle",
854 u
"\u25e6": "openbullet",
855 u
"\u263a": "smileface",
856 u
"\u263b": "invsmileface",
863 u
"\u2666": "diamond",
864 u
"\u266a": "musicalnote",
865 u
"\u266b": "musicalnotedbl",
869 class AFMError(Exception):
876 _READ_CHARMETRICS
= 3
883 # various parsing functions
888 raise AFMError("Expecting int, got '%s'" % s
)
892 if s
[0] != "<" or s
[-1] != ">":
894 return int(s
[1:-1], 16)
896 raise AFMError("Expecting hexadecimal int, got '%s'" % s
)
902 raise AFMError("Expecting float, got '%s'" % s
)
904 def _parsefloats(s
, nos
):
907 result
= map(float, numbers
)
908 if len(result
) != nos
:
911 raise AFMError("Expecting list of %d numbers, got '%s'" % (s
, nos
))
915 # XXX: check for invalid characters in s
925 raise AFMError("Expecting boolean, got '%s'" % s
)
928 class AFMcharmetrics
:
929 def __init__(self
, code
, widths
=None, vvector
=None, name
=None, bbox
=None, ligatures
=None):
932 self
.widths
= [None] * 2
935 self
.vvector
= vvector
938 if ligatures
is None:
941 self
.ligatures
= ligatures
945 def __init__(self
, degree
, min_ptsize
, min_kern
, max_ptsize
, max_kern
):
947 self
.min_ptsize
= min_ptsize
948 self
.min_kern
= min_kern
949 self
.max_ptsize
= max_ptsize
950 self
.max_kern
= max_kern
954 def __init__(self
, name1
, name2
, x
, y
):
962 def __init__(self
, name
, parts
):
967 class AFMfile(metric
.metric
):
969 def __init__(self
, file):
970 self
.metricssets
= 0 # int, optional
971 self
.fontname
= None # str, required
972 self
.fullname
= None # str, optional
973 self
.familyname
= None # str, optional
974 self
.weight
= None # str, optional
975 self
.fontbbox
= None # 4 floats, required
976 self
.version
= None # str, optional
977 self
.notice
= None # str, optional
978 self
.encodingscheme
= None # str, optional
979 self
.mappingscheme
= None # int, optional (not present in base font programs)
980 self
.escchar
= None # int, required if mappingscheme == 3
981 self
.characterset
= None # str, optional
982 self
.characters
= None # int, optional
983 self
.isbasefont
= 1 # bool, optional
984 self
.vvector
= None # 2 floats, required if metricssets == 2
985 self
.isfixedv
= None # bool, default: true if vvector present, false otherwise
986 self
.capheight
= None # float, optional
987 self
.xheight
= None # float, optional
988 self
.ascender
= None # float, optional
989 self
.descender
= None # float, optional
990 self
.stdhw
= None # float, optional
991 self
.stdvw
= None # float, optional
992 self
.underlinepositions
= [None] * 2 # int, optional (for each direction)
993 self
.underlinethicknesses
= [None] * 2 # float, optional (for each direction)
994 self
.italicangles
= [None] * 2 # float, optional (for each direction)
995 self
.charwidths
= [None] * 2 # 2 floats, optional (for each direction)
996 self
.isfixedpitchs
= [None] * 2 # bool, optional (for each direction)
997 self
.charmetrics
= None # list of character metrics information, optional
998 self
.charmetricsdict
= {} # helper dictionary mapping glyph names to character metrics information
999 self
.trackkerns
= None # list of track kernings, optional
1000 self
.kernpairs
= [None] * 2 # list of list of kerning pairs (for each direction), optional
1001 self
.kernpairsdict
= {} # helper dictionary mapping glyph names to kerning pairs, first direction
1002 self
.kernpairsdict1
= {} # helper dictionary mapping glyph names to kerning pairs, second direction
1003 self
.composites
= None # list of composite character data sets, optional
1005 if self
.isfixedv
is None:
1006 self
.isfixedv
= self
.vvector
is not None
1007 # XXX we should check the constraints on some parameters
1009 # the following methods process a line when the reader is in the corresponding
1010 # state and return the new state
1011 def _processline_start(self
, line
):
1012 key
, args
= line
.split(None, 1)
1013 if key
!= "StartFontMetrics":
1014 raise AFMError("Expecting StartFontMetrics, no found")
1015 return _READ_MAIN
, None
1017 def _processline_main(self
, line
):
1019 key
, args
= line
.split(None, 1)
1022 if key
== "Comment":
1023 return _READ_MAIN
, None
1024 elif key
== "MetricsSets":
1025 self
.metricssets
= _parseint(args
)
1026 if direction
is not None:
1027 raise AFMError("MetricsSets not allowed after first (implicit) StartDirection")
1028 elif key
== "FontName":
1029 self
.fontname
= _parsestr(args
)
1030 elif key
== "FullName":
1031 self
.fullname
= _parsestr(args
)
1032 elif key
== "FamilyName":
1033 self
.familyname
= _parsestr(args
)
1034 elif key
== "Weight":
1035 self
.weight
= _parsestr(args
)
1036 elif key
== "FontBBox":
1037 self
.fontbbox
= _parsefloats(args
, 4)
1038 elif key
== "Version":
1039 self
.version
= _parsestr(args
)
1040 elif key
== "Notice":
1041 self
.notice
= _parsestr(args
)
1042 elif key
== "EncodingScheme":
1043 self
.encodingscheme
= _parsestr(args
)
1044 elif key
== "MappingScheme":
1045 self
.mappingscheme
= _parseint(args
)
1046 elif key
== "EscChar":
1047 self
.escchar
= _parseint(args
)
1048 elif key
== "CharacterSet":
1049 self
.characterset
= _parsestr(args
)
1050 elif key
== "Characters":
1051 self
.characters
= _parseint(args
)
1052 elif key
== "IsBaseFont":
1053 self
.isbasefont
= _parsebool(args
)
1054 elif key
== "VVector":
1055 self
.vvector
= _parsefloats(args
, 2)
1056 elif key
== "IsFixedV":
1057 self
.isfixedv
= _parsebool(args
)
1058 elif key
== "CapHeight":
1059 self
.capheight
= _parsefloat(args
)
1060 elif key
== "XHeight":
1061 self
.xheight
= _parsefloat(args
)
1062 elif key
== "Ascender":
1063 self
.ascender
= _parsefloat(args
)
1064 elif key
== "Descender":
1065 self
.descender
= _parsefloat(args
)
1066 elif key
== "StdHW":
1067 self
.stdhw
= _parsefloat(args
)
1068 elif key
== "StdVW":
1069 self
.stdvw
= _parsefloat(args
)
1070 elif key
== "StartDirection":
1071 direction
= _parseint(args
)
1072 if 0 <= direction
<= 2:
1073 return _READ_DIRECTION
, direction
1075 raise AFMError("Wrong direction number %d" % direction
)
1076 elif (key
== "UnderLinePosition" or key
== "UnderlineThickness" or key
== "ItalicAngle" or
1077 key
== "Charwidth" or key
== "IsFixedPitch"):
1078 # we implicitly entered a direction section, so we should process the line again
1079 return self
._processline
_direction
(line
, 0)
1080 elif key
== "StartCharMetrics":
1081 if self
.charmetrics
is not None:
1082 raise AFMError("Multiple character metrics sections")
1083 self
.charmetrics
= [None] * _parseint(args
)
1084 return _READ_CHARMETRICS
, 0
1085 elif key
== "StartKernData":
1086 return _READ_KERNDATA
, None
1087 elif key
== "StartComposites":
1088 if self
.composites
is not None:
1089 raise AFMError("Multiple composite character data sections")
1090 self
.composites
= [None] * _parseint(args
)
1091 return _READ_COMPOSITES
, 0
1092 elif key
== "EndFontMetrics":
1093 return _READ_END
, None
1094 elif key
[0] in string
.lowercase
:
1095 # ignoring private commands
1097 return _READ_MAIN
, None
1099 def _processline_direction(self
, line
, direction
):
1101 key
, args
= line
.split(None, 1)
1104 if key
== "UnderLinePosition":
1105 self
.underlinepositions
[direction
] = _parseint(args
)
1106 elif key
== "UnderlineThickness":
1107 self
.underlinethicknesses
[direction
] = _parsefloat(args
)
1108 elif key
== "ItalicAngle":
1109 self
.italicangles
[direction
] = _parsefloat(args
)
1110 elif key
== "Charwidth":
1111 self
.charwidths
[direction
] = _parsefloats(args
, 2)
1112 elif key
== "IsFixedPitch":
1113 self
.isfixedpitchs
[direction
] = _parsebool(args
)
1114 elif key
== "EndDirection":
1115 return _READ_MAIN
, None
1117 # we assume that we are implicitly leaving the direction section again,
1118 # so try to reprocess the line in the header reader state
1119 return self
._processline
_main
(line
)
1120 return _READ_DIRECTION
, direction
1122 def _processline_charmetrics(self
, line
, charno
):
1123 if line
.rstrip() == "EndCharMetrics":
1124 if charno
!= len(self
.charmetrics
):
1125 raise AFMError("Fewer character metrics than expected")
1126 return _READ_MAIN
, None
1127 if charno
>= len(self
.charmetrics
):
1128 raise AFMError("More character metrics than expected")
1132 for s
in line
.split(";"):
1136 key
, args
= s
.split(None, 1)
1138 if char
is not None:
1139 raise AFMError("Cannot define char code twice")
1140 char
= AFMcharmetrics(_parseint(args
))
1142 if char
is not None:
1143 raise AFMError("Cannot define char code twice")
1144 char
= AFMcharmetrics(_parsehex(args
))
1145 elif key
== "WX" or key
== "W0X":
1146 char
.widths
[0] = _parsefloat(args
), 0
1148 char
.widths
[1] = _parsefloat(args
), 0
1149 elif key
== "WY" or key
== "W0Y":
1150 char
.widths
[0] = 0, _parsefloat(args
)
1152 char
.widths
[1] = 0, _parsefloat(args
)
1153 elif key
== "W" or key
== "W0":
1154 char
.widths
[0] = _parsefloats(args
, 2)
1156 char
.widths
[1] = _parsefloats(args
, 2)
1158 char
.vvector
= _parsefloats(args
, 2)
1160 # XXX: we should check that name is valid (no whitespace, etc.)
1162 char
.name
= _parsestr(args
)
1164 char
.bbox
= _parsefloats(args
, 4)
1166 successor
, ligature
= args
.split(None, 1)
1167 char
.ligatures
.append((_parsestr(successor
), ligature
))
1169 raise AFMError("Undefined command in character widths specification: '%s'", s
)
1171 raise AFMError("Character metrics not defined")
1173 self
.charmetrics
[charno
] = char
1175 self
.charmetricsdict
[char
.name
] = char
1176 return _READ_CHARMETRICS
, charno
+1
1178 def _processline_kerndata(self
, line
):
1180 key
, args
= line
.split(None, 1)
1183 if key
== "Comment":
1184 return _READ_KERNDATA
, None
1185 if key
== "StartTrackKern":
1186 if self
.trackkerns
is not None:
1187 raise AFMError("Multiple track kernings data sections")
1188 self
.trackkerns
= [None] * _parseint(args
)
1189 return _READ_TRACKKERN
, 0
1190 elif key
== "StartKernPairs" or key
== "StartKernPairs0":
1191 if self
.kernpairs
[0] is not None:
1192 raise AFMError("Multiple kerning pairs data sections for direction 0")
1193 self
.kernpairs
[0] = [None] * _parseint(args
)
1194 return _READ_KERNPAIRS
, (0, 0)
1195 elif key
== "StartKernPairs1":
1196 if self
.kernpairs
[1] is not None:
1197 raise AFMError("Multiple kerning pairs data sections for direction 1")
1198 self
.kernpairs
[1] = [None] * _parseint(args
)
1199 return _READ_KERNPAIRS
, (1, 0)
1200 elif key
== "EndKernData":
1201 return _READ_MAIN
, None
1203 raise AFMError("Unsupported key %s in kerning data section" % key
)
1205 def _processline_trackkern(self
, line
, i
):
1207 key
, args
= line
.split(None, 1)
1210 if key
== "Comment":
1211 return _READ_TRACKKERN
, i
1212 elif key
== "TrackKern":
1213 if i
>= len(self
.trackkerns
):
1214 raise AFMError("More track kerning data sets than expected")
1215 degrees
, args
= args
.split(None, 1)
1216 self
.trackkerns
[i
] = AFMtrackkern(int(degrees
), *_parsefloats(args
, 4))
1217 return _READ_TRACKKERN
, i
+1
1218 elif key
== "EndTrackKern":
1219 if i
< len(self
.trackkerns
):
1220 raise AFMError("Fewer track kerning data sets than expected")
1221 return _READ_KERNDATA
, None
1223 raise AFMError("Unsupported key %s in kerning data section" % key
)
1225 def _processline_kernpairs(self
, line
, (direction
, i
)):
1227 key
, args
= line
.split(None, 1)
1230 if key
== "Comment":
1231 return _READ_KERNPAIRS
, (direction
, i
)
1232 elif key
== "EndKernPairs":
1233 if i
< len(self
.kernpairs
[direction
]):
1234 raise AFMError("Fewer kerning pairs than expected")
1235 return _READ_KERNDATA
, None
1237 if i
>= len(self
.kernpairs
[direction
]):
1238 raise AFMError("More kerning pairs than expected")
1241 name1
, name2
, x
, y
= args
.split()
1243 raise AFMError("Expecting name1, name2, x, y, got '%s'" % args
)
1248 hex1
, hex2
, x
, y
= args
.split()
1250 raise AFMError("Expecting <hex1>, <hex2>, x, y, got '%s'" % args
)
1251 name1
= _parsehex(hex1
)
1252 name2
= _parsehex(hex2
)
1257 name1
, name2
, x
= args
.split()
1259 raise AFMError("Expecting name1, name2, x, got '%s'" % args
)
1262 self
.kernpairs
[direction
][i
] = AFMkernpair(name1
, name2
, _parsefloat(x
), 0)
1265 name1
, name2
, y
= args
.split()
1267 raise AFMError("Expecting name1, name2, y, got '%s'" % args
)
1270 self
.kernpairs
[direction
][i
] = AFMkernpair(name1
, name2
, 0, _parsefloat(y
))
1272 raise AFMError("Unknown key '%s' in kern pair section" % key
)
1273 kernpair
= AFMkernpair(name1
, name2
, x
, y
)
1274 self
.kernpairs
[direction
][i
] = kernpair
1276 self
.kernpairsdict1
[name1
, name2
] = kernpair
1278 self
.kernpairsdict
[name1
, name2
] = kernpair
1279 return _READ_KERNPAIRS
, (direction
, i
+1)
1281 def _processline_composites(self
, line
, i
):
1282 if line
.rstrip() == "EndComposites":
1283 if i
< len(self
.composites
):
1284 raise AFMError("Fewer composite character data sets than expected")
1285 return _READ_MAIN
, None
1286 if i
>= len(self
.composites
):
1287 raise AFMError("More composite character data sets than expected")
1292 for s
in line
.split(";"):
1296 key
, args
= s
.split(None, 1)
1299 name
, no
= args
.split()
1301 raise AFMError("Expecting name number, got '%s'" % args
)
1305 name1
, x
, y
= args
.split()
1307 raise AFMError("Expecting name x y, got '%s'" % args
)
1308 parts
.append((name1
, _parsefloat(x
), _parsefloat(y
)))
1310 raise AFMError("Unknown key '%s' in composite character data section" % key
)
1311 if len(parts
) != no
:
1312 raise AFMError("Wrong number of composite characters")
1313 return _READ_COMPOSITES
, i
+1
1316 # state of the reader, consisting of
1317 # - the main state, i.e. the type of the section
1318 # - a parameter sstate
1319 state
= _READ_START
, None
1320 # Note that we do a line by line processing here, since one
1321 # of the states (_READ_DIRECTION) can be entered implicitly, i.e.
1322 # without a corresponding StartDirection section and we thus
1323 # may need to reprocess a line in the context of the new state
1326 mstate
, sstate
= state
1327 if mstate
== _READ_START
:
1328 state
= self
._processline
_start
(line
)
1330 # except for the first line, any empty will be ignored
1331 if not line
.strip():
1333 if mstate
== _READ_MAIN
:
1334 state
= self
._processline
_main
(line
)
1335 elif mstate
== _READ_DIRECTION
:
1336 state
= self
._processline
_direction
(line
, sstate
)
1337 elif mstate
== _READ_CHARMETRICS
:
1338 state
= self
._processline
_charmetrics
(line
, sstate
)
1339 elif mstate
== _READ_KERNDATA
:
1340 state
= self
._processline
_kerndata
(line
)
1341 elif mstate
== _READ_TRACKKERN
:
1342 state
= self
._processline
_trackkern
(line
, sstate
)
1343 elif mstate
== _READ_KERNPAIRS
:
1344 state
= self
._processline
_kernpairs
(line
, sstate
)
1345 elif mstate
== _READ_COMPOSITES
:
1346 state
= self
._processline
_composites
(line
, sstate
)
1348 raise AFMError("Undefined state in AFM reader")
1350 def fucking_scale(self
):
1354 def width_ds(self
, glyphname
):
1355 return self
.charmetricsdict
[glyphname
].widths
[0][0]
1357 def width_pt(self
, glyphnames
, size
):
1358 return sum([self
.charmetricsdict
[glyphname
].widths
[0][0] for glyphname
in glyphnames
])*size
/self
.fucking_scale()
1360 def height_pt(self
, glyphnames
, size
):
1361 return max([self
.charmetricsdict
[glyphname
].bbox
[3] for glyphname
in glyphnames
])*size
/self
.fucking_scale()
1363 def depth_pt(self
, glyphnames
, size
):
1364 return min([self
.charmetricsdict
[glyphname
].bbox
[1] for glyphname
in glyphnames
])*size
/self
.fucking_scale()
1366 def resolveligatures(self
, glyphnames
):
1368 while i
< len(glyphnames
):
1369 for glyphname
, replacement
in self
.charmetricsdict
[glyphnames
[i
-1]].ligatures
:
1370 if glyphname
== glyphnames
[i
]:
1371 glyphnames
[i
-1] = replacement
1378 def resolvekernings(self
, glyphnames
, size
=None):
1379 result
= [None]*(2*len(glyphnames
)-1)
1380 for i
, glyphname
in enumerate(glyphnames
):
1381 result
[2*i
] = glyphname
1383 kernpair
= self
.kernpairsdict
.get((glyphnames
[i
-1], glyphname
))
1385 if size
is not None:
1386 result
[2*i
-1] = kernpair
.x
*size
/self
.fucking_scale()
1388 result
[2*i
-1] = kernpair
.x
1391 def writePDFfontinfo(self
, file, seriffont
=False, symbolfont
=True):
1393 if self
.isfixedpitchs
[0]:
1401 if self
.italicangles
[0]:
1403 file.write("/Flags %d\n" % flags
)
1404 if self
.italicangles
[0] is not None:
1405 file.write("/ItalicAngles %d\n" % self
.italicangles
[0])
1406 if self
.ascender
is not None:
1407 ascent
= self
.ascender
1408 elif self
.fontbbox
is not None:
1409 ascent
= self
.fontbbox
[3]
1411 ascent
= 1000 # guessed default
1412 file.write("/Ascent %d\n" % ascent
)
1413 if self
.descender
is not None:
1414 descent
= self
.descender
1415 elif self
.fontbbox
is not None:
1416 descent
= self
.fontbbox
[3]
1418 descent
= -200 # guessed default
1419 file.write("/Descent %d\n" % descent
)
1420 if self
.fontbbox
is not None:
1421 file.write("/FontBBox [%d %d %d %d]\n" % tuple(self
.fontbbox
))
1423 # the fontbbox is required, so we have to have to provide some default
1424 file.write("/FontBBox [0 %d 1000 %d]\n" % (descent
, ascent
))
1425 if self
.capheight
is not None:
1426 file.write("/CapHeight %d\n" % self
.capheight
)
1428 # the CapHeight is required, so we have to have to provide some default
1429 file.write("/CapHeight %d\n" % ascent
)
1430 if self
.stdvw
is not None:
1432 elif self
.weight
is not None and ("bold" in self
.weight
.lower() or "black" in self
.weight
.lower()):
1433 stemv
= 120 # guessed default
1435 stemv
= 70 # guessed default
1436 file.write("/StemV %d\n" % stemv
)
1439 if __name__
== "__main__":
1440 a
= AFMfile("/opt/local/share/texmf-dist/fonts/afm/yandy/lucida/lbc.afm")
1441 print a
.charmetrics
[0].name
1442 a
= AFMfile("/usr/share/enscript/hv.afm")
1443 print a
.charmetrics
[32].name