emWin & STemWin & uCGUI 的中文支持

已经有很多移植例子了,为什么还要写一个?
    因为看了很多例子,基本都是按照uCGUI的处理方式,需要一个GUI_UC_EncodeNone.c文件处理非unicode中文字体编码,原子提供的例子也是这样的方式,,但在我这里,显示有很多问题,可以说不能工作,至少STemWinV5.26V5.28都有问题这个移植例子是基于以往例子的改进版本。不知道之前的版本会不会如此。
     
     
    GUI_Type.h和GUI.h定义了多个结构体,基于这些结构体,实现了各种字体的框架。
   
    结构体GUI_FONT定义了整个字体的信息以及接口函数指针,如字体高度、宽度、显示该字体的接口函数、计算该字体字符串长度宽度的函数、判断某个字符是否属于该字体等等。当YDist>YSize时,相当于上下行字符之间插入间隔。
    struct GUI_FONT {
                  GUI_DISPCHAR*     pfDispChar;//显示该字体单个字符的接口函数
                  GUI_GETCHARDISTX*pfGetCharDistX;//计算该字体单个字符的像素宽度
                  GUI_GETFONTINFO*  pfGetFontInfo;//获取该字体的信息
                  GUI_ISINFONT*     pfIsInFont;//判断某个字符是否属于该字体
                  GUI_GETCHARINFO  * pfGetCharInfo; //获取该字体单个字符信息
                  const tGUI_ENC_APIList* pafEncode;//该字体字符串操作接口
                  U8 YSize; //该字体的Y轴高度,指的是显示信息高度
                  U8 YDist; //该字体的Y轴距离,指的是字体占用高度,YDist>=YSize
                     char XMag; //该字体的X轴放大
                    char YMag; //该字体的Y轴放大
                    union {
                         constvoid          GUI_UNI_PTR * pFontData;
                        constGUI_FONT_MONO GUI_UNI_PTR * pMono;
                        constGUI_FONT_PROP GUI_UNI_PTR * pProp;
                    } p; //多功能指针
                    U8 Baseline;    //该字体Y轴行数?
                    U8 LHeight;     /* height of a small lower case character(a,x) */
                    U8 CHeight;     /* height of a small upper case character(A,X) */
            };

    下面定义了GUI_FONT结构体里面的函数指针类型。
    typedefvoid GUI_DISPCHAR    (U16 c);
    typedefint  GUI_GETCHARDISTX(U16P c, int * pSizeX);
    typedefvoid GUI_GETFONTINFO (const GUI_FONT * pFont, GUI_FONTINFO * pfi);
    typedefchar GUI_ISINFONT    (const GUI_FONT *pFont, U16 c);
    typedefint  GUI_GETCHARINFO (U16P c,GUI_CHARINFO_EXT * pInfo);
   
    结构体GUI_FONTINFO定义了字体信息,其中Baseline,LHeight,CHeight在GUI_FONT结构体里面也有对应的成员。
    typedefstruct {
        U16Flags;
        U8Baseline;    //字体高度
        U8LHeight;     /* height of a small lowercase character (a,x) */
        U8CHeight;     /* height of a small uppercase character (A,X) */
    } GUI_FONTINFO;
   
    结构体GUI_CHARINFO定义了字符信息,当XDist>XSize时,相当于相邻字符之间插入间隔。
    typedefstruct {
        U8XSize; //字体X轴宽度,指的是显示信息宽度
        U8XDist; //字体X轴距离,指的是字体占用宽度,XDist>=XSize
        U8BytesPerLine; //字体X轴字节数
        constunsigned char * pData;
    } GUI_CHARINFO;
   
结构体GUI_CHARINFO_EXT定义了字符扩展信息,作为GUI_GETCHARINFO函数指针所指向的函数参数。
typedefstruct {
    U8XSize;
    U8YSize;
    I8XPos;
    I8YPos;
    U8XDist;
    constunsigned char * pData;
} GUI_CHARINFO_EXT;
   
    结构体tGUI_ENC_APIList定义了该字体字符串操作函数指针。
    typedefint  tGUI_GetLineDistX(const char * s,int Len);
    typedefint  tGUI_GetLineLen  (const char * s, int MaxLen);
    typedefvoid tGL_DispLine     (const char * s,int Len);
    typedefstruct {
        tGUI_GetLineDistX* pfGetLineDistX; //获取该字体字符串X轴占用的像素点数
        tGUI_GetLineLen   * pfGetLineLen; //获取该字体字符串的长度
        tGL_DispLine      * pfDispLine; //显示该字体字符串
    } tGUI_ENC_APIList;
   
    结构体GUI_FONT_PROP定义了字体多个编码区域的地址和信息,因为一个字体可能存在多个编码区域,每个区域都有各自的信息,字体高度宽区可能都不一样。
    typedefstruct GUI_FONT_PROP {
    U16PFirst; //区域第一个字符的编码
    U16PLast;  //区域最好一个字符的编码
    constGUI_CHARINFO  * paCharInfo; //属于该区域字符的字体信息
    conststruct GUI_FONT_PROP * pNext; //指向字体下一个编码区域
    } GUI_FONT_PROP;
   
    基于上述这些结构体,我们开始实现中文汉字支持功能,字体名字为CNHZK。由于没有emWin源代码,这里参照了uCGUI的核心源码,如参照GUIEncSJ.C文件的GetLineDistX、_GetLineLen_SJIS、_DispLine_SJIS函数实现。此外还参照了GUI_SIF_Prop.c、GUI_GetFontInfo.C、GUIAAChar4.c、F16_HK.C等文件。
    需要注意:网上大多数中文支持都是参照uCGUI支持中文的移植方式,需要用到GUI_UC_EncodeNone.c文件处理非unicode中文字体编码,这里需要删掉,否则中文显示会抖动窜动。实际上,如果实现了GUICNHZK_DispLine函数,则每次显示HZK字体字符串,都会调用该函数,而这个函数是我们自己实现的,这样我们就可以自己处理中文字体编码细节了,如果没有实现GUICNHZK_DispLine,则GUI核心会直接调用GUICNHZK_DispChar函数,这时候GUI核心要被告知如何处理字体编码,但怎么告知呢?emWin不开源,不好解决。按照uCGUI那种方式实现GUI_UC_EncodeNone.c,工作的有问题,至少在STemWinV5.26和V5.28上面都有问题。
目前支持12、16、24三种大小,将HZK12,HZK16, HZK24字库文件放置在SDCard或者外置SpiFlash等存储介质。按照类似的方法,可以扩展支持其他各种各样的字体。

    首先在GUIType.h增加下列声明和宏定义。
    externconst tGUI_ENC_APIList GUI_ENC_APIList_CNHZK;//
    /*HZK12, HZK16, HZK24 : chinese 16x12, 16x16, 24x24 fonts */
    #defineGUI_FONTTYPE_CNHZK        \
        GUICNHZK_DispChar,            \
        GUICNHZK_GetCharDistX,        \
        GUICNHZK_GetFontInfo,         \
        GUICNHZK_IsInFont,           \
        GUICNHZK_GetCharInfo,         \
        &GUI_ENC_APIList_CNHZK
   
    其次在GUI.h添加下列字体声明和宏定义。
    externGUI_CONST_STORAGE  GUI_FONT      GUI_Font16x12_CNHZK;//
    externGUI_CONST_STORAGE  GUI_FONT      GUI_Font16x16_CNHZK;//
    externGUI_CONST_STORAGE  GUI_FONT      GUI_Font24x24_CNHZK;//
    #defineGUI_FONT_16x12_CNHZK            &GUI_Font16x12_CNHZK//
    #defineGUI_FONT_16x16_CNHZK            &GUI_Font16x16_CNHZK//
    #defineGUI_FONT_24x24_CNHZK            &GUI_Font24x24_CNHZK//
   
    定义GUI_Font16x12_CNHZK字体的相关信息。
///Chinese_Font_16x12Define Start///
GUI_CONST_STORAGE  GUI_CHARINFO    GUI_Font16x12_CNHZK_CharInfo[2] = {
    {8, 8,  1, (void*)0},//ASCII8x12,X轴宽度为8,1字节,Y轴高度为12
    {16, 16, 2, (void*)0},//CHINESE16x12,X轴宽度为16,2字节,Y轴高度为12
};

GUI_CONST_STORAGE  GUI_FONT_PROP    GUI_Font16x12_CNHZK_PropHZK = {
    0xA1A1, //HZK12字库第一个字符的编码
    0xFFFF, //HZK12字库最后一个字符的编码
    &GUI_Font16x12_CNHZK_CharInfo[1], //HZK12字库字体信息
    (void *)0,
};

GUI_CONST_STORAGE  GUI_FONT_PROP    GUI_Font16x12_CNHZK_PropASC = {
    0x0000, //ASCII12字库第一个字符的编码
    0x007F, //ASCII12字库最后一个字符的编码
    &GUI_Font16x12_CNHZK_CharInfo[0], //ASCII12字库字体信息
    (void GUI_CONST_STORAGE*)&GUI_Font16x12_CNHZK_PropHZK, //指向HZK12字库
};

GUI_CONST_STORAGE  GUI_FONT   GUI_Font16x12_CNHZK = {
    GUI_FONTTYPE_CNHZK,//接口函数指针列表
    12, //字体Y轴高度
    12, //字体Y轴距离
    1, //字体X轴放大
    1, //字体Y轴放大
    (void GUI_CONST_STORAGE*)&GUI_Font16x12_CNHZK_PropASC //指向Prop列表
};
Chinese_Font_16x12Define End
   
    定义GUI_Font16x16_CNHZK字体的相关信息。
///Chinese_Font_16x16Define Start///
GUI_CONST_STORAGE  GUI_CHARINFO    GUI_Font16x16_CNHZK_CharInfo[2] = {
    {16, 16, 2, (void*)0},//ASCII 16x16,X轴宽度为16,2字节,Y轴高度为16
    {16, 16, 2, (void*)0},//CHINESE 16x16,X轴宽度为16,2字节,Y轴高度为16
};

GUI_CONST_STORAGE  GUI_FONT_PROP    GUI_Font16x16_CNHZK_PropHZK = {
    0xA1A1, //HZK16字库第一个字符的编码
    0xFFFF, //HZK16字库最后一个字符的编码
    &GUI_Font16x16_CNHZK_CharInfo[1], //HZK16字库字体信息
    (void *)0,
};

GUI_CONST_STORAGE  GUI_FONT_PROP    GUI_Font16x16_CNHZK_PropASC = {
    0x0000, //ASCII16字库第一个字符的编码
    0x007F, //ASCII16字库最后一个字符的编码
    &GUI_Font16x16_CNHZK_CharInfo[0], //ASCII16字库字体信息
    (void GUI_CONST_STORAGE*)&GUI_Font16x16_CNHZK_PropHZK, //指向HZK16字库
};

GUI_CONST_STORAGE  GUI_FONT   GUI_Font16x16_CNHZK = {
    GUI_FONTTYPE_CNHZK,//接口函数指针列表
    16, //字体Y轴高度
    16, //字体Y轴距离
    1, //字体X轴放大
    1, //字体Y轴放大
    (void GUI_CONST_STORAGE*)&GUI_Font16x16_CNHZK_PropASC //指向Prop列表
};
//Chinese_Font_16x16Define End//
   
    定义GUI_Font24x24_CNHZK字体的相关信息。
/Chinese_Font_24x24Define Start/
GUI_CONST_STORAGE  GUI_CHARINFO    GUI_Font24x24_CNHZK_CharInfo[2] = {
    {24, 24, 3, (void*)0},//ASCII 24x24,X轴宽度为24,3字节,Y轴高度为24
    {24, 24, 3, (void*)0},//CHINESE 24x24,X轴宽度为24,3字节,Y轴高度为24
};

GUI_CONST_STORAGE  GUI_FONT_PROP    GUI_Font24x24_CNHZK_PropHZK = {
    0xA1A1, //HZK24字库第一个字符的编码
    0xFFFF, //HZK24字库最后一个字符的编码
    &GUI_Font24x24_CNHZK_CharInfo[1], //HZK24字库字体信息
    (void *)0,
};

GUI_CONST_STORAGE  GUI_FONT_PROP    GUI_Font24x24_CNHZK_PropASC = {
    0x0000, //ASCII24字库第一个字符的编码
    0x007F, //ASCII24字库最后一个字符的编码
    &GUI_Font24x24_CNHZK_CharInfo[0], //ASCII24字库字体信息
    (void GUI_CONST_STORAGE*)&GUI_Font24x24_CNHZK_PropHZK, //指向HZK24字库
};

GUI_CONST_STORAGE  GUI_FONT   GUI_Font24x24_CNHZK = {
    GUI_FONTTYPE_CNHZK,//接口函数指针列表
    24, //字体Y轴高度
    24, //字体Y轴距离
    1, //字体X轴放大
    1, //字体Y轴放大
    (void GUI_CONST_STORAGE*)&GUI_Font24x24_CNHZK_PropASC //指向Prop列表
};
//Chinese_Font_24x24Define End//
   
    从存储介质获取字体数据的接口函数,如果是ASCII字符(小于等于127),则从Font12.c、Font16.c、Font24.c三个文件获取字体数字,如果是汉字,则从外部存储介质读取字体数据。
    //getdata from file named of HZK12, HZK16, HZK24
staticvoid GUI_GetChineseFontData(const GUI_FONT_PROP GUI_UNI_PTR *pProp,  U16P c)
   
    显示中文字体单个字符的接口函数。
    voidGUICNHZK_DispChar(U16 c)
   
    获取中文字体单个字符的X轴宽度,还有乘以放大系数(一般为1)。
    intGUICNHZK_GetCharDistX(U16P c, int *pSizeX)
        *pSizeX = (pProp->paCharInfo)->XSize *GUI_pContext->pAFont->XMag;
   
    获取中文字体信息,
    voidGUICNHZK_GetFontInfo(const GUI_FONT * pFont, GUI_FONTINFO * pfi)
   
    判断字符c是否属于中文字体,根据GUI_FONT_PROP结构体的First和Last判断。
    charGUICNHZK_IsInFont(const GUI_FONT * pFont, U16 c)
        if((c >= pProp->First) && (c <= pProp->Last) )
   
    这个函数暂时没有实现。
    intGUICNHZK_GetCharInfo(U16P c, GUI_CHARINFO_EXT * pInfo)
   
    获取中文字体字符串的像素总长度,其内部进一步调用GUICNHZK_GetCharDistX获取每一个字符的像素宽度,需要注意的是ASCII字符占用1个字节,中文占用2个字节。
    intGUICNHZK_GetLineDistX(const char * s, int Len)
   
    获取中文字体字符串的长度,需要注意,ASCII字符占用1字节,中文占用2字节。
    intGUICNHZK_GetLineLen(const char * s, int MaxLen)

    显示中文字体字符串。
    voidGUICNHZK_DispLine(const char * s, int Len)

    中文字体字符串操作函数指针结构体。
    consttGUI_ENC_APIList  GUI_ENC_APIList_CNHZK ={
        GUICNHZK_GetLineDistX,
        GUICNHZK_GetLineLen,
        GUICNHZK_DispLine,
  };


底层函数的实现。

/*********************************************************************
*
*       GUICNHZK_DispChar
*
* Purpose:
*   This is the routine that displays a character. It is used by all
*   other routines which display characters as a subroutine.
*/
//void GUI##Type##_DispChar(U16P c);
void GUICNHZK_DispChar(U16 c)
{
    GUI_DRAWMODE  OldDrawMode, DrawMode;
    const GUI_FONT_PROP GUI_UNI_PTR *pProp;
        const GUI_CHARINFO GUI_UNI_PTR  *pCharInfo;
        
    //see if c is belong to the font scope
        pProp = GUI_pContext->pAFont->p.pProp;
    for (; pProp; pProp = pProp->pNext) {
        if( (c >= pProp->First) && (c <= pProp->Last) )  break;
    }
        if(0 == pProp)  return;
        
        //save and set DrawMode
        DrawMode = GUI_pContext->TextMode;
        OldDrawMode  = LCD_SetDrawMode(DrawMode);
        
        //Get font data from HZK12, HZK16, HZK24
        GUI_GetChineseFontData(pProp, c);
        //write font data
        pCharInfo = pProp->paCharInfo;
        LCD_DrawBitmap(GUI_pContext->DispPosX, GUI_pContext->DispPosY,
                                   pCharInfo->XSize, GUI_pContext->pAFont->YSize,
                                   GUI_pContext->pAFont->XMag, GUI_pContext->pAFont->YMag,
                                   1,        /* Bits per Pixel */
                                   pCharInfo->BytesPerLine,
                                   &GUI_FontDataBuf[0],
                                   &LCD_BKCOLORINDEX
                                   );
        
        //Fill empty pixel lines
        if (GUI_pContext->pAFont->YDist > GUI_pContext->pAFont->YSize) {
                int YMag = GUI_pContext->pAFont->YMag;
                int YDist = GUI_pContext->pAFont->YDist * YMag;
                int YSize = GUI_pContext->pAFont->YSize * YMag;
                if (DrawMode != LCD_DRAWMODE_TRANS) {
                        LCD_COLOR OldColor = GUI_GetColor();
                        GUI_SetColor(GUI_GetBkColor());
                        LCD_FillRect(GUI_pContext->DispPosX, GUI_pContext->DispPosY + YSize,
                                                 GUI_pContext->DispPosX + pCharInfo->XSize,
                                                 GUI_pContext->DispPosY + YDist);
                        GUI_SetColor(OldColor);
                }
        }
        
        //Restore draw mode
        LCD_SetDrawMode(OldDrawMode);
        GUI_pContext->DispPosX += pCharInfo->XDist * GUI_pContext->pAFont->XMag;
}

/*********************************************************************
*
*       GUICNHZK_GetCharDistX
*/
//int  GUI##Type##_GetCharDistX(U16P c, int * pSizeX);
int GUICNHZK_GetCharDistX(U16P c, int *pSizeX)
{
    const GUI_FONT_PROP GUI_UNI_PTR  *pProp = GUI_pContext->pAFont->p.pProp;
        
    for(; pProp; pProp = pProp->pNext) {
        if( (c >= pProp->First) && (c <= pProp->Last) )  break;
    }
        
        if(pProp){
                *pSizeX = (pProp->paCharInfo)->XSize * GUI_pContext->pAFont->XMag;
        }else{
                *pSizeX = 0;
        }
        
    return  *pSizeX;
}

/*********************************************************************
*
*       GUICNHZK_GetFontInfo
*/
//void GUI##Type##_GetFontInfo (const GUI_FONT * pFont, GUI_FONTINFO * pfi);
void GUICNHZK_GetFontInfo(const GUI_FONT * pFont, GUI_FONTINFO * pfi)
{
        uint32_t FontCode;
        
        GUI_USE_PARA(pFont);
        
        //ysize - 12, 16, 24
        FontCode = GUI_pContext->pAFont->YSize;
        if(12 == FontCode){
                pfi->Baseline = 12;
                pfi->LHeight  = 12;
                pfi->CHeight  = 12;
                pfi->Flags    = GUI_FONTINFO_FLAG_PROP;
        }else if(16 == FontCode){
                pfi->Baseline = 16;
                pfi->LHeight  = 16;
                pfi->CHeight  = 16;
                pfi->Flags    = GUI_FONTINFO_FLAG_PROP;
        }else if(24 == FontCode){
                pfi->Baseline = 24;
                pfi->LHeight  = 24;
                pfi->CHeight  = 24;
                pfi->Flags    = GUI_FONTINFO_FLAG_PROP;
        }else{
                return;
        }
        
}

/*********************************************************************
*
*       GUICNHZK_IsInFont
*/
//char GUI##Type##_IsInFont    (const GUI_FONT * pFont, U16 c);
char GUICNHZK_IsInFont(const GUI_FONT * pFont, U16 c)
{
        const GUI_FONT_PROP GUI_UNI_PTR  *pProp = GUI_pContext->pAFont->p.pProp;
        
        GUI_USE_PARA(pFont);
        
    for(; pProp; pProp = pProp->pNext) {
        if( (c >= pProp->First) && (c <= pProp->Last) )  break;
    }
        
        if(pProp){
                return  1;
        }else{
                return  0;
        }
}

/*********************************************************************
*
*       GUICNHZK_GetCharInfo
*/
//int  GUI##Type##_GetCharInfo (U16P c, GUI_CHARINFO_EXT * pInfo)
int GUICNHZK_GetCharInfo(U16P c, GUI_CHARINFO_EXT * pInfo)
{
        return  0;
}

/*********************************************************************
*
*       GUICNHZK_GetLineDistX
*/
int GUICNHZK_GetLineDistX(const char * s, int Len)
{
        int  Dist =0, SizeX;
        U16  c0, c1;
        
        if(0 == s)  return 0;
        
        while( ((c0=*(const U8*)s) !=0) && Len >=0 ) {
                s++; Len--;
                if (c0 > 127) {
                        c1 = *(const U8*)s++;
                        Len--;
                        Dist += GUICNHZK_GetCharDistX((c1<<8)|c0, &SizeX);
                } else {
                        Dist += GUICNHZK_GetCharDistX(c0, &SizeX);
                }
        }
        
        return Dist;
}

/*********************************************************************
*
*       GUICNHZK_GetLineLen
* Purpose:
*   Returns the number of characters in a string.
*/
int GUICNHZK_GetLineLen(const char * s, int MaxLen)
{
        int Len =0;
        U16 c0;
        
        while( ((c0=*(const U8*)s) !=0) && Len < MaxLen ) {
                s++;
                if (c0 > 127) {
                        Len++;  s++;
                } else {
                        switch (c0) {
                                case '\n': return Len;
                        }
                }
                Len++;
        }
        return Len;
}

/*********************************************************************
*
*       GUICNHZK_DispLine
*/
void GUICNHZK_DispLine(const char * s, int Len)
{
        U16  c0, c1;
        
        while (--Len >=0) {
                c0 = *(const U8*)s++;
                if (c0 > 127) {
                        c1 = *(const U8*)s++;
                        Len--;
                        GUICNHZK_DispChar((c1<<8) | c0);
                } else {
                        GUICNHZK_DispChar(c0);
                }
        }
}

/*********************************************************************
*
*       GUI_ENC_APIList_CNHZK
*/
const tGUI_ENC_APIList  GUI_ENC_APIList_CNHZK = {
        GUICNHZK_GetLineDistX,
        GUICNHZK_GetLineLen,
        GUICNHZK_DispLine,
};

你可能感兴趣的:(emWin & STemWin & uCGUI 的中文支持)