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())