Page 1 of 2

Inaccurate results from Font:getWidth()

Posted: Fri Nov 03, 2017 5:59 pm
by grump
I'm getting unexpected values from Font:getWidth() with some fonts. The reported width for a given string is too small. This code should draw an "A" and a red box that encloses it:

Code: Select all

local gfx = love.graphics
gfx.setNewFont("Power.ttf", 128)

function love.draw()
	local test = "A"
	gfx.setColor(255, 255, 255)
	gfx.print(test, 10, 10)
	gfx.setColor(255, 0, 0)
	gfx.rectangle("line", 10.5, 10.5, gfx.getFont():getWidth(test), gfx.getFont():getHeight())
end
The result looks like this:
Image

It happens only with some fonts, and not with all glyphs of a font. And it doesn't seem to be a problem with the glyph width, since the error remains constant even with longer strings:
Image

Anyone know what causes this and how to fix it or work around it?

Re: Inaccurate results from Font:getWidth()

Posted: Fri Nov 03, 2017 8:12 pm
by Fuzzlix
May be the font has bugs. This happens sometimes when you are using free fonts.
If you want to keep using this font, i suggest you add a additional character to the string for (allmost) propper calculation. ( in your case:
gfx.getFont():getWidth(test.." ")
or
gfx.getFont():getWidth(test.."_")

Re: Inaccurate results from Font:getWidth()

Posted: Fri Nov 03, 2017 8:37 pm
by grump
Fuzzlix wrote: Fri Nov 03, 2017 8:12 pm May be the font has bugs. This happens sometimes when you are using free fonts.
If you want to keep using this font, i suggest you add a additional character to the string for (allmost) propper calculation. ( in your case:
gfx.getFont():getWidth(test.." ")
or
gfx.getFont():getWidth(test.."_")
The thing is, I'm writing a tool that processes user supplied fonts and it requires accurate glyph sizes from any font. This is one of the last bugs I need to fix before I can release an alpha version. It's a pretty useless tool if I can't fix this :(

Re: Inaccurate results from Font:getWidth()

Posted: Fri Nov 03, 2017 8:39 pm
by zorg
Almost proper or not, the font itself looks italicized, meaning the top is leaning out of the "normal" glyph width area, in other words, the base of the characters are indeed inside that bounding box!

The error is constant exactly because the font itself defined some glyph sizes "incorrectly", or at the very least, not to what you expected; just because they reach further doesn't mean that the next glyph will start later, getting a bigger offset and messing things up (that's technically what you want to achieve).

The additional space included in the calculation wouldn't work as good, since apparently not all glyphs have this issue, so there might be some texts that wouldn't have glyphs being cut off, potentially messing with alignment.

Another hackish but workable way would be to just define (in pixels, let's say) how many extra units you want the total width to be appended by; that only needs to take into account the very last character in a line, for the above stated reason(s).

That said, it's most probably not an issue with Font:getWidth itself, it's a font issue... the only Löve related issue could be that the edges of such glyphs get cut off when drawing them, but i think that was already fixed.
grump wrote: Fri Nov 03, 2017 8:37 pm The thing is, I'm writing a tool that processes user supplied fonts and it requires accurate glyph sizes from any font. This is one of the last bugs I need to fix before I can release an alpha version. It's a pretty useless tool if I can't fix this :(
Processes as in? Turns them into an atlas/imagedata with all characters laid out nicely? Yes, that could cause some issues; usually you'd want to handle this with extra parameters that the users can supply for the fonts, like how much a glyph extends beyond its defined width.
Spacing's not an exact science.

Re: Inaccurate results from Font:getWidth()

Posted: Fri Nov 03, 2017 8:59 pm
by slime
It looks like the font file baked kerning information into its glyph advance values or something? In any case, text width, height, and other metrics are not the same as glyph texture dimensions inside the font's texture atlas. You can use Rasterizer and GlyphData objects to query that information if you really need, although they aren't well-documented right now.

Re: Inaccurate results from Font:getWidth()

Posted: Fri Nov 03, 2017 10:48 pm
by grump
zorg wrote: Fri Nov 03, 2017 8:39 pm Almost proper or not, the font itself looks italicized, meaning the top is leaning out of the "normal" glyph width area, in other words, the base of the characters are indeed inside that bounding box!
Yes, I considered that as well, but it does not explain why it only is that way for some glyphs and not for others:
Image
Processes as in?
As in taking every glyph from the font, turn them into an image, apply stuff to each glyph and save the whole thing as an ImageFont. RIght now some characters get cut off because I don't get the right widths. And I just discovered that the height is off as well in rare cases :(
slime wrote: Fri Nov 03, 2017 8:59 pm You can use Rasterizer and GlyphData objects to query that information if you really need, although they aren't well-documented right now.
I'll look into that, thanks!

Edit: Okay, I looked into it. GlyphData has two potentially relevant methods: getAdvance() and getBoundingBox(). I don't understand what they return; the values returned have no relation to the font size, and they are rather small. Can you give me a hint how to determine the exact bounds of a glyph in pixels?

Re: Inaccurate results from Font:getWidth()

Posted: Sun Nov 05, 2017 11:15 am
by grump
Bump. I still need some help here. How can I calculate/query accurate glyph bounds?
Image
This is unacceptable for my use case. I need to draw text on exact positions, I don't want it randomly shifted around in either direction.

I'm about to hack an awkward solution that draws each glyph on a large Canvas, gets the ImageData and uses mapPixel to calculate the pixel boundaries. I really don't wanna do that.

Re: Inaccurate results from Font:getWidth()

Posted: Sun Nov 05, 2017 12:19 pm
by Azhukar
Post the font I'll give it a shot.

Re: Inaccurate results from Font:getWidth()

Posted: Sun Nov 05, 2017 12:34 pm
by grump
Azhukar wrote: Sun Nov 05, 2017 12:19 pm Post the font I'll give it a shot.
https://www.dafont.com/power-2.font

I'm looking for a solution that works with any font though, not just a hack for a specific one.

Re: Inaccurate results from Font:getWidth()

Posted: Sun Nov 05, 2017 2:06 pm
by Azhukar
Played around with the undocumented rasterizer, managed to draw the actual outline of a letter.

Code: Select all

local testFont = love.graphics.newFont("Power.ttf", 128)

local rasterizer = love.font.newRasterizer("Power.ttf",128)
local glyphData = rasterizer:getGlyphData("A")
for k,v in pairs(getmetatable(glyphData)) do
	print(k,v)
end
print(glyphData:getBoundingBox())

function love.draw()
	love.graphics.setFont(testFont)
	local text = "A"
	local x,y = 10,100
	local fontHeight = love.graphics.getFont():getHeight()
	local fontWidth = love.graphics.getFont():getWidth(text)
	
	love.graphics.setColor(255,255,255,255)
	love.graphics.print(text,x,y)
	
	love.graphics.setColor(255,0,0,255)
	local gx,gy,width,height = rasterizer:getGlyphData(text):getBoundingBox()
	love.graphics.rectangle("line",x+gx+0.5,y+gy+0.5,width,fontHeight)
end
The metatable stuff is to get the undocumented function names.