-
Notifications
You must be signed in to change notification settings - Fork 259
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
Switch to using fonttools #418
Comments
Thank you for initiating this issue @gmischler! Currently, the ttfonts.TTFontFile class contains all the font-parsing logic.
I think a starting point could be to rewrite Then, in a second phase, care should be taken to ensure backward compatibility Contributions are welcome! |
If the transition is done right (and assuming the current solution works correctly), I don't see why there should be any difference in the output at all. |
I would like to help with this! even if I'm new to fonts and new to how to embed fonts in PDFs so I think I will make some mistakes along the road.
I managed to use fonttools inside I'm finding problems in using fonttools inside
Where I can find new information to keep going? |
Simply put: We only want to include the data that is actually needed to render the PDF.
TTF files can contain a large number of different tables, some of which are only used on a particular OS, or serve some other special purposes. Many of the "dropped" tables could be used to help select the right glyph (eg. "gsub"), or to position it optimally (eg. kerning). These are tasks that need to happen when the file is created (if at all), so there's no benefit in including that data in there, since a PDF reader would have no use for it. In fact, making it easier to access some of the other tables (eg. "gsub" for solving #365) is one of the primary purposes of using fonttools in the first place. |
Good job @RedShy!
It comes directly from the PHP original code: I couldn't explain its role clearly... @gmischler already provided an excellent answer. I don't have more useful information to share here... |
The most comprehensive information I've found on the font file format and the meaning of the various tables is from Microsoft: OpenType Specification Version 1.9 |
Thank you both! it’s really encouraging and motivating to receive thoroughly answers!
It makes sense and now it’s more clear!
I managed to do that inside # font tools
ft = ttLib.TTFont(ttffilename)
scale = 1000 / ft["head"].unitsPerEm
ascent = ft["hhea"].ascent * scale
descent = ft["hhea"].descent * scale
try:
capHeight = ft["OS/2"].sCapHeight * scale
except AttributeError:
capHeight = ascent
bbox = (
f"[{ft['head'].xMin * scale:.0f} {ft['head'].yMin * scale:.0f}"
f" {ft['head'].xMax * scale:.0f} {ft['head'].yMax * scale:.0f}]"
)
stemV = 50 + int(pow((ft["OS/2"].usWeightClass / 65), 2))
italicAngle = ft["post"].italicAngle
underlinePosition = ft["post"].underlinePosition * scale
underlineThickness = ft["post"].underlineThickness * scale
flags = 4
if ft["post"].isFixedPitch:
flags |= 1
if ft["post"].italicAngle != 0:
flags |= 64
if ft["OS/2"].usWeightClass >= 600:
flags |= 262144
aw = ft["hmtx"].metrics[".notdef"][0]
defaultWidth = scale * aw
name = ft["name"].getBestFullName()
charWidths = [len(ft.getBestCmap().keys()) - 1]
for char in ft.getBestCmap().keys():
if char in (0, 65535) or char >= 196608:
continue
glyph = ft.getBestCmap()[char]
aw = ft["hmtx"].metrics[glyph][0]
if char >= len(charWidths):
size = (((char + 1) // 1024) + 1) * 1024
delta = size - len(charWidths)
if delta > 0:
charWidths += [defaultWidth] * delta
w = round(scale * aw + 0.001) or 65535 # ROUND_HALF_UP
charWidths[char] = w
ttf = TTFontFile()
ttf.getMetrics(ttffilename)
assert ascent == ttf.ascent
assert descent == ttf.descent
assert capHeight == ttf.capHeight
assert bbox == (
f"[{ttf.bbox[0]:.0f} {ttf.bbox[1]:.0f}"
f" {ttf.bbox[2]:.0f} {ttf.bbox[3]:.0f}]"
)
assert italicAngle == ttf.italicAngle
assert stemV == ttf.stemV
assert underlinePosition == ttf.underlinePosition
assert underlineThickness == ttf.underlineThickness
assert flags == ttf.flags
assert defaultWidth == ttf.defaultWidth After this, I wanted to do the same with For now what I understood about But how exactly the font has to be "cleaned" (in order to create it with
|
"Use the source, luke!" 😉 I guess there's no other way to figure it out than to step through the existing code, look where it gets its data from, and then replace that source with fonttools. Anyone else would have to go through the same steps to give you a better answer, and whoever originally wrote that code is probably not following the project anymore. If it turns out to be too confusing for the direct approach, you could try to refactor the existing code first. Try to simplify it by farming out the code dealing with individual tables (or other data structures) to seperate methods with speaking names. In a second step, you can then transition one of those at a time. Such a refactoring might also help to simplify future modifications and extensions. |
Loved the Star Wars reference! 😁
Okay then, I'm a bit busy these days, but I will try to do it in the following weeks
Yes it's a good idea |
Hi @RedShy! |
Hi! Unfortunately I could not work much on this in the last days. But still I would like to give my contribution! In the following days I hope I will have more time to dedicate |
Given that this migration has been beautifully made by @RedShy in #477, |
Well, this task looks quite finished, so I guess we can declare it as such. |
Problem
Currently fpdf2 uses its own ttfonts.py module to read and process the TrueType family of font files.
This obviously works for what whe're doing so far, and with the most common types of such files.
But there are several problems with that approach.
Solution
Fortunately, other people have already dealt with those issues. There are libraries available that can be used to access the data in font files without having to worry about how it is actually stored and how that might change over time.
In the Python world, Fonttools seems to be weapon of choice. According to the description, it is implemented in pure Python, and it seems to be under very active continuous development.
Fonttools actually does a lot more than what we need, what we would use is essentially just
fontTools.ttLib()
.Additional context
Open questions
The text was updated successfully, but these errors were encountered: