(转)在SDL工程中让SDL_ttf渲染汉字

有时候在关于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的相互转化。

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

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


时间: 2024-08-13 12:13:01

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

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

oocss的概念 众多开发者忽视了css的表现(认为它) oocss将页面可重用的元素抽象成一个类,用class加以描述,而与其对应的HTML即可看成是此类的一个实例. oocss的作用 1.加强代码复用以便方便维护. 2.减少cs体积 3.提升渲染效率 4.组件库思想,栅格布局可共用,减少选择器,方便扩展. 注意事项 1.不要直接定义子节点,应该把共性放在父类中 2.结构和皮肤相分离 3.容器与内容相分离 4.抽象出可重用的元素,建好组件库,在组件库内寻找可用的元素组装页面 5.往你想要扩展的

.net 工程中引用出现感叹号

在工程中引用出现感叹号,有两个原因 原因1:  这是由于之前引用的Dll文件不见了. 右键有感叹号的项,然后选择 "属性" 里边有一个路径属性 这个路径就是之前这个Dll文件的路径,现在这个文件不在了,你需要找到现在这个文件的路径 右键有感叹号的项,然后选择"移除" 右键"引用",选择添加引用,然后选择那个不在的dll的真实路径 其他的项用相同的方式处理 原因2:可能是引用的.Net版本高于了当前工程的.Net版本 更改所引用的工程文件的.Net

在Qt工程中加Boost

摘要: Boost是一个很强大的C++库,堪比STL,里面有很多非常优秀的类库.我不多介绍,详情见官网:http://www.boost.org/ 要在我们的Qt工程中把这个库加进去应该怎么做呢?我今晚试了一下. Boost是一个很强大的C++库,堪比STL,里面有很多非常优秀的类库.我不多介绍,详情见官网:http://www.boost.org/ 要在我们的Qt工程中把这个库加进去应该怎么做呢?我今晚试了一下. 我从网上下载了Boost压缩文件,下载地址:boost_1_52_0.tar.g

step4-----&gt;往工程中添加Spring的子项目spring IO Platform-------&gt;通过maven添加相关框架(pom.xml)

添加Spring IO Platform的目的: 避免自己的project的外部依赖(external dependencies)之间产生版本冲突问题.更多详细信息参见:Spring IO Platform概述 具体操作步骤: step1,往自己的工程中添加Spring IO Platform 编写project的pom.xml,添加如下代码,引入Spring IO Platform <dependencyManagement> <dependencies> <depende

step4---&gt;往工程中添加Spring框架----&gt;修改maven的配置文件pom.xml,向工程中添加spring框架的某些模块

1.本文内容: 本文介绍使用maven向自己的项目中添加各种框架的方法,即如何配置maven的pom.xml来让maven帮助管理这些框架(包括Spring.SpringMVC.hibernate框架等等). 2.使用maven向自己的工程中添加框架: 2.1概述 若想使用maven向自己的工程中添加三方框架(如Spring.SpringMVC等),需要先确保你的工程是maven工程,如果你还不知道该如何在myeclipse中建立一个maven web project,请参考相关教程. 2.2使

在C++工程中main函数之前跑代码的廉价方法(使用全局变量和全局函数)

[cpp] view plain copy // test.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <windows.h> #include <crtdbg.h> /// 在C++工程中main函数之前跑代码的廉价方法 /// 利用全局变量可以赋可变初值的事实 /// mainCRTStartup() => _cin

在VC工程中添加多语言支持[转]

随着贸易国际化,在软件开发过程中,常会碰到需在现有中文版软件加入多语言支持的情况.由于不同语言版本间的差别通常仅是软件操作界面的不同,为实现多语言支持,使用纯资源DLL是一个不错的解决之道.所谓纯资源DLL是指只包含资源的DLL,譬如:快捷键.对话框.字符串.菜单.工具条.位图.图标.版本信息等等. 具体做法是:利用VC可视化编辑环境为每种语言制作一套资源ID一一对应的资源集并编译生成DLL文件.应用程序初始化时按预设的语言设置选择合适的资源DLL调入,使用资源时依据资源ID进行访问,这样即可实

Android工程中加入图片,报错cannot be resolved or is not a field

SDK和ADT为22.6.2版本 工程为4.4.2 今天在写Android代码的时候,往工程中加入了几张图片,然后在代码中使用R.drawable调用时,一直报错 cannot be resolved or is not a field 然后我查看了gen目录下的R.java文件,发现里面已经有我加入的图片资源ID了,觉得很奇怪,一般是无法生成R.java文件的时候才会出现这种现象啊 在网上查了资料也未见有可以解决我这个问题的方法,然后我就把我的代码从头到尾重新看了一遍,开始也没有发现什么异常,

iOS工程中的info.plist文件的完整研究

原地址:http://blog.sina.com.cn/s/blog_947c4a9f0100zf41.html 们建立一个工程后,会在Supporting files下面看到一个"工程名-Info.plist"的文件,这个是对工程做一些运行期配置的文件,很重要,不能删除. 如果你在网上下载的工程中的这个文件名只是Info.plist,那么恭喜你,这个工程太老了,是用包含SDK2.0以前的Xcode生成的,不过没关系,不影响使用. 如果你使用文本编辑器打开这个文件,你会发现这是一个XM