如何确定2字体具有同等字形? [英] How to determine if 2 fonts have equivalent glyphs?

查看:172
本文介绍了如何确定2字体具有同等字形?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

本Q&放大器; A由统一code字符在Swing没有灵感呈现,在实际使用什么字体但由于它没有回答询问具体问题,我决定进入作为自己的Q&安培; A。这里的问题是..

如何判断两个字体,对于一个给定的文本,在返回相同的字符字形实际上等同?


解决方案

这里使用的技巧是比较的GlyphVector 返回的字符串的兴趣。这种方法的症结可以在方法中可以看出 fontsAreEquivalentForText(字体,字体,字符串)

下面是宋体

一个例子输出

图形用户界面有三个基本组成部分。


  1. 文本到文本字段的GUI顶部测试。在这里,我们检查字符串敏捷的棕色狐狸跳过懒狗的英文字母。

  2. 所有字体列表显示在左侧。

  3. 在当前的字体是从所有的字体列表中选择时,会弹出一个撤销的(它需要一段时间来检查超过400的字体!)对话框,逐步建立在右边的列表中。这份名单是等效字体(并应包括所选择的字体,除非一个编程错误)。

code

 进口java.awt中的*。
java.awt.event中导入*。
进口java.awt.font.FontRenderContext;
进口java.awt.geom.Area中;
进口java.awt.image.BufferedImage中;
进口的javax.swing *。
进口javax.swing.border.EmptyBorder中;
javax.swing.event中导入*。公共类FontEquivalence {    公共布尔fontsAreEquivalentForText(字体F1,F2字体,文本字符串){
        区域面积以=新领域(
                f1.deriveFont(25F)。
                createGlyphVector(FontRenderContext中,文本)。
                getOutline());
        区区域2 =新Area(
                f2.deriveFont(25F)。
                createGlyphVector(FontRenderContext中,文本)。
                getOutline());
        返回area2.equals(区域);
    }    公共无效findEquivalentFonts(最终字体字型){
        如果(对话== NULL){
            对话框= getDialog(UI);
        }
        fontChecker =新的SwingWorker(){            @覆盖
            保护对象doInBackground()抛出异常{
                dialog.setLocationRelativeTo(UI);
                sameFontListModel.clear();
                字符串s = inputString.getText();
                INT fontNumber = fonts.length;
                progress.setMaximum(fontNumber);
                INT二= 1;
                对于(字体F:字体){
                    如果(fontsAreEquivalentForText(F,字体,S)){
                        sameFontListModel.addElement(F);
                    }
                    progress.setValue(二++);
                    如果(fontChecker.isCancelled()){
                        打破;
                    }
                }
                dialog.setVisible(假);
                返回null;
            }
        };
        fontChecker.execute();
        dialog.setVisible(真);
    }    公众的JDialog getDialog(JComponent的COMP){
        集装箱CONT = comp.getTopLevelAncestor();
        架F = NULL;
        如果(续的instanceof帧){
            F =(帧)续;
        }
        最终的JDialog D =新的JDialog(F,
                搜索+ fonts.length +字型的等价物。,
                真正);
        JPanel的P =新JPanel(新的BorderLayout(15,15));
        p.setBorder(新EmptyBorder(40,100,40,100));
        p.add(进度,BorderLayout.CENTER);        JButton的取消=的新的JButton(取消);
        ActionListener的人=新的ActionListener(){            @覆盖
            公共无效的actionPerformed(ActionEvent的五){
                fontChecker.cancel(真);                d.setVisible(假);
            }
        };
        cancel.addActionListener(人);
        JPanel的控制=新JPanel(新的FlowLayout(FlowLayout.CENTER));
        control.add(取消);
        p.add(控制,BorderLayout.PAGE_END);        d.add(P);
        d.pack();        返回D组;
    }    公共JComponent中的getUI(){
        如果(UI == NULL){
            UI =新JPanel(新的BorderLayout(2,2));
            inputString =新的JTextField(文字,15);
            inputString.setFont(inputString.getFont()的deriveFont(20F));
            ui.add(inputString,BorderLayout.PAGE_START);
            GraphicsEnvironment中GE = GraphicsEnvironment中。
                    getLocalGraphicsEnvironment();
            字体= ge.getAllFonts();
            最后JList中的FontList =新的JList(字体);
            ListSelectionListener LSL =新ListSelectionListener(){                @覆盖
                公共无效的valueChanged(ListSelectionEvent E){
                    如果(!e.getValueIsAdjusting()){
                        字体字型=(字体)fontList.getSelectedValue();
                        findEquivalentFonts(字体);
                    }
                }
            };
            fontList.addListSelectionListener(LSL);
            fontList.setCellRenderer(新FontCellRenderer());
            fontList.setVisibleRowCount(15);
            ui.add(新JScrollPane的(的FontList),BorderLayout.LINE_START);            JList的列表=新的JList(sameFontListModel);
            list.setCellRenderer(新FontCellRenderer());
            ui.add(新JScrollPane的(列表));            BufferedImage的双向=新的BufferedImage(
                    1,1,BufferedImage.TYPE_INT_RGB);
            Graphics2D的G = bi.createGraphics();
            的FontRenderContext = g.getFontRenderContext();            进度= JProgressBar的新(0,fonts.length);
            progress.setStringPainted(真);
        }
        返回UI;
    }    JPanel的UI = NULL;
    JTextField的inputString;
    字符串文本=敏捷的棕色狐狸跳过懒狗。
    字体[]字体;
    DefaultListModel sameFontListModel =新DefaultListModel();
    的FontRenderContext FontRenderContext中;
    的JDialog对话框;
    SwingWorker的fontChecker;
    进度JProgressBar的;    公共静态无效的主要(字串[] args){
        可运行R =新的Runnable(){
            @覆盖
            公共无效的run(){
                JFrame的F =新的JFrame(字体等);
                f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                f.setContentPane(新FontEquivalence()信息getUI());
                f.pack();
                f.setLocationByPlatform(真);
                f.setVisible(真);
            }
        };
        SwingUtilities.invokeLater(R);
    }
}类FontCellRenderer扩展DefaultListCellRenderer {    公共组件getListCellRendererComponent(
            JList的列表,
            对象的值,
            INT指数,
            布尔isSelected,
            布尔cellHasFocus){
        JLabel的标签=(JLabel的)super.getListCellRendererComponent(
                列表值,索引,isSelected,cellHasFocus);
        字体字型=(字体)值;
        label.setFont(font.deriveFont(20F));
        label.setText(font.getName());
        返回标签;
    }
}

更新

StanislavL提醒我一些脆弱性在评论此方法:


  

一个注意:使用 Font.layoutGlyphVector(),而不是 createGlyphVector()。目前的解决方案可能会产生一些字体的重新排序字形错误的结果。大约从的Javadoc createGlyphVector()搜索结果这个方法确实没有其他的处理,除了字形到字符的映射。这意味着,这个方法不适合某些脚本,如阿拉伯语,希伯来语,泰语,印度语和,需要重新排序,整形或连字替换有用。搜索结果我见过像这样用阿拉伯语和希伯来语渲染。


我将离开这个code原样,但详细内容见<一href=\"http://docs.oracle.com/javase/8/docs/api/java/awt/Font.html#layoutGlyphVector-java.awt.font.FontRenderContext-char:A-int-int-int-\"相对=nofollow> Font.layoutGlyphVector(FontRenderContext中,CHAR [],开始,限制,标志) 其中:


  

返回一个新的的GlyphVector 对象,执行文本,如果可能的全面布局。完整布局需要复杂的文本,如阿拉伯语或印地文。针对不同脚本的支持取决于字体和实现。 ..


This Q&A was inspired by Unicode char not rendering in Swing, what font is used in real? but since it does not answer the specific question asked, I decided to enter it as its own Q&A. The question here is..

How to determine if two fonts, for a given text, are effectively equivalent in returning identical character glyphs?

解决方案

The trick used here is to compare the GlyphVector returned for the String of interest. The crux of this approach can be seen in the method fontsAreEquivalentForText(Font,Font,String).

Here is an example output for Arial.

The GUI has three basic components.

  1. The text to test in a text field at the top of the GUI. Here we check the letters of the alphabet in the string The quick brown fox jumps over the lazy dog.
  2. The list of all fonts is shown on the left.
  3. When a font is selected from the list of all the fonts, it will pop a cancellable (it takes a while to check over 400 fonts!) dialog that progressively builds the list on the right. This list is the equivalent fonts (and should include the selected font, barring a programming error).

Code

import java.awt.*;
import java.awt.event.*;
import java.awt.font.FontRenderContext;
import java.awt.geom.Area;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.*;

public class FontEquivalence {

    public boolean fontsAreEquivalentForText(Font f1, Font f2, String text) {
        Area area1 = new Area(
                f1.deriveFont(25f).
                createGlyphVector(fontRenderContext, text).
                getOutline());
        Area area2 = new Area(
                f2.deriveFont(25f).
                createGlyphVector(fontRenderContext, text).
                getOutline());
        return area2.equals(area1);
    }

    public void findEquivalentFonts(final Font font) {
        if (dialog == null) {
            dialog = getDialog(ui);
        }
        fontChecker = new SwingWorker() {

            @Override
            protected Object doInBackground() throws Exception {
                dialog.setLocationRelativeTo(ui);
                sameFontListModel.clear();
                String s = inputString.getText();
                int fontNumber = fonts.length;
                progress.setMaximum(fontNumber);
                int ii = 1;
                for (Font f : fonts) {
                    if (fontsAreEquivalentForText(f, font, s)) {
                        sameFontListModel.addElement(f);
                    }
                    progress.setValue(ii++);
                    if (fontChecker.isCancelled()) {
                        break;
                    }
                }
                dialog.setVisible(false);
                return null;
            }
        };
        fontChecker.execute();
        dialog.setVisible(true);
    }

    public JDialog getDialog(JComponent comp) {
        Container cont = comp.getTopLevelAncestor();
        Frame f = null;
        if (cont instanceof Frame) {
            f = (Frame) cont;
        }
        final JDialog d = new JDialog(f, 
                "Searching " + fonts.length + " fonts for equivalents..", 
                true);
        JPanel p = new JPanel(new BorderLayout(15, 15));
        p.setBorder(new EmptyBorder(40, 100, 40, 100));
        p.add(progress, BorderLayout.CENTER);

        JButton cancel = new JButton("Cancel");
        ActionListener al = new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                fontChecker.cancel(true);

                d.setVisible(false);
            }
        };
        cancel.addActionListener(al);
        JPanel control = new JPanel(new FlowLayout(FlowLayout.CENTER));
        control.add(cancel);
        p.add(control, BorderLayout.PAGE_END);

        d.add(p);
        d.pack();

        return d;
    }

    public JComponent getUI() {
        if (ui == null) {
            ui = new JPanel(new BorderLayout(2, 2));
            inputString = new JTextField(text, 15);
            inputString.setFont(inputString.getFont().deriveFont(20f));
            ui.add(inputString, BorderLayout.PAGE_START);
            GraphicsEnvironment ge = GraphicsEnvironment.
                    getLocalGraphicsEnvironment();
            fonts = ge.getAllFonts();
            final JList fontList = new JList(fonts);
            ListSelectionListener lsl = new ListSelectionListener() {

                @Override
                public void valueChanged(ListSelectionEvent e) {
                    if (!e.getValueIsAdjusting()) {
                        Font font = (Font) fontList.getSelectedValue();
                        findEquivalentFonts(font);
                    }
                }
            };
            fontList.addListSelectionListener(lsl);
            fontList.setCellRenderer(new FontCellRenderer());
            fontList.setVisibleRowCount(15);
            ui.add(new JScrollPane(fontList), BorderLayout.LINE_START);

            JList list = new JList(sameFontListModel);
            list.setCellRenderer(new FontCellRenderer());
            ui.add(new JScrollPane(list));

            BufferedImage bi = new BufferedImage(
                    1, 1, BufferedImage.TYPE_INT_RGB);
            Graphics2D g = bi.createGraphics();
            fontRenderContext = g.getFontRenderContext();

            progress = new JProgressBar(0, fonts.length);
            progress.setStringPainted(true);
        }
        return ui;
    }

    JPanel ui = null;
    JTextField inputString;
    String text = "The quick brown fox jumps over the lazy dog.";
    Font[] fonts;
    DefaultListModel sameFontListModel = new DefaultListModel();
    FontRenderContext fontRenderContext;
    JDialog dialog;
    SwingWorker fontChecker;
    JProgressBar progress;

    public static void main(String[] args) {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                JFrame f = new JFrame("Font Equivalence");
                f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
                f.setContentPane(new FontEquivalence().getUI());
                f.pack();
                f.setLocationByPlatform(true);
                f.setVisible(true);
            }
        };
        SwingUtilities.invokeLater(r);
    }
}

class FontCellRenderer extends DefaultListCellRenderer {

    public Component getListCellRendererComponent(
            JList list,
            Object value,
            int index,
            boolean isSelected,
            boolean cellHasFocus) {
        JLabel label = (JLabel) super.getListCellRendererComponent(
                list, value, index, isSelected, cellHasFocus);
        Font font = (Font) value;
        label.setFont(font.deriveFont(20f));
        label.setText(font.getName());
        return label;
    }
}

Update

StanislavL alerted me to some fragility in this method in a comment:

A note: Use Font.layoutGlyphVector() rather than createGlyphVector(). Current solution may generate wrong results for some fonts which reorder glyphs. From Javadoc about createGlyphVector()

This method does no other processing besides the mapping of glyphs to characters. This means that this method is not useful for some scripts, such as Arabic, Hebrew, Thai, and Indic, that require reordering, shaping, or ligature substitution.

I've seen something like this with Arabic and Hebrew rendering.

I will leave this code as-is, but for more details see Font.layoutGlyphVector(FontRenderContext,char[],start,limit,flags) which:

Returns a new GlyphVector object, performing full layout of the text if possible. Full layout is required for complex text, such as Arabic or Hindi. Support for different scripts depends on the font and implementation. ..

这篇关于如何确定2字体具有同等字形?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆