dompdf / php-font-lib

A library to read, parse, export and make subsets of different types of font files.
GNU Lesser General Public License v2.1
1.74k stars 253 forks source link

Ascender and Descender calculation seems off #7

Closed TeckniX closed 9 months ago

TeckniX commented 11 years ago

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.

--- Want to back this issue? **[Post a bounty on it!](https://www.bountysource.com/issues/1304232-ascender-and-descender-calculation-seems-off?utm_campaign=plugin&utm_content=tracker%2F317728&utm_medium=issues&utm_source=github)** We accept bounties via [Bountysource](https://www.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F317728&utm_medium=issues&utm_source=github).
shokre commented 8 years ago

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:

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.
jmatthiesen81 commented 2 years ago

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

bsweeney commented 2 years ago

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.

sergey-shambir commented 1 year ago

@shokre Thanks a lot, the workaround works! I've written a PHP script that does the following:


This issue is probably caused by the difference between the terms "Ascender" / "Descender" in AFM and TrueType

  1. 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
  2. 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.

bsweeney commented 10 months ago

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.