tractatus/pptx-env/lib/python3.12/site-packages/fontTools/pens/hashPointPen.py
TheFlow 2298d36bed fix(submissions): restructure Economist package and fix article display
- Create Economist SubmissionTracking package correctly:
  * mainArticle = full blog post content
  * coverLetter = 216-word SIR— letter
  * Links to blog post via blogPostId
- Archive 'Letter to The Economist' from blog posts (it's the cover letter)
- Fix date display on article cards (use published_at)
- Target publication already displaying via blue badge

Database changes:
- Make blogPostId optional in SubmissionTracking model
- Economist package ID: 68fa85ae49d4900e7f2ecd83
- Le Monde package ID: 68fa2abd2e6acd5691932150

Next: Enhanced modal with tabs, validation, export

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-24 08:47:42 +13:00

89 lines
3.5 KiB
Python

# Modified from https://github.com/adobe-type-tools/psautohint/blob/08b346865710ed3c172f1eb581d6ef243b203f99/python/psautohint/ufoFont.py#L800-L838
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
If you want to compare a glyph from a source format which supports floating point
coordinates and transformations against a glyph from a format which has restrictions
on the precision of floats, e.g. UFO vs. TTF, you must use an appropriate rounding
function to make the values comparable. For TTF fonts with composites, this
construct can be used to make the transform values conform to F2Dot14:
> ttf_hash_pen = HashPointPen(ttf_glyph_width, ttFont.getGlyphSet())
> ttf_round_pen = RoundingPointPen(ttf_hash_pen, transformRoundFunc=partial(floatToFixedToFloat, precisionBits=14))
> ufo_hash_pen = HashPointPen(ufo_glyph.width, ufo)
> ttf_glyph.drawPoints(ttf_round_pen, ttFont["glyf"])
> ufo_round_pen = RoundingPointPen(ufo_hash_pen, transformRoundFunc=partial(floatToFixedToFloat, precisionBits=14))
> ufo_glyph.drawPoints(ufo_round_pen)
> assert ttf_hash_pen.hash == ufo_hash_pen.hash
"""
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" # offcurve
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})]")