Skip to content
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

gfx.getFontMetrics.stringWidth gives different width than pdFont.getStringWidth / 1000 * fontSize #16

Closed
megri opened this issue Mar 15, 2019 · 5 comments

Comments

@megri
Copy link
Contributor

megri commented Mar 15, 2019

To calculate the width of text using PDFBox you can use pdFont.getStringWidth(theAlphabet) * 1000 / fontSize. From my experiments this gives a precise measurement of the text's width.

Using pdfBoxGraphics2d.getFontMetrics(font).stringWidth(alphabet) the width is different (and, from my experimentations, incorrect)

@rototor
Copy link
Owner

rototor commented Mar 15, 2019

Can you provide a small test case (preferred as a pull request) which demonstrate this inaccurate measurement? Is this inaccuracy depending on the used font or does it happen with all fonts?

A correct fix would need to extend the IPdfBoxGraphics2DFontTextDrawer interface to also provide metric data for the fonts, and then hook the FontMetrics into that.

As I'm leaving for holiday tomorrow I won't have time the next two weeks to look into this. But a test case which clearly shows the problem would help me.

@megri
Copy link
Contributor Author

megri commented Mar 17, 2019

I added a small test case :)
#17

@megri
Copy link
Contributor Author

megri commented Mar 18, 2019

I'll look into implementing some form of 3rd party FontMetrics inside FontTextDrawer. It kind of feels like the whole thing (FontTextDrawer) could be hidden away inside the PdfBoxGraphics2D-class, which would also remove one moving piece (creating the FontTextDrawer, registering the fonts and then adding it to the Graphics2D-context). It feels a bit clumsy. WDYT?

@rototor
Copy link
Owner

rototor commented Mar 18, 2019

@megri The FontTextDrawer is there for a reason. It needs to be customizable for different use cases:

  1. Exactly reproducing whats drawn using a regular BufferedImage Graphics2D. This is done be using vector shapes, which bloats the PDF file but let the text display 1:1 as on the BufferedImage Graphics 2D.
  2. Only use the builtin PDF Fonts, which every PDF viewer should support. This reduces the file size massively, but the text may look a little bit different depending on the PDF viewer. Also anything bidi (i.e. hebrew, arabic, ...) won't work.
  3. Use the TTF fonts underlying the Graphics2D Font-Objects. As it is not possible to get the TTF file associated with a given Font object (at least not in a portable, Java 9 compatible way), you have to register the fonts yourself. Bidi won't work also.

You can get bidi to work with PDFont's, you just have to somehow bridge the HarfBuzz functionality or use something like ICU. To do so you could derive from the FontTextDrawer and "just" implement that stuff correctly... (No, this is not easy and out of scope for this project)

Also if you have more then one Graphics2D in your PDF you can reuse the FontTextDrawer and therefor reuse the PDFont's. You may even want to bridge your own font management stuff (like https://github.com/danfickle/openhtmltopdf does).

Beside this, it's still a bug that pdFont.getStringWidth() and the getFontMetrics().stringWidth() don't match. But when when implementing this you must have the three different use cases in mind.

rototor added a commit that referenced this issue Jun 8, 2020
This is only possible if there is any PDFont. This leads to more exact string widths.

Only the string widths get more accurate with this method. If you try to do any kind of layout beside advancing the text position you should really consider using TextLayout (which will *always* lead to vector glyphs embedded).
@rototor
Copy link
Owner

rototor commented Jun 15, 2020

I've released a new version with a fix for this. I.e. if you have registered a font then the font metrics of the PDFont are used for the stringWidth(). If the font is not registered and the text is vectorized, then it behaves the old way, as that matches the resulting text graphic.

@rototor rototor closed this as completed Jun 15, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants