Unregister font with GraphicsEnvironment?

房东的猫 提交于 2019-12-19 02:52:11

问题


I recently found out how to register a TTF font with the local GraphicsEnvironment, s.t., for my use case (SVG-to-PNG transcoding), Apache Batik may recognize the font:

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);
}

However, I was wondering if I could unregister any pre-existing fonts in order to guarantee that only the fonts I register will be used in transcoding.

There is no GraphicsEnvironment#unregisterFont(...), how could I achieve this instead?

PS: I don't want to subclass GraphicsEnvironment, as I cannot assume the presence any specific subclass, like sun.awt.Win32GraphicsEnvironment.

EDIT: Some more infos:

  • As sun.font.FontManager changes with Java7 (from class to interface, and whatnot), I'd rather not use any workaround relying on it.
  • My JVM is the Oracle JVM.

回答1:


This cannot be done without reflection of private static variables and such... are you sure you need to do this?

Check out the source code to sun.font.FontManager.registerFont, it may already have the safety you desire. (This is the method that does the actual work when you call 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;
}


来源:https://stackoverflow.com/questions/23523648/unregister-font-with-graphicsenvironment

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!