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