Reputation: 948
When writing text** to a Graphics2D
object, I'm finding that the x position of the text changes when I change the size of the font. As the size increases, the x position increases. This happens no matter what method I use to write the text: drawString
, fill
or draw
with a GlyphVector
, or drawGlyphVector
.
** both the beginning character of the text and the font type change this behavior: Sans Serif fonts, where the beginning character's left-most stroke is a vertical line (P, H, L, E, etc...) are the most affected. If the font is Serif and/or the beginning character's left-most stroke is not vertical (W, y, Y, T, X, etc...), this behavior is decreased or eliminated.
Here's a sample program that illustrates this behavior:
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
public class FontSizeTest {
public FontSizeTest() {
super();
}
public static void main(String[] args) throws IOException {
int width = 700, height = 120;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = image.createGraphics();
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, width, height);
FontRenderContext frc = g2d.getFontRenderContext();
Font font = new Font(Font.SANS_SERIF, Font.PLAIN, 10);
GlyphVector gv;
Rectangle pixelBounds;
g2d.setColor(Color.BLACK);
g2d.translate(10, 100);
for(float size : new float[]{40f, 80f, 120f}) {
font = font.deriveFont(size);
gv = font.createGlyphVector(frc, "Hello World");
pixelBounds = gv.getPixelBounds(frc, 0, 0);
System.out.printf("font: %s%npixel bounds: %s%n", font, pixelBounds);
g2d.fill(gv.getOutline());
g2d.draw(pixelBounds);
}
g2d.dispose();
File pngFile = new File("FontSizeTest.png");
ImageIO.write(image, "png", pngFile);
System.out.printf("png file written: %s%n", pngFile.getCanonicalPath());
}
}
The output of this program is info to the console:
font: java.awt.Font[family=SansSerif,name=SansSerif,style=plain,size=40]
pixel bounds: java.awt.Rectangle[x=4,y=-31,width=217,height=31]
font: java.awt.Font[family=SansSerif,name=SansSerif,style=plain,size=80]
pixel bounds: java.awt.Rectangle[x=7,y=-62,width=432,height=63]
font: java.awt.Font[family=SansSerif,name=SansSerif,style=plain,size=120]
pixel bounds: java.awt.Rectangle[x=11,y=-93,width=651,height=94]
png file written: FontSizeTest.png
And the image:
Note how the larger font sizes draw offset from the smaller font sizes.
If this is expected behavior, I can adjust for it by getting the offset from the pixel bounds and adjusting the x coordinate using translate
; I'm just not sure this is the expected behavior. I feel like I'm doing something wrong - missing some piece of the Graphics2D
programming approach.
Upvotes: 2
Views: 1191
Reputation: 4039
This effect is normal behaviour of Fonts. Even Microsoft Word has this offset in textlines with different sizes.
If you want to align all of your textlines at the same pixel line you could use translate
with your calculated pixel bounds as you mentioned.
A way more elegant way is to shift your glyphs positions in the GlyphVector. That will also result in a shift of the getPixelBounds
result.
public static void adjust(GlyphVector gv){
// calc the adjust Factor
int adjust = (int)Math.round(gv.getGlyphVisualBounds(0).getBounds2D().getMinX());
// Shift all the Glyphs in Vector
for (int i = 0; i < gv.getNumGlyphs(); i++) {
Point2D point = gv.getGlyphPosition(i);
gv.setGlyphPosition( i, new Point2D.Double(
point.getX() - adjust,
point.getY()));
}
}
Use it in your code after you create the Glyph Vector and you get the result you want.
gv = font.createGlyphVector(frc, "Hello World");
adjust(gv);
Upvotes: 2