New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
HashPointPen fails with ufoLib2 #3421
Comments
Using the format But the F2Dot14 precision comes into play once the components are scaled by a fractional number. Example: Scaled in the font editor by 91.3 %, represented in the two formats:
|
But that's literally a difference between the two components... TTF necessarily has to store an approximation, so that is lossy, and therefore I would expect a different hash. |
Formatting the values with Scale 1.0, 1.0:
Scale 0.913, 0.913:
|
But UFO does not use F2Dot14, so this allows different values to hash the same. So it does not "solve" the problem, it hides an actual difference. |
but that is exactly what is desired in this case, because the hashpointpen is being used to determine whether the glyfs have changed and the hinting is thus invalidated. A slightly different float in the UFO that will then be rounded off to the fractional value when compiled the TTF does not actually matter, what matters is the F2Dot14 |
maybe the pen could take a callable that will be used to round these and the caller (in this case ufo2ft I suppose?) will pass the desired floatToFixed |
FYI there's also |
Ah, I didn't realize that. But yeah, then a more mallable solution may be warranted, as HashPointPen doesn't advertize itself as "hash glyphs equal when they are are equal in TTF form". |
I'm using the HashPointPen to check if I can transfer TrueType byte code from a UFO to a TTF. Currently that marks all composites as different, though the difference is negligible*. If the hash used *) The hinting editor would have showed me the F2Dot14 approximations anyway, so that is what's actually hinted |
are you using the |
Thanks for your comments. I've made a PR. Now I only apply the round function to the scale values of the transformation, as the x and y offsets are stored as integers in TTF. In theory, you could have a UFO with fractional coordinates/offsets, and a TTF with rounded coordinates/offsets. Do we have to consider that case as well? Even CFF may be affected by the precision issue, in case both the UFO and the CFF table use fractional coordinates. |
BTW ufo2ft is not affected by this, as it only compares the stored glyph hash against the calculated current glyph hash in the UFO. |
With the PR, I still get a difference for components with a scale of -1.0:
|
We have |
Thanks, Behdad. Wow, this is really hard. Opening a UFO with ufoLib2, the type of the transformation's scale values may either be a float or an int:
(Sure, that's also what the UFO spec says) So an editor that quietly changes a scale of 1.0 to 1 or vice versa will invalidate a stored hash if there is no post-processing on the scale values. |
since in python |
This seems like a FontLab Studio 5 bug. It exports a scale of -1.0 as -0.99994 into a TTF, i.e. -16383/16384 instead of -16384/16384. |
After some more digging, it seems that the original difference 1 vs 1.0 lies in the way the UFO is created. When the UFO is built in memory, and then the hash is calculated, it contains floats. When the UFO is written to disk, then opened again (also with ufoLib2), and the hash is calculated, it contains ints. I can work around this in my UFO builder, but maybe the HashPointPen should do some normalization there. The HashPointPen has deviated from the UFO spec considerably (but for the better; I think the UFO spec should be updated). But maybe it is a good idea to reinstate the rounding as specified? Per the spec, coordinates and component offsets are rounded to max. 3 decimals; the transformation matrix values are rounded to max. 8 decimals:
|
PR to round as in UFO spec: #3427 |
I'm using the HashPointPen to check glyphs from a UFO (opened with ufoLib2) against glyphs from a TTF.
Both produce different hashes for identical glyphs when the glyph is a composite.
As you can see, the difference is that the transformation (scale) is stored as an int when the pen is fed by the TTF, but as a float when it is fed by the UFO.
fonttools/Lib/fontTools/pens/hashPointPen.py
Lines 68 to 69 in 679a5c0
I guess the HashPointPen should be changed to even out this difference, but what would be preferred? The scales in the transformation are stored as F2Dot14 values in a TTF, so for maximum precision, we should probably always write out the full F2Dot14?
The text was updated successfully, but these errors were encountered: