Ascender and Descender calculation seems off
While use one of the Google webfonts: drsugiyama-regular, i noticed that php-font-lib created some really high ascender and descender limits, causing some extra line spacing. (DomPDF use)
Link to the font used from Google's web font: http://www.google.com/fonts/#ChoosePlace:select/Collection:Dr+Sugiyama
Are the ascender and descender wrong in the font, causing this issue? If you look at the font loaded within the browser, paragraph layouts do not seem to show the extra line spacing.
I can confirm the issue.
Using Google Open Sans Regular font .afm file created with FontForge has following metrics:
UnderlineThickness 102
UnderlinePosition -103
Ascender 760
Descender -240
FontBBox -550 -271 1205 1048
while .ufm file created with php-font-lib has:
UnderlineThickness 50
UnderlinePosition -75
FontHeightOffset 0
Ascender 1069
Descender -293
FontBBox -550 -271 1204 1048
Rendering .pdf using DomPDF library with debugLayout enabled, native PDF fonts are rendered properly while custom Open Sans .ttf fonts (included with @font-face) are rendered with vertical offset (DejaVu Sans font with pre-generated metrics is included in DomPDF).
Sample: metric-broken.pdf
After manually replacing metrics in .ufm file with metrics from .afm file generated with FontForge, rendering is improved (Note: Only Open Sans Regular metrics are updated)
Sample: metric-fontforge.pdf
I've located the issue in AdobeFontMetrics.php (in php-font-lib), and the following simple metric-hack.diff makes DomPDF rendering more consistent with rendering of native PDF fonts. It seems that values in hhea header are not properly converted.
Sample: metric-hack.pdf
NOTICE: I'm not quite sure that this is the right way to solve this issue. I've done tests only with Open Sans (variants Regular and Bold), and DejaVu Sans Regular fonts, and only with DomPDF library.
Workaround for DomPDF
Use custom fontDir and fontCache, and one of the following:
- Create
.afmfile with FontForge and rename it to.ufmor - manually tweak Ascender and FontHeightOffset by hand in generated
.ufmfile.
Package versions
# composer show
dompdf/dompdf v0.7.0 DOMPDF is a CSS 2.1 compliant HTML to PDF converter
phenx/php-font-lib 0.4 A library to read, parse, export and make subsets of different types of ...
phenx/php-svg-lib 0.1 A library to read, parse and export to PDF SVG files.
Hey fellows,
during our implementation of a design editor, based on KonvaJS where the customer can declare and place marker elements, we had big trouble with this issue. The post-rendering of dynamic elements is processed via DomPDF. Due to the wrong calculation of the Ascender and Descender, the text is not placed at the correct position.
I was calculating a lot of time and came to the following result.
Before the call of e.g. $font->normalizeFUnit($hhea["ascent"]) in \FontLib\AdobeFontMetrics::write the ascender and descender values should be added and the sum put in relation to the unitsPerEm. The relation factor from $unitsPerEm / ($ascent + $descent) should be multiplied with the ascender and descender values and the results passed to the $font->normalizeFUnit calls.
After I made these changes, our rendered PDFs are looking perfect.
Best regards Jan
Thanks for the issue analysis! Feel free to submit a pull request if you have time, but we'll review and work that into an upcoming release regardless if appropriate.
@shokre Thanks a lot, the workaround works! I've written a PHP script that does the following:
- loads the OpenSans font using
FontMetrics::registerFont() - postprocesses ".ufm" files to override
Ascender/Descender(values760and-240suitable for all OpenSans font variants)
This issue is probably caused by the difference between the terms "Ascender" / "Descender" in AFM and TrueType
- Adobe Font Metrics File Format Specification v4.1 states that
Ascenderis the Y-axis distance between the top of the latin "d" letter and the origin (i.e. 0 in glyph coordinates)Descenderis the Y-axis distance between the bottom of the latin "p" letter and the origin
- Apple's TrueType Reference Manual - Apple Developer states that
typoAscenderis the maximum of glyph ascender valuestypoDescenderis the mimimum of glyph descender values
So Ascender/Descender in AFM cannot be calculated from TrueType font metadata (neither "hhea" nor "OS/2"). Maybe dompdf can read "glyf" table in TrueType font file, find parameters for latin "d" and "p" letters and use their yMax / yMin as Ascender / Descender for Adobe Font Metrics file.
Unfortunately, I'm not ready to make patch and submit pull request now.
Maybe dompdf can read "glyf" table in TrueType font file, find parameters for latin "d" and "p" letters and use their yMax / yMin as Ascender / Descender for Adobe Font Metrics file.
This is exactly right, except that php-font-lib should be doing the work so that the values in the AFM/UFM are correct. I tested with Open Sans and get the expected results.
The updated logic will populate CapHeight (H), XHeight (x), Ascender (d), and Descender (p) values based on the glyph data as outlined by the specification. Ascender and Descender will fall back to the old logic if their respective glyphs are not present since the spec language around those values is that they are "usually" or "typically" based on those characters. I couldn't think of a related TrueType table record to reference for the other two values so they will not have a fallback and will be excluded if their glyphs are not present.