Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
377 views
in Technique[技术] by (71.8m points)

string - How to get the precise bounding box of a character in Java

I am trying to get the precise bounding box of a character in Java. Is it normal that if I perform (for example in a Swing component):

public class MyFrame extends JFrame {
   public MyFrame() {
     super();
     this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
   }

   private void computeWidth() {
     String character = "A";
     JLabel label = new JLabel();
     Font font = label.getFont();
     font = font.deriveFont(12);

     // method with FontMetrics 
     FontMetrics fontMetrics = this.getFontMetrics(font);
     Rectangle2D recWithMetrics = fontMetrics.getStringBounds(character, this.getGraphics());
     System.out.println("recWithMetrics : " + recWithMetrics);

     // method with GlyphVector outline
     FontRenderContext ctx = new FontRenderContext(new AffineTransform(), true, true);
     GlyphVector gv = font.createGlyphVector(ctx, character);
     Rectangle2D recWithOutline = gv.getOutline().getBounds2D();
     System.out.println("recWithOutline : " + recWithOutline);
   }

   public static void main(String[] args) {
      MyFrame frame = new MyFrame();
      frame.computeWidth();
      frame.setVisible(true);
   }
}

recWithMetrics and recWithOutline don't have the same values at all, is it due to the fact that the method using the FontMetrics includes the advance?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I've found it 'simpler' to get the Shape of the text and work with that.

enter image description here

import java.awt.*;
import java.awt.geom.*;
import java.awt.font.*;
import java.awt.image.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;

public class TextBoundingBox {

    private JComponent ui = null;
    public static String string = "Red outline shows bounds of text";
    public static Font font = new Font(Font.SANS_SERIF, Font.BOLD, 36);

    TextBoundingBox() {
        initUI();
    }

    public void initUI() {
        if (ui != null) {
            return;
        }

        ui = new JPanel(new BorderLayout(4, 4));
        ui.setBorder(new EmptyBorder(4, 4, 4, 4));

        ui.add(new JLabel(new ImageIcon(getImage())));
    }

    private static BufferedImage getImage() {
        Shape shape = getShapeOfText(font, string);
        Rectangle2D boundsRectangle = shape.getBounds2D();
        double w = boundsRectangle.getWidth();
        double h = boundsRectangle.getHeight();
        int wBig = (int) (w * 1.1);
        int hBig = (int) (h * 2);
        BufferedImage bi = new BufferedImage(
                wBig, hBig, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = bi.createGraphics();
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, wBig, hBig);

        g.setColor(Color.BLACK);
        g.fill(moveShapeToCenter(shape, wBig, hBig));
        g.setColor(Color.RED);
        g.draw(moveShapeToCenter(boundsRectangle, wBig, hBig));
        g.dispose();

        return bi;
    }

    public static Shape moveShapeToCenter(Shape shape, int w, int h) {
        Rectangle2D b = shape.getBounds2D();
        double xOff = -b.getX() + ((w - b.getWidth()) / 2d);
        double yOff = -b.getY() + ((h - b.getHeight()) / 2d);
        AffineTransform move = AffineTransform.getTranslateInstance(xOff, yOff);
        return move.createTransformedShape(shape);
    }

    public static Shape getShapeOfText(Font font, String msg) {
        BufferedImage bi = new BufferedImage(
                1, 1, BufferedImage.TYPE_INT_RGB);

        Graphics2D g = bi.createGraphics();

        FontRenderContext frc = g.getFontRenderContext();
        GlyphVector gv = font.createGlyphVector(frc, msg);

        return gv.getOutline();
    }

    public JComponent getUI() {
        return ui;
    }

    public static void main(String[] args) {
        Runnable r = () -> {
            TextBoundingBox o = new TextBoundingBox();

            JFrame f = new JFrame(o.getClass().getSimpleName());
            f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            f.setLocationByPlatform(true);

            f.setContentPane(o.getUI());
            f.pack();
            f.setMinimumSize(f.getSize());

            f.setVisible(true);
        };
        SwingUtilities.invokeLater(r);
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...