|
|
|
import hashlib |
|
|
|
from fontTools.pens.basePen import MissingComponentError |
|
from fontTools.pens.pointPen import AbstractPointPen |
|
|
|
|
|
class HashPointPen(AbstractPointPen): |
|
""" |
|
This pen can be used to check if a glyph's contents (outlines plus |
|
components) have changed. |
|
|
|
Components are added as the original outline plus each composite's |
|
transformation. |
|
|
|
Example: You have some TrueType hinting code for a glyph which you want to |
|
compile. The hinting code specifies a hash value computed with HashPointPen |
|
that was valid for the glyph's outlines at the time the hinting code was |
|
written. Now you can calculate the hash for the glyph's current outlines to |
|
check if the outlines have changed, which would probably make the hinting |
|
code invalid. |
|
|
|
> glyph = ufo[name] |
|
> hash_pen = HashPointPen(glyph.width, ufo) |
|
> glyph.drawPoints(hash_pen) |
|
> ttdata = glyph.lib.get("public.truetype.instructions", None) |
|
> stored_hash = ttdata.get("id", None) # The hash is stored in the "id" key |
|
> if stored_hash is None or stored_hash != hash_pen.hash: |
|
> logger.error(f"Glyph hash mismatch, glyph '{name}' will have no instructions in font.") |
|
> else: |
|
> # The hash values are identical, the outline has not changed. |
|
> # Compile the hinting code ... |
|
> pass |
|
""" |
|
|
|
def __init__(self, glyphWidth=0, glyphSet=None): |
|
self.glyphset = glyphSet |
|
self.data = ["w%s" % round(glyphWidth, 9)] |
|
|
|
@property |
|
def hash(self): |
|
data = "".join(self.data) |
|
if len(data) >= 128: |
|
data = hashlib.sha512(data.encode("ascii")).hexdigest() |
|
return data |
|
|
|
def beginPath(self, identifier=None, **kwargs): |
|
pass |
|
|
|
def endPath(self): |
|
self.data.append("|") |
|
|
|
def addPoint( |
|
self, |
|
pt, |
|
segmentType=None, |
|
smooth=False, |
|
name=None, |
|
identifier=None, |
|
**kwargs, |
|
): |
|
if segmentType is None: |
|
pt_type = "o" |
|
else: |
|
pt_type = segmentType[0] |
|
self.data.append(f"{pt_type}{pt[0]:g}{pt[1]:+g}") |
|
|
|
def addComponent(self, baseGlyphName, transformation, identifier=None, **kwargs): |
|
tr = "".join([f"{t:+}" for t in transformation]) |
|
self.data.append("[") |
|
try: |
|
self.glyphset[baseGlyphName].drawPoints(self) |
|
except KeyError: |
|
raise MissingComponentError(baseGlyphName) |
|
self.data.append(f"({tr})]") |
|
|