Java 是否在GraphicsEnvironment中注销字体?

Java 是否在GraphicsEnvironment中注销字体?,java,fonts,awt,batik,Java,Fonts,Awt,Batik,我最近发现了如何在本地GraphicsEnvironment s.t.注册TTF字体。对于我的用例(SVG到PNG的转码),Apache Batik可能会识别这种字体: import java.awt.Font; import java.awt.FontFormatException; import java.awt.GraphicsEnvironment; // [...] GraphicsEnvironment lge = GraphicsEnvironment.getLocalGrap

我最近发现了如何在本地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.Win32GraphicsEnvironment

编辑:更多信息:

  • 随着sun.font.FontManager随着Java7的变化(从类到接口,等等),我不希望使用依赖它的任何解决方法
  • 我的JVM是Oracle JVM

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

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

      public boolean registerFont(字体){
      /*不应使用“null”调用此方法。
      *打电话的人有责任确保这一点。
      */
      如果(字体==null){
      返回false;
      }
      /*只有在我们开始使用此API时才初始化这些对象*/
      已同步(regFamilyKey){
      if(createdByFamilyName==null){
      createdByFamilyName=新哈希表();
      createdByFullName=新哈希表();
      }
      }
      如果(!FontAccess.getFontAccess().isCreatedFont(字体)){
      返回false;
      }
      /*我们希望确保此字体不能覆盖现有字体
      *已安装字体。请检查以下条件:
      *-族名称不是已安装字体的名称
      *-全名不是已安装字体的全名
      *-族名称与已安装字体的全名不同
      *-全名与已安装字体的族名称不同
      *最后两个可能起初看起来很奇怪,但原因是
      *(不幸的是)字体构造器不区分这些。
      *这种问题的一个极端例子是字体
      *姓“Dialog.Plain”和全名“Dialog”。
      *这里有一个可能过于严格的限制是
      *应用程序希望提供现有族的新成员
      *它将被拒绝。但是由于JRE可以执行合成
      *在许多情况下,造型是不必要的。
      *我们不会对注册字体应用相同的逻辑
      *要做到这一点,让我们假设他们有理由。这不会造成问题
      *除了他们自己。
      */
      HashSet name=getInstalledNames();
      语言环境l=getSystemStartupLocale();
      字符串familyName=font.getFamily(l.toLowerCase();
      字符串fullName=font.getFontName(l).toLowerCase();
      if(names.contains(familyName)| | names.contains(fullName)){
      返回false;
      }
      /*检查通过,现在注册字体*/
      哈希表家族表;
      哈希表fullNameTable;
      如果(!maybeMultipAppContext()){
      familyTable=createdByFamilyName;
      fullNameTable=createdByFullName;
      Fontsarregistered=真;
      }否则{
      AppContext AppContext=AppContext.getAppContext();
      家谱=
      (哈希表)appContext.get(regFamilyKey);
      全名表=
      (哈希表)appContext.get(regFullNameKey);
      如果(familyTable==null){
      familyTable=新哈希表();
      fullNameTable=新哈希表();
      appContext.put(regFamilyKey,familyTable);
      put(regFullNameKey,fullNameTable);
      }
      FontsarreRegisteredPerAppContext=true;
      }
      /*创建FontFamily并将字体添加到表中*/
      Font2D Font2D=FontUtilities.getFont2D(字体);
      int style=font2D.getStyle();
      FontFamily=familyTable.get(familyName);
      if(family==null){
      family=新FontFamily(font.getFamily(l));
      familyTable.put(familyName,family);
      }
      /*如果不使用应用程序上下文,请删除名称缓存项。
      *为了适应这样一种情况,代码可能首先注册了一个普通代码
      *家庭成员,然后使用它,现在正在注册一个大胆的家庭
      *成员,我们需要移除所有家庭成员,以便
      *新风格可以被采用,而不是继续合成。
      */
      如果(Fontsarreregistered){
      removeFromCache(family.getFont(Font.PLAIN));
      removeFromCache(family.getFont(Font.BOLD));
      removeFromCache(family.getFont(Font.ITALIC));
      移除缓存(family.getFont(Font.BOLD | Font.ITALIC));
      removeFromCache(fullNameTable.get(fullName));
      }
      setFont(font2D,样式);
      fullNameTable.put(fullName,font2D);
      返回true;
      }
      
      FontManager API随着Java7的变化而变化,所以,是的,我不想使用反射来处理这个问题。你在哪里找到源代码的?这是OpenJDK吗?我的JVM是Oracle的。@RobertG单击文章顶部的链接。在格雷普编码上
      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;
      }