2

I have a class extending BufferedImage which should display as a string provided to it's constructor. The reason I wish to do this is to allow the anti-aliasing functionality of graphics2D (see my previous question for more details, and if you have any better suggestions then by all means suggest them!). I now have the BufferedImage class working, however I cannot figure out how to determine the required width and height in order to display the input string before actually setting the font. I also cannot find a way to resize the BufferedImage parent once its initial size has been set. Here is my code:

import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;

public class Test extends JFrame{
    public Test(){
        this.add(new JLabel(new ImageIcon(new IconImage("Test", new Font("Sans-Serif", Font.PLAIN, 16)))));
        this.setVisible(true);
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        this.pack();
    }

    class IconImage extends BufferedImage{
        public IconImage(String text, Font font){
            super(..., ..., BufferedImage.TYPE_INT_ARGB);//*****Unknown dimensions*****

            Graphics2D g2d = (Graphics2D) this.getGraphics();
            g2d.setFont(font);
            g2d.setColor(Color.BLACK);

            int stringHeight = (int) g2d.getFontMetrics().getStringBounds(text, g2d).getHeight();  
            g2d.drawString(text, 0 , stringHeight);
            g2d.dispose();
        }
    }

    public static void main(String[] args){
        new Test(); 
    }
}

Any advice? Thanks.

Community
  • 1
  • 1
Hungry
  • 1,645
  • 1
  • 16
  • 26
  • may i ask why you try to create the image first and then create the button? would it be possible your you to do it the other way round? (if yes: you could measure the button and after that create that image) btw: how to display a graphics bigger than your component - it works but gets clipped... – Martin Frank Sep 23 '14 at 11:05
  • As the actual implementation just creates a button, then calls `setIcon` and `setRolloverIcon`. I could not figure out how to perform anti-aliasing on just a button which has had `setText` called on it. – Hungry Sep 23 '14 at 11:13

2 Answers2

2

Two possible solutions:

  1. Create a tiny BufferedImage (1x1) just to get the Graphics object and do your calculations. Then create the real image
  2. Create an BufferedImage of arbitrary dimensions and scale the text to the size of the BufferedImage. For an example of scaling, see StandardPrint.preview
ControlAltDel
  • 33,923
  • 10
  • 53
  • 80
2

I only found relatively circumstantial code. One needs FontMetrics, which depends on the granphics device (screen/printer).

Hence I make an overlarge image, compatible to the screen.

static BufferedImage textToImage(Font font, String text) {
    BufferedImage testImg = GraphicsEnvironment.getLocalGraphicsEnvironment()
            .getDefaultScreenDevice()
            .getDefaultConfiguration()
            .createCompatibleImage(1000, 100);
    FontMetrics fm;

    Graphics2D g = testImg.createGraphics();
    g.setFont(font);
    fm = g.getFontMetrics(font);
    Rectangle2D bounds = fm.getStringBounds(text, g);
    System.out.println("Bounds: " + bounds);
    g.setColor(Color.WHITE);
    g.fillRect(0, 0, testImg.getWidth(), testImg.getHeight());
    g.setColor(Color.MAGENTA.darker());
    g.drawString(text, 0, fm.getHeight() - fm.getDescent());
    g.dispose();

    Rectangle viewR = new Rectangle(0, 0, 1000, 100);
    Rectangle iconR = new Rectangle();
    Rectangle textR = new Rectangle();
    String displayedText = SwingUtilities.layoutCompoundLabel(fm, text, null,
                     SwingConstants.TOP, SwingConstants.LEFT, 0, 0,
                     viewR, iconR, textR, 0);

    System.out.println("textR: " + textR);
    BufferedImage img = testImg.getSubimage(0, 0, textR.width, textR.height);
    return img;
}

The string bounds are a floating point rectangle. Using SwingUtilities.layoutComponentLabel by comparison, one sees that the bounds are rounded up one and a half pixel: a font may shift a pixel part to have sharp edges.

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138