유닉스에서 현대 한글 11,172자 출력 방법 및 옛 한글 출력 방법, 기타 문제점.


[ 다음 글들 ] [ 이어서 글올리기(답하기) ] [ 자바 묻고 답하기 ]

글쓴이 :김덕태 1998년 5월 04일 18:17:42

In Reply to: JDK 1.1, 1.2의 한글 관련 인코딩과 기타 posted by 김덕태 on 1998년 4월 22일 16:13:34:

다음 화일들을 소스 코드내에 설명된 대로 설치해서 사용하시면 됩니다.
KSC5601 기호 및 한자는 KSC5601 폰트를 사용하고, 한글 음절은
Hanterm 조합 폰트를 사용하여 출력하게 됩니다.


수정된 내용은 다음과 같습니다.


1. 코드 변환 클래스의 몇가지 버그 교정


2. 유니코드 2.0의 첫가끝 코드를 사용하여 현대 한글 뿐만 아니라,
Hanterm 조합 폰트가 제공하는 옛 한글도 출력할 수 있으며,
초성, 종성, 종성, 초성 + 중성, 초성 + 종성, 중성 + 종성,
초성 + 중성 + 종성 등등 다양하게 조합되는 한글도
출력할 수 있습니다.


3. 한글 사용에 보다 적절하도록 "Monospaced" 폰트를 설정하여,
KSC 5601 문자의 넓이가 아스키 문자의 2배가 되도록 함으로써
자바로 만들어진 텍스트 에디터등을 제대로 사용할 수 있게 합니다.


문제점.
=======


1. 조합 폰트의 glyph 부족
=======================
한텀 조합 폰트로 일부 옛 한글을 출력할 수 있었으나,
유니코드내의 옛 한글 자모에 비하면 턱없이 부족합니다.


한텀 조합 폰트를 재배치하거나 이에 덧붙임으로써 누락된 한글 자모를
추가시킨 후, 다음 코드 변환 클래스를 약간만 수정하면 모든 옛한글 (약
50만자 가량)을 화면에 출력할 수 있습니다.


하지만, 옛한글까지 고려했을 때, 한텀 조합 폰트의 설계 (중복된 초성
glyph 10개씩, 중복 중성 glyph 3 ~ 4개씩, 중복된 종성 glyph 4개씩)가
여전히 충분히 유효한지는 잘 모르겠습니다.


옛한글 출력에 대해서는 개인적으로는 그다지 필요성을 느끼지는 못하지만,
컴퓨터가 정보 표현의 자유를 제한시키기보다는 보다 쉽게 정보를 표현,
저장, 전달할 수 있는 수단이 되어야 한다는 보다 큰 관점에서 본다면,
한텀 조합 폰트가 이와 같이 확장되고, 그 폰트 인코딩이 폭넓게 받아들여지는
표준이 되는 것이 바람직하다고 봅니다.


또한, 그래야만 그 코드 변환 클래스가 JDK에 내장되어 배포될 수 있고,
따라서, 일반 사용자가 코드 변환 클래스를 설치하는 번잡함을 피할 수가 있습니다.
(특히, 애플릿의 경우)


2. JDK 1.2beta3의 문자 출력 루틴의 문제점
===============================
코드 변환 클래스의 convert 메쏘드가 출력할 버퍼는
코드 변환 클래스를 사용하는 측에서 제공하여야 하며,
이때, 충분한 출력 버퍼의 크기를 잡아주는 데
사용되는 메쏘드가 getMaxBytesPerChar 메쏘드입니다.
이와같이 하면, JDK 1.1.6까지는 문제없이 동작하나,
JDK 1.2beta3에서는 다음과 같은 예외가 발생하여
한글 음절이 출력되지 않습니다.


java.lang.ArrayIndexOutOfBoundsException: 4
at CharToByteX11Johab.composeHangul(CharToByteX11Johab.java:331)
at CharToByteX11Johab.convert(CharToByteX11Johab.java:70)
at sun.awt.PlatformFont.makeConvertedMultiFontChars(PlatformFont.java:471)
at sun.awt.motif.X11Graphics.drawMFChars(Native Method)
at sun.awt.motif.X11Graphics.drawChars(X11Graphics.java:351)
......


원인은 makeConvertedMultiFontChars 메쏘드내에서
getMaxBytesPerChar 메쏘드를 사용하지 않고
무조건 출력 버퍼의 크기를 4 바이트로 잡아줌으로써
Hanterm 조합 폰트의 6 바이트 출력을 수용하지 못하기 때문인 것으로 보이며,
이는 조합형 폰트를 사용하는 데 상당히 심각한 문제입니다.


3. JDK 1.2beta3의 이미지 버퍼링 버그
=================================
폰트 프로퍼티 화일과 코드 변환 클래스를 설치해도,
AWT 컴포넌트 (특히, TextField, TextArea)들은 이에 따라 적절히 동작하지 않습니다.


그러나, drawString, drawChars 메쏘드를 사용하여 출력할 때는
이러한 문제가 생기지 않습니다.
따라서, AWT 컴포넌트와는 달리 JDK 1.1.x에서의 Swing 컴포넌트는 이들
화일의 설치에 따라 제대로 동작합니다.


JDK 1.2beta3에서는 버퍼링을 사용하여 출력된 한글이 화면에는
출력되지 않는 버그가 있습니다.


Swing 컴포넌트를 사용하는 경우, 일반적으로 Image 클래스를 사용하여
더블 버퍼링을 하면서 동작하게 되므로, JDK 1.2beta3에서의 Swing
컴포넌트에서는 한글이 제대로 출력되지 않습니다.
물론, 더블 버퍼링을 하지 않고 Swing 컴포넌트를 사용하면 됩니다만,
화면 반짝임 현상때문에 별로 좋은 방법이 되지 못합니다.



========== CharToByteX11Johab.java (코드 변환 클래스) ============


/*
* @(#)CharToByteX11Johab.java 1.0 98/05/03
*
* Purposes:
* 1. Enable displaying all 11,172 Modern hangul syllables with Hanterm
* johab fonts on Unix
* 2. Enable displaying some of Unicode 2.0 ancient hangul syllables
* with Hanterm johab fonts on Unix
* 3. Enable displaying all of Unicode 2.0 ancient hangul syllables with
* possible future extended Hanterm johab fonts on Unix
*
* Installation Instructions:
* 1. Install Hanterm Johab fonts and a proper font property file to Unix system.
* (Confer http://calab.kaist.ac.kr/~dtkim/java/ )
* 2. Make a directory "jdk1.x.x/classes/"
* 3. Compile this class into "jdk1.x.x/classes/"
*
* Author: Deogtae Kim , 98/05/03
*
* Based on: Hanterm source code adapted by Jungshik Shin
*/


import sun.io.CharToByteConverter;
import sun.io.MalformedInputException;
import sun.io.UnknownCharacterException;
import sun.io.ConversionBufferFullException;


public class CharToByteX11Johab extends CharToByteConverter
{
int state = START;


public static final int START = 0;
public static final int LEADING_CONSONANT = 1;
public static final int VOWEL = 2;


int l = 0x5f; // leading consonant
int v = 0; // vowel
int t = 0; // trailing consonant


/*
* This method indicates the charset name for this font.
*/
public String getCharacterEncoding()
{
return "X11Johab";
}


/*
* This method indicates the range this font covers.
*/
public boolean canConvert(char ch)
{
if ( 0xac00 <= ch && ch <= 0xd7a3 // Modern hangul syllables
|| 0x1100 <= ch && ch <= 0x1112 // modern leading consonants (19)
|| 0x1113 <= ch && ch <= 0x1159 // ancient leading consonants (71)
&& lconBase[ch-0x1100] != 0
|| ch == 0x115f // leading consonants filler
|| 0x1160 <= ch && ch <= 0x1175 // modern vowels (21)
|| 0x1176 <= ch && ch <= 0x11a2 // ancient vowels (45)
&& vowBase[ch-0x1160] != 0
|| 0x11a8 <= ch && ch <= 0x11c2 // modern trailing consonants (27)
|| 0x11c3 <= ch && ch <= 0x11f9 // ancient trailing consonants (55)
&& tconBase[ch-0x11a7] != 0 )
return true;
return false;
}


/*
* This method converts the unicode to this font index.
* Note: ConversionBufferFullException is not handled
* since this class is only used for character display.
*/
public int convert(char[] input, int inStart, int inEnd,
byte[] output, int outStart, int outEnd)
throws MalformedInputException,
UnknownCharacterException
{
charOff = inStart;
byteOff = outStart;


for (; charOff < inEnd; charOff++)
{
char ch = input[charOff];
if (0xac00 <= ch && ch <= 0xd7a3)
{
if ( state != START )
composeHangul(output);
ch -= 0xac00;
l = (ch / 588); // 588 = 21*28
v = ( ch / 28 ) % 21 + 1;
t = ch % 28;
composeHangul(output);
} else if (0x1100 <= ch && ch <= 0x115f)
{ // leading consonants (19 + 71 + 1)
if ( state != START )
composeHangul(output);
l = ch - 0x1100;
state = LEADING_CONSONANT;
} else if (1160 <= ch && ch <= 0x11a2)
{ // vowels (1 + 21 + 45)
v = ch - 0x1160;
state = VOWEL;
} else if (0x11a8 <= ch && ch <= 0x11f9)
{ // modern trailing consonants (27)
t = ch - 0x11a7;
composeHangul(output);
} else
{
throw new UnknownCharacterException();
}
}


if ( state != START )
composeHangul( output );


return byteOff - outStart;
}


public int flush(byte output[], int i, int j)
throws MalformedInputException
{
byteOff = 0;
int len = 0;
if ( state != START )
{
composeHangul( output );
len = byteOff;
}
byteOff = charOff = 0;
return len;
}


public void reset()
{
byteOff = charOff = 0;
state = START;
l = 0x5f;
v = t = 0;
}


public int getMaxBytesPerChar()
{
return 6;
}


// The base font index for leading consonants


static final short[] lconBase = {
// modern leading consonants (19)
1, 11, 21, 31, 41, 51,
61, 71, 81, 91, 101, 111,
121, 131, 141, 151, 161, 171,
181,


// ancient leading consonants (71 + reserved 5 + filler 1)
0, 0, 0, 0, 0, 0, // \u1113 ~ :
0, 0, 0, 0, 0, 201, // \u1119 ~ :
0, 221, 251, 0, 0, 0, // \u111f ~ :
0, 0, 281, 0, 0, 0, // \u1125 ~ :
191, 0, 211, 0, 231, 0, // \u112b ~ :
0, 241, 0, 0, 0, 291, // \u1131 ~ :
0, 0, 0, 0, 0, 0, // \u1137 ~ :
0, 0, 0, 261, 0, 0, // \u113d ~ :
0, 0, 0, 0, 0, 0, // \u1143 ~ :
0, 0, 0, 271, 0, 0, // \u1149 ~ :
0, 0, 0, 0, 0, 0, // \u114f ~ :
0, 0, 0, 0, 301, // \u1155 ~ :
0, 0, 0, 0, 0, // \u115a ~ : reserved
0, // \u115f : leading consonant filler
};


// The base font index for vowels


static final short[] vowBase = {
// modern vowels (filler + 21)
0,311,314,317,320,323, // (Fill), A, AE, YA, YAE, EO
326,329,332,335,339,343, // E, YEO, YE, O, WA, WAE
347,351,355,358,361,364, // OI, YO, U, WEO, WE, WI
367,370,374,378, // YU, EU, UI, I


// ancient vowels (45)
0, 0, 0, 0, 0, 0, // \u1176 ~ : A-O, A-U, YA-O, YA-YO, EO-O, EO-U
0, 0, 0, 0, 0, 0, // \u117c ~ : EO-EU, YEO-O, YEO-U, O-EO, O-E, O-YE
0, 0, 381, 384, 0, 0, // \u1182 ~ : O-O, O-U, YO-YA, YO-YAE, YO-YEO, YO-O
387, 0, 0, 0, 0, 0, // \u1188 ~ : YO-I, U-A, U-AE, U-EO-EU, U-YE, U-U
0, 0, 0, 390, 393, 0, // \u118e ~ : YU-A, YU-EO, YU-E, YU-YEO, YU-YE, YU-U
396, 0, 0, 0, 0, 0, // \u1194 ~ : YU-I, EU-U, EU-EU, YI-U, I-A, I-YA
0, 0, 0, 0, 399, 0, // \u119a ~ : I-O, I-U, I-EU, I-ARAEA, ARAEA, ARAEA-EO
0, 402, 0 // \u11a0 ~ : ARAEA-U, ARAEA-I,SSANGARAEA
};


// The base font index for trailing consonants


static final short[] tconBase = {
// modern trailing consonants (filler + 27)
0,
405, 409, 413, 417, 421,
425, 429, 433, 437, 441,
445, 459, 453, 457, 461,
465, 469, 473, 477, 481,
485, 489, 493, 497, 501,
505, 509,


// ancient trailing consonants (55)
0, 0, 0, 0, 0, 0, // \u11c3 ~ :
0, 0, 0, 0, 0, 0, // \u11c9 ~ :
0, 0, 0, 0, 0, 0, // \u11cf ~ :
0, 0, 0, 0, 513, 517, // \u11d5 ~ :
0, 0, 0, 0, 0, 0, // \u11db ~ :
0, 0, 0, 0, 0, 0, // \u11e1 ~ :
0, 0, 0, 0, 0, 0, // \u11e7 ~ :
0, 0, 0, 525, 0, 0, // \u11ed ~ :
0, 0, 0, 0, 0, 0, // \u11f3 ~ :
521 // \u11f9:
};


// The mapping from vowels to leading consonant type
// in absence of trailing consonant


static final short[] lconMap1 = {
0,0,0,0,0,0, // (Fill), A, AE, YA, YAE, EO
0,0,0,1,3,3, // E, YEO, YE, O, WA, WAE
3,1,2,4,4,4, // OI, YO, U, WEO, WE, WI
2,1,3,0, // YU, EU, UI, I


// ancient vowels (45)
3, 4, 3, 3, 3, 4, // \u1176 ~ : A-O, A-U, YA-O, YA-YO, EO-O, EO-U
4, 3, 4, 3, 3, 3, // \u117c ~ : EO-EU, YEO-O, YEO-U, O-EO, O-E, O-YE
1, 1, 3, 3, 3, 1, // \u1182 ~ : O-O, O-U, YO-YA, YO-YAE, YO-YEO, YO-O
3, 4, 4, 4, 4, 2, // \u1188 ~ : YO-I, U-A, U-AE, U-EO-EU, U-YE, U-U
3, 3, 3, 3, 3, 2, // \u118e ~ : YU-A, YU-EO, YU-E, YU-YEO, YU-YE, YU-U
4, 2, 2, 4, 0, 0, // \u1194 ~ : YU-I, EU-U, EU-EU, YI-U, I-A, I-YA
3, 4, 3, 0, 1, 3, // \u119a ~ : I-O, I-U, I-EU, I-ARAEA, ARAEA, ARAEA-EO
2, 3, 1 // \u11a0 ~ : ARAEA-U, ARAEA-I, SSANGARAEA
};


// The mapping from vowels to leading consonant type
// in presence of trailing consonant


static final short[] lconMap2 = {
5,5,5,5,5,5, // (Fill), A, AE, YA, YAE, EO
5,5,5,6,8,8, // E, YEO, YE, O, WA, WAE
8,6,7,9,9,9, // OI, YO, U, WEO, WE, WI
7,6,8,5, // YU, EU, UI, I


// ancient vowels (45)
8, 9, 8, 8, 8, 9, // \u1176 ~ : A-O, A-U, YA-O, YA-YO, EO-O, EO-U
9, 8, 9, 8, 8, 8, // \u117c ~ : EO-EU, YEO-O, YEO-U, O-EO, O-E, O-YE
6, 6, 8, 8, 8, 6, // \u1182 ~ : O-O, O-U, YO-YA, YO-YAE, YO-YEO, YO-O
8, 9, 9, 9, 9, 7, // \u1188 ~ : YO-I, U-A, U-AE, U-EO-EU, U-YE, U-U
8, 8, 8, 8, 8, 7, // \u118e ~ : YU-A, YU-EO, YU-E, YU-YEO, YU-YE, YU-U
9, 7, 7, 9, 5, 5, // \u1194 ~ : YU-I, EU-U, EU-EU, YI-U, I-A, I-YA
8, 9, 8, 5, 6, 8, // \u119a ~ : I-O, I-U, I-EU, I-ARAEA, ARAEA, ARAEA-EO
7, 8, 6 // \u11a0 ~ : ARAEA-U, ARAEA-I, SSANGARAEA
};


// vowel type ; 1 = o and its alikes, 0 = others
static final short[] vowType = {
0,0,0,0,0,0,
0,0,0,1,1,1,
1,1,0,0,0,0,
0,1,1,0,


// ancient vowels (45)
1, 0, 1, 1, 1, 0, // \u1176 ~ : A-O, A-U, YA-O, YA-YO, EO-O, EO-U
0, 1, 0, 1, 1, 1, // \u117c ~ : EO-EU, YEO-O, YEO-U, O-EO, O-E, O-YE
1, 1, 0, 0, 0, 0, // \u1182 ~ : O-O, O-U, YO-YA, YO-YAE, YO-YEO, YO-O
0, 0, 0, 0, 0, 0, // \u1188 ~ : YO-I, U-A, U-AE, U-EO-EU, U-YE, U-U
0, 0, 0, 0, 0, 0, // \u118e ~ : YU-A, YU-EO, YU-E, YU-YEO, YU-YE, YU-U
0, 0, 0, 0, 0, 0, // \u1194 ~ : YU-I, EU-U, EU-EU, YI-U, I-A, I-YA
0, 0, 0, 0, 0, 0, // \u119a ~ : I-O, I-U, I-EU, I-ARAEA, ARAEA, ARAEA-EO
0, 0, 0 // \u11a0 ~ : ARAEA-U, ARAEA-I, SSANGARAEA
};


// The mapping from trailing consonants to vowel type


static final int[] tconType = {
0, 1, 1, 1, 2, 1,
1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1,
1, 1, 1, 1,


// ancient trailing consonants (55)
1, 1, 1, 1, 1, 1, // \u11c3 ~ :
1, 1, 1, 1, 1, 1, // \u11c9 ~ :
1, 1, 1, 1, 1, 1, // \u11cf ~ :
1, 1, 1, 1, 1, 1, // \u11d5 ~ :
1, 1, 1, 1, 1, 1, // \u11db ~ :
1, 1, 1, 1, 1, 1, // \u11e1 ~ :
1, 1, 1, 1, 1, 1, // \u11e7 ~ :
1, 1, 1, 1, 1, 1, // \u11ed ~ :
1, 1, 1, 1, 1, 1, // \u11f3 ~ :
1 // \u11f9:
};


// The mapping from vowels to trailing consonant type


static final int[] tconMap = {
0, 0, 2, 0, 2, 1, // (Fill), A, AE, YA, YAE, EO
2, 1, 2, 3, 0, 0, // E, YEO, YE, O, WA, WAE
0, 3, 3, 1, 1, 1, // OI, YO, U, WEO, WE, WI
3, 3, 0, 1, // YU, EU, UI, I


// ancient vowels (45)
3, 3, 3, 3, 3, 3, // \u1176 ~ : A-O, A-U, YA-O, YA-YO, EO-O, EO-U
3, 3, 3, 1, 0, 0, // \u117c ~ : EO-EU, YEO-O, YEO-U, O-EO, O-E, O-YE
3, 3, 3, 1, 0, 3, // \u1182 ~ : O-O, O-U, YO-YA, YO-YAE, YO-YEO, YO-O
0, 0, 0, 0, 0, 3, // \u1188 ~ : YO-I, U-A, U-AE, U-EO-EU, U-YE, U-U
0, 1, 1, 1, 1, 3, // \u118e ~ : YU-A, YU-EO, YU-E, YU-YEO, YU-YE, YU-U
1, 3, 3, 3, 2, 2, // \u1194 ~ : YU-I, EU-U, EU-EU, YI-U, I-A, I-YA
3, 3, 3, 1, 3, 0, // \u119a ~ : I-O, I-U, I-EU, I-ARAEA, ARAEA, ARAEA-EO
3, 2, 3 // \u11a0 ~ : ARAEA-U, ARAEA-I, SSANGARAEA
};


void composeHangul(byte[] output)
{
int ind;



if ( lconBase[l] != 0 )
{ // non-filler and supported by Hanterm Johab fonts
ind = lconBase[l] + ( t > 0 ? lconMap2[v] : lconMap1[v] );
output[byteOff++] = (byte) (ind / 256);
output[byteOff++] = (byte) (ind % 256);
}


if ( vowBase[v] != 0 )
{ // non-filler and supported by Hanterm Johab fonts
ind = vowBase[v];
if ( vowType[v] == 1)
{ //'o' and alikes
// GIYEOK and KIEUK got special treatment
ind += ( (l == 0 || l == 15) ? 0 : 1)
+ (t > 0 ? 2 : 0 );
}
else
{
ind += tconType[t];
}


output[byteOff++] = (byte) (ind / 256);
output[byteOff++] = (byte) (ind % 256);
}


if ( tconBase[t] != 0 )
{ // non-filler and supported by Hanterm Johab fonts
ind = tconBase[t] + tconMap[v];
output[byteOff++] = (byte) (ind / 256);
output[byteOff++] = (byte) (ind % 256);
} else
{
output[byteOff++] = (byte) 0;
output[byteOff++] = (byte) 0;
}


state = START;
l = 0x5f;
v = t = 0;
}
}




다음 글들:



이어서 글올리기(답하기)

이름:
E-Mail:
제목:
내용:
관련 URL(선택):
URL 제목(선택):
관련 이미지 URL:


[ 다음 글들 ] [ 이어서 글올리기(답하기) ] [ 자바 묻고 답하기 ]