2011/05/08

全Linux生活:第7天(2) - EUDC.TTE

From Evernote:

全Linux生活:第7天(2) - EUDC.TTE

這其實不是我日常生活會遇到的問題,而是工作上的需要,只是剛好也是跟非Windows環境(AIX&Linux)有關的議題。最近我們正在進行的一個提案,需要在AIX與Linux環境下進行"難字"列印,其實說穿了就是所謂的"使用者造字"。目前常見的是使用滿天星公司的字霸系統,我沒去研究字霸有沒有AIX或Linux版,可是這個客戶的字霸是Windows版,我們以前的系統雖然Server端是AIX系統,但至少客戶端都還是Windows,因此難字的顯示與列印全交給Windows與字霸就好了。但這次這個提案的作法從頭到尾都沒有Windows,這時候如果列印資料中有難字該如何列印呢?

我們稍微研究了一下字霸的作法發現一件事,那就是其實字霸採用的是標準Windows使用者造字的模式,也就是它會在Windows掛一個EUDC.TTE的字型檔在系統中:

     [HKEY_CURRENT_USER\EUDC\950]
     "SystemDefaultEUDCFont"="C:\\WINDOWS\\EUDC.tte"

只是這副檔名有點怪,*.TTE是什麼鬼?這個檔其實是個標準的truetype字型檔,如果把副檔名TTE改成TTF,可以發現Windows是認得這個檔的,檔案點兩下甚至可以開得起來。

所以接下來要做的事就比較簡單了。我們只要把這個檔讀出來,把我們要的字畫出來問題就解決了。講到這裡,我只能說Java真是佛心來的!針對Truetype的處理Java早就內建了,我們只要用就好了,以下是大致的用法:

    private Font eudc;
    private Font eudc24;
    public boolean reloadEudcFont() {
      try {
        File eudcFile = new File(eudcFontPath);
          if (eudcFile.exists()) {
            eudc = Font.createFont(Font.TRUETYPE_FONT, eudcFile);
            eudc24 = eudc.deriveFont(Font.PLAIN, 24);
            return true;
        }
        eudc = null;
        eudc24 = null;
      } catch (Throwable t) {
        t.printStackTrace();
      }
      return false;
    }

接下來,要抓某個難字的bitmap大致可以這樣做:

    public int[] grepUdcImage(int width, int height, char c) {
      try {
        int w = width;
        int h = height;
        BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
        Graphics g = image.getGraphics();
        if (regularFont.canDisplay(c))
          g.setFont(regularFont);
        else
          g.setFont(eudc24);
        g.setColor(Color.WHITE);
        g.drawString("" + c, 0, h - 5);
        int[] pixels = new int[w * h];
        PixelGrabber pg = new PixelGrabber(image, 0, 0, w, h, pixels, 0, w);
        try {
          pg.grabPixels();
        } catch (InterruptedException e) {
          logger.error("Interrupted waiting for pixels!");
        }
        if ((pg.getStatus() & ImageObserver.ABORT) != 0) {
          logger.error("Image fetch aborted or errored!");
        }
        return pixels;
      } catch (Throwable t) {
        t.printStackTrace();
      }
      return null;
    }

要注意一點,這個TTE檔內部的編碼是Unicode,所以要找出我們要的難字,你必須知道那個字的Unicode。因為我們沒有MS950(BIG5)跟Unicode的對照表(這部份其實是字霸另一個主要功能),所以只要先有人幫我們把該轉的碼先轉好,到我們這邊的處理就沒有問題了,關於這點,倒是不用擔心,因為我們要列印的字,在使用者鍵入難字的時候早就把難字轉成Unicode了,畢竟目前使用者日常操作的電腦百分之兩百一定是Windows,如果萬一真的不是Windows,比方說是手機或iPad(或Android),反正它也打不出難字,所以也不用擔心。

No comments: