硬汉嵌入式论坛

 找回密码
 立即注册
查看: 11627|回复: 3
收起左侧

[μCGUI] 关于ucgui的汉字字库问题(转载自www.ucgui.com)

[复制链接]

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107101
QQ
发表于 2012-11-3 10:23:21 | 显示全部楼层 |阅读模式
下面这个链表是如何生成的呢?有什么原则和规律?
GUI_FLASH const GUI_FONT_PROP GUI_Font__21_Prop2
= {
0x00A0                                                           /* first character */,
0x00FF                                                          /* last character  */,
&GUI_Font__21_CharInfo[ 96]                      /* address of first character */,
(void GUI_FLASH *)&GUI_Font__21_Prop3 /* pointer to next GUI_FONT_PROP */
};

GUI_FLASH const GUI_FONT_PROP GUI_Font__21_Prop1 = {
   0x0020                                                           /* first character */,
0x007F                                                           /* last character  */,
&GUI_Font__21_CharInfo[  0]                        /* address of first character */,
(void GUI_FLASH *)&GUI_Font__21_Prop2 /* pointer to next GUI_FONT_PROP */
};

GUI_FLASH const GUI_FONT GUI_Font__21 = {
GUI_FONTTYPE_PROP /* type of font    */,
21                                                                 /* height of font  */,
21                                                                 /* space of font y */,
1                                                                  /* magnification x */,
1                                                                  /* magnification y */,
(void GUI_FLASH *)&GUI_Font__21_Prop1};
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107101
QQ
 楼主| 发表于 2012-11-3 10:24:55 | 显示全部楼层
关于如何生成, 其实原理比较简单,但要理解生成了之后是如何应用显示文字(E文与中文),那么还要深入了解UCGUI,

近期我将写一篇这个文章, 时间太紧, 本来好几篇文章都理解得差不多了,就是没有动手, 近期请关注...
这里我先贴上一位网友自己写的生成程序, 其实我也想写一个的, 主要是两点要理解:
1. 汉字库的结构.如HZK16,HZK24等, 了解他是为了找到指定机内码的汉字的点阵.
2. UCGUI中关于文字显示的.C源文件的结构, 这个可以参照已经有的.
下面是一位网友的生成.C文件的代码.
先分析一下他生成的文件,虽然字体结构没对,但他的其他声名都是可以的,首先找到
unicode----内码对照表(我就是用他生成一个二维数组),在gui.h中把笔画定义来过来用,
根据内码查询ucdos汉字库(我用的hz16k)或windows字库(还没研究 : (),这是我写的一个的程序实现,请各位大虾指正
void CHanziDlg::OnCreatefontdot()
{
   
   CFile fhz;
   unsigned char bv,bv1,tmpbv;
   DWORD offset;
   CString strftmp,strFont;
   int i;
   char font[100];
   char filepath[]=".\\\\hz16_16h.c";
char Title[]="/* C-file generated by uc/GUI-FontConvert  \\rCompiled:    Jul 23 2003 at 13:13:49\\r\\n  (c)
2003  Xiang_xudong, Inc.\\rwww.superxxd.com\\r\\n  (c) 2003~  Superxxd\\r
  Source file: Fonthz16_16.c\\r  Font: HZK16\\r  Height: 16点阵\\r*/";
   m_FontList.ResetContent();
   m_FontList.AddString("生成开始...");
   log(filepath,Title);
   log(filepath,"#include \\"GUI.H\\" ");
   log(filepath,"#ifndef GUI_FLASH");
   log(filepath,"  #define GUI_FLASH");
   log(filepath,"#endif");
   log(filepath,"/*");
   log(filepath,"The following line needs to be included in any file selecting the");
   log(filepath,"font. A good place would be GUIConf.H");
   log(filepath,"*/");
   log(filepath,"extern GUI_FLASH const GUI_FONT GUI_FontHZ16_16H;");
   log(filepath,"/* Start of unicode area <Basic Latin> */");

   if(!fhz.Open("hzk16",CFile::modeRead))
   {
    MessageBox("File open failed");
    return ;
   }
   char Unicode[100];
   char tempbuf[10];
   char buf[10];
   char buf1[10];
   DWORD lenth=fhz.GetLength();
   CString csGuiFontProp;
   CString csGuiFontCharInfo;
   CString temp_Prop;
   //GUI_Font_PropN.
   int n=1;
   int countProp=1;
   BOOL bSetFirst=FALSE;
   BOOL bWriteProp=FALSE;
   int StartNMnumber=1;
   int ENDNMnumber=25415;
  // for(;;)
   for(int ii=0;ii<25415;ii++)
//   while(TRUE)
   {
        if (UNICODE_TO_NM_TABLE[ii].NM==NULL)
  {
   if(bSetFirst==TRUE)
   {
    bSetFirst=FALSE;
    temp_Prop.Format("0x%s%s",buf1,buf);
    csGuiFontProp.Replace("NULL",temp_Prop);
                GUI_Font_PropN.AddHead(csGuiFontProp);
    countProp+=1;
    }
   
   continue;
  }
  bv1=GetLowBytes(UNICODE_TO_NM_TABLE[ii].NM);
  bv=GetHiBytes(UNICODE_TO_NM_TABLE[ii].NM);
        //if(bv1==0)
  if((bv1==0xa1) && (bv==0xa2))
  {
              int i_iii=0;
         
  }
  if( bv1<0xa1||bv1>0xfe )
  {
   if(bSetFirst==TRUE)
   {
    bSetFirst=FALSE;
    temp_Prop.Format("0x%s%s",buf1,buf);
    csGuiFontProp.Replace("NULL",temp_Prop);
                GUI_Font_PropN.AddHead(csGuiFontProp);
    countProp+=1;
    }
   
   continue;
  }
  if( bv<0xa1||bv>0xfe )
  {
   if(bSetFirst==TRUE)
   {
    bSetFirst=FALSE;
    temp_Prop.Format("0x%s%s",buf1,buf);
    csGuiFontProp.Replace("NULL",temp_Prop);
                GUI_Font_PropN.AddHead(csGuiFontProp);
    countProp+=1;
    }
   
   continue;
  }
  offset=((bv-161)*94+(bv1-161))*32;
  if(offset>lenth)
   continue;
  fhz.Seek(offset,CFile::begin);
     m_FontList.ResetContent();
         
        itoa(GetHiBytes(UNICODE_TO_NM_TABLE[ii].UNICODE),tempbuf,16);
  if(GetHiBytes(UNICODE_TO_NM_TABLE[ii].UNICODE)<0x10)
   sprintf(buf1,"0%s",tempbuf);
  else
   sprintf(buf1,"%s",tempbuf);
  itoa(GetLowBytes(UNICODE_TO_NM_TABLE[ii].UNICODE),tempbuf,16);
  if(GetLowBytes(UNICODE_TO_NM_TABLE[ii].UNICODE)<0x10)
   sprintf(buf,"0%s",tempbuf);
  else
   sprintf(buf,"%s",tempbuf);
  tmpbv=bv;
  int zero_count=0;
  /*for(i=1;i<=32;i++)
  {
   fhz.Read(&tmpbv,sizeof(tmpbv));
   if(tmpbv==0)
               zero_count++;
  }
  if(zero_count==32)
   continue;
   */
        sprintf(Unicode,"GUI_FLASH const unsigned char acFontHZ16_16_%s%s[32] = {/*code %s%s */",buf1,buf,buf1,buf);  
      log(filepath,Unicode);
  for(i=1;i<=32;i++)
  {
   fhz.Read(&bv,sizeof(bv));
   strftmp.Format("%s\\0",FontData[bv]);
   if(i!=32)
    strftmp+=",";
   if(!(i%2))
     strftmp+="\\0\\r\\x0a";
   strFont+=strftmp;
   if(!(i%2))
   {
     sprintf(font,"%s",strFont);
     log(filepath,font);
     m_FontList.AddString(strFont);
     strFont.Empty();
   }
  }
csGuiFontCharInfo.Format("{   16,   16,  2, (void GUI_FLASH*)&acFontHZ16_16_%s%s}, /* code %s%s */",buf1,buf,buf1,buf);
     GUI_FONT_CharInfo.AddTail(csGuiFontCharInfo);   
  if(bSetFirst==FALSE)
  {
   bSetFirst=TRUE;
   csGuiFontProp.Format("GUI_FLASH const GUI_FONT_PROP GUI_FontHZ16_16_Prop%d = {",countProp);
   temp_Prop.Format("   0x%s%s /*first character */",buf1,buf);
   csGuiFontProp+="\\r";
   csGuiFontProp+=temp_Prop;
   csGuiFontProp+="\\r";
   csGuiFontProp+="  ,NULL /* last character */";
   csGuiFontProp+="\\r";
   temp_Prop.Format("  ,&GUI_FontHZ16_16_CharInfo[  %d] /* address of first character */",n-1);
   csGuiFontProp+=temp_Prop;
   csGuiFontProp+="\\r";
   if(ii<ENDNMnumber-1)
    temp_Prop.Format("  ,(void GUI_FLASH *)&GUI_FontHZ16_16_Prop%d /* pointer to next GUI_FONT_PROP */",countProp+1);
   else
    temp_Prop.Format("  ,(void *)0/* pointer to next GUI_FONT_PROP */",countProp+1);
   csGuiFontProp+=temp_Prop;
   
   csGuiFontProp+="\\r";
   csGuiFontProp+="};";
   }
        n+=1;
  log(filepath,"};");
      log(filepath,"\\r");
  UpdateData(false);
  //Sleep(100);
   }
   fhz.Close();
if(bSetFirst==TRUE)
{
  bSetFirst=FALSE;
  temp_Prop.Format("0x%s%s",buf1,buf);
  csGuiFontProp.Replace("NULL",temp_Prop);
  GUI_Font_PropN.AddHead(csGuiFontProp);
}
csGuiFontProp=_T("GUI_FLASH const GUI_FONT GUI_FontHZ16_16 = {");
csGuiFontProp+="\\r";
csGuiFontProp+=" GUI_FONTTYPE_PROP /* type of font    */";
csGuiFontProp+="\\r";
csGuiFontProp+=",16 /* height of font  */";
csGuiFontProp+="\\r";
csGuiFontProp+=",16 /* space of font y */";
csGuiFontProp+="\\r";
csGuiFontProp+=",1 /* magnification x */";
csGuiFontProp+="\\r";
csGuiFontProp+=",1 /* magnification y */";
csGuiFontProp+="\\r";
csGuiFontProp+=",(void GUI_FLASH *)&GUI_FontHZ16_16_Prop1";
csGuiFontProp+="\\r";
csGuiFontProp+="};";
    GUI_Font_PropN.AddTail(csGuiFontProp);
   csGuiFontCharInfo.Format("GUI_FLASH const GUI_CHARINFO GUI_FontHZ16_16_CharInfo[%d] = {",n-1);
   GUI_FONT_CharInfo.AddHead(csGuiFontCharInfo);
   char tempstr[300];
   int iii=0;
   POSITION pos = GUI_FONT_CharInfo.GetHeadPosition();
   for(iii=0;iii<GUI_FONT_CharInfo.GetCount();iii++)
   {
     csGuiFontCharInfo=GUI_FONT_CharInfo.GetNext(pos);
        strcpy(tempstr,csGuiFontCharInfo);
  log(filepath,tempstr);
   }
   log(filepath,"};");
   pos = GUI_Font_PropN.GetHeadPosition();
   for(iii=0;iii<GUI_Font_PropN.GetCount();iii++)
   {
     csGuiFontCharInfo=GUI_Font_PropN.GetNext(pos);
        strcpy(tempstr,csGuiFontCharInfo);
  log(filepath,tempstr);
  log(filepath,"\\r");
   }
   
}
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107101
QQ
 楼主| 发表于 2012-11-3 11:06:42 | 显示全部楼层
不用太客气, 这个结构的还是比较容易理解的, 你如果结合源码进行调试, 就更清楚了, 现在我简要说几点, 以后详细说明:
1.你所说的字体是UCGUI中的均衡字体, 在UCGUI中有两种类型字体, 一种是等宽字体(MonospacedFont),
即字体当中所有字都是同一宽度,它在UCGUI中的相应结构体是GUI_FONT_MONO, 一种是均衡字体
(Proportionalfont), 这种字体中的字都有自己独立的宽度, 字体内的每个字都可以有不同宽度, 它在UCGUI
中的相应结构体是GUI_FONT_PROP,对于等宽字体, 一般都是将所有字的点阵存放在一个数组中, 因为每
个字都宽度相同. 对于均衡字体, 则要单独用数组来定义每个字符的点阵,然后将每一个字符的宽高及点阵存
为一个数组即字符信息(ucgui中对应结体为GUI_CHARINFO),所有字符信息再存到一个数组当即称为字符集,

它包含每个字的字符信息(点阵高宽及一行占几个字节), 所谓一行占几个字节,是指这个字体的点阵每一行有
多少个字节, 它与宽度高度单位不同, 宽度高度的单位是象素数.


2. 另外特别指出的是, 在等宽字体中不仅所有字符宽度相同,高宽也是相等的; 对于均衡字体, 不仅可以宽度不同,

高度也可以不同, 每一行有多少个字节自然也不同, 在均衡字体中每一个字符都单独定义之后才组成字体的字符集.


3. 字符集的问题, 在UCGUI中每种字体含的字符集不同, 这个可以参看UCGUI手册中的"Standard Font"一章,这一
章中对于字符集有如下描述:
ASCII: Only ASCII characters 0x20-0x7E (0x7F).[仅包含0x20-0x7E这个范围内的ansii字符]
1: ASCII characters and European extensions 0xA0 -0xFF.[除0x20-0x7E这个范围内的ansii字符, 还有0xA0 - 0xFF
这个范围内的欧洲字符集,这里要指出美国英语只用到0x20-0x7E, 它只考虑了自己的须求, 没有考虑其它国家的须求,

在欧洲是有拉丁字符的,所以欧洲国家扩展了剩余的0xA0 - 0xFF这个范围内的来表示欧洲的字符集, 其实我们国家的
汉字也是在这个范围内扩展的,不过我们用的是二个字节来表示一个汉字, 是因为汉字太多, 这区区94个值无法满足
汉字的须求, 94*94就差不多了.汉字用到的第一个值为0xb0a1(啊), 最后一个为0xf7fe(齄), 在机内码1当中只用到
a1+15~a0+86这个范围的,关于机内码是这个意思: 对于"啊"字模,机内码0xb0,0xa1), 0xb0为"啊"字的机内码1,
0xa1为机内码2.对于机内码2合使用是0xa1~0xff这个范围内的所有值, 关于机内码及汉字显示的原理及汉字库的
构成,本论坛中有专门的一篇文章介绍--"ucgui中处理汉字显示的说明", 请查看此贴, 这里不多说了, 所以范围是这样确定的.]


HK: Hiragana and Katakana[日文平假名与片假名].
1HK: ASCII, European extensions, Hiragana and Katakana[ansii,欧洲字符集,日文平假与片假].
D: Digit fonts[数字及运算符号集].
以上的ASCII/1/HK/1Hk/D都是字符集的简单代号.

3. 回过头来再看你的GUI_Font__21_Prop2,GUI_Font__21_Prop1.那么很容易理解,GUI_Font__21_Prop2
是欧洲字符集, 范围当然是0xa0-0xff.GUI_Font__21_Prop1中存的是ASCII字符集. 至于GUI_Font__21_CharInfo
中则存的是全部的字符集的点阵信息,包含所有字符信息. 最后, 将字体中包含的所有字符集用链表连接起来.

再将这个链表头指针存到字体结构(GUI_FONT)中的存放均衡字体的指针(const GUI_FONT_PROP* pProp)当中,

这样在处理字符的显示, 可以在这链表中查找所要显示的字符是在哪一个字符集中, 从而找到它的字符信息(即点阵数据及宽高).
typedef struct {
  GUI_DISPCHAR*     pfDispChar;
  GUI_GETCHARDISTX* pfGetCharDistX;
  GUI_GETFONTINFO*  pfGetFontInfo;
  GUI_ISINFONT*     pfIsInFont;
  tGUI_ENC_APIList* pafEncode;
  U8 YSize;
  U8 YDist;
  U8 XMag;
  U8 YMag;
  union {//此联合处存放均衡或是待宽字符集信息...
    void  *pFontData;
    const GUI_FONT_MONO* pMono;
    const GUI_FONT_PROP* pProp;
  } p;
  U8 Baseline;
} GUI_FONT;
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107101
QQ
 楼主| 发表于 2012-11-3 11:33:47 | 显示全部楼层
"请问如何将所用的字符用链表连接起来?"...
这个链接你没有看到吗?? 比如你说的
在GUI_Font__21_Prop1中的(void GUI_FLASH *)&GUI_Font__21_Prop2/* pointer to next GUI_FONT_PROP */
在GUI_Font__21_Prop2中的(void GUI_FLASH *)&GUI_Font__21_Prop3/* pointer to next GUI_FONT_PROP */
在GUI_FONT_MONO当中的成员next就是指向一下字符集的...
这个链表是人工写成的.....链表最后一个成员的next指向空....
这个链表的构造, 其实还是为了使用, 所以要理解它, 就要理解是如何用的.
均衡字体的显示, 是在GUIPROPAA_DispChar这个函数中处理的, 要理解链表的构造就要理解这个函数,下面做简要的分析....
void GUIPROPAA_DispChar(U16P c) {
  int BytesPerLine;
  GUI_DRAWMODE DrawMode = GUI_Context.TextMode;
  const GUI_FONT_PROP* pProp = GUIPROP_FindChar(GUI_Context.pAFont->p.pProp, c);
  if (pProp) {
    GUI_DRAWMODE OldDrawMode;
    const GUI_CHARINFO* pCharInfo = pProp->paCharInfo+(c-pProp->First);
    BytesPerLine = pCharInfo->BytesPerLine;
    OldDrawMode  = LCD_SetDrawMode(DrawMode);
    Draw  ( GUI_Context.DispPosX, GUI_Context.DispPosY,
                       (pCharInfo->XSize+1)/2,
                       GUI_Context.pAFont->YSize,
                       BytesPerLine,
                       (U8 const*) pCharInfo->pData
                       );
    LCD_SetDrawMode(OldDrawMode); /* Restore draw mode */
    GUI_Context.DispPosX += (pCharInfo->XDist+1)/2;
  }
}
而理解GUIPROPAA_DispChar的重点, 就是要理解它当中调用的用来寻找要显示的字符的字符信息的函数
GUIPROP_FindChar, GUIPROP_FindChar主要是寻找字符所在的字符集(其实这个字符集在汉字应用当中,有些不同.
在hzk12.c中, 作者是将汉字接区来分集的, 下面我们以hzk12.c中的构造来讲解字符集链表:
hzk12.c中共分成(0xa1a1~0xa1fe),(0xa2a1~0xa2fe)...(0xf7a1~0xf7fe)共分成86个字集, 另外加上(0x0020, 0x007f)
这个ANSCII字符集, hzk12.c中的链表中就其有87个字符集,这里的字符集的意义就不再是一个标准的字符集了, 而只
能称之为字符的集合而已, 没有严格意义上的字符集的意思).
hzk12.c中, 字符集链表构成为: 字符集链表第一个元素为ascii字符集,第二个为机内码处于(0xa1a1~0xa1fe)间的汉字集,

最后一个为(0xf7a1,0xf7fe)....
了解了汉字库的这个字符集链表的构成, 那么现在来看一下如何寻找一个要显示的字符处于哪个字符集当中, 找了
那个字符集才能找到这个字符的字符信息....
static const GUI_FONT_PROP* GUIPROP_FindChar(const GUI_FONT_PROP* pProp, U16P c) {
  for (pProp = GUI_Context.pAFont->p.pProp; pProp; pProp=(const GUI_FONT_PROP*) pProp->pNext) {
    if ((c>=pProp->First) && (c<=pProp->Last))
      break;
  }
  return pProp;
}
GUIPROP_FindChar其实就是查找字符的机内码是位于哪个字符集之间, 比如寻找"啊"字,机内码为0xb0a1,
那么由上查找,就可以知道它是位于链表中第16(0xb0-0xa1=16)个字符集(机内码处于0xb0a1~0xb0fe)当中,

那么就返回这个字符集的指针.找到了要显示的字符所处的字符集, 再根据:
    const GUI_CHARINFO* pCharInfo = pProp->paCharInfo+(c-pProp->First);
c-pProp->First即为该字符在此字符集中的偏移,  pProp->paCharInfo为该字符集中第一个字符地址...
这样就找到了要显示的字符的字符信息了(宽高及点阵数等), 理解了这个过程, 那么反过来理解这个字符集
为何要如此构造, 就比较容易了...
比如说: 为什么要将汉字分成86个字符集合?这是由于汉字的机内码并没有用到所有的0xffff--xa1a1=0x5e5e中
连续的值, 而是间断的, 0xa1a1~0xa1fe用到了,0xa200~0xa2a1这段当中的值不能用(因为机内码2小于0xa1了),

只能用0xa2a1~0xa2fe,所以这个特性决定了汉字的机内码分布是显区段的, 不能用一个单一的GUI_FONT_PROP
结点来表示出所有的字符集, 因为汉字是区间分布的,不是连续的.
比如说, 如下所示:
GUI_FLASH  const GUI_FONT_PROP GUI_FontHZ12_Propa1= {
      0xa1a1,
      0xfefe,
      &GUI_FontHZ12_CharInfo[  96],
      (void *)&GUI_FontHZ12_Propa2
};         
用以下一个结点来表示所有汉字, 如同ACSII, 那么我们分析一下它为什么不可以:
首先对于区间(0xa1a1~0xa1fe)这第一个区间, 在以上的结构下, 这个区间内的字符还是能够正确找到所要
显示的字符信息.但对于(0xa2a1~0xa2fe)这个区间的,pProp->paCharInfo+(c-pProp->First)显然无法找到字符信息.

这是GUI_FontHZ12_CharInfo这个所有字符信息集数组的结构决定的, 因为汉字未用的区间的在它上面没有体现,

它上面存放的是将分隔开的汉字区间连在一起的,这样你就无法根据pProp->paCharInfo+(c-pProp->First)来找到字符的位置了....
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-18 01:56 , Processed in 0.158111 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表