Search code examples
javaswinggraphics2d

measuring text bounds in Swing Graphics2d


I am measuring text bounds in Swing graphics using this method but it doesn't cover entire text. it works bad specially in measuring height... it gets better when I input English texts but I should use Persian fonts.

texts and bounds image

private Rectangle getStringBounds(Graphics2D g2, String str,
                                  float x, float y)
{
    FontRenderContext frc = g2.getFontRenderContext();
    GlyphVector gv = g2.getFont().createGlyphVector(frc, str);
    return gv.getPixelBounds(null, x, y);
}

this is how I draw texts and bounds:

g.drawString(text, x-textBounds.width/2, y+textBounds.height/2);
g.drawRect(x-textBounds.width/2, y-textBounds.height/2, textBounds.width, textBounds.height);

Solution

  • Here are two ways to get the complete font. I just grabbed some random persian text off of the internet because OP couldn't be bothered to paste a small example.

    public class BoxInFont {
        String text = "سادگی، قابلیت تبدیل";
        int ox = 50;
        int oy = 50;
        void buildGui(){
            JFrame frame = new JFrame("Boxed In Fonts");
    
            JPanel panel = new JPanel(){
                @Override
                protected void paintComponent(Graphics g){
                    super.paintComponent(g);
                    Graphics2D g2d = (Graphics2D)g;
                    g.drawString(text, ox, oy);
                    Font f = g.getFont();
                    Rectangle2D charBounds = f.getStringBounds(text, g2d.getFontRenderContext());
                    GlyphVector gv = f.layoutGlyphVector(g2d.getFontRenderContext(), text.toCharArray(), 0, text.length(), GlyphVector.FLAG_MASK);
                    Rectangle2D bounds = gv.getVisualBounds();
                    g2d.translate(ox, oy);
                    //g2d.drawRect((int)bounds.getX() + ox, (int)bounds.getY() + oy, (int)bounds.getWidth(), (int)bounds.getHeight());
                    g2d.draw(bounds);
                    g2d.draw(charBounds);
                    System.out.println("vis: " + bounds);
                    System.out.println("char: "  + charBounds);
                }
            };
            frame.add(panel);
            frame.setSize(400, 400);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
        }
    
    
        public static void main(String[] args){
    
            EventQueue.invokeLater(()->new BoxInFont().buildGui());
    
        }
    }
    

    Both boxes that are drawn completely encapsulate the text. I think visual bounds is a tighter fit.

    The problem with what OP is doing, they are ignoring x and y values of the rectangle returned. They are only using the width and height. If you look at the output of this program, you can see that the x and y are not 0.

    vis: java.awt.geom.Rectangle2D$Float[x=-0.2056962,y=-9.814648,w=96.76176,h=13.558318] char: java.awt.geom.Rectangle2D$Float[x=0.0,y=-12.568359,w=97.0,h=15.310547]