在graphicenvironment中取消字体注册



我最近发现了如何向本地GraphicsEnvironment, s.t注册TTF字体,对于我的用例(svg到png转码),Apache Batik可能会识别字体:

import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.GraphicsEnvironment;
// [...]
GraphicsEnvironment lge = GraphicsEnvironment.getLocalGraphicsEnvironment();
try {
    Font font = Font.createFont(Font.TRUETYPE_FONT, fontFile);
    lge.registerFont(font);
} catch (FontFormatException e) {
    logger.warn(e.getMessage(), e);
} catch (IOException e) {
    logger.warn(e.getMessage(), e);
}

然而,我想知道我是否可以取消注册任何预先存在的字体,以保证只有我注册的字体将在转码中使用。

没有GraphicsEnvironment#unregisterFont(…),我怎么能做到这一点呢?

PS:我不想继承GraphicsEnvironment,因为我不能假设存在任何特定的子类,如sun.awt. win32graphicsenvirenvironment。

EDIT:更多信息:

  • 由于sun.font.FontManager随着Java7的变化而变化(从类到接口,等等),我宁愿不使用任何依赖于它的变通方法。
  • 我的JVM是Oracle JVM。

如果没有私有静态变量的反射,这是不可能做到的。你确定要这么做吗?

查看sun.font.FontManager.registerFont的源代码,它可能已经具有您想要的安全性。(这是在调用GraphicsEnvironment.registerFont时执行实际工作的方法)

public boolean registerFont(Font font) {
    /* This method should not be called with "null".
     * It is the caller's responsibility to ensure that.
     */
    if (font == null) {
        return false;
    }
    /* Initialise these objects only once we start to use this API */
    synchronized (regFamilyKey) {
        if (createdByFamilyName == null) {
            createdByFamilyName = new Hashtable<String,FontFamily>();
            createdByFullName = new Hashtable<String,Font2D>();
        }
    }
    if (! FontAccess.getFontAccess().isCreatedFont(font)) {
        return false;
    }
    /* We want to ensure that this font cannot override existing
     * installed fonts. Check these conditions :
     * - family name is not that of an installed font
     * - full name is not that of an installed font
     * - family name is not the same as the full name of an installed font
     * - full name is not the same as the family name of an installed font
     * The last two of these may initially look odd but the reason is
     * that (unfortunately) Font constructors do not distinuguish these.
     * An extreme example of such a problem would be a font which has
     * family name "Dialog.Plain" and full name of "Dialog".
     * The one arguably overly stringent restriction here is that if an
     * application wants to supply a new member of an existing family
     * It will get rejected. But since the JRE can perform synthetic
     * styling in many cases its not necessary.
     * We don't apply the same logic to registered fonts. If apps want
     * to do this lets assume they have a reason. It won't cause problems
     * except for themselves.
     */
    HashSet<String> names = getInstalledNames();
    Locale l = getSystemStartupLocale();
    String familyName = font.getFamily(l).toLowerCase();
    String fullName = font.getFontName(l).toLowerCase();
    if (names.contains(familyName) || names.contains(fullName)) {
        return false;
    }
    /* Checks passed, now register the font */
    Hashtable<String,FontFamily> familyTable;
    Hashtable<String,Font2D> fullNameTable;
    if (!maybeMultiAppContext()) {
        familyTable = createdByFamilyName;
        fullNameTable = createdByFullName;
        fontsAreRegistered = true;
    } else {
        AppContext appContext = AppContext.getAppContext();
        familyTable =
            (Hashtable<String,FontFamily>)appContext.get(regFamilyKey);
        fullNameTable =
            (Hashtable<String,Font2D>)appContext.get(regFullNameKey);
        if (familyTable == null) {
            familyTable = new Hashtable<String,FontFamily>();
            fullNameTable = new Hashtable<String,Font2D>();
            appContext.put(regFamilyKey, familyTable);
            appContext.put(regFullNameKey, fullNameTable);
        }
        fontsAreRegisteredPerAppContext = true;
    }
    /* Create the FontFamily and add font to the tables */
    Font2D font2D = FontUtilities.getFont2D(font);
    int style = font2D.getStyle();
    FontFamily family = familyTable.get(familyName);
    if (family == null) {
        family = new FontFamily(font.getFamily(l));
        familyTable.put(familyName, family);
    }
    /* Remove name cache entries if not using app contexts.
     * To accommodate a case where code may have registered first a plain
     * family member and then used it and is now registering a bold family
     * member, we need to remove all members of the family, so that the
     * new style can get picked up rather than continuing to synthesise.
     */
    if (fontsAreRegistered) {
        removeFromCache(family.getFont(Font.PLAIN));
        removeFromCache(family.getFont(Font.BOLD));
        removeFromCache(family.getFont(Font.ITALIC));
        removeFromCache(family.getFont(Font.BOLD|Font.ITALIC));
        removeFromCache(fullNameTable.get(fullName));
    }
    family.setFont(font2D, style);
    fullNameTable.put(fullName, font2D);
    return true;
}

最新更新