php-font-lib
php-font-lib copied to clipboard
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
.afm
file with FontForge and rename it to.ufm
or - manually tweak Ascender and FontHeightOffset by hand in generated
.ufm
file.
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
(values760
and-240
suitable 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
-
Ascender
is the Y-axis distance between the top of the latin "d" letter and the origin (i.e. 0 in glyph coordinates) -
Descender
is the Y-axis distance between the bottom of the latin "p" letter and the origin
-
- Apple's TrueType Reference Manual - Apple Developer states that
-
typoAscender
is the maximum of glyph ascender values -
typoDescender
is 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.