Нужен способ масштабирования шрифта в соответствии с прямоугольником
Я просто написал код для масштабирования шрифта, чтобы он соответствовал (длине) прямоугольника. Он начинается с ширины 18 и итерации вниз до тех пор, пока он не подходит.
Это кажется ужасно неэффективным, но я не могу найти способ без него.
Эта строка предназначена для ярлыков в сетке игр, которая масштабируется, поэтому я не вижу решения для работы (обертывание, отсечение и прокрутка по прямоугольнику все неприемлемы).
На самом деле довольно быстро, я делаю это для сотен прямоугольников, и это достаточно быстро, чтобы просто замедлить его.
Если никто не придумает ничего лучшего, я просто загружу начальное предположение из таблицы (так, чтобы оно было намного ближе, чем 18), и используйте это - за исключением задержки, он отлично работает.
public Font scaleFont(String text, Rectangle rect, Graphics g, Font pFont) {
float nextTry=18.0f;
Font font=pFont;
while(x > 4) {
font=g.getFont().deriveFont(nextTry);
FontMetrics fm=g.getFontMetrics(font);
int width=fm.stringWidth(text);
if(width <= rect.width)
return font;
nextTry*=.9;
}
return font;
}
Ответы
Ответ 1
код полу-psuedo:
public Font scaleFont(String text, Rectangle rect, Graphics g, Font pFont) {
float fontSize = 20.0f;
Font font = pFont;
font = g.getFont().deriveFont(fontSize);
int width = g.getFontMetrics(font).stringWidth(text);
fontSize = (rect.width / width ) * fontSize;
return g.getFont().deriveFont(fontSize);
}
Я не уверен, почему вы проходите в pFont, поскольку он не используется...
Ответ 2
Вы можете использовать поиск интерполяции:
public static Font scaleFont(String text, Rectangle rect, Graphics g, Font pFont) {
float min=0.1f;
float max=72f;
float size=18.0f;
Font font=pFont;
while(max - min <= 0.1) {
font = g.getFont().deriveFont(size);
FontMetrics fm = g.getFontMetrics(font);
int width = fm.stringWidth(text);
if (width == rect.width) {
return font;
} else {
if (width < rect.width) {
min = size;
} else {
max = size;
}
size = Math.min(max, Math.max(min, size * (float)rect.width / (float)width));
}
}
return font;
}
Ответ 3
Измените все переменные ширины на float вместо int для лучшего результата.
public static Font scaleFontToFit(String text, int width, Graphics g, Font pFont)
{
float fontSize = pFont.getSize();
float fWidth = g.getFontMetrics(pFont).stringWidth(text);
if(fWidth <= width)
return pFont;
fontSize = ((float)width / fWidth) * fontSize;
return pFont.deriveFont(fontSize);
}
Ответ 4
private Font scaleFont ( String text, Rectangle rect, Graphics gc )
{
final float fMinimumFont = 0.1f;
float fMaximumFont = 1000f;
/* Use Point2d.Float to hold ( font, width of font in pixels ) pairs. */
Point2D.Float lowerPoint = new Point2D.Float ( fMinimumFont, getWidthInPixelsOfString ( text, fMinimumFont, gc ) );
Point2D.Float upperPoint = new Point2D.Float ( fMaximumFont, getWidthInPixelsOfString ( text, fMaximumFont, gc ) );
Point2D.Float midPoint = new Point2D.Float ();
for ( int i = 0; i < 50; i++ )
{
float middleFont = ( lowerPoint.x + upperPoint.x ) / 2;
midPoint.setLocation ( middleFont, getWidthInPixelsOfString ( text, middleFont, gc ) );
if ( midPoint.y >= rect.getWidth () * .95 && midPoint.y <= rect.getWidth () )
break;
else if ( midPoint.y < rect.getWidth () )
lowerPoint.setLocation ( midPoint );
else if ( midPoint.y > rect.getWidth () )
upperPoint.setLocation ( midPoint );
}
fMaximumFont = midPoint.x;
Font font = gc.getFont ().deriveFont ( fMaximumFont );
/* Now use Point2d.Float to hold ( font, height of font in pixels ) pairs. */
lowerPoint.setLocation ( fMinimumFont, getHeightInPixelsOfString ( text, fMinimumFont, gc ) );
upperPoint.setLocation ( fMaximumFont, getHeightInPixelsOfString ( text, fMaximumFont, gc ) );
if ( upperPoint.y < rect.getHeight () )
return font;
for ( int i = 0; i < 50; i++ )
{
float middleFont = ( lowerPoint.x + upperPoint.x ) / 2;
midPoint.setLocation ( middleFont, getHeightInPixelsOfString ( text, middleFont, gc ) );
if ( midPoint.y >= rect.getHeight () * .95 && midPoint.y <= rect.getHeight () )
break;
else if ( midPoint.y < rect.getHeight () )
lowerPoint.setLocation ( midPoint );
else if ( midPoint.y > rect.getHeight () )
upperPoint.setLocation ( midPoint );
}
fMaximumFont = midPoint.x;
font = gc.getFont ().deriveFont ( fMaximumFont );
return font;
}
private float getWidthInPixelsOfString ( String str, float fontSize, Graphics gc )
{
Font font = gc.getFont ().deriveFont ( fontSize );
return getWidthInPixelsOfString ( str, font, gc );
}
private float getWidthInPixelsOfString ( String str, Font font, Graphics gc )
{
FontMetrics fm = gc.getFontMetrics ( font );
int nWidthInPixelsOfCurrentFont = fm.stringWidth ( str );
return (float) nWidthInPixelsOfCurrentFont;
}
private float getHeightInPixelsOfString ( String string, float fontSize, Graphics gc )
{
Font font = gc.getFont ().deriveFont ( fontSize );
return getHeightInPixelsOfString ( string, font, gc );
}
private float getHeightInPixelsOfString ( String string, Font font, Graphics gc )
{
FontMetrics metrics = gc.getFontMetrics ( font );
int nHeightInPixelsOfCurrentFont = (int) metrics.getStringBounds ( string, gc ).getHeight () - metrics.getDescent () - metrics.getLeading ();
return (float) nHeightInPixelsOfCurrentFont * .75f;
}
Ответ 5
Вы можете повысить эффективность, используя бинарный шаблон поиска - высокий/низкий с некоторой степенью детализации - либо 1, 0,5, либо 0,25 балла.
Например, догадаться до 18, слишком высоко? Переместиться на 9, слишком низко? 13,5, слишком низкая? 15,75, слишком высокий? 14
Ответ 6
Другим очевидным способом будет текст, предварительно нарисованный на растровом изображении, а затем сглаживание растрового изображения в соответствии с прямоугольником; но из-за дизайна шрифтов ручной работы и намеков и т.д. поиск правильного размера шрифта дает наилучший результат (хотя, возможно, и не самый быстрый).