查找适合区域的最大字体大小-Java
我的JPanel中有一个区域以点(0,0)和(宽度、高度)为边界。它是一个正方形 我有话要说查找适合区域的最大字体大小-Java,java,jpanel,fontmetrics,Java,Jpanel,Fontmetrics,我的JPanel中有一个区域以点(0,0)和(宽度、高度)为边界。它是一个正方形 我有话要说 String s; 我想找到s可以使用的最大字体大小。现在,我知道有一种方法可以使用FontMetrics和for循环来不断增加字体大小,直到它不适合该区域。但是这是非常低效的,必须有一种方法来计算给定字体类型的字体大小,例如“Courier”,它将适合这个区域 坏方法示例: Font f = new Font("Courier", Font.PLAIN, 1); FontMetrics fm = t
String s;
我想找到s
可以使用的最大字体大小。现在,我知道有一种方法可以使用FontMetrics和for循环来不断增加字体大小,直到它不适合该区域。但是这是非常低效的,必须有一种方法来计算给定字体类型的字体大小,例如“Courier”,它将适合这个区域
坏方法示例:
Font f = new Font("Courier", Font.PLAIN, 1);
FontMetrics fm = this.getFontMetrics(f); //this is a JPanel
do {
f = new Font("Courier", Font.PLAIN, f.getSize()+1);
fm = this.getFontMetrics(f);
while(fm.stringWidth(s) < width && fm.getHeight() < height);
Font f=新字体(“Courier”,Font.PLAIN,1);
FontMetrics fm=this.getFontMetrics(f)//这是一个JPanel
做{
f=新字体(“Courier”,Font.PLAIN,f.getSize()+1);
fm=this.getFontMetrics(f);
while(fm.stringWidth
我也遇到了同样的问题,并找到了一个稍微优化了一点的解决方案,而不仅仅是迭代所有字体大小。我尝试通过调整添加或减去的差异来收敛到最佳字体大小,直到发现差异字体大小小于1
Graphics2D graphics = image.createGraphics();
graphics.setColor(Color.black);
if (subtitleFont == null) {
//create rectangle first (from a separate library
int[] rect = matrix.getEnclosingRectangle();
// define the maximum rect for the text
Rectangle2D maxRect = new Rectangle2D.Float(0, 0, w - 7, h - rect[0] - rect[3] - 10);
subtitleX = 0;
subtitleY = 0;
// starting with a very big font due to a high res image
float size = 80f * 4f;
// starting with a diff half the size of the font
float diff = size / 2;
subtitleFont = graphics.getFont().deriveFont(Font.BOLD).deriveFont(size);
FontMetrics fontMetrics = graphics.getFontMetrics(subtitleFont);
Rectangle2D stringBounds = null;
while (Math.abs(diff) > 1) {
subtitleFont = subtitleFont.deriveFont(size);
graphics.setFont(subtitleFont);
fontMetrics = graphics.getFontMetrics(subtitleFont);
stringBounds = fontMetrics.getStringBounds(options.subtitle, graphics);
stringBounds = new Rectangle2D.Float(0f, 0f, (float) (stringBounds.getX() + stringBounds.getWidth()), (float) ( stringBounds.getHeight()));
if (maxRect.contains(stringBounds)) {
if (0 < diff) {
diff = Math.abs(diff);
} else if (diff < 0) {
diff = Math.abs(diff) / 2;
}
} else {
if (0 < diff) {
diff = - Math.abs(diff) / 2;
} else if (diff < 0) {
if (size <= Math.abs(diff)) {
diff = - Math.abs(diff) / 2;
} else {
diff = - Math.abs(diff);
}
}
}
size += diff;
}
subtitleX = (int) ((w/2) - (stringBounds.getWidth() / 2));
subtitleY = (int) (h - maxRect.getHeight() + fontMetrics.getAscent());
}
graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
graphics.drawString(options.subtitle, subtitleX, subtitleY);
Graphics2D graphics=image.createGraphics();
图形.设置颜色(颜色.黑色);
如果(字体==null){
//首先创建矩形(从单独的库中
int[]rect=matrix.getEnclosuringRectangle();
//定义文本的最大矩形
rectangle2dmaxrect=新的Rectangle2D.Float(0,0,w-7,h-rect[0]-rect[3]-10);
x=0;
副标题y=0;
//由于图像的分辨率很高,所以开始使用非常大的字体
浮子尺寸=80f*4f;
//以字体大小一半的差异开始
浮差=尺寸/2;
subtitleFont=graphics.getFont().deriveFont(Font.BOLD).deriveFont(size);
FontMetrics FontMetrics=graphics.getFontMetrics(字体);
矩形2D stringBounds=null;
而(数学绝对值(差值)>1){
subtitleFont=subtitleFont.deriveFont(大小);
graphics.setFont(字幕字体);
fontMetrics=graphics.getFontMetrics(字体);
stringBounds=fontMetrics.getStringBounds(options.subtitle,graphics);
stringBounds=newRectangle2D.Float(0f,0f,(Float)(stringBounds.getX()+stringBounds.getWidth(),(Float)(stringBounds.getHeight());
if(maxRect.contains(stringBounds)){
if(0 如果(size是的,我也遇到了同样的问题,我知道你所说的“低效”是什么意思
我尝试了一种解决方案,通过字体大小测量字符串的单位计数:1(默认值)
例如:
String line = "This is a test";
Font font = Font.createFont(Font.TRUETYPE_FONT, new File("/var/fonts/times.ttf"));
FontRenderContext ctx = new FontRenderContext(font.getTransform(), false, false);
Rectangle2D rect = font.getStringBounds(line, ctx);
BigDecimal widthUnits = BigDecimal.valueof(rect.getWidth());
然后,按字体大小1得到行的宽度单位。如果它除以区域宽度并保留整数部分(向下舍入),则在水平方向上得到最大字体大小
int maxSizeHor = BigDecimal.valueOf(width)
.divide(widthUnits, 1, BigDecimal.ROUND_DOWN)
.intValue();
但是,这不是很长。您还应该计算垂直方向上的最大字体大小。幸运的是,具有相同字体样式和字体大小的每一行具有相同的高度。如果有多行,您可以使用:
lines.length * each height in font size 1.
例如:
String[] lines = new String{"This is a test", "Hello World!"};
BigDecimal heightUnits = BigDecimal.valueOf(rect.getHeight())
.multiply(BigDecimal.valueOf(lines.length));
int maxSizeVer = BigDecimal.valueOf(height)
.divide(heightUnits
.multiply(BigDecimal.valueOf(lines.length)),
1,BigDecimal.ROUND_DOWN)
.intValue();
最后,比较并获取最小值作为最大字体大小:
Math.min(maxSizeHor, maxSizeVer)
但是,我遇到了另一个问题:将单个字符“I”作为输入字符串,字体大小为:1,您将得到宽度单位:0.0。然而,实际上,它不会为零,尽管它是一个非常小的值。因此,我将1000设置为默认字体大小,并在每次处理后除以1000。然后,我得到非零值。对于非等距字体,每个字符都可以为零不同的宽度。因此,您必须迭代字符串的长度,将每个字符的相对宽度相加,然后乘以当前字体大小的一个系数。这听起来和您已经描述的方法一样“低效”。但这太低效了-你需要它有多高的效率?我已经在生产代码中成功地实现了这种方法,每秒钟用文本绘制数百个多边形,而且工作非常顺利-而且是在Java 1.4上。所以你们都在说这是最好的方法?我只是认为会有更好的方法。@CodeGuy:是的,差不多。我的意思是,你是否真的因此而在性能上经历了有意义的减速?如果不是,我就不会费心去优化它。理论上,你可以用稍微好一点的算法来加速它,但这不值得付出努力。比较一下掉蛋问题: