zoukankan      html  css  js  c++  java
  • 在SDL工程中让SDL_ttf渲染汉字 分类: ffmpeg-SDL-VLC-Live555 2014-12-29 17:48 215人阅读 评论(0) 收藏

    有时候在关于SDL的博文中看到一些评论,说SDL对中文的支持不佳,因为当程序涉及中文时总是输出乱码。

     

    照我个人观点,这里面很多都是误解。下面就根据我在windows下使用SDL的情况,说说我的观点。

     

    SDL作为一个跨平台的库,在字符方面有它独特的地方。那就是,它的运行库支持的字符编码为UTF8,而不是windows中常见的各种本地字符编码。比如中文版windows使用的codepage 936,也有称其为GBK的,实际上是对基于GB2312字符集的EUC-CN编码方式做了一个基于UNICODE字符集中的CJK子集的拓展所产生的一种字符硬件编码方式。

     

    比如说SDL_WM_SetCaption这个函数,它就接受一个UTF8字符串,来设置窗口的标题。

     

    不知为何,我在SDL的文档中并没有找到关于SDL的函数使用UTF8编码的说明。这可能是造成对SDL的中文兼容性的误解的其中一个原因。

     

    无论如何,这种设计是有道理的,因为它不仅兼容了使用不同本地字符集的平台,还避免了造成广泛的可移植性问题的UCS2UCS4之争。

     

    关于汉字渲染,常见的一个SDL扩展库就是SDL_ttf,它可以支持TrueType字体的渲染,无疑非常吸引人。

     

    windows版本的SDL_ttf运行库的一个问题是,它没有遵循SDL中的关于UTF8的习惯,而是提供了3个类似的函数来渲染文字。

     

    也就是TTF_RenderUTF8_SolidTTF_RenderText_SolidTTF_RenderUNICODE_Solid三个函数。

    其中TTF_RenderText_Solid能正确渲染ascii字符串,而TTF_RenderUTF8_SolidTTF_RenderUNICODE_Solid分别用于渲染UTF8编码的和UCS2编码的字符串。

     

    在windows中使用SDL时,如果需要渲染汉字,就需要将本地字符集转化为UTF8字符集。

     

    当然,如果从unicode字符集转换成UTF8字符集,那就更方便了。另外插一句,在MinGW编译环境下使用unicode字符时,务必记得给gcc编译器传递参数“-finput-charset=GBK”,否则会提示不合法的字节序列。

     

    在本地字符编码(这里我们着重于讨论中文windows中使用的codepage 936本地字符编码),UTF8字符编码和unicode字符编码3个编码方式互相转换的时候可以使用windows中的WideCharToMultiByteMultiByteToWideChar这两个函数。当然也可以使用C运行时库的wcstombsmbstowcs,这2个函数的可移植性更好(如果需要在windows以外的系统中作转换时这可能是有用的,不过这一点在linux下没用因为它直接使用UTF8编码)。

     

    在windows中配合WideCharToMultiByteMultiByteToWideChar转换字符串的格式当然很好,不过如果使用wcstombsmbstowcs时,需要注意的是windows在这里不支持utf8格式,(详见MSDN中关于setlocale的条目:http://msdn.microsoft.com/zh-cn/library/x99tb11d.aspx),也就是这个时候需要我们自己来完成从unicode到utf8的转换。

     

    这个问题可以参考一下2篇文章:

    http://www.cppblog.com/jacky2019/archive/2007/03/08/19431.html

    http://blog.sina.com.cn/s/blog_473f16d001000406.html

     

    演示一小段程序,我这里没有使用unicode字符串而是使用了本地字符编码,在运行时再进行转换,也就是直接从本地编码转为UTF8编码。

    这里不仅使用了SDL_ttf,还需要一个雅黑.ttf文件,这个需要在系统分区的WindowsFonts文件夹里复制出来,原文件名是msyh.ttf,复制到程序所在文件夹,并改名为雅黑.ttf。这里主要演示用UTF字符串正确的使用文件名中带中文的文件。

     

    代码
    1 #include <sdl/sdl.h>
    2 #include <sdl/sdl_ttf.h>
    3 #include <windows.h>
    4  char *localeToUTF8(char *src){
    5 static char *buf = NULL;
    6 if(buf){
    7 free(buf);
    8 buf = NULL;
    9 }
    10 wchar_t *unicode_buf;
    11 int nRetLen = MultiByteToWideChar(CP_ACP,0,src,-1,NULL,0);
    12 unicode_buf = (wchar_t*)malloc((nRetLen+1)*sizeof(wchar_t));
    13 MultiByteToWideChar(CP_ACP,0,src,-1,unicode_buf,nRetLen);
    14 nRetLen = WideCharToMultiByte(CP_UTF8,0,unicode_buf,-1,NULL,0,NULL,NULL);
    15 buf = (char*)malloc(nRetLen+1);
    16 WideCharToMultiByte(CP_UTF8,0,unicode_buf,-1,buf,nRetLen,NULL,NULL);
    17 free(unicode_buf);
    18 return buf;
    19 }
    20 
    21  int main(int argc,char *argv[]){
    22 SDL_Surface *screen = SDL_SetVideoMode(640,480,32,SDL_SWSURFACE);
    23 SDL_WM_SetCaption(localeToUTF8("在SDL中渲染汉字吧!"),NULL);
    24 TTF_Init();
    25 TTF_Font *font = TTF_OpenFont(localeToUTF8("雅黑.ttf"), 28);
    26 SDL_Color textColor = {255, 255, 255};
    27 if(!font){
    28 MessageBox(0,0,"no",0);
    29 return -1;
    30 }
    31 SDL_Surface *text = NULL;
    32 text = TTF_RenderUTF8_Solid(font,localeToUTF8("中文!"),textColor);
    33 SDL_BlitSurface(text,NULL,screen,NULL);
    34 SDL_Flip(screen);
    35 SDL_Event event;
    36 while(SDL_PollEvent(&event),event.type != SDL_QUIT);
    37 return 0;
    38 }
    39  

     

    这里有一个短小的多的函数解释了从本地字符集到UTF8的相互转化。

     

    代码——UTF8转本地字符集
    1 #include <stdio.h>
    2 #include <stdlib.h>
    3 #include <locale.h>
    4 #include <string.h>
    5  char *utf8ToLocal(char *src){
    6 wchar_t wbuf[100];
    7 static char buf[100];
    8 char *uchar = (char*)wbuf;
    9 char *pSrc = src;
    10 //初始化数据,便于产生unicode中的ascii字符
    11   memset(wbuf,0,sizeof wbuf);
    12 while(*pSrc!=''){
    13 if(*pSrc < 0){//如果不是ascii字符
    14   uchar[1] = ((pSrc[0] & 0x0f)<<4) + ((pSrc[1] >>2) & 0x0f);
    15 uchar[0] = ((pSrc[1] & 0x03)<<6) + (pSrc[2] & 0x3f);
    16 pSrc += 3;//对于非ascii字符,UTF8编码里占3字节
    17   uchar += 2;//windows中宽字符占2字节,在linux下应改为4
    18   }
    19 else{
    20 uchar[0] = pSrc[0];//对于ascii字符,可以直接复制
    21   pSrc += 1;
    22 uchar += 2;
    23 }
    24 }
    25 setlocale(LC_ALL,"");//默认的字符集是“C”,在这里改为本地字符集
    26 //在CP936的系统中,上面这句调用等价于setlocale(LC_ALL,".936");
    27   wcstombs(buf,wbuf,100);
    28 //正确调用setlocale函数后,我们可以安全的使用wcstombs了
    29 //它会为我们转换字符编码格式,从UNICODE转为本地字符集
    30   return buf;
    31 }
    32 
    33  int main()
    34 {
    35 char *text = NULL;
    36 text = utf8ToLocal("xE6xB1x89xE5xADx97");
    37 printf("%s ",text);
    38 return 0;
    39 }
    40  

     

    这里的"xE6xB1x89xE5xADx97"是一串UTF8编码的字符串,内容是“汉字”。

  • 相关阅读:
    核心动画03-图标抖动.mp4
    核心动画02-CAKeyframeAnimation帧动画
    核心动画01-CABasicAnimation
    CALayer参考文献
    CALayer04-自定义图层
    CALayer03-隐式动画
    CALayer02-创建新图层
    iOS开发中的网络请求
    IT教育课程考评系统开发-06
    IT教育课程考评系统开发-05
  • 原文地址:https://www.cnblogs.com/mao0504/p/4706471.html
Copyright © 2011-2022 走看看