`
gavinju
  • 浏览: 31310 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Unix/Linux中中文图像输出乱码问题。

阅读更多

最近,在把条码系统集成到Oracle EBS平台上时,老是遇到中文乱码问题。服务器用Apache 1.3.EBS 平台的应用服务器JRun.
经过多方查找资料,现拿出自己的解决方案供后续遇到此类问题的程序员参考:

在Unix/Linux上令JVM支持中文输出

如果用户使用的是UNIX的远程服务器,就会遇到中文字体在图像中输出的问题,特别是由于许多管理员并不喜欢把主机的locale定为zh(因为意味着可能出乱码
或必须装微形图形终端象zhcon,但很多情况下这样的条件并不具备)。大部分程序员的JAVA经验苟限于JSP脚本程序,部分熟练的程序员大概开发过中间件、servlet、
applet或在WINDOWS上运行的GUI程序。如果开发的jfreechart是使用WINDOWS作为主机运行的话,可以略过这一段,但如果使用的是UNIX类型的服务器的话,就常常遇到
意想不到的中文显示困难,甚至还未到输出中文字体的阶段,程序就报告 display异常错误。原因就在于,JAVA awt原来是针对(X)windows GUI编写的程序,它常常
需要使用display 1:0的设置设定显示方式,在服务器模式下(象jsp或servlet),根本就不会有XWindowns运行,这时就会在许多程序中引起can not got
display setting to 0:0的错误,包括jfreechart。解决办法是在JVM启动中增加-Djava.awt.headless=true的设置。但这样又带来另一个问题,
会令使用象frame.getImage()方法的代码中引起headless  Exception,导致程序中止,而使用ImageBuffer的程序就不会受到影响。

象jfreechart这样基于java awt,java Swing, java 2D API和程序应用到Linux/UNIX上,中文字体的输出是一个必须解决的问题,否则连jfreereport都不能使用了。
servlet也会碰到类似的问题,但解决方式显得相对简单,servlet package已经内置了解决办法,一般情况下,在 servlet抬头设两句:

response.setContentType("text/html;charset=UTF-8");
request.setCharacterEncoding("UTF-8"); 

中文乱码就不得存在。与简单的jsp/servlet字符集转换相比,这个问题要复杂得多,甚至比一般的linux中文化还要复杂。在正常情况下,
jre只包含少数几种字体(Font),但可以从X 系统,象windows获得喜欢的字体支持;因此,如果开发者和使用者是在中文WINDOWS系统上开发,
大概不会发觉问题的存在。但一旦当程序发布到 UNIX/Linux系统上后,就会发现图形中的中文字符成为一个个的问号或者小方框。而此时,
象jsp/servlet这样的程序在客户端的显示却是完全正常的。一般情况下,JAVA默认情况下是使用en_OTF-8,或者ISO_8859_1读入字符串,因此,
象JSP通常使用从8859_1强制转型为gb3312/GBK,就可以正常显示中文,但是在上述的情形下,这种强制转型地是完全无效的。为什么呢?
如果程序员的系统概念是清晰的话,就会明白, JSP/SERVLET的字符串输出,只是输出字型,然后由客户端(一般是浏览器)在客户端桌面重整字型,
用的是客户端的字体,而相反,JfreeChart这样的图形程序输出的是一个图像,用的是服务器端jre的字体,与Xwindows的字体也无关。
当系统本身不带有字型时(font),这正是服务器所常见的,就只能向jre添加支持中文的字体(font)才能根本上解决这个问题。

Jre 的字体设置原理与Xwindows相似,并延用相同的工具,事实上,二进制字体文件延用相同的标准,各个公司间的字体集,象联想、方正、
微软以及 linux Xwindows下是相同的,完全可以互相拷贝,仅仅是读取字体的方式流程和设置方式稍有区别。目录提及linux汉化的文章,
其中主要就是增加中文字体的支持,很多是废话连篇,不知其所以然乱撞一通后惊呼"搞定啦"这样不可重复的形式。所以这里先复习一下,
然后和JRE的设置对照,原理就会显得比较清晰。目前linux的字体有两处使用,一是linux console下的字体,二是Xwin等应用程序的字体,
包括象zhcon这样的伪console程序。每处应用字体的程序都可以有自已的字体设置目录;但随着Linux集成程度的强化,
都倾向向通过默认的unixsocket7000端口调用xfs的字体服务。因此,字体设置只需对xfs进行设置就可以完成。一些文章声称要停掉XFS,
实际上毫无必要;xfs的调用仅仅是作为一个在XFConfig中的FontPath选项,作为另一个添加字体的方法,就是直接把包含字体的目录添加到FontPath,
然后手工执行ttmkfdir――恰恰这本来是xfs设计代替您去做的。用户实际上需要做的,要么是直接在图形工具中把字体文件添加到fonts:\\\中,
或者是手工把字体文件加到xfs的目录下的对应locale的目录中,一般是在 /usr/share/lib/fonts/zh_CN/TrueType,重启xfs就搞定了。
作为手工添加到XFConfig中的目录,在XWin 中,简单地说,字体位图文件是通用的,包括对JRE,放在某一个目录中,
用户需要做的就是通知XWIN这些目录在什么地方,设置的位置就在 /etc/X11/XConfig的FontPath项。运行ttmkfdir命令生成fonts.dir文件,
实际上都是字体调用的对照表,另外用户可以编辑fonts.alias这样的文件,目的就是让字体有个易记的名字。因此,
字体的安装关键在于字体位图文件(拷到某个目录),对照文件(由 ttmkfdir命令生成),和字体别名设置,所不同的是,
在Xwin中这些由xfs自动完成,在jre中,就要开发者自已手工完成。

就Jre 而言,字体位图目录是固定的,在$JRE_HOME/lib/fonts目录中;fonts.dir*的目录对照表文件也是一样的,同样是由 ttmkdir程序生成,而相当于别名等设置的文件,集中在$JRE_HOME/lib目录下的*font.properties*"文件中定义。如果 JVM能直接支持中文输出,那么就要求*font.properties*属性文件中指示的字体型本身是支持中文的(换言之,JSDK自带的字体文件是不支持中文的)。按http://java.sun.com/j2se/1.3/docs/guide/intl/fontprop.html的说明,JVM按以下顺序搜索字体属性文件,尖括号是JVM检测的系统属性:

font.properties.<language></language>_<region></region>_<encoding></encoding>.<osversion></osversion>
font.properties.<language></language>_<region></region>_<encoding></encoding>
font.properties.<language></language>_<region></region>.<osversion></osversion>
font.properties.<language></language>_<region></region>
font.properties.<language></language>_<encoding></encoding>.<osversion></osversion>
font.properties.<language></language>_<encoding></encoding>
font.properties.<language></language>_<osversion></osversion>
font.properties.<language></language>
font.properties.<encoding></encoding>.<osversion></osversion>
font.properties.<encoding></encoding>
font.properties.<osversion></osversion>
font.properties


但在大多数情况下,实际上只需要面向一个font.properties文件。重新编一个font.properties文件是一项艰苦的工程,幸好在 Linux中有一个font.properties.zh.Turbo,本来是面向TurboLinux用户,不过在大多数情况下可以基于它修改。把这个文件重命名为font.properties,覆盖掉原来的文件,但系统这时仍不支持中文,查看一下,就会发现 font.properties.zh.Turbo文件中的"-tlc-song-medium-r-normal--*-%d-*-*-c-*-gbk -0"字型在fonts.dir对照表中并不具备,这种字型包含在TurboLinux的系统字型库中。下面的方法有两个,一是安装这种字体,二是更改另一种字体型库并重新指定。TurboLinux的字体安装文件名字是ttf-zh-song*rpm,在互联网上可以找到,安装后把 /usr/lib/X11/fonts/tt下的ttf文件拷贝到$JRE_HOME/lib/fonts目录下,重新生成fonts.dir文件。第二种办法就是重找字体库,微软WINDOWS上的fonts目录下的ttf文件一般可用,但更全的是从http://www.microsoft.com/china/windows2000/downloads/18030.asp 下载它的字符集文件,安装后把ttf拷到JRE的fonts目录下;另外, XWin如果支持中文的话,可以从/usr/lib/X11/fonts/TrueType下找到一两个支持中文的字体文件。

把这些文件统统拷到JRE的fonts目录并不能令JVM立刻支持中文,回想一下前面提到的,在font.properties中指定的文字类型,必须有一个对照表fonts.dir指示JVM如何把用户调用的font类型匹配到相应的字型文件上。因此,运行ttmkfdir > fonts.dir生成新的对照表。用Vi打开这个文件,最上面的数字是系统可以调用的字型数目,下面的属性值对左侧就是物理字型名称,右侧是它的编号,这就是用到font.properties 文件中指明使用的编号(包含了设置,左侧的就是字符的别名,即虚拟字型),区别仅仅是把0-0-0c-0这类设置中的某几项改作通配符和%d接受调用参数而已,不改也行,大不了输出的字难看一点(反正我不是美工,不太关心)。用可用的字型编号代替了font.properties中无效的字型设置后,理论上似乎JVM已经支持中文了,但在实际操作上,仍是经常见到问号、空格之类,原因就在于JAVA对中文的支持不但与运行环境有关,还与编译参数有关,如果类文件不是以gb2312/encoding编译的话,等同于读入是OTF-8/8859_1,这时再转换也没有用了,因此,如果是drawString 之类的,必须切记使用(-encoding gb2312);当然,如果操作系统本身已经是中文的话,这条就由编译器自动采纳了。



在正式环境中ZplPrinter.java中加入
将String fontNameT = fontName 修改为
String fontNameT = new String(fontName.getBytes("iso-8859-1"), "utf-8");

在UNIX服务器上执行
cp $OA_JRE_TOP/jre/lib/font.properties.zh_EUC_CN $OA_JRE_TOP/jre/lib/font.properties,
重新启动Apache,问题解决.

二。郁闷的是,在AIX中配置有所不同,正好这两种情况都被我遇到了

1:将jdk升级为jdk1.4,然后加上运行参数 –Djava.awt.headless=true 即可。
2:虚拟一个图形环境。一般在linux下使用Xvfb来虚拟一个图形环境,在linux命令行键入Xvfb :0 -screen 0 1024x768x16 & ,不过在使用之前要对Xvfb进行设置。我在本机上没有调试成功。各位可以试一下。
3:使用第三方工具包。可以使用 pja包,下载地址 http://www.eteks.com/pja/en/#Download ,使用方法见解决方案。

headless是指由于一些服务器(比如大型机)运行的环境比较特殊,不存在真实的设备去处理一些输入输出,比如显卡,键盘鼠标;这时就需要虚拟一些运行环境出来,或者就不要用到这些设备的相关操作(比如输入输出)。然而运行java.awt包又需要一个的图形环境,由此产生了异常。

讨论:这个问题在java中称为headless问题,是jdk1.3的bug,bug报告见http://developer.java.sun.com/developer/bugParade/bugs/4281163.html 。jdk1.4已经做了修正,文档见http://java.sun.com/j2se/1.4.1/docs/guide/awt/AWTChanges.html






Linux找不到字体文件,象“宋体”,没设置fonts.dir的话是绝对不可用的!       http://<nobr target="_blank" onmouseout="kwL(event, this);" onclick="return kwC();" style="border-bottom: 1px dotted rgb(102, 0, 255); color: rgb(102, 0, 255); background-color: transparent; text-decoration: underline;" onmouseover="kwE(event,1, this);" id="key1" onmousemove="kwM(1);" oncontextmenu="return false;">java</nobr>.sun.com/j2se/1.3/docs/guide/intl/fontprop.html   
  主要的操作就是copy字体文件到$JRE_HOME$/lib/fonts下,ttmkfdir生成fonts.dir(定义字型),并修改fonts.properties设置对应字型的别名

 


X 字库定义全名为 X Logical Font Description,简称为 XLFD 或称字库名。点阵字体语法如下:

-hp- 字体名称 - 粗细 -r-normal--<dot>-<point>-<resX>-<resY>-c- 字符集

X 字库

字体名称

song:宋体

粗细

medium:中等粗细
bold:加粗字

dot

字体点数

point

字体图数

resX

X 分辨率

resY

Y 分辨率

字符集

gb2312.1980-1:GB2312 中文字集
iso646.1991-irv:ISO 英文字符和数字集
iso10646.2000-cn:Unicode/ISO10646基本平面(BMP)
iso10646-1:Unicode/ISO10646基本平面(BMP)
iso10646p2-2:Unicode/ISO10646 第二平面(plane-2)

下表所列为简体中文系统环境所提供的 X 字体定义和其文件名的对照。
 X 字体定义及其文件名对照

文件名                                                                                             X字库定义(X Logical Font Description)
song18a.pcf                             -hp-song-medium-r-normal--18-180-75-75-c-80-iso646.1991-irv

zyhei.ttf                                      -zyec-zycjkhei-medium-r-normal--0-0-0-0-m-0-gb2312.1980-1

zyhei.ttf                                      -zyec-zycjkhei-medium-r-normal--0-0-0-0-m-0-iso646.1991-irv

zysong.ttf                                  -zyec-zycjksun-medium-r-normal--0-0-0-0-m-0-gb2312.1980-1

fzfs.ttf                                         -bdfz-fzfangsong-medium-r-normal--0-0-0-0-m-0-gb2312.1980-1

fzkt.ttf                                          -bdfz-fzkai-medium-r-normal--0-0-0-0-m-0-gb2312.1980-1

X 字体定义指定法

在指定一串相同大小但不同编码的 X 字体定义时,可使用较简单的指定方式。将前面字体和后面的字符集省略,以通配字符 * 号代替。例如:

-*-song-medium-r-normal--18-* 指定所有不同编码的 18 大小的点阵宋体字-*-song-medium-r-normal--24-* 指定所有不同编码的 24 大小的点阵宋体字-*-zycjksun-medium-r-normal-30-* 指定所有不同编码的 30 大小的 TrueType 宋体字-*-zycjkhei-medium-r-normal-18-* 指定所有不同编码的 18 大小的 TrueType 黑体字


X 环境参数的字体指定法

例如指定点阵字体:

*fontList: -*-song-medium-r-normal--24-*:

此冒号是必备的

又如指定 TrueType 字体:

*fontList:-*-zycjksun-medium-r-normal-40-*-**-m-*:

若要在环境参数 *fontList 指定多个 X 字体定义,则字体定义间须以分号 (;) 隔开。

*fontList: -*-song-medium-r-normal--18-180-75-75-c-160-gb2312.1980-1;\

-*-song-medium-r-normal--24-240-75-75-c-240-gb2312.1980-1;\

-*-song-medium-r-normal--34-340-75-75-c-340-gb2312.1980-1:

 


 


 
















分享到:
评论

相关推荐

    UNIX环境高级编程第二版

    另外,从提供的部分内容中,我们可以看到很多乱码,这可能是因为OCR技术在处理扫描文本时,由于字体、图像清晰度或者扫描质量等因素导致的识别错误。这种情况下,读者可能需要对照原书内容进行校对和理解,以便更好...

    changefile.zip

    从描述来看,该程序可能在运行过程中遇到了中文乱码问题,并提供了相应的解决方案。 JavaFX是一个用于创建桌面和移动应用的Java库,它提供了丰富的图形用户界面(GUI)组件和功能。使用JavaFX,开发者可以构建跨...

    《码书:编码与解码的战争》

    Windows系统使用的是ANSI编码,而Unix/Linux系统通常使用UTF-8。Java的File类提供了处理不同编码文件名的方法。 总的来说,《码书:编码与解码的战争》这本书可能会深入讲解这些编码和解码的概念、原理以及在Java中...

    《计算机基础习题集》-原始数据.rar

    Windows中的FAT32、NTFS,以及Unix/Linux的EXT系列文件系统是常见的例子。理解文件命名规则、目录结构、权限管理等内容,对于日常文件操作至关重要。 五、网络基础 计算机网络使多台计算机能够相互通信。TCP/IP协议...

    简易记事本

    4. **文本格式处理**:虽然记事本不支持复杂的文本格式,但需要处理基础的文本格式,如换行符(Windows使用`\r\n`,而Unix/Linux使用`\n`)和文本编码(如ASCII、UTF-8)。 5. **剪贴板操作**:复制、剪切和粘贴是...

    UNICODE系列讲座(CHM).rar

    除此之外,可能还会涵盖Unicode在操作系统中的应用,如Windows API、Linux或Unix环境下的Unicode支持,以及如何在编程语言如Java、C++、Python、JavaScript等中处理Unicode字符串。学习者将了解到如何正确地读写...

    计算机基础教案三.pdf

    系统软件包括操作系统(如Windows XP、UNIX、Linux、DOS),应用软件则包括用户直接使用的软件,如办公软件、图像处理软件、浏览器等。 #### 3. 操作系统基础 操作系统是计算机系统的核心软件,它负责管理计算机...

    w3m-0.5.3.tar.zip

    在Linux和Unix环境中,`tar`命令用于打包文件或目录,而`.gz`是gzip压缩格式,用于进一步减小文件大小。`.zip`则是广泛使用的跨平台文件压缩格式,适用于Windows和各种Unix-like系统。结合这两种压缩方式,可以提供...

    专转本计算机基础知识.pdf

    软件部分则涉及不同的操作系统,包括Windows系列(如Windows 2000、Windows XP、Windows Vista等)、UNIX、Linux等。课程内容会涉及到操作系统的基本概念、文件系统的管理、命令行的使用等基础知识。 2. 编程语言和...

    PHP入门到精通

    20.4解决数据库乱码问题 第3篇 高级应用 PHP网络开发(教学录像:42分33秒) 21.1电子邮件的原理 21.2系统的配置需求(SMTP和POP3服务器安装配置) 21.3应用PHP发送和接收电子邮件 PHP与XML技术(教学录像:31分17秒...

    PHP入门到精通02

    20.4解决数据库乱码问题 第3篇 高级应用 PHP网络开发(教学录像:42分33秒) 21.1电子邮件的原理 21.2系统的配置需求(SMTP和POP3服务器安装配置) 21.3应用PHP发送和接收电子邮件 PHP与XML技术(教学录像:31分17秒...

    网络部部门考核试题

    - **BIOS设置**:BIOS(基本输入/输出系统)设置与网络连接问题关系不大。 **答案解析**:本题的答案是A.DNS设置。 #### 14. 网线接入路由器的正确接口 **知识点解析:** - **路由器接口**: - **LAN口**:用于...

Global site tag (gtag.js) - Google Analytics