When drawing a large version of ��� (\u266B) with g.drawString() the font changes: the connecting beam points down, instead of up and the glyph is suddenly smaller. FontMetrics still reflect the width and height of what a properly scaled glyph would have looked like. This last fact makes this especially problematic, as the glyphs cannot be positioned properly anymore.
Demo Code:
==========
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
public class UnicodeFontMetricsIssues {
public static void main(final String[] args) {
final String note = "\u266B";
final String xNoteY = "\u266BY";
final String xY = "XY";
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new BorderLayout());
final JPanel iconPanel = new JPanel(new FlowLayout());
frame.getContentPane().add(iconPanel, BorderLayout.CENTER);
final TextIcon noteIcon = new TextIcon(note);
final TextIcon xNoteYIcon = new TextIcon(xNoteY);
final TextIcon xYIcon = new TextIcon(xY);
iconPanel.add(noteIcon);
iconPanel.add(xNoteYIcon);
iconPanel.add(xYIcon);
final JSlider slider = new JSlider(1, 2000, 1);
slider.setSnapToTicks(false);
final JPanel sliderPanel = new JPanel(new FlowLayout());
sliderPanel.add(slider);
final JLabel scaleFactorLabel = new JLabel("1.0");
sliderPanel.add(scaleFactorLabel);
frame.getContentPane().add(sliderPanel, BorderLayout.SOUTH);
slider.addChangeListener(e -> {
final float scaleFactor = slider.getValue()/100f;
noteIcon.setScaleFactor(scaleFactor);
xNoteYIcon.setScaleFactor(scaleFactor);
xYIcon.setScaleFactor(scaleFactor);
scaleFactorLabel.setText("" + scaleFactor);
frame.invalidate();
});
SwingUtilities.invokeLater(() -> {
frame.setSize(500, 800);
frame.setVisible(true);
});
}
private static class TextIcon extends JLabel {
private final String text;
public TextIcon(final String text) {
this.text = text;
setIcon(createIconWithText(1f));
}
public void setScaleFactor(final float scaleFactor) {
setIcon(createIconWithText(scaleFactor));
}
private ImageIcon createIconWithText(final float scaleFactor) {
final int width = 400;
final int height = 200;
final BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
final Graphics2D g2d = (Graphics2D)image.getGraphics();
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
final float originalSize = g2d.getFont().getSize2D();
g2d.setFont(g2d.getFont().deriveFont(originalSize * scaleFactor));
final FontMetrics metrics = g2d.getFontMetrics();
// fill whole background
g2d.setColor(Color.GREEN);
g2d.fillRect(0, 0, width, height);
// draw string bounds as RED background
final Rectangle2D rect = metrics.getStringBounds(text, g2d);
g2d.setColor(Color.RED);
g2d.fillRect((width - (int) rect.getWidth()) / 2, 0, (int)rect.getWidth(), (int)rect.getHeight());
// draw string
g2d.setColor(Color.BLACK);
g2d.drawString(text, (width - (int) rect.getWidth()) / 2, metrics.getAscent());
g2d.dispose();
return new ImageIcon(image);
}
}
}
The demo code lets you change the size of the font, showing a scale factor. The RED background shows the bounding box for the string.
The issue is illustrated in the attached screenshots and movie.