http://sdickinson.com/wordpress/wp-content/themes/HashOne
http://sdickinson.com/wordpress
Obox Signature Series Subscribe to my RSS feed

0 Comments Java Font issues

Article written by the brilliant Sam on the 27 Apr 2009 , in the Java category

An interesting problem I came across at work today (well, came across on Friday, solved today).  Basically I needed to get two fonts of different sizes (only containing numbers) to line up at the top on one side, and the bottom on another.

Problem is that the Java labels were taking into account the Ascenders and Descenders which were different heights due to the fonts being different sizes.

I’ve made a bit of a pic that describes all the info you can get from the Java FontMetrics class.

FontInfo

Basically, because I was only using numbers, they effectively were the ‘a’ in this picture (there were ascent’s above them)

So what I needed to do was calculate the difference between the top of the characters and the top of the area in both the sizes.  Problem is that you can’t easily just get the height of the font.  Ascent is given by FontMetrics.getAscent(), Decents similar, Leading same again.  So what I ended up having to do was get the actual glyph of the character, and subtract that from ascent size (which as you can see in the picture, comes from the baseline – shown in red).

Code follows (m_fntBig and m_fntSmall are the large and small font member variables):-

// Hack to get the font metrics
java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(2,2,java.awt.image.BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = image.createGraphics();
FontMetrics fmBig = g2.getFontMetrics(m_fntBig);
FontMetrics fmSmall = g2.getFontMetrics(m_fntSmall);
 
// Get the size of a 0 (strangely enough you can't do this with Font Metrics)
GlyphVector gvSmall = m_fntSmall.createGlyphVector(fmSmall.getFontRenderContext(), "0");
int nGlyphSmallHeight = gvSmall.getGlyphPixelBounds(0, null, 0, 0).height;
GlyphVector gvBig = m_fntBig.createGlyphVector(fmSmall.getFontRenderContext(), "0");
int nGlyphBigHeight = gvBig.getGlyphPixelBounds(0, null, 0, 0).height;
 
int nTopOffset = (fmBig.getMaxAscent() - nGlyphBigHeight) - (fmSmall.getMaxAscent() - nGlyphSmallHeight);

So the code above basically gives us the offsets we need to use to line up the top.

Unfortunately, I did a stupid thing, and to line up the bottoms, I was just calculating the difference in the descenders, which as you can see in my picture above, is wrong. We need to include the leading space too (interestingly it’s pronounced Ledding and comes from the amount of Lead used between the lines in printing presses – Wikipedia has some great info on it).

So to calculate the bottom difference we get:-

int nBottomOffset =  (fmBig.getMaxDescent() + fmBig.getLeading()) - (fmSmall.getMaxDescent() + fmSmall.getLeading());

Now we have the offsets for both the top and bottom, and we can now move our labels around as needed (in my case, I had 3 labels within a SpringLayout) and will work with most fonts and sizes (as long as the numbers are all the same height, which is a reasonable assumption in a financial product).

Read More Add a Comment