J2me点阵字

系统 1728 0

前言:开发J2ME过程中,我们会发现平台本身提供的字体太小,而且样式有限,严重影响游戏性的提高。不废话,进入正题。

      首先,我们了解到:一个GB2312汉字是由两个字节编码的,范围为A1A1~FEFE。A1-A9为符号区,B0到F7为汉字区。每一个区有94个字符(注意:这只是编码的许可范围,不一定都有字型对应,比如符号区就有很多编码空白区域)。下面以汉字“我”为例,介绍如何在HZK16文件中找到它对应的32个字节的字模数据。
      前面说到一个汉字占两个字节,这两个中前一个字节为该汉字的区号,后一个字节为该字的位号。其中,每个区记录94个汉字,位号为该字在该区中的位置。所以要找到“我”在hzk16库中的位置就必须得到它的区码和位码。(为了区别使用了区码和区号,其实是一个东西,别被我误导了)
      区码:区号(汉字的第一个字节)-0xa0 (因为汉字编码是从0xa0区开始的,所以文件最前面就是从0xa0区开始,要算出相对区码)
      位码:位号(汉字的第二个字节)-0xa0
      这样我们就可以得到汉字在HZK16中的绝对偏移位置: offset=(94*(区码-1)+(位码-1))*32
      注解: 
      1、区码减1是因为数组是以0为开始而区号位号是以1为开始的 
      2、(94*(区号-1)+位号-1)是一个汉字字模占用的字节数
      3、最后乘以32是因为汉字库文应从该位置起的32字节信息记录该字的字模信息(前面提到一个汉字要有32个字节显示)

       代码如下:

Java代码 复制代码
  1. import  java.io.InputStream;   
  2.   
  3. import  javax.microedition.lcdui.Graphics;   
  4.   
  5.   
  6. /**  
  7.  * 点阵字,可以实现9*9,10*10,11*11,12*12,13*13,14*14,15*15,16*16等点阵字的绘制  
  8.  * @author 夜梦星辰  
  9.  * @email babala_234@163.com  
  10.  *   
  11.  */   
  12. public   class  RasterFont {   
  13.      public   final   static  String ENCODE =  "GB2312" ;   
  14.   
  15.      private  String fontFileName;     //点阵字文件名   
  16.      private   int  diameter;            //字大小,支持9-16   
  17.   
  18.      /** Creates a new instance of CustomFont */   
  19.      public  RasterFont(String fontFileName, int  diameter) {   
  20.          this .fontFileName = fontFileName;   
  21.          this .diameter=diameter;   
  22.     }   
  23.   
  24.      /**  
  25.      * 绘制点阵中文汉字,gb2312  
  26.      *   
  27.      * @param g         画笔  
  28.      * @param str       需要绘制的文字  
  29.      * @param x         屏幕显示位置x  
  30.      * @param y         屏幕显示位置y  
  31.      * @param color     文字颜色  
  32.      *   
  33.      */   
  34.      protected   void  drawString(Graphics g, String str,  int  x,  int  y,  int  color) {   
  35.          byte [] data =  null ;   
  36.          int [] code =  null ;   
  37.          int  interval;    //字间间隔   
  38.          int  i16;         //两字节一行,即16位   
  39.         g.setColor(color);   
  40.          for  ( int  index =  0 ; index < str.length(); index++)    
  41.         {   
  42.             interval=index*diameter;   
  43.                
  44.              if  (str.charAt(index) <  0x80 // 非中文   
  45.             {   
  46.                 g.drawString(str.substring(index, index +  1 ), x+interval, y,  0 );   
  47.             }   
  48.              else   
  49.             {   
  50.                 code = getByteCode(str.substring(index, index +  1 ));   
  51.                 data = read(code[ 0 ], code[ 1 ]);   
  52.                  for  ( int  line =  0 ; line < diameter; line++)    
  53.                 {   
  54.                     i16= data[line<< 1 ]& 0x000000ff ;   
  55.                     i16 = i16 <<  8  | (data[(line<< 1 )+ 1 ]& 0x000000ff );  // 16位整形值,注意先通过与运算转为int   
  56.                      for ( int  i= 0 ;i<diameter;i++)   
  57.                     {   
  58.                          if  ((i16 & ( 0x8000  >> i)) !=  0 ){       //逐位测试:通过与1进行与运算   
  59.                             g.drawLine(x +i+interval, y + line, x+i+interval, y + line);   
  60.                         }   
  61.                     }   
  62.                 }   
  63.             }   
  64.         }   
  65.     }   
  66.   
  67.      /**  
  68.      * 读取文字信息  
  69.      *   
  70.      * @param areaCode  区码  
  71.      * @param posCode   位码  
  72.      * @return      文字数据  
  73.      */   
  74.      protected   byte [] read( int  areaCode,  int  posCode) {   
  75.          byte [] data =  null ;   
  76.          try  {   
  77.              int  area = areaCode -  0xa0 // 获得真实区码   
  78.              int  pos = posCode -  0xa0 ;    // 获得真实位码   
  79.   
  80.             InputStream in = getClass().getResourceAsStream(fontFileName);   
  81.              int  bytePerLine=(diameter- 1 ) / 8 + 1 ;   
  82.              int  bytePerFont= bytePerLine*diameter;   
  83.              long  offset =bytePerFont*((area -  1 ) *  94  + pos -  1 );   
  84.             in.skip(offset);   
  85.             data =  new   byte [bytePerFont];   
  86.             in.read(data,  0 , bytePerFont);   
  87.             in.close();   
  88.         }  catch  (Exception ex) {   
  89.         }   
  90.          return  data;   
  91.     }   
  92.   
  93.      /**  
  94.      * 获得文字的区位码  
  95.      *   
  96.      * @param str  
  97.      * @return int[2]  
  98.      */   
  99.      protected   int [] getByteCode(String str) {   
  100.          int [] byteCode =  new   int [ 2 ];   
  101.          try  {   
  102.              byte [] data = str.getBytes(ENCODE);   
  103.             byteCode[ 0 ] = data[ 0 ]& 0x000000ff ;   
  104.             byteCode[ 1 ] = data[ 1 ]& 0x000000ff ;   
  105.         }  catch  (Exception e) {   
  106.             e.printStackTrace();   
  107.         }   
  108.          return  byteCode;   
  109.     }   
  110.   
  111. }  
    import java.io.InputStream;

import javax.microedition.lcdui.Graphics;


/**
 * 点阵字,可以实现9*9,10*10,11*11,12*12,13*13,14*14,15*15,16*16等点阵字的绘制
 * @author 夜梦星辰
 * @email babala_234@163.com
 * 
 */
public class RasterFont {
 public final static String ENCODE = "GB2312";

 private String fontFileName; //点阵字文件名
 private int diameter;   //字大小,支持9-16

 /** Creates a new instance of CustomFont */
 public RasterFont(String fontFileName,int diameter) {
  this.fontFileName = fontFileName;
  this.diameter=diameter;
 }

 /**
  * 绘制点阵中文汉字,gb2312
  * 
  * @param g   画笔
  * @param str  需要绘制的文字
  * @param x   屏幕显示位置x
  * @param y   屏幕显示位置y
  * @param color  文字颜色
  * 
  */
 protected void drawString(Graphics g, String str, int x, int y, int color) {
  byte[] data = null;
  int[] code = null;
  int interval; //字间间隔
  int i16;  //两字节一行,即16位
  g.setColor(color);
  for (int index = 0; index < str.length(); index++) 
  {
   interval=index*diameter;
   
   if (str.charAt(index) < 0x80) // 非中文
   {
    g.drawString(str.substring(index, index + 1), x+interval, y, 0);
   }
   else
   {
    code = getByteCode(str.substring(index, index + 1));
    data = read(code[0], code[1]);
    for (int line = 0; line < diameter; line++) 
    {
     i16= data[line<<1]&0x000000ff;
     i16 = i16 << 8 | (data[(line<<1)+1]&0x000000ff); // 16位整形值,注意先通过与运算转为int
     for(int i=0;i<diameter;i++)
     {
      if ((i16 & (0x8000 >> i)) != 0){  //逐位测试:通过与1进行与运算
       g.drawLine(x +i+interval, y + line, x+i+interval, y + line);
      }
     }
    }
   }
  }
 }

 /**
  * 读取文字信息
  * 
  * @param areaCode 区码
  * @param posCode 位码
  * @return   文字数据
  */
 protected byte[] read(int areaCode, int posCode) {
  byte[] data = null;
  try {
   int area = areaCode - 0xa0; // 获得真实区码
   int pos = posCode - 0xa0; // 获得真实位码

   InputStream in = getClass().getResourceAsStream(fontFileName);
   int bytePerLine=(diameter-1) /8+1;
   int bytePerFont= bytePerLine*diameter;
   long offset =bytePerFont*((area - 1) * 94 + pos - 1);
   in.skip(offset);
   data = new byte[bytePerFont];
   in.read(data, 0, bytePerFont);
   in.close();
  } catch (Exception ex) {
  }
  return data;
 }

 /**
  * 获得文字的区位码
  * 
  * @param str
  * @return int[2]
  */
 protected int[] getByteCode(String str) {
  int[] byteCode = new int[2];
  try {
   byte[] data = str.getBytes(ENCODE);
   byteCode[0] = data[0]&0x000000ff;
   byteCode[1] = data[1]&0x000000ff;
  } catch (Exception e) {
   e.printStackTrace();
  }
  return byteCode;
 }

}
  

     另外,经过测试,我发现如果采用稀疏矩阵来保存点阵图可以节省不少内存,请大家看看以下是HZK16的统计数据:

统计结果:零位有:1538534,非零位有:602394,总位数为:2140928,非零位占百分比:0.28

 

分析:
1个字占的位数是2^8=256位
 如果转为稀疏矩阵的话,则占的位数为2*0.28*2^8≈144位
 可以节省到56%(≈144/256)的内存

J2me点阵字


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论