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

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

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

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

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

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

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

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

也就是TTF_RenderUTF8_Solid,TTF_RenderText_Solid和TTF_RenderUNICODE_Solid三个函数。

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

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

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

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

在windows中配合WideCharToMultiByte和MultiByteToWideChar转换字符串的格式当然很好,不过如果使用wcstombs和mbstowcs时,需要注意的是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文件,这个需要在系统分区的Windows\Fonts文件夹里复制出来,原文件名是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转本地字符集
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <string.h>
char *utf8ToLocal(char *src){
wchar_t wbuf[];
static char buf[];
char *uchar = (char*)wbuf;
char *pSrc = src;
//初始化数据,便于产生unicode中的ascii字符
memset(wbuf,,sizeof wbuf);
while(*pSrc!='\0'){
if(*pSrc < ){//如果不是ascii字符
uchar[] = ((pSrc[] & 0x0f)<<) + ((pSrc[] >>) & 0x0f);
uchar[] = ((pSrc[] & 0x03)<<) + (pSrc[] & 0x3f);
pSrc += ;//对于非ascii字符,UTF8编码里占3字节
uchar += ;//windows中宽字符占2字节,在linux下应改为4
}
else{
uchar[] = pSrc[];//对于ascii字符,可以直接复制
pSrc += ;
uchar += ;
}
}
setlocale(LC_ALL,"");//默认的字符集是“C”,在这里改为本地字符集
//在CP936的系统中,上面这句调用等价于setlocale(LC_ALL,".936");
wcstombs(buf,wbuf,);
//正确调用setlocale函数后,我们可以安全的使用wcstombs了
//它会为我们转换字符编码格式,从UNICODE转为本地字符集
return buf;
} int main()
{
char *text = NULL;
text = utf8ToLocal("\xE6\xB1\x89\xE5\xAD\x97");
printf("%s\n",text);
return ;
}
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!='\0'){
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("\xE6\xB1\x89\xE5\xAD\x97");
37 printf("%s\n",text);
38 return 0;
39 }
40  

这里的"\xE6\xB1\x89\xE5\xAD\x97"是一串UTF8编码的字符串,内容是“汉字”。

出自:http://www.cnblogs.com/bombless/archive/2010/11/21/SDL-using-chinese-character.html


(转)在SDL工程中让SDL_ttf渲染汉字的更多相关文章

  1. 在SDL工程中让SDL_ttf渲染汉字

    有时候在关于SDL的博文中看到一些评论,说SDL对中文的支持不佳,因为当程序涉及中文时总是输出乱码. 照我个人观点,这里面很多都是误解.下面就根据我在windows下使用SDL的情况,说说我的观点. ...

  2. Cocos2d-JS工程中的文件结构

    res文件夹存放资源文件 src文件夹是主要的程序代码 app.js是实现游戏场景的JavaScript文件 resource.js在src文件夹中,定义资源对应的变量 config.json保存模拟 ...

  3. CSS在工程中改变之面向对象的 CSS

    oocss的概念 众多开发者忽视了css的表现(认为它) oocss将页面可重用的元素抽象成一个类,用class加以描述,而与其对应的HTML即可看成是此类的一个实例. oocss的作用 1.加强代码 ...

  4. 清除Android工程中没用到的资源

    项目需求一改再改,UI一调再调,结果就是项目中一堆已经用不到但却没有清理的垃圾资源,不说工程大小问题,对新进入项目的人或看其他模块的代码的人来说,这些没清理的资源可能也可能会带来困扰,所以最好还是清理 ...

  5. unity导出工程导入到iOS原生工程中详细步骤

    一直想抽空整理一下unity原生工程导入iOS原生工程中的详细步骤.做iOS+vuforia+unity开发这么长时间了.从最初的小小白到现在的小白.中间趟过了好多的坑.也有一些的小小收货.做一个喜欢 ...

  6. CEGUI0.8.4引入到自己工程中

    首先要确定你的CEGUI已经完全编译好,若未进行这一步请参照http://www.cnblogs.com/wenguang1996/p/5027522.html 打开VS2012新建C++工程,然后添 ...

  7. 关于在工程中添加新文件时的LNK2019错误的一个解决办法

    我这几天一直在研究Qt的串口程序,在读懂了官方给出的实例程序后我决定把其多线程的串口监视程序加入到我自己的工程中,便直接把问价复制到自己的工程下面,在Qt中加入到自己的工程中,但是总是出现LNK201 ...

  8. 用CMake设置Visual Studio工程中预处理器定义值

    构建VS工程时预处理值是不可缺少的,如动态库的导出配置等.在通过CMake构建VS工程时,可以通过CMake命令进行定义,下面讲三种应用. 字符集:默认装填下VS工程是多字节字符集,如果需要使用Uni ...

  9. iOS开发--Swift 如何完成工程中Swift和OC的混编桥接(Cocoapods同样适用)

    由于SDK现在大部分都是OC版本, 所以假如你是一名主要以Swift语言进行开发的开发者, 就要面临如何让OC和Swift兼容在一个工程中, 如果你没有进行过这样的操作, 会感觉异常的茫然, 不用担心 ...

随机推荐

  1. 【delphi】关键字详解

    absolute {它使得你能够创建一个新变量, 并且该变量的起始地址与另一个变量相同.} var Str: ]; StrLen: Byte absolute Str; {这个声明指定了变量StrLe ...

  2. 【转】MySQL查看表占用空间大小(转)

    //先进去MySQL自带管理库:information_schema //自己的数据库:rokid_cas_music_test //自己的表:data_song_thirdparty mysql&g ...

  3. C++中虚函数的作用是什么?它应该怎么用呢?

    虚函数联系到多态,多态联系到继承.所以本文中都是在继承层次上做文章.没了继承,什么都没得谈. 下面是对C++的虚函数这玩意儿的理解. 一, 什么是虚函数(如果不知道虚函数为何物,但有急切的想知道,那你 ...

  4. Oracle 自启动配置

    最后是放在rc.d/rc.local  里面,否则脚本编写错误 Linux有可能都启不来 [root@ChenJun-CentOS6 bin]# vi /etc/init.d/oracle #!/bi ...

  5. 获得discuz7.2 目录下所有文件,并写到txt

    # -*- coding: utf-8 -*- import os fileList = [] dzList = [] def GetFileList(path): List = [] for roo ...

  6. linux跑火车的命令sl

    http://forum.ubuntu.org.cn/viewtopic.php?t=250890 ubuntu下可以通过 apt-get install sl 安装.执行sl会出来什么呢?帖一下: ...

  7. 基于jQuery自适应宽度跟高度可自定义焦点图

    基于jQuery自适应宽度跟高度可自定义焦点图.这是一款带左右箭头,缩略小图切换的jQuery相册代码.效果图如下: 在线预览   源码下载 实现的代码. html代码: <section cl ...

  8. EnumUtil

    EnumUtil.cs using System; using System.Collections.Generic; using System.ComponentModel; using Syste ...

  9. Ehcache 缓存监控配置

    监控 ehcache缓存: 1,下载: http://terracotta.org/downloads/open-source/destination?name=ehcache-monitor-kit ...

  10. PPP或PPPOE身份验证PAP和CHAP

    PPP或PPPOE都支持身份验证,有两种验证方式:PAP和CHAP. PAP,Passwd Authentication Protocol,密码验证协议,以客户端明文方式传递用户名和密码,服务器和本省 ...