Open jansindl3r opened 1 month ago
and of course solves the issue, that that seems wrong? If you think it's a solve, can you do it or shall i PR it?
if baseAnchor is not None:
anchors["baseAnchors"].update({baseCoverage[baseRecordIndex]: {"x": baseAnchor.XCoordinate, "y": baseAnchor.YCoordinate}})
Caveat: I’m not an expert in how mark positioning works ... but:
A BaseAnchor
being None seems to be a valid case. In a ttx dump this is expressed width emtpy="1"
like in this example:
<BaseRecord index="3">
<BaseAnchor index="0" Format="1">
<XCoordinate value="138"/>
<YCoordinate value="-40"/>
</BaseAnchor>
<BaseAnchor index="1" empty="1"/>
</BaseRecord>
But while your solution would fix that correctly, it seems that extractor isn't handling all the intricacies of mark positioning well. E.g. the method you quoted only ever uses the first BaseAnchor
of a BaseRecord
, while certain marks would reference the other anchors of a BaseRecord
via the Class
value of their MarkRecord
. So some anchors are lost, respectively marks are attached to a wrong anchor in the extracted file.
Thanks for your reply! May I ask when would one want to have empty anchors? I only found this issue in not so well crafted fonts so I somehow assumed it's a mistake
what about something like this?
for baseRecordIndex, baseRecord in enumerate(subtable.BaseArray.BaseRecord if subtableIsType4 else subtable.Mark2Array.Mark2Record):
baseRecord = baseRecord.BaseAnchor if subtableIsType4 else baseRecord.Mark2Anchor
for baseAnchor in baseRecord:
if baseAnchor:
anchors["baseAnchors"].update({baseCoverage[baseRecordIndex]: {"x": baseAnchor.XCoordinate, "y": baseAnchor.YCoordinate}})
Caveat: I’m not an expert in how mark positioning works ... but:
A
BaseAnchor
being None seems to be a valid case. In a ttx dump this is expressed widthemtpy="1"
like in this example:<BaseRecord index="3"> <BaseAnchor index="0" Format="1"> <XCoordinate value="138"/> <YCoordinate value="-40"/> </BaseAnchor> <BaseAnchor index="1" empty="1"/> </BaseRecord>
But while your solution would fix that correctly, it seems that extractor isn't handling all the intricacies of mark positioning well. E.g. the method you quoted only ever uses the first
BaseAnchor
of aBaseRecord
, while certain marks would reference the other anchors of aBaseRecord
via theClass
value of theirMarkRecord
. So some anchors are lost, respectively marks are attached to a wrong anchor in the extracted file.
Ahh, so you can have more than one class of marks in the same lookup, and attach them to different anchors on each base, or even not attach some at all.
Like in this case, same lookup is used for attaching marks above (like gravecomb
, which is tagged as class 1
in lookup 2
) and below (like dotbelowcomb
, which is tagged as class 0
in the same lookup). And then some glyphs, like franc
have attachment points for both classes of combining marks, while some other glyphs only have on of these points, but not both (like uni02F3
(MODIFIER LETTER LOW RING) only has the attachment point for marks below, tagged as class 0
).
This definitely hadn't occurred in the font I'm tinkering with and was testing on, so yeah, I implemented the extraction incorrectly.
I guess I'll try fixing this properly now that I have a font to test on.
@jansindl3r, could you check if my change linked to above works as intended?
I extracted JunigardenSwash successfully with it, and see one mark on uni02F3
and two marks on franc
in the resulting UFO, but I guess it would be better if you checked as well.
If this works, I'll make a PR and it can be merged whenever maintainers have the time for it.
Actually, I'm pretty certain that the patch works. I checked omacronbelow
, which has five anchors in the OTF, and same five anchors are also visible in the UFO file.
Still would love feedback from somebody else though.
Thanks for the work! I checked with other font and there is still issue. I can't really share this font, but I will try to find another that causes this error
anchors["baseAnchors"].update({baseCoverage[baseRecordIndex]: {"x": baseAnchor.XCoordinate, "y": baseAnchor.YCoordinate}})
^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'XCoordinate'
sorry! I forgot to change branch. All good, works well, thanks!!
Oh! I was going to have another look, now I'm glad I won't have to. :D
Ive got users reporting, is this resolved?
>> File "/Applications/RoboFont_4_official.app/Contents/Resources/lib/python3.12/extractor/formats/opentype.py", line 1170, in _gatherAnchorsForLookup
12/11/2024 14:19:28 > OUTPUT > ROBOFONT >> File "/Applications/RoboFont_4_official.app/Contents/Resources/lib/python3.12/extractor/formats/opentype.py", line 1195, in _handleAnchorLookupType4Format1
12/11/2024 14:19:28 > OUTPUT > ROBOFONT >> AttributeError: 'NoneType' object has no attribute 'XCoordinate'
I dont see any test added to extractor please add test as soon as possible @rimas-kudelis @jansindl3r
@benkiel next time, no merging without any added tests
it was for the fonts I had problem with. It seems weird as in the current version line 1195 doesn't have _handleAnchorLookupType4Format1
its inside the RoboFont4.5 release
test are needed! mistakes can happen but tests prevent this from happening, please add them
Even if I had written a test when initially implementing anchor extraction, it would not have prevented this from happening because I wouldn't have written one correctly because I didn't wasn't aware of a font that would have failed such test (if I was, I would have implemented current logic from the get go).
Also, while I do understand that tests are a good thing, I can't honestly promise that I'll get to writing this missing test anytime soon (or indeed ever), sorry.
euh dont understand...
those anchors comes from mark to base or mark to mark features, you just write those features, compile to binary and test against them...
Maybe we should revert this PR until tests are added.
The testsuite of this package is currently very minimal (8 assertions in total), so if you go down the path of removing all code that is not properly tested, I'm afraid you may end up with very little code remaining here.
If you know how to quickly build a proper test for this feature, I would applaud you it if you did that. For me, it would likely take much more time, because I'm new to Python, Tox, and even fonts in general, and I'd rather spend that time polishing the font I wanted this feature for (and even that activity is on pause at the moment).
I think that Rimas did a good job improving the tool (Thanks!), enabling it to process many more fonts than before. Previously, it would fail on almost every font I tested. Only a few, well-crafted fonts made it through. The one I shared here was just first font from dafont that I randomly tried to see if it fails.
I think that Rimas did a good job improving the tool (Thanks!),
To be fair, I was also the one who broke the tool in the first place.
I get an error when extracting some fonts, like this one "JunigardenSerif_PERSONAL_USE_ONLY.otf"
https://www.dafont.com/de/junigarden-swash.font
I use this library in a plugin, when it's installed locally it works fine, but when my plugin is installed from pypi. It gives an error. I installed your library as editable and see that baseAnchor can sometimes be None.
Here is my plugin https://github.com/no-design-foundry/filters-rasterizer
Here is a proof when I print baseAnchor
then of course this error comes up