Проверка целостности шрифта в Java

Я пытаюсь перечислить все моноширинные шрифты, доступные на пользовательской машине. Я могу получить все семейства шрифтов в Swing через:

String[] fonts = GraphicsEnvironment.getLocalGraphicsEnvironment()
                                    .getAvailableFontFamilyNames();

Есть ли способ выяснить, какие из них являются моноширинными?

Спасибо заранее.

Ответ 1

Вы можете использовать метод getWidths() FontMetrics. Согласно JavaDoc:

Получает предварительные ширины первых 256 символов в шрифте. Продвижение - это расстояние от самой левой точки до самой правой точки на базовой линии. Обратите внимание, что продвижение строки не обязательно является суммой достижений ее персонажей.С >

Вы можете использовать метод charWidth(char) класса FontMetrics. Например:

Set<String> monospaceFontFamilyNames = new HashSet<String>();

GraphicsEnvironment graphicsEnvironment = GraphicsEnvironment.getLocalGraphicsEnvironment();
String[] fontFamilyNames = graphicsEnvironment.getAvailableFontFamilyNames();

BufferedImage bufferedImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
Graphics graphics = bufferedImage.createGraphics();

for (String fontFamilyName : fontFamilyNames) {
    boolean isMonospaced = true;

    int fontStyle = Font.PLAIN;
    int fontSize = 12;
    Font font = new Font(fontFamilyName, fontStyle, fontSize);
    FontMetrics fontMetrics = graphics.getFontMetrics(font);

    int firstCharacterWidth = 0;
    boolean hasFirstCharacterWidth = false;
    for (int codePoint = 0; codePoint < 128; codePoint++) { 
        if (Character.isValidCodePoint(codePoint) && (Character.isLetter(codePoint) || Character.isDigit(codePoint))) {
            char character = (char) codePoint;
            int characterWidth = fontMetrics.charWidth(character);
            if (hasFirstCharacterWidth) {
                if (characterWidth != firstCharacterWidth) {
                    isMonospaced = false;
                    break;
                }
            } else {
                firstCharacterWidth = characterWidth;
                hasFirstCharacterWidth = true;
            }
        }
    }

    if (isMonospaced) {
        monospaceFontFamilyNames.add(fontFamilyName);
    }
}

graphics.dispose();

Ответ 2

Простейший метод, который не требует создания BufferedImage для получения объекта Graphics и т.д.:

    Font fonts[] = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
    List<Font> monoFonts1 = new ArrayList<>();

    FontRenderContext frc = new FontRenderContext(null, RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT, RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT);
    for (Font font : fonts) {
        Rectangle2D iBounds = font.getStringBounds("i", frc);
        Rectangle2D mBounds = font.getStringBounds("m", frc);
        if (iBounds.getWidth() == mBounds.getWidth()) {
            monoFonts1.add(font);
        }
    }

Ответ 3

Сравните нарисованные длины нескольких символов (m, i, 1,. должно быть хорошим набором).

Для моноширинных шрифтов они будут равны, для шрифтов с переменной шириной они не будут.

Ответ 4

В соответствии с этим ответом, Java не слишком много знает о деталях шрифта, поэтому вам придется делать некоторые сравнения размеров шрифта.

Ответ 5

Вероятно, не применимо для вашего случая, но если вы просто хотите установить шрифт в моноширинный шрифт, используйте логическое имя шрифта:

Font mono = new Font("Monospaced", Font.PLAIN, 12);

Это будет гарантированный моноширинный шрифт в вашей системе.