>  기사  >  운영 및 유지보수  >  Java Linux 파일의 중국어 문자 왜곡 문제를 해결하는 방법

Java Linux 파일의 중국어 문자 왜곡 문제를 해결하는 방법

藏色散人
藏色散人원래의
2021-12-14 14:33:335617검색

Java Linux 파일의 중국어 왜곡 문자에 대한 솔루션: 1. jdk1.8의 sun 소스 코드를 다운로드합니다. 2. 글꼴 생성을 물리적 글꼴에서 논리 글꼴로 변경합니다. 3. 서비스를 다시 시작합니다.

Java Linux 파일의 중국어 문자 왜곡 문제를 해결하는 방법

이 기사의 운영 환경: linux5.9.8 시스템, jdk1.8, Dell G3 컴퓨터.

Java Linux 파일의 중국어 문자 깨짐 문제를 해결하는 방법?

Linux 환경의 Java 중국어 문자 깨짐 해결 방법

최근에 많은 친구들이 Java 문자 깨짐 문제에 직면한 적이 있습니다. 또한 "텍스트를 사용하여 그림을 생성하는 과정" "중국어 및 특수 문자가 깨짐" 문제를 해결했습니다. 나는 sun.font 및 sun.awt에서 다양한 소스 코드를 디버깅하는 데 많은 시간을 보냈고 마침내 메커니즘을 이해하고 현재 문제를 해결했습니다. 문제, 이제 문제 해결 과정을 알려드리겠습니다. 나중에 다시 발생하지 않도록 기록해 두세요.

발생한 문제

다음은 제가 실행하려는 코드입니다(매우 단순화되었지만 의미는 동일합니다).

public static void main(String[] args) throws IOException {
   File file = new File("test.png");
   Font font = new Font("宋体", Font.PLAIN, 10);
   BufferedImage bi = new BufferedImage(400, 200, BufferedImage.TYPE_INT_ARGB);
   Graphics2D g2 = (Graphics2D) bi.getGraphics();
   g2.setBackground(Color.WHITE);
   g2.clearRect(0, 0, 400, 200);
   g2.setFont(font);
   g2.setColor(Color.BLACK);
   g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
   g2.drawString("为什么没有(ꐚꌒꑿꆺ)(ꐚꌒꑿꆺ)这名字特殊不?@¥¥¥ 为什么没有(ꐚꌒꑿꆺ)(ꐚꌒꑿꆺ)这名字特 ", 0, 10);
   g2.dispose();
   ImageIO.write(bi, PNG, file);
}

물론 목표는 test.png를 열 때 다음 장면을 보는 것입니다.

로컬 디버깅에 문제가 없어 테스트머신(Linux)에 올려놓고 실행해 보니 실행 결과가 놀라웠습니다.

jdk1.8 sun 소스코드 다운로드

따라가세요. 일관된 프로그래머 스타일 : 문제가 있으면 Debug!
비결은 현재 소스 코드 패키지에 더 이상 sun 패키지의 코드가 포함되어 있지 않다는 것입니다!
다행히 Java는 OpenJDK의 코드가 기본적으로 JVM 소스 코드와 동일하다는 것을 공식적으로 확인했습니다. OpenJDK8u: jdk8u에서 직접 다운로드할 수 있습니다.

소스 코드를 사용하여 디버깅하는 방법에 대해서는 쓰지 않겠습니다. ... 이건 기본이 아니니 이 글은 읽지 마세요.

문제 찾기

소스 코드를 직접 다운로드하고, 원격 중단점을 사용하여 서버에서 실행해 보세요. 디버깅 중에 문제를 일으킨 첫 번째 코드를 발견했습니다. 로컬 서버와 테스트 서버 간의 불일치:

JVM이 글꼴을 생성할 때 FontManagerFactory를 사용하여 글꼴 관리자를 얻고, 서로 다른 시스템이 서로 다른 FontManager를 사용하는 것으로 나타났습니다. Mac은 CFontManager를 사용하고 Linux는 X11FontManager를 사용합니다!

이 두 FontManager의 차이점은 무엇인가요?

CFontManager는 CFont를 Font2D로 생성합니다. 이 CFont는 Mac용으로 특별히 JVM에서 만든 클래스입니다. 클래스 및 메서드에 대한 설명을 보면 Mac 환경에서 물리적 글꼴이 CFont로 래핑되는 경우가 있다는 것을 알 수 있습니다. :

X11FontManager로 생성된Font2D는 논리적 글꼴과 물리적 글꼴을 포함하는 컬렉션입니다. X11FontManager는 FcFontManager를 상속하고, FcFontManager는 SunFontManager의 loadFonts() 메서드를 직접 사용하여 FontManager의 chooseLocaleFonts() 메서드를 구현하는 방법을 살펴보겠습니다. 로드됨:

논리적 글꼴과 물리적 글꼴

여기서의 코드 디버깅을 통해 기본적으로 다른 환경에서의 글꼴 로딩 문제임을 확인했으니 리눅스 환경 디버깅 시 발견되는 논리적 글꼴 그리고 물리적 글꼴이란 무엇일까요?

물리적 글꼴

물리적 글꼴은 TrueType 또는 PostScript Type 1과 같은 글꼴 기술을 사용하여 문자 시퀀스를 글리프 시퀀스에 매핑하는 글리프 데이터와 테이블을 포함하는 실제 글꼴 라이브러리입니다. Java 플랫폼의 모든 구현은 트루타입 글꼴을 지원합니다. 다른 글꼴 기술에 대한 지원은 구현에 따라 다릅니다. 실제 글꼴은 Helvetica, Palatino, HonMincho 등의 글꼴 이름이나 기타 다양한 글꼴 이름을 사용할 수 있습니다. 일반적으로 각 실제 글꼴은 제한된 쓰기 시스템 세트(예: 라틴 문자만 또는 일본어 및 기본 라틴어만 지원)만 지원합니다. 사용 가능한 물리적 글꼴 세트는 구성에 따라 다릅니다. 특정 글꼴이 필요한 애플리케이션은 createFont 메서드를 사용하여 이러한 글꼴을 묶고 인스턴스화할 수 있습니다.

논리 글꼴

논리 글꼴은 모든 Java 런타임 환경(Serif, SansSerif, Monospaced, Dialog 및 DialogInput)에서 지원해야 하는 Java 플랫폼에서 정의한 5가지 글꼴 계열입니다. 이러한 논리적 글꼴은 실제 글꼴 라이브러리가 아닙니다. 또한 논리적 글꼴 이름을 물리적 글꼴에 매핑하는 것은 Java 런타임 환경입니다. 매핑은 구현에 따라 다르며 일반적으로 로케일에 따라 다르므로 제공되는 모양과 사양은 다양합니다. 일반적으로 광범위한 문자를 포괄하기 위해 각 논리적 글꼴 이름은 여러 물리적 글꼴에 매핑됩니다.

问题解决

debug的源码很多,但是此次问题的关键点就在这里了,其它debug内容就不贴了。
既然已经确认了本地(mac环境)是native的代码帮我们做了物理字体的封装,转换成了CFont进行渲染,而Linux环境的X11FontManager只是帮我们加载了物理字体和逻辑字体,但是却需要我们自己进行选择,那么解决问题的第一步就显而易见了:将Font的创建从物理字体改为逻辑字体

1 //  Serif、SansSerif、Monospaced、Dialog 和 DialogInput 随意选择
2 Font font = new Font("Serif", Font.PLAIN, 10);

改完以后执行代码,仍然是乱码!继续Debug,发现是Linux上逻辑字体Serif映射的物理字体没有中文字体和对应的特殊符号字体,这就很简单了,直接在Linux上安装中文字体(simsun.ttf),再安装特殊符号“ꐚꌒꑿꆺ”可显示的字体(mysi.ttf),将这两个字体也放到了jdk的fonts目录(JAVA_HOME/jre/lib/fonts)下。文章后面有Linux字体安装方法。

完成上面的改动之后,重启服务,再次执行成功显示!热烈庆祝~~~~

JVM逻辑字体映射配置

以上的改动已经可以解决中文和特殊字符乱码问题,但是我在Debug过程中发现在逻辑字体加载过程中,JVM会参考一个配置文件,代码在sun.awt.FontConfiguration中,这个配置类完成了逻辑字体和物理字体的映射,也指导了SunFontManager创建逻辑字体,而这个FontConfiguration读取的配置文件就是fontconfig.properties,这个配置文件目录是JAVA_HOME/jre/lib

查阅了一下资料,JVM字体配置文件的加载顺序如下:
JAVA_HOME/jre/lib/fontconfig.OS.Version.properties
JAVA_HOME/jre/lib/fontconfig.OS.Version.bfc
JAVA_HOME/jre/lib/fontconfig.OS.properties
JAVA_HOME/jre/lib/fontconfig.OS.bfc
JAVA_HOME/jre/lib/fontconfig.Version.properties
JAVA_HOME/jre/lib/fontconfig.Version.bfc
JAVA_HOME/jre/lib/fontconfig.properties
JAVA_HOME/jre/lib/fontconfig.bfc

OS是系统,例如:Linux、CentOs、RedHat等;Version是版本号

在这个配置文件中可以修改逻辑字体与物理字体的对应关系,也就是说可以手动的修改Serif、SansSerif、Monospaced、Dialog 和 DialogInput这五个逻辑字体在不同场景下所使用的真正物理字体。

举个栗子,下面的配置将serif.plain逻辑字体的中文使用simsun.ttf,拉丁文使用java自带字体:

# @(#)linux.fontconfig.SuSE.properties 1.2 03/10/17
#
# Copyright 2003 Sun Microsystems, Inc. All rights reserved.
#

# Version
version=1

# Component Font Mappings
serif.plain.chinese=-misc-simsun-medium-r-normal--*-%d-*-*-c-*-iso10646-1
serif.plain.latin-1=-b&h-lucidabright-medium-r-normal--*-%d-*-*-p-*-iso8859-1

# Search Sequences
sequence.allfonts=latin-1,chinese

# Exclusion Ranges

# Font File Names
filename.-misc-simsun-medium-r-normal--*-%d-*-*-c-*-iso10646-1=/usr/share/fonts/myfonts/simsun.ttf

Linux安装字体

  • Linux字体目录:/usr/share/fonts
  • 在fonts下面新建一个目录,例如:mkdir myfonts
  • 将需要安装的字体放到新建目录下面,例如:cp ~/test/simsun.ttf /usr/share/fonts/myfonts
  • 进入到myfonts目录:cd /usr/share/fonts/myfonts
  • 执行如下命令:
    • mkfontscale
    • mkfontdir
    • fc-cache -fv
  • 查看是否已经安装对应的字体:fc-list
  • fc-cache -fv 命令用来刷新linux的字体缓存,使其立刻生效

PS:以上所有操作基本都需要root权限

推荐学习:《linux视频教程

위 내용은 Java Linux 파일의 중국어 문자 왜곡 문제를 해결하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.