问题描述

虽然在前面基础上,已经能接受并显示中文了,但每次运行程序都要重新画那么多字符,很慢。考虑利用FengGUI先生成自己的png图片及与之对应的font文件,之后运行时就导入这两个文件,这样就不会每次运行都重新画字符,将快很多。

解决方案

  • 在fenggui中想实现中文的支持,但每次运行程序都得重新画字符,这样很慢,因为中文字符比英文字符多很多倍。
    但fenggui提供了可以从外面引入png及xml的方法,这就表示可以使用自己的png图片库。
    下面是生成png及与之对应的xml(这里写成了test.font文件,其实一回事)的方案,当然支持中文的部分不只是这一点点,应该结合前面的修改来看,才会是完整的支持中文的解决方案。
    最终生成的font文件大小有8M多,png有480多K。


在fenggui中生成与png文件对应的font文件:
font文件主要格式如下:
<?xml version='1.0' encoding='utf-8'?>

<Font>
  <CharacterPixmap x="72" y="145"width="15" height="29" charWidth="15">
     <character><![CDATA[~]]></character>
  </CharacterPixmap>
// ..... 这种在实际应用font文件时不能作为注释
</Font>
x, y, width, height表示这个字符所在的格子(一个rectangle,矩形)的位置及大小,其中(x,y)是该矩形的最下角的坐标,左上角的坐标
为(x, y + height),右下角的坐标为(x +width, y), 右上角的坐标为(x + width, y + height)。
charWidth表示字符所占的宽度。


 第一步:
修改代码:
org.fenggui.util.CharacterPixmap源文件中, 修改之处的源代码:
public CharacterPixmap(ITexture texture, int x, int y, int width, int height,char c, int charWidth)
  {
    super(texture, x, y, width, height);
    this.charWidth = charWidth;
    character = c;
  }
修改之后的代码:

    File file;
    FileOutputStream fos;

    public CharacterPixmap(ITexture texture, int x, int y, int width,int height, char c, int charWidth) {
        super(texture, x, y, width, height);
        this.charWidth = charWidth;
        character = c;

        //生产font文件
        if (file == null) {
            file = newFile("D:\\test.font");
        }

        try {
            if (fos == null) {
                fos = newFileOutputStream(file, true);
            }
            String s = "<CharacterPixmap x=\"" + x + "\" y=\"" + y +"\" width=\"" + width + "\" height=\""+ height + "\" charWidth=\"" + charWidth+"\">\n" +
                   "    <character><![CDATA[" + c +"]]></character>\n" +
                   "  </CharacterPixmap>\n\n";
            fos.write(s.getBytes());
        } catch (IOException e) {
            System.out.println("写入test.font文件时发生异常!");
            e.printStackTrace();
        }
    }

这里写入font文件的变量名x, y, width,height, charWidth等要与下面解析它们的这代码中的一致:
org.fenggui.util.FontSAXHandler类:

@Override
  public void startElement(String uri, String localName, StringqName, Attributes attributes) throws SAXException
  {
    if (qName.equals("CharacterPixmap"))
    {
      x = 0;
      y = 0;
      width = 0;
      height = 0;
      charWidth = 0;

      x =Integer.parseInt(attributes.getValue("x"));
      y =Integer.parseInt(attributes.getValue("y"));
      width =Integer.parseInt(attributes.getValue("width"));
      height = Integer.parseInt(attributes.getValue("height"));
      charWidth =Integer.parseInt(attributes.getValue("charWidth"));

    }
    else if (qName.equals("character"))
      builder = new StringBuilder();
  }

第二步:


在包org.fenggui.util.fonttoolkit中的FontFactory类里, 打开这句代码:
saveImageToDisk(bi, "D:\\test.png");
生产test.png图片

第三步:
在org.fenggui.binding.render.ImageFont类的
public void process(InputOutputStream stream) throws IOException,IXMLStreamableException方法中
打开这段代码:
boolean antialiasing = stream.processAttribute("antialiasing", true,false);
                java.awt.FontawtFont = new java.awt.Font(name, type, size);
                StringalphabetStr = stream.processAttribute("alphabet","unknown", "utf8");
                if(alphabetStr.equalsIgnoreCase("utf8"))
                   f = FontFactory.renderStandardFont(awtFont, antialiasing,Alphabet.UTF8);
                else if(alphabetStr.equalsIgnoreCase("english"))
                   f = FontFactory.renderStandardFont(awtFont, antialiasing,Alphabet.ENGLISH);
                else if(alphabetStr.equalsIgnoreCase("german"))
                   f = FontFactory.renderStandardFont(awtFont, antialiasing,Alphabet.GERMAN);
                else if(alphabetStr.equalsIgnoreCase("french"))
                   f = FontFactory.renderStandardFont(awtFont, antialiasing,Alphabet.FRENCH);
                else if(alphabetStr.equalsIgnoreCase("danish"))
                   f = FontFactory.renderStandardFont(awtFont, antialiasing,Alphabet.DANISH);
                else if(alphabetStr.equalsIgnoreCase("estonian"))
                   f = FontFactory.renderStandardFont(awtFont, antialiasing,Alphabet.ESTONIAN);
同时在该方法中关闭:
//                f = newImageFont("D:\\test.png", "D:\\test.font");

这样就可以生产png图片以及与之相对应的font文件了,但是font文件格式还不对,还得手动在最前面加上
<?xml version='1.0' encoding='utf-8'?>

<Font>
其中<?xml version='1.0' encoding='utf-8'?>这句代码前面不能有空格,以前好像遇到有空格时出过问题的情况的。
再font文件最末加上</Font>结束标签。

完成以上步骤之后就完成了fenggui中完整的png图片与font文件的生产了,由于中文汉字很多,所以生成这两个文件需要很长一段时间。

生产了这两个文件之后,第二次运行时,需要注意一下几步:

第一步:
关闭这段代码:
//生产font文件
//        if (file == null) {
//            file = newFile("D:\\test.font");
//        }
//
//        try {
//            if (fos == null) {
//                fos = newFileOutputStream(file, true);
//            }
//            String s = "<CharacterPixmap x=\"" + x + "\" y=\"" + y +"\" width=\"" + width + "\" height=\""+ height + "\" charWidth=\"" + charWidth+"\">\n" +
//                   "    <character><![CDATA[" + c +"]]></character>\n" +
//                   "  </CharacterPixmap>\n\n";
//            fos.write(s.getBytes());
//        } catch (IOException e) {
//            System.out.println("写入test.font文件时发生异常!");
//            e.printStackTrace();
//        }


第二步:
关闭:
//    saveImageToDisk(bi, "D:\\test.png");

第三步:
打开 f = new ImageFont("D:\\test.png","D:\\test.font");

关闭:
//                booleanantialiasing = stream.processAttribute("antialiasing", true, false);
//               java.awt.Font awtFont = new java.awt.Font(name, type, size);
//                StringalphabetStr = stream.processAttribute("alphabet","unknown", "utf8");
//                if(alphabetStr.equalsIgnoreCase("utf8"))
//                   f = FontFactory.renderStandardFont(awtFont, antialiasing,Alphabet.UTF8);
//                else if(alphabetStr.equalsIgnoreCase("english"))
//                   f = FontFactory.renderStandardFont(awtFont, antialiasing,Alphabet.ENGLISH);
//                else if(alphabetStr.equalsIgnoreCase("german"))
//                   f = FontFactory.renderStandardFont(awtFont, antialiasing,Alphabet.GERMAN);
//                else if(alphabetStr.equalsIgnoreCase("french"))
//                   f = FontFactory.renderStandardFont(awtFont, antialiasing,Alphabet.FRENCH);
//                else if(alphabetStr.equalsIgnoreCase("danish"))
//                   f = FontFactory.renderStandardFont(awtFont, antialiasing,Alphabet.DANISH);
//                else if(alphabetStr.equalsIgnoreCase("estonian"))
//                   f = FontFactory.renderStandardFont(awtFont, antialiasing,Alphabet.ESTONIAN);

 

当然,fenggui自身也有writeFontData方法,功能是写对应的font文件,但我每次使用都会报错,干脆自己弄了一个。

最后一点小问题:

在org.fenggui.util.Alphabet类中,必须默认使用UTF8,否则,本次运行是支持中文,但生成的png图片库中并没有将中文字符写进去,所以下一次使用自己生成的font文件及png图片时就会出问题,具体原因还在思考中。