打印

grlib中英文混合显示方法,汉字取模非常方便

[复制链接]
8126|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
allyzc|  楼主 | 2015-9-30 14:38 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
Grlib, TE, ST, ui, AC
本帖最后由 allyzc 于 2015-9-30 14:36 编辑

本方法从 “基于汉字字模的Stellaris+GUI控件驱动设计.pdf“  修改。
建立hanzi16x16.c文件:

一、在hanzi16x16.c定义汉字字模数据结构:
typedef struct{
     const unsigned char data[32];//16*16的汉字占用32个字节
     const unsigned char code[3];//汉字内码索引,包含\0,占用3个字节
}HanziTypeDef_16x16;//16*16汉字字模数据结构


二、使用PCtoLCD2002制作汉字字模:

设置软件取模格式:高位在前


汉字取模,如果汉字多可以使用如下文本的方式。


三、在hanzi16x16.c文件定义保存字模的数组,直接把数据复制过来就好,不用做任何修改,非常方便。


四、制作所有英文ansi字模数组,注意格式如下

使用上面所说的文本方式,点击生成英文点阵字库

在hanzi16x16.c文件定义保存所有英文ansi字模的数组,把点阵数据制过来就好

如图中红框注释部分编译不通过,要把“ ”里面编译器不认识的删除掉

五、在grlib.h中的tFont结构体添加一个指向汉字的指针
typedef struct
{
    //
    //! The format of the font.  Can be one of FONT_FMT_UNCOMPRESSED or
    //! FONT_FMT_PIXEL_RLE.
    //
    uint8_t ui8Format;

    //
    //! The maximum width of a character; this is the width of the widest
    //! character in the font, though any individual character may be narrower
    //! than this width.
    //
    uint8_t ui8MaxWidth;//这里我们用来保存汉字的宽

    //
    //! The height of the character cell; this may be taller than the font data
    //! for the characters (to provide inter-line spacing).
    //
    uint8_t ui8Height;//这里我们用来保存汉字的高

    //
    //! The offset between the top of the character cell and the baseline of
    //! the glyph.  The baseline is the bottom row of a capital letter, below
    //! which only the descenders of the lower case letters occur.
    //
    uint8_t ui8Baseline;

    //
    //! The offset within pui8Data to the data for each character in the font.
    //
    uint16_t pui16Offset[96];//这个我们用第一个元素保存有多少个汉字

    //
    //! A pointer to the data for the font.
    //
    const uint8_t *pui8Data;//这里我们可以保存英文点阵的指针
    //A pointer to the data for the Chinese font.
    const uint8_t *CHFontdata;//这是我们添加的,添加在这里,添加一个指向汉字的指针
}
tFont;


六、设置一个判断标识符来区分当前字符是字母还是汉字, 因此在 grlib.h 中添加汉
字标识符:
// Indicates that the font data is stored in an uncompressed format.
#define FONT_FMT_UNCOMPRESSED 0x00 //
//!Indicates that the font data is stored using a pixel-based RLE format.
#define FONT_FMT_PIXEL_RLE 0x01
//Indicates that the font data is stored in Chinese format.
#define FONT_CH_STYLE 0x02//添加在这里
七、在grlib.h 中字体声明
extern const tFont g_sFontCH16;
#define g_psFontCH16 (const tFont *)&g_sFontCH16



八、定义16*16的字体
//***********16x16 的汉字字体结构体***********//
const tFont g_sFontCH16=
{
     FONT_CH_STYLE,//这里使用我们上面添加的汉字标识符
     16,//宽16
     16,//高16
     16,//这个不知道用来干嘛,我们用不到,随便填
     {(sizeof(Hanzi_16x16)/sizeof(HanziTypeDef_16x16))},//记录有多少个汉字,保存在这个数组的第一个元素
     Ansi_8x16,//英文点阵指针
     Hanzi_16x16[0].data,//汉字点阵指针,用Hanzi_16x16[0]表示指向第一个汉字
};


九、在 Stellaris GUI 中控件的字符显示最终是调用函数 GrStringDraw 完成的,
其在 StellarisWare\grlib\String.c 中进行了具体的实现。 因此, 在 GrStringDraw
中添加实现汉字显示的具体代码:if(pContext->psFont->ui8Format == FONT_CH_STYLE )
    {
         char *pString = (char *)pcString;//取得要显示字符串的指针
          while ( *pString )//判断字符串是否结束
          {
               if ( *pString < 128 )//如果小128,则为字母
               {
                   LCD_Char_En(pContext, pString, i32X, i32Y);//显示一个字母
                   pString += 1;//指针指向下一个
                   i32X += (pContext->psFont->ui8MaxWidth/2);//这里显示的位置向右移动一个字母的宽度
               }
               else
               {
                    LCD_Char_Cn(pContext, pString, i32X, i32Y);//大于128则表示是汉字
                    pString += 2;//为什么加2呢,因为汉字的保存就是保存汉字的内码,占用2个字节
                    i32X += pContext->psFont->ui8MaxWidth;//这里显示的位置向右移动一个汉字的宽度
               }
          }
          return;
    }



十 、因为上面调用了函数LCD_Char_En(pContext, pString, i32X, i32Y);//在LCD上显示一个字母
所以在string.c中添加它的实现代码
void LCD_Char_En(const tContext *pContext, char *acsii, uint16_t x, uint16_t y)
{      
uint8_t temp, t;
uint8_t xpos;//记录横向的字节标识
uint8_t ypos;//记录纵向的字节标识

//一行中有多少个字节,8*16的英文,就是宽度为8,一个字节8位,刚好一个字节
//更直观应该是(pContext->psFont->ui8MaxWidth)/2/8,
uint8_t hByteSize = (pContext->psFont->ui8MaxWidth/16);

//获取一个英文字模纵向多少有行,8*16的英文,就是16行
uint8_t vSize = pContext->psFont->ui8Height;

//这里获取这次字母点阵第一个数据的地址,pui8Data就是上面保存英文点阵的指针
//pui8Data[(*acsii)*hByteSize*vSize]就是我们所需,为什么是(*acsii)*hByteSize*vSize
//在做英文字模时就是按acsii顺序排列的,如A即在65位置,
//如8*16英文,即65*横向所需字节1*纵向的行数16,之间的8*16个字节都是这个字母的数据
acsii = (char *)&pContext->psFont->pui8Data[(*acsii)*hByteSize*vSize];

for ( ypos = 0 ; ypos < vSize; ypos++ )
{
for (xpos=0; xpos<hByteSize; xpos++)
{
temp = *acsii;//取得具体字节数据
for(t=0; t<8; t++)
{
if(temp & 0x80)
{
GrPixelDraw(pContext, x+(xpos*8)+t, y+ypos);//这个就是画点了
}
temp <<= 1;
}
acsii++;//指向下一个字节
}
}
}

11、因为上面调用了函数LCD_Char_Cn(pContext, pString, i32X, i32Y);//在LCD上显示一个汉字
所以在string.c中添加它的实现代码,和上面的差不多
void LCD_Char_Cn(const tContext *pContext, char *hanzi, uint16_t x, uint16_t y)   
{      
     uint8_t temp, t;
     uint8_t xpos;
     uint8_t ypos;

     //下面的表示一个汉字字模所占的字节数,16*16的点阵
     //就是纵向行数16*横向字节数2+汉字内码和\0即3=35个字节
     //也就是上面定义的HanziTypeDef_16x16结构体的大小35
     uint8_t hzASize = pContext->psFont->ui8Height*pContext->psFont->ui8MaxWidth/8+3;

     //横向所需字节,如16*16的汉字,就是横向占用2个字节
     uint8_t hByteSize = (pContext->psFont->ui8MaxWidth/8);
     uint16_t hanziId = getHanziId(pContext, hanzi);//这里多了一个获取汉字的位置

     if ( hanziId == 0xffff )
     {
         return;//如果是0xffff,表示取不到汉字的位置,即没有这个汉字的字模,直接反回
     }
    //这里获取这次汉字字模第一个数据的地址,如16*16的汉字

     // 第5个汉字的字模第一个数据的地址 就是5*35的位置
     hanzi = (char *)&pContext->psFont->CHFontdata[hanziId*hzASize];

     //上面的上英文的一样
     for ( ypos = 0 ; ypos < (pContext->psFont->ui8Height); ypos++ )
     {
          for (xpos=0; xpos<hByteSize; xpos++)
          {
               temp = *hanzi;
               for(t=0; t<8; t++)
               {
                    if(temp & 0x80)
                    {
                         GrPixelDraw(pContext, x+(xpos*8)+t, y+ypos);
                    }
                    temp <<= 1;
               }
               hanzi++;
          }
     }
   
}


12、获取汉字位置uint16_t getHanziId(const tContext *pContext, char *hanzi)
所以在string.c中添加它的实现代码
uint16_t getHanziId(const tContext *pContext, char *hanzi)
{
     uint16_t i = 0;

     //表示一个汉字字模所占的字节数如16*16汉字即16*2+3=35了
     uint8_t hzASize = pContext->psFont->ui8Height*pContext->psFont->ui8MaxWidth/8+3;
     //这里i从1开始,如果汉字内码2个都相同,即找到了汉字所在的位置

     //为什么是-3,-2呢,比如第一个汉字35-3,35-2就是汉字内码的第一和第二个字节
     for (i = 1; i <= pContext->psFont->pui16Offset[0]; ++i)
     {
          if ((hanzi[0] == pContext->psFont->CHFontdata[hzASize*i-3]) &&
               (hanzi[1] == pContext->psFont->CHFontdata[hzASize*i-2]))
          {
               return i-1;//因为上面i从1开始,返回i-1,即数组下标是从0开始的
          }
     }
     return 0xffff;//找不到所需的汉字
}


附上效果图
GrContextFontSet(&g_sContext, g_psFontCH16);
GrStringDraw(&g_sContext, "检测到SD卡,正在读取", -1, 132, 89, 0);


附上PDF版: grlib中英文混合显示方法,汉字取模非常方便.pdf (735.28 KB)
源代码:pan.baidu.com/s/1c0whlOc

相关帖子

沙发
yiyigirl2014| | 2015-9-30 14:53 | 只看该作者
这个以前用过,相当省事,特别显示特定字符的

使用特权

评论回复
板凳
allyzc|  楼主 | 2015-9-30 14:56 | 只看该作者
yiyigirl2014 发表于 2015-9-30 14:53
这个以前用过,相当省事,特别显示特定字符的

是的,最近工作有用到,又做有笔记,所以就粘出来了

使用特权

评论回复
地板
dirtwillfly| | 2015-9-30 15:06 | 只看该作者
感谢分享

使用特权

评论回复
5
稳稳の幸福| | 2015-9-30 19:56 | 只看该作者
有个好主意,直接把字库文件放到U盘,运行时候从里面调取。

使用特权

评论回复
6
Roderman_z| | 2015-9-30 20:40 | 只看该作者
这个字模软件很不错啊

使用特权

评论回复
7
yiyigirl2014| | 2015-9-30 20:41 | 只看该作者
这么好的软件,以前不知道

使用特权

评论回复
8
yiyigirl2014| | 2015-10-13 15:05 | 只看该作者
下面的界面是如何做的,是用的OS吗?

使用特权

评论回复
9
allyzc|  楼主 | 2015-10-14 14:25 | 只看该作者
yiyigirl2014 发表于 2015-10-13 15:05
下面的界面是如何做的,是用的OS吗?

直接画完图片,再在其上面画文字

使用特权

评论回复
10
hngy41| | 2022-8-4 15:50 | 只看该作者
多谢分享

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

3

主题

14

帖子

1

粉丝