{"id":16410333,"url":"https://github.com/ctrlcctrlv/opentype_pfed","last_synced_at":"2026-05-30T16:31:24.865Z","repository":{"id":148743519,"uuid":"325961096","full_name":"ctrlcctrlv/OpenType_PfEd","owner":"ctrlcctrlv","description":"Python parser implementation of the (non-standard) OpenType `PfEd` table used in FontForge and PfaEdit","archived":false,"fork":false,"pushed_at":"2021-01-01T17:55:07.000Z","size":353,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-02-18T06:13:46.336Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ctrlcctrlv.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-01-01T10:52:31.000Z","updated_at":"2021-01-01T17:55:09.000Z","dependencies_parsed_at":null,"dependency_job_id":"9fa5b892-a66c-435b-9c28-ba43851f5083","html_url":"https://github.com/ctrlcctrlv/OpenType_PfEd","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ctrlcctrlv%2FOpenType_PfEd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ctrlcctrlv%2FOpenType_PfEd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ctrlcctrlv%2FOpenType_PfEd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ctrlcctrlv%2FOpenType_PfEd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ctrlcctrlv","download_url":"https://codeload.github.com/ctrlcctrlv/OpenType_PfEd/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240405276,"owners_count":19796161,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-11T06:23:59.302Z","updated_at":"2026-05-30T16:31:24.831Z","avatar_url":"https://github.com/ctrlcctrlv.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# OpenType `PfEd` table: Python implementation\n\nThis is a Python implementation of the OpenType `PfEd` (PfaEdit) table.\n\n`PfEd` is a quite obscure table, but quite useful. It has some elements, like guidelines and comments , that are worth more widely standardizing in OpenType I think.\n\nFor now this is just a reader that is 90% done as of 1 January 2021.\n\n(Not promising to finish this!)\n\n## Input\n\nInput should be all the raw bytes found in the `PfEd` table of an OpenType (or SFNT) font.\n\nThere are two examples in `examples/`:\n\n* `examples/PfEd` — `InterestingPfEdTable.otf`, the example font I posted at [fonttools/fonttools#464](https://github.com/fonttools/fonttools/issues/464) on 28 April 2018 which contains all `PfEd` tables except `cvtc`;\n* `examples/PfEd2` — [TT2020](https://github.com/ctrlcctrlv/TT2020)'s `PfEd` in the state it was in on my hard drive 1 January 2021.\n\n## Usage\n\n```python3\nfrom OpenType_PfEd import PfEd, PfEdBuffer\n\nwith open(\"OpenType_PfEd/examples/PfEd2\", \"rb\") as f:\n\tbuf = PfEdBuffer(f.read())\npfed = PfEd(buf)\npfed.parse()\nimport pprint\npprint.pprint(pfed.subtables)\n```\n\nGives us:\n\n```text\nINFO:  Got PfEd table version 10000 of length 4 subtables (length 0x000a60e0 bytes)\nINFO:  Subtable tagged GSUB starts @ 0x00000028\nINFO:  Subtable tagged GPOS starts @ 0x000005c0\nINFO:  Subtable tagged guid starts @ 0x00000608\nINFO:  Subtable tagged layr starts @ 0x000007a8\n{'GPOS': [('mark1', [('mark1-1', ['theclass'])]),\n          ('fracq', [('fracq subtable', [])])],\n 'GSUB': [('fracf', [('fracf subtable', [])]),\n          ('fracs',\n           [('fracs contextual 0', []),\n            ('fracs contextual 1', []),\n            ('fracs contextual 2', [])]),\n          ('Single Substitution lookup 2',\n           [('Single Substitution lookup 2 subtable', [])]),\n          ('Single Substitution lookup 3',\n           [('Single Substitution lookup 3 subtable', [])]),\n          ('Single Substitution lookup 4',\n           [('Single Substitution lookup 4 subtable', [])]),\n          ('fracn', [('fracn subtable', [])]),\n          ('Single Substitution lookup 6',\n           [('Single Substitution lookup 6 subtable', [])]),\n          ('fracn3', [('fracn3 subtable', [])]),\n          ('Single Substitution lookup 8',\n           [('Single Substitution lookup 8 subtable', [])]),\n          ('fracn4', [('fracn4 subtable', [])]),\n          ('Single Substitution lookup 10',\n           [('Single Substitution lookup 10 subtable', [])]),\n          ('fracn5', [('fracn5 subtable', [])]),\n          ('Single Substitution lookup 12',\n           [('Single Substitution lookup 12 subtable', [])]),\n          ('fracn6', [('fracn6 subtable', [])]),\n          ('Single Substitution lookup 14',\n           [('Single Substitution lookup 14 subtable', [])]),\n          ('fracn7', [('fracn7 subtable', [])]),\n          ('Single Substitution lookup 16',\n           [('Single Substitution lookup 16 subtable', [])]),\n          ('fracn8', [('fracn8 subtable', [])]),\n          ('Single Substitution lookup 18',\n           [('Single Substitution lookup 18 subtable', [])]),\n          ('fracn9', [('fracn9 subtable', [])]),\n          ('Single Substitution lookup 20',\n           [('Single Substitution lookup 20 subtable', [])]),\n          ('fracn10', [('fracn10 subtable', [])]),\n          ('Single Substitution lookup 22',\n           [('Single Substitution lookup 22 subtable', [])]),\n          ('ligahebrew', [('ligahebrew subtable', [])]),\n          ('ligalatin', [('ligalatin subtable', [])])],\n 'guid': {'desc': '',\n          'guidelines': [{'name': 'Bottom (Cyrl)',\n                          'pos': -130,\n                          'type': 'Horizontal'},\n                         {'name': 'Bottom (Hebr)',\n                          'pos': -97,\n                          'type': 'Horizontal'},\n                         {'name': 'Bottom (yud, Hebr)',\n                          'pos': 225,\n                          'type': 'Horizontal'},\n                         {'name': 'Mid-bar (Armn)',\n                          'pos': 259,\n                          'type': 'Horizontal'},\n                         {'name': 'Mid-bar (Cyrl)',\n                          'pos': 292,\n                          'type': 'Horizontal'},\n                         {'name': 'x-height', 'pos': 404, 'type': 'Horizontal'},\n                         {'name': 'Top (Hebr)',\n                          'pos': 460,\n                          'type': 'Horizontal'},\n                         {'name': 'Top (Cyrl)',\n                          'pos': 529,\n                          'type': 'Horizontal'}],\n          'version': 1},\n 'layr': [{'name': 'Spiro',\n           'ranges': [{'last': 0, 'offsets': [1065], 'start': 0},\n                      {'last': 5, 'offsets': [2648], 'start': 5},\n                      {'last': 15,\n                       'offsets': [5112, 0, 7632, 0, 8084],\n                       'start': 11},\n                      {'last': 23, 'offsets': [8320], 'start': 23},\n                      {'last': 27, 'offsets': [9596, 11016], 'start': 26},\n                      {'last': 33, 'offsets': [11482], 'start': 33},\n                      {'last': 43,\n                       'offsets': [15341, 16338, 18448, 20180, 21789, 0, 23027],\n                       'start': 37},\n                      {'last': 51,\n                       'offsets': [24105, 25387, 27919],\n                       'start': 49},\n                      {'last': 54, 'offsets': [29394], 'start': 54},\n                      {'last': 58, 'offsets': [30342], 'start': 58},\n                      {'last': 85,\n                       'offsets': [31264,\n                                   31680,\n                                   33334,\n                                   34930,\n                                   36480,\n                                   0,\n                                   38193,\n                                   39312,\n                                   41769,\n                                   0,\n                                   43469,\n                                   44547,\n                                   45969,\n                                   46417,\n                                   48995,\n                                   50389,\n                                   51782,\n                                   53374,\n                                   55164,\n                                   56229,\n                                   58112],\n                       'start': 65},\n                      {'last': 90, 'offsets': [59433], 'start': 90},\n                      {'last': 98,\n                       'offsets': [60908, 0, 61612, 63176],\n                       'start': 95},\n                      {'last': 101, 'offsets': [64128], 'start': 101},\n                      {'last': 104, 'offsets': [66880], 'start': 104},\n                      {'last': 112,\n                       'offsets': [69223, 0, 71428, 72663, 0, 74195],\n                       'start': 107},\n                      {'last': 161, 'offsets': [74944], 'start': 161},\n                      {'last': 171, 'offsets': [77332], 'start': 171},\n                      {'last': 327, 'offsets': [78802, 0, 79272], 'start': 325},\n                      {'last': 333, 'offsets': [80116], 'start': 333},\n                      {'last': 372, 'offsets': [80748], 'start': 372},\n                      {'last': 383, 'offsets': [82352, 0, 84438], 'start': 381},\n                      {'last': 396,\n                       'offsets': [86524, 88268, 0, 89661],\n                       'start': 393},\n                      {'last': 410, 'offsets': [91657], 'start': 410},\n                      {'last': 420, 'offsets': [93154, 0, 95506], 'start': 418},\n                      {'last': 428, 'offsets': [97524], 'start': 428},\n                      {'last': 435, 'offsets': [99233], 'start': 435},\n                      {'last': 448, 'offsets': [100996], 'start': 448},\n                      {'last': 465, 'offsets': [104322], 'start': 465},\n                      {'last': 476, 'offsets': [105406, 107848], 'start': 475},\n                      {'last': 480, 'offsets': [109282], 'start': 480},\n                      {'last': 501, 'offsets': [113931, 115077], 'start': 500},\n                      {'last': 540, 'offsets': [116535], 'start': 540},\n...[snip]...\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fctrlcctrlv%2Fopentype_pfed","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fctrlcctrlv%2Fopentype_pfed","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fctrlcctrlv%2Fopentype_pfed/lists"}