| import unittest |
| import os |
| import sys |
| from fontTools import t1Lib |
| from fontTools.pens.basePen import NullPen |
| from fontTools.misc.psCharStrings import T1CharString |
| import random |
| |
| |
| CWD = os.path.abspath(os.path.dirname(__file__)) |
| DATADIR = os.path.join(CWD, 'data') |
| # I used `tx` to convert PFA to LWFN (stored in the data fork) |
| LWFN = os.path.join(DATADIR, 'TestT1-Regular.lwfn') |
| PFA = os.path.join(DATADIR, 'TestT1-Regular.pfa') |
| PFB = os.path.join(DATADIR, 'TestT1-Regular.pfb') |
| WEIRD_ZEROS = os.path.join(DATADIR, 'TestT1-weird-zeros.pfa') |
| # ellipsis is hinted with 55 131 296 131 537 131 vstem3 0 122 hstem |
| ELLIPSIS_HINTED = os.path.join(DATADIR, 'TestT1-ellipsis-hinted.pfa') |
| |
| |
| class FindEncryptedChunksTest(unittest.TestCase): |
| |
| def test_findEncryptedChunks(self): |
| with open(PFA, "rb") as f: |
| data = f.read() |
| chunks = t1Lib.findEncryptedChunks(data) |
| self.assertEqual(len(chunks), 3) |
| self.assertFalse(chunks[0][0]) |
| # the second chunk is encrypted |
| self.assertTrue(chunks[1][0]) |
| self.assertFalse(chunks[2][0]) |
| |
| def test_findEncryptedChunks_weird_zeros(self): |
| with open(WEIRD_ZEROS, 'rb') as f: |
| data = f.read() |
| |
| # Just assert that this doesn't raise any exception for not finding the |
| # end of eexec |
| t1Lib.findEncryptedChunks(data) |
| |
| |
| class DecryptType1Test(unittest.TestCase): |
| |
| def test_decryptType1(self): |
| with open(PFA, "rb") as f: |
| data = f.read() |
| decrypted = t1Lib.decryptType1(data) |
| self.assertNotEqual(decrypted, data) |
| |
| |
| class ReadWriteTest(unittest.TestCase): |
| |
| def test_read_pfa_write_pfb(self): |
| font = t1Lib.T1Font(PFA) |
| data = self.write(font, 'PFB') |
| self.assertEqual(font.getData(), data) |
| |
| def test_read_and_parse_pfa_write_pfb(self): |
| font = t1Lib.T1Font(PFA) |
| font.parse() |
| saved_font = self.write(font, 'PFB', dohex=False, doparse=True) |
| self.assertTrue(same_dicts(font.font, saved_font)) |
| |
| def test_read_pfb_write_pfa(self): |
| font = t1Lib.T1Font(PFB) |
| # 'OTHER' == 'PFA' |
| data = self.write(font, 'OTHER', dohex=True) |
| self.assertEqual(font.getData(), data) |
| |
| def test_read_and_parse_pfb_write_pfa(self): |
| font = t1Lib.T1Font(PFB) |
| font.parse() |
| # 'OTHER' == 'PFA' |
| saved_font = self.write(font, 'OTHER', dohex=True, doparse=True) |
| self.assertTrue(same_dicts(font.font, saved_font)) |
| |
| def test_read_with_path(self): |
| import pathlib |
| font = t1Lib.T1Font(pathlib.Path(PFB)) |
| |
| @staticmethod |
| def write(font, outtype, dohex=False, doparse=False): |
| temp = os.path.join(DATADIR, 'temp.' + outtype.lower()) |
| try: |
| font.saveAs(temp, outtype, dohex=dohex) |
| newfont = t1Lib.T1Font(temp) |
| if doparse: |
| newfont.parse() |
| data = newfont.font |
| else: |
| data = newfont.getData() |
| finally: |
| if os.path.exists(temp): |
| os.remove(temp) |
| return data |
| |
| |
| class T1FontTest(unittest.TestCase): |
| |
| def test_parse_lwfn(self): |
| # the extended attrs are lost on git so we can't auto-detect 'LWFN' |
| font = t1Lib.T1Font(LWFN, kind="LWFN") |
| font.parse() |
| self.assertEqual(font['FontName'], 'TestT1-Regular') |
| self.assertTrue('Subrs' in font['Private']) |
| |
| def test_parse_pfa(self): |
| font = t1Lib.T1Font(PFA) |
| font.parse() |
| self.assertEqual(font['FontName'], 'TestT1-Regular') |
| self.assertTrue('Subrs' in font['Private']) |
| |
| def test_parse_pfb(self): |
| font = t1Lib.T1Font(PFB) |
| font.parse() |
| self.assertEqual(font['FontName'], 'TestT1-Regular') |
| self.assertTrue('Subrs' in font['Private']) |
| |
| def test_getGlyphSet(self): |
| font = t1Lib.T1Font(PFA) |
| glyphs = font.getGlyphSet() |
| i = random.randrange(len(glyphs)) |
| aglyph = list(glyphs.values())[i] |
| self.assertTrue(hasattr(aglyph, 'draw')) |
| self.assertFalse(hasattr(aglyph, 'width')) |
| aglyph.draw(NullPen()) |
| self.assertTrue(hasattr(aglyph, 'width')) |
| |
| |
| class EditTest(unittest.TestCase): |
| |
| def test_edit_pfa(self): |
| font = t1Lib.T1Font(PFA) |
| ellipsis = font.getGlyphSet()["ellipsis"] |
| ellipsis.decompile() |
| program = [] |
| for v in ellipsis.program: |
| try: |
| program.append(int(v)) |
| except: |
| program.append(v) |
| if v == 'hsbw': |
| hints = [55, 131, 296, 131, 537, 131, 'vstem3', 0, 122, 'hstem'] |
| program.extend(hints) |
| ellipsis.program = program |
| # 'OTHER' == 'PFA' |
| saved_font = self.write(font, 'OTHER', dohex=True, doparse=True) |
| hinted_font = t1Lib.T1Font(ELLIPSIS_HINTED) |
| hinted_font.parse() |
| self.assertTrue(same_dicts(hinted_font.font, saved_font)) |
| |
| @staticmethod |
| def write(font, outtype, dohex=False, doparse=False): |
| temp = os.path.join(DATADIR, 'temp.' + outtype.lower()) |
| try: |
| font.saveAs(temp, outtype, dohex=dohex) |
| newfont = t1Lib.T1Font(temp) |
| if doparse: |
| newfont.parse() |
| data = newfont.font |
| else: |
| data = newfont.getData() |
| finally: |
| if os.path.exists(temp): |
| os.remove(temp) |
| return data |
| |
| |
| def same_dicts(dict1, dict2): |
| if dict1.keys() != dict2.keys(): |
| return False |
| for key, value in dict1.items(): |
| if isinstance(value, dict): |
| if not same_dicts(value, dict2[key]): |
| return False |
| elif isinstance(value, list): |
| if len(value) != len(dict2[key]): |
| return False |
| for elem1, elem2 in zip(value, dict2[key]): |
| if isinstance(elem1, T1CharString): |
| elem1.compile() |
| elem2.compile() |
| if elem1.bytecode != elem2.bytecode: |
| return False |
| else: |
| if elem1 != elem2: |
| return False |
| elif isinstance(value, T1CharString): |
| value.compile() |
| dict2[key].compile() |
| if value.bytecode != dict2[key].bytecode: |
| return False |
| else: |
| if value != dict2[key]: |
| return False |
| return True |
| |
| |
| if __name__ == '__main__': |
| import sys |
| sys.exit(unittest.main()) |