GNU Unifont 17.0.05 Pan-Unicode font with complete Unicode Plane 0 coverage and partial coverage of higher planes

unihangul-support.c
Go to the documentation of this file.
1/**
2 @file unihangul-support.c
3
4 @brief Functions for converting Hangul letters into syllables
5
6 This file contains functions for reading in Hangul letters
7 arranged in a Johab 6/3/1 pattern and composing syllables
8 with them. One function maps an iniital letter (choseong),
9 medial letter (jungseong), and final letter (jongseong)
10 into the Hangul Syllables Unicode block, U+AC00..U+D7A3.
11 Other functions allow formation of glyphs that include
12 the ancient Hangul letters that Hanterm supported. More
13 can be added if desired, with appropriate changes to
14 start positions and lengths defined in "hangul.h".
15
16 @author Paul Hardy
17
18 @copyright Copyright © 2023 Paul Hardy
19*/
20/*
21 LICENSE:
22
23 This program is free software: you can redistribute it and/or modify
24 it under the terms of the GNU General Public License as published by
25 the Free Software Foundation, either version 2 of the License, or
26 (at your option) any later version.
27
28 This program is distributed in the hope that it will be useful,
29 but WITHOUT ANY WARRANTY; without even the implied warranty of
30 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 GNU General Public License for more details.
32
33 You should have received a copy of the GNU General Public License
34 along with this program. If not, see <http://www.gnu.org/licenses/>.
35*/
36
37#include <stdio.h>
38#include "hangul.h"
39
40
41/**
42 @brief Read hangul-base.hex file into a unsigned char array.
43
44 Read a Hangul base .hex file with separate choseong, jungseong,
45 and jongseong glyphs for syllable formation. The order is:
46
47 - Empty glyph in 0x0000 position.
48 - Initial consonants (choseong).
49 - Medial vowels and dipthongs (jungseong).
50 - Final consonants (jongseong).
51 - Individual letter forms in isolation, not for syllable formation.
52
53 The letters are arranged with all variations for one letter
54 before continuing to the next letter. In the current
55 encoding, there are 6 variations of choseong, 3 of jungseong,
56 and 1 of jongseong per letter.
57
58 @param[in] Input file pointer; can be stdin.
59 @param[out] Array of bit patterns, with 32 8-bit values per letter.
60 @return The maximum code point value read in the file.
61*/
62 unsigned
63 hangul_read_base8 (FILE *infp, unsigned char base[][32]) {
64 unsigned codept;
65 unsigned max_codept;
66 int i, j;
67 char instring[MAXLINE];
68
69
70 max_codept = 0;
71
72 while (fgets (instring, MAXLINE, infp) != NULL) {
73 sscanf (instring, "%X", &codept);
74 codept -= PUA_START;
75 /* If code point is within range, add it */
76 if (codept < MAX_GLYPHS) {
77 /* Find the start of the glyph bitmap. */
78 for (i = 1; instring[i] != '\0' && instring[i] != ':'; i++);
79 if (instring[i] == ':') {
80 i++; /* Skip over ':' to get to start of bitmap. */
81 for (j = 0; j < 32; j++) {
82 sscanf (&instring[i], "%2hhX", &base[codept][j]);
83 i += 2;
84 }
85 if (codept > max_codept) max_codept = codept;
86 }
87 }
88 }
89
90 return max_codept;
91}
92
93
94/**
95 @brief Read hangul-base.hex file into a unsigned array.
96
97 Read a Hangul base .hex file with separate choseong, jungseong,
98 and jongseong glyphs for syllable formation. The order is:
99
100 - Empty glyph in 0x0000 position.
101 - Initial consonants (choseong).
102 - Medial vowels and dipthongs (jungseong).
103 - Final consonants (jongseong).
104 - Individual letter forms in isolation, not for syllable formation.
105
106 The letters are arranged with all variations for one letter
107 before continuing to the next letter. In the current
108 encoding, there are 6 variations of choseong, 3 of jungseong,
109 and 1 of jongseong per letter.
110
111 @param[in] Input file pointer; can be stdin.
112 @param[out] Array of bit patterns, with 16 16-bit values per letter.
113 @return The maximum code point value read in the file.
114*/
115 unsigned
116 hangul_read_base16 (FILE *infp, unsigned base[][16]) {
117 unsigned codept;
118 unsigned max_codept;
119 int i, j;
120 char instring[MAXLINE];
121
122
123 max_codept = 0;
124
125 while (fgets (instring, MAXLINE, infp) != NULL) {
126 sscanf (instring, "%X", &codept);
127 codept -= PUA_START;
128 /* If code point is within range, add it */
129 if (codept < MAX_GLYPHS) {
130 /* Find the start of the glyph bitmap. */
131 for (i = 1; instring[i] != '\0' && instring[i] != ':'; i++);
132 if (instring[i] == ':') {
133 i++; /* Skip over ':' to get to start of bitmap. */
134 for (j = 0; j < 16; j++) {
135 sscanf (&instring[i], "%4X", &base[codept][j]);
136 i += 4;
137 }
138 if (codept > max_codept) max_codept = codept;
139 }
140 }
141 }
142
143 return max_codept;
144}
145
146
147/**
148 @brief Decompose a Hangul Syllables code point into three letters.
149
150 Decompose a Hangul Syllables code point (U+AC00..U+D7A3) into:
151
152 - Choseong 0-19
153 - Jungseong 0-20
154 - Jongseong 0-27 or -1 if no jongseong
155
156 All letter values are set to -1 if the letters do not
157 form a syllable in the Hangul Syllables range. This function
158 only handles modern Hangul, because that is all that is in
159 the Hangul Syllables range.
160
161 @param[in] codept The Unicode code point to decode, from 0xAC00 to 0xD7A3.
162 @param[out] initial The 1st letter (choseong) in the syllable.
163 @param[out] initial The 2nd letter (jungseong) in the syllable.
164 @param[out] initial The 3rd letter (jongseong) in the syllable.
165*/
166 void
167 hangul_decompose (unsigned codept, int *initial, int *medial, int *final) {
168
169 if (codept < 0xAC00 || codept > 0xD7A3) {
170 *initial = *medial = *final = -1;
171 }
172 else {
173 codept -= 0xAC00;
174 *initial = codept / (28 * 21);
175 *medial = (codept / 28) % 21;
176 *final = codept % 28 - 1;
177 }
178
179 return;
180}
181
182
183/**
184 @brief Compose a Hangul syllable into a code point, or 0 if none exists.
185
186 This function takes three letters that can form a modern Hangul
187 syllable and returns the corresponding Unicode Hangul Syllables
188 code point in the range 0xAC00 to 0xD7A3.
189
190 If a three-letter combination includes one or more archaic letters,
191 it will not map into the Hangul Syllables range. In that case,
192 the returned code point will be 0 to indicate that no valid
193 Hangul Syllables code point exists.
194
195 @param[in] initial The first letter (choseong), 0 to 18.
196 @param[in] medial The second letter (jungseong), 0 to 20.
197 @param[in] final The third letter (jongseong), 0 to 26 or -1 if none.
198 @return The Unicode Hangul Syllables code point, 0xAC00 to 0xD7A3.
199*/
200 unsigned
201 hangul_compose (int initial, int medial, int final) {
202 unsigned codept;
203
204
205 if (initial >= 0 && initial <= 18 &&
206 medial >= 0 && medial <= 20 &&
207 final >= 0 && final <= 26) {
208
209 codept = 0xAC00;
210 codept += initial * 21 * 28;
211 codept += medial * 28;
212 codept += final + 1;
213 }
214 else {
215 codept = 0;
216 }
217
218 return codept;
219}
220
221
222/**
223 @brief Determine index values to the bitmaps for a syllable's components.
224
225 This function reads these input values for modern and ancient Hangul letters:
226
227 - Choseong number (0 to the number of modern and archaic choseong - 1.
228 - Jungseong number (0 to the number of modern and archaic jungseong - 1.
229 - Jongseong number (0 to the number of modern and archaic jongseong - 1, or -1 if none.
230
231 It then determines the variation of each letter given the combination with
232 the other two letters (or just choseong and jungseong if the jongseong value
233 is -1).
234
235 These variations are then converted into index locations within the
236 glyph array that was read in from the hangul-base.hex file. Those
237 index locations can then be used to form a composite syllable.
238
239 There is no restriction to only use the modern Hangul letters.
240
241 @param[in] choseong The 1st letter in the syllable.
242 @param[in] jungseong The 2nd letter in the syllable.
243 @param[in] jongseong The 3rd letter in the syllable, or -1 if none.
244 @param[out] cho_index Index location to the 1st letter variation from the hangul-base.hex file.
245 @param[out] jung_index Index location to the 2nd letter variation from the hangul-base.hex file.
246 @param[out] jong_index Index location to the 3rd letter variation from the hangul-base.hex file.
247*/
248 void
249 hangul_hex_indices (int choseong, int jungseong, int jongseong,
250 int *cho_index, int *jung_index, int *jong_index) {
251
252 int cho_variation, jung_variation, jong_variation; /* Letter variations */
253
254 void hangul_variations (int choseong, int jungseong, int jongseong,
255 int *cho_variation, int *jung_variation, int *jong_variation);
256
257
258 hangul_variations (choseong, jungseong, jongseong,
259 &cho_variation, &jung_variation, &jong_variation);
260
261 *cho_index = CHO_HEX + choseong * CHO_VARIATIONS + cho_variation;
262 *jung_index = JUNG_HEX + jungseong * JUNG_VARIATIONS + jung_variation;;
263 *jong_index = jongseong < 0 ? 0x0000 :
264 JONG_HEX + jongseong * JONG_VARIATIONS + jong_variation;
265
266 return;
267}
268
269
270/**
271 @brief Determine the variations of each letter in a Hangul syllable.
272
273 Given the three letters that will form a syllable, return the variation
274 of each letter used to form the composite glyph.
275
276 This function can determine variations for both modern and archaic
277 Hangul letters; it is not limited to only the letters combinations
278 that comprise the Unicode Hangul Syllables range.
279
280 This function reads these input values for modern and ancient Hangul letters:
281
282 - Choseong number (0 to the number of modern and archaic choseong - 1.
283 - Jungseong number (0 to the number of modern and archaic jungseong - 1.
284 - Jongseong number (0 to the number of modern and archaic jongseong - 1, or -1 if none.
285
286 It then determines the variation of each letter given the combination with
287 the other two letters (or just choseong and jungseong if the jongseong value
288 is -1).
289
290 @param[in] choseong The 1st letter in the syllable.
291 @param[in] jungseong The 2nd letter in the syllable.
292 @param[in] jongseong The 3rd letter in the syllable, or -1 if none.
293 @param[out] cho_var Variation of the 1st letter from the hangul-base.hex file.
294 @param[out] jung_var Variation of the 2nd letter from the hangul-base.hex file.
295 @param[out] jong_var Variation of the 3rd letter from the hangul-base.hex file.
296*/
297 void
298 hangul_variations (int choseong, int jungseong, int jongseong,
299 int *cho_var, int *jung_var, int *jong_var) {
300
301 int cho_variation (int choseong, int jungseong, int jongseong);
302 int jung_variation (int choseong, int jungseong, int jongseong);
303 int jong_variation (int choseong, int jungseong, int jongseong);
304
305 /*
306 Find the variation for each letter component.
307 */
308 *cho_var = cho_variation (choseong, jungseong, jongseong);
309 *jung_var = jung_variation (choseong, jungseong, jongseong);
310 *jong_var = jong_variation (choseong, jungseong, jongseong);
311
312
313 return;
314}
315
316
317/**
318 @brief Return the Johab 6/3/1 choseong variation for a syllable.
319
320 This function takes the two or three (if jongseong is included)
321 letters that comprise a syllable and determine the variation
322 of the initial consonant (choseong).
323
324 Each choseong has 6 variations:
325
326 Variation Occurrence
327 --------- ----------
328 0 Choseong with a vertical vowel such as "A".
329 1 Choseong with a horizontal vowel such as "O".
330 2 Choseong with a vertical and horizontal vowel such as "WA".
331 3 Same as variation 0, but with jongseong (final consonant).
332 4 Same as variation 1, but with jongseong (final consonant).
333 Also a horizontal vowel pointing down, such as U and YU.
334 5 Same as variation 2, but with jongseong (final consonant).
335 Also a horizontal vowel pointing down with vertical element,
336 such as WEO, WE, and WI.
337
338 In addition, if the vowel is horizontal and a downward-pointing stroke
339 as in the modern letters U, WEO, WE, WI, and YU, and in archaic
340 letters YU-YEO, YU-YE, YU-I, araea, and araea-i, then 3 is added
341 to the initial variation of 0 to 2, resulting in a choseong variation
342 of 3 to 5, respectively.
343
344 @param[in] choseong The 1st letter in the syllable.
345 @param[in] jungseong The 2nd letter in the syllable.
346 @param[in] jongseong The 3rd letter in the syllable.
347 @return The choseong variation, 0 to 5.
348*/
349 int
350 cho_variation (int choseong, int jungseong, int jongseong) {
351 int cho_variation; /* Return value */
352
353 /*
354 The Choseong cho_var is determined by the
355 21 modern + 50 ancient Jungseong, and whether
356 or not the syllable contains a final consonant
357 (Jongseong).
358 */
359 static int choseong_var [TOTAL_JUNG + 1] = {
360 /*
361 Modern Jungseong in positions 0..20.
362 */
363/* Location Variations Unicode Range Vowel # Vowel Names */
364/* -------- ---------- -------------- ------- ----------- */
365/* 0x2FB */ 0, 0, 0, // U+1161..U+1163-->[ 0.. 2] A, AE, YA
366/* 0x304 */ 0, 0, 0, // U+1164..U+1166-->[ 3.. 5] YAE, EO, E
367/* 0x30D */ 0, 0, // U+1167..U+1168-->[ 6.. 7] YEO, YE
368/* 0x313 */ 1, // U+1169 -->[ 8] O
369/* 0x316 */ 2, 2, 2, // U+116A..U+116C-->[ 9..11] WA, WAE, WE
370/* 0x31F */ 1, 4, // U+116D..U+116E-->[12..13] YO, U
371/* 0x325 */ 5, 5, 5, // U+116F..U+1171-->[14..16] WEO, WE, WI
372/* 0x32E */ 4, 1, // U+1172..U+1173-->[17..18] YU, EU
373/* 0x334 */ 2, // U+1174 -->[19] YI
374/* 0x337 */ 0, // U+1175 -->[20] I
375 /*
376 Ancient Jungseong in positions 21..70.
377 */
378/* Location Variations Unicode Range Vowel # Vowel Names */
379/* -------- ---------- -------------- ------- ----------- */
380/* 0x33A: */ 2, 5, 2, // U+1176..U+1178-->[21..23] A-O, A-U, YA-O
381/* 0x343: */ 2, 2, 5, // U+1179..U+117B-->[24..26] YA-YO, EO-O, EU-U
382/* 0x34C: */ 2, 2, 5, // U+117C..U+117E-->[27..29] EO-EU, YEO-O, YEO-U
383/* 0x355: */ 2, 5, 5, // U+117F..U+1181-->[30..32] O-EO, O-E, O-YE,
384/* 0x35E: */ 4, 4, 2, // U+1182..U+1184-->[33..35] O-O, O-U, YO-YA,
385/* 0x367: */ 2, 2, 5, // U+1185..U+1187-->[36..38] YO-YAE, YO-YEO, YO-O,
386/* 0x370: */ 2, 5, 5, // U+1188..U+118A-->[39..41] YO-I, U-A, U-AE,
387/* 0x379: */ 5, 5, 5, // U+118B..U+118D-->[42..44] U-EO-EU, U-YE, U-U,
388/* 0x382: */ 5, 5, 5, // U+118E..U+1190-->[45..47] YU-A, YU-EO, YU-E,
389/* 0x38B: */ 5, 5, 2, // U+1191..U+1193-->[48..50] YU-YEO, YU-YE, YU-U,
390/* 0x394: */ 5, 2, 2, // U+1194..U+1196-->[51..53] YU-I, EU-U, EU-EU,
391/* 0x39D: */ 2, 0, 0, // U+1197..U+1199-->[54..56] YI-U, I-A, I-YA,
392/* 0x3A6: */ 2, 5, 2, // U+119A..U+119C-->[57..59] I-O, I-U, I-EU,
393/* 0x3AF: */ 0, 1, 2, // U+119D..U+119F-->[60..62] I-ARAEA, ARAEA, ARAEA-EO,
394/* 0x3B8: */ 1, 2, 1, // U+11A0..U+11A2-->[63..65] ARAEA-U, ARAEA-I,SSANGARAEA,
395/* 0x3C1: */ 2, 5, 0, // U+11A3..U+11A5-->[66..68] A-EU, YA-U, YEO-YA,
396/* 0x3CA: */ 2, 2, // U+11A6..U+11A7-->[69..70] O-YA, O-YAE,
397#ifdef EXTENDED_HANGUL
398/* 0x3D0: */ 2, 4, 5, // U+D7B0..U+D7B2-->[71..73] O-YEO, O-O-I, YO-A,
399/* 0x3D9: */ 5, 2, 5, // U+D7B3..U+D7B5-->[74..76] YO-AE, YO-EO, U-YEO,
400/* 0x3E2: */ 5, 5, 4, // U+D7B6..U+D7B8-->[77..79] U-I-I, YU-AE, YU-O,
401/* 0x3EB: */ 5, 2, 5, // U+D7B9..U+D7BB-->[80..82] EU-A, EU-EO, EU-E,
402/* 0x3F4: */ 4, 2, 3, // U+D7BC..U+D7BE-->[83..85] EU-O, I-YA-O, I-YAE,
403/* 0x3FD: */ 3, 3, 2, // U+D7BF..U+D7C1-->[86..88] I-YEO, I-YE, I-O-I,
404/* 0x406: */ 2, 2, 0, // U+D7C2..U+D7C4-->[89..91] I-YO, I-YU, I-I,
405/* 0x40F: */ 2, 2, // U+D7C5..U+D7C6-->[92..93] ARAEA-A, ARAEA-E,
406/* 0x415: */ -1 // Mark end of list of vowels.
407#else
408/* 0x310: */ -1 // Mark end of list of vowels.
409#endif
410 };
411
412
413 if (jungseong < 0 || jungseong >= TOTAL_JUNG) {
414 cho_variation = -1;
415 }
416 else {
417 cho_variation = choseong_var [jungseong];
418 if (choseong >= 0 && jongseong >= 0 && cho_variation < 3)
419 cho_variation += 3;
420 }
421
422
423 return cho_variation;
424}
425
426
427/**
428 @brief Whether vowel has rightmost vertical stroke to the right.
429
430 @param[in] vowel Vowel number, from 0 to TOTAL_JUNG - 1.
431 @return 1 if this vowel's vertical stroke is wide on the right side; else 0.
432*/
433 int
434 is_wide_vowel (int vowel) {
435 int retval; /* Return value. */
436
437 static int wide_vowel [TOTAL_JUNG + 1] = {
438 /*
439 Modern Jungseong in positions 0..20.
440 */
441/* Location Variations Unicode Range Vowel # Vowel Names */
442/* -------- ---------- -------------- ------- ----------- */
443/* 0x2FB */ 0, 1, 0, // U+1161..U+1163-->[ 0.. 2] A, AE, YA
444/* 0x304 */ 1, 0, 1, // U+1164..U+1166-->[ 3.. 5] YAE, EO, E
445/* 0x30D */ 0, 1, // U+1167..U+1168-->[ 6.. 7] YEO, YE
446/* 0x313 */ 0, // U+1169 -->[ 8] O
447/* 0x316 */ 0, 1, 0, // U+116A..U+116C-->[ 9..11] WA, WAE, WE
448/* 0x31F */ 0, 0, // U+116D..U+116E-->[12..13] YO, U
449/* 0x325 */ 0, 1, 0, // U+116F..U+1171-->[14..16] WEO, WE, WI
450/* 0x32E */ 0, 0, // U+1172..U+1173-->[17..18] YU, EU
451/* 0x334 */ 0, // U+1174 -->[19] YI
452/* 0x337 */ 0, // U+1175 -->[20] I
453 /*
454 Ancient Jungseong in positions 21..70.
455 */
456/* Location Variations Unicode Range Vowel # Vowel Names */
457/* -------- ---------- -------------- ------- ----------- */
458/* 0x33A: */ 0, 0, 0, // U+1176..U+1178-->[21..23] A-O, A-U, YA-O
459/* 0x343: */ 0, 0, 0, // U+1179..U+117B-->[24..26] YA-YO, EO-O, EU-U
460/* 0x34C: */ 0, 0, 0, // U+117C..U+117E-->[27..29] EO-EU, YEO-O, YEO-U
461/* 0x355: */ 0, 1, 1, // U+117F..U+1181-->[30..32] O-EO, O-E, O-YE,
462/* 0x35E: */ 0, 0, 0, // U+1182..U+1184-->[33..35] O-O, O-U, YO-YA,
463/* 0x367: */ 1, 0, 0, // U+1185..U+1187-->[36..38] YO-YAE, YO-YEO, YO-O,
464/* 0x370: */ 0, 0, 1, // U+1188..U+118A-->[39..41] YO-I, U-A, U-AE,
465/* 0x379: */ 0, 1, 0, // U+118B..U+118D-->[42..44] U-EO-EU, U-YE, U-U,
466/* 0x382: */ 0, 0, 1, // U+118E..U+1190-->[45..47] YU-A, YU-EO, YU-E,
467/* 0x38B: */ 0, 1, 0, // U+1191..U+1193-->[48..50] YU-YEO, YU-YE, YU-U,
468/* 0x394: */ 0, 0, 0, // U+1194..U+1196-->[51..53] YU-I, EU-U, EU-EU,
469/* 0x39D: */ 0, 0, 0, // U+1197..U+1199-->[54..56] YI-U, I-A, I-YA,
470/* 0x3A6: */ 0, 0, 0, // U+119A..U+119C-->[57..59] I-O, I-U, I-EU,
471/* 0x3AF: */ 0, 0, 0, // U+119D..U+119F-->[60..62] I-ARAEA, ARAEA, ARAEA-EO,
472/* 0x3B8: */ 0, 0, 0, // U+11A0..U+11A2-->[63..65] ARAEA-U, ARAEA-I,SSANGARAEA,
473/* 0x3C1: */ 0, 0, 0, // U+11A3..U+11A5-->[66..68] A-EU, YA-U, YEO-YA,
474/* 0x3CA: */ 0, 1, // U+11A6..U+11A7-->[69..70] O-YA, O-YAE
475#ifdef EXTENDED_HANGUL
476/* 0x3D0: */ 0, 0, 0, // U+D7B0..U+D7B2-->[71..73] O-YEO, O-O-I, YO-A,
477/* 0x3D9: */ 1, 0, 0, // U+D7B3..U+D7B5-->[74..76] YO-AE, YO-EO, U-YEO,
478/* 0x3E2: */ 1, 1, 0, // U+D7B6..U+D7B8-->[77..79] U-I-I, YU-AE, YU-O,
479/* 0x3EB: */ 0, 0, 1, // U+D7B9..U+D7BB-->[80..82] EU-A, EU-EO, EU-E,
480/* 0x3F4: */ 0, 0, 1, // U+D7BC..U+D7BE-->[83..85] EU-O, I-YA-O, I-YAE,
481/* 0x3FD: */ 0, 1, 0, // U+D7BF..U+D7C1-->[86..88] I-YEO, I-YE, I-O-I,
482/* 0x406: */ 0, 0, 1, // U+D7C2..U+D7C4-->[89..91] I-YO, I-YU, I-I,
483/* 0x40F: */ 0, 1, // U+D7C5..U+D7C6-->[92..93] ARAEA-A, ARAEA-E,
484/* 0x415: */ -1 // Mark end of list of vowels.
485#else
486/* 0x310: */ -1 // Mark end of list of vowels.
487#endif
488 };
489
490
491 if (vowel >= 0 && vowel < TOTAL_JUNG) {
492 retval = wide_vowel [vowel];
493 }
494 else {
495 retval = 0;
496 }
497
498
499 return retval;
500}
501
502
503/**
504 @brief Return the Johab 6/3/1 jungseong variation.
505
506 This function takes the two or three (if jongseong is included)
507 letters that comprise a syllable and determine the variation
508 of the vowel (jungseong).
509
510 Each jungseong has 3 variations:
511
512 Variation Occurrence
513 --------- ----------
514 0 Jungseong with only chungseong (no jungseong).
515 1 Jungseong with chungseong and jungseong (except nieun).
516 2 Jungseong with chungseong and jungseong nieun.
517
518 @param[in] choseong The 1st letter in the syllable.
519 @param[in] jungseong The 2nd letter in the syllable.
520 @param[in] jongseong The 3rd letter in the syllable.
521 @return The jungseong variation, 0 to 2.
522*/
523 inline int
524 jung_variation (int choseong, int jungseong, int jongseong) {
525 int jung_variation; /* Return value */
526
527 if (jungseong < 0) {
528 jung_variation = -1;
529 }
530 else {
531 jung_variation = 0;
532 if (jongseong >= 0) {
533 if (jongseong == 3)
534 jung_variation = 2; /* Vowel for final Nieun. */
535 else
536 jung_variation = 1;
537 }
538 }
539
540
541 return jung_variation;
542}
543
544
545/**
546 @brief Return the Johab 6/3/1 jongseong variation.
547
548 There is only one jongseong variation, so this function
549 always returns 0. It is a placeholder function for
550 possible future adaptation to other johab encodings.
551
552 @param[in] choseong The 1st letter in the syllable.
553 @param[in] jungseong The 2nd letter in the syllable.
554 @param[in] jongseong The 3rd letter in the syllable.
555 @return The jongseong variation, always 0.
556*/
557 inline int
558 jong_variation (int choseong, int jungseong, int jongseong) {
559
560 return 0; /* There is only one Jongseong variation. */
561}
562
563
564/**
565 @brief Given letters in a Hangul syllable, return a glyph.
566
567 This function returns a glyph bitmap comprising up to three
568 Hangul letters that form a syllable. It reads the three
569 component letters (choseong, jungseong, and jungseong),
570 then calls a function that determines the appropriate
571 variation of each letter, returning the letter bitmap locations
572 in the glyph array. Then these letter bitmaps are combined
573 with a logical OR operation to produce a final bitmap,
574 which forms a 16 row by 16 column bitmap glyph.
575
576 @param[in] choseong The 1st letter in the composite glyph.
577 @param[in] jungseong The 2nd letter in the composite glyph.
578 @param[in] jongseong The 3rd letter in the composite glyph.
579 @param[in] hangul_base The glyphs read from the "hangul_base.hex" file.
580 @return syllable The composite syllable, as a 16 by 16 pixel bitmap.
581*/
582 void
583 hangul_syllable (int choseong, int jungseong, int jongseong,
584 unsigned char hangul_base[][32], unsigned char *syllable) {
585
586 int i; /* loop variable */
587 int cho_hex, jung_hex, jong_hex;
588 unsigned char glyph_byte;
589
590
591 hangul_hex_indices (choseong, jungseong, jongseong,
592 &cho_hex, &jung_hex, &jong_hex);
593
594 for (i = 0; i < 32; i++) {
595 glyph_byte = hangul_base [cho_hex][i];
596 glyph_byte |= hangul_base [jung_hex][i];
597 if (jong_hex >= 0) glyph_byte |= hangul_base [jong_hex][i];
598 syllable[i] = glyph_byte;
599 }
600
601 return;
602}
603
604
605/**
606 @brief See if two glyphs overlap.
607
608 @param[in] glyph1 The first glyph, as a 16-row bitmap.
609 @param[in] glyph2 The second glyph, as a 16-row bitmap.
610 @return 0 if no overlaps between glyphs, 1 otherwise.
611*/
612 int
613 glyph_overlap (unsigned *glyph1, unsigned *glyph2) {
614 int overlaps; /* Return value; 0 if no overlaps, -1 if overlaps. */
615 int i;
616
617 /* Check for overlaps between the two glyphs. */
618
619 i = 0;
620 do {
621 overlaps = (glyph1[i] & glyph2[i]) != 0;
622 i++;
623 } while (i < 16 && overlaps == 0);
624
625 return overlaps;
626}
627
628
629/**
630 @brief Combine two glyphs into one glyph.
631
632 @param[in] glyph1 The first glyph to overlap.
633 @param[in] glyph2 The second glyph to overlap.
634 @param[out] combined_glyph The returned combination glyph.
635*/
636 void
637 combine_glyphs (unsigned *glyph1, unsigned *glyph2,
638 unsigned *combined_glyph) {
639 int i;
640
641 for (i = 0; i < 16; i++)
642 combined_glyph [i] = glyph1 [i] | glyph2 [i];
643
644 return;
645}
646
647
648/**
649 @brief Print one glyph in Unifont hexdraw plain text style.
650
651 @param[in] fp The file pointer for output.
652 @param[in] codept The Unicode code point to print with the glyph.
653 @param[in] this_glyph The 16-row by 16-column glyph to print.
654*/
655 void
656 print_glyph_txt (FILE *fp, unsigned codept, unsigned *this_glyph) {
657 int i;
658 unsigned mask;
659
660
661 fprintf (fp, "%04X:", codept);
662
663 /* for each this_glyph row */
664 for (i = 0; i < 16; i++) {
665 mask = 0x8000;
666 fputc ('\t', fp);
667 while (mask != 0x0000) {
668 if (mask & this_glyph [i]) {
669 fputc ('#', fp);
670 }
671 else {
672 fputc ('-', fp);
673 }
674 mask >>= 1; /* shift to next bit in this_glyph row */
675 }
676 fputc ('\n', fp);
677 }
678 fputc ('\n', fp);
679
680 return;
681}
682
683
684/**
685 @brief Print one glyph in Unifont hexdraw hexadecimal string style.
686
687 @param[in] fp The file pointer for output.
688 @param[in] codept The Unicode code point to print with the glyph.
689 @param[in] this_glyph The 16-row by 16-column glyph to print.
690*/
691 void
692 print_glyph_hex (FILE *fp, unsigned codept, unsigned *this_glyph) {
693
694 int i;
695
696
697 fprintf (fp, "%04X:", codept);
698
699 /* for each this_glyph row */
700 for (i = 0; i < 16; i++) {
701 fprintf (fp, "%04X", this_glyph[i]);
702 }
703 fputc ('\n', fp);
704
705 return;
706}
707
708
709/**
710 @brief Convert Hangul Jamo choseong, jungseong, and jongseong into a glyph.
711
712 @param[in] glyph_table The collection of all jamo glyphs.
713 @param[in] jamo The Unicode code point, 0 or 0x1100..0x115F.
714 @param[out] jamo_glyph The output glyph, 16 columns in each of 16 rows.
715*/
716 void
717 one_jamo (unsigned glyph_table [MAX_GLYPHS][16],
718 unsigned jamo, unsigned *jamo_glyph) {
719
720 int i; /* Loop variable */
721 int glyph_index; /* Location of glyph in "hangul-base.hex" array */
722
723
724 /* If jamo is invalid range, use blank glyph, */
725 if (jamo >= 0x1100 && jamo <= 0x11FF) {
726 glyph_index = jamo - 0x1100 + JAMO_HEX;
727 }
728 else if (jamo >= 0xA960 && jamo <= 0xA97F) {
729 glyph_index = jamo - 0xA960 + JAMO_EXTA_HEX;
730 }
731 else if (jamo >= 0xD7B0 && jamo <= 0xD7FF) {
732 glyph_index = jamo - 0x1100 + JAMO_EXTB_HEX;
733 }
734 else {
735 glyph_index = 0;
736 }
737
738 for (i = 0; i < 16; i++) {
739 jamo_glyph [i] = glyph_table [glyph_index] [i];
740 }
741
742 return;
743}
744
745
746/**
747 @brief Convert Hangul Jamo choseong, jungseong, and jongseong into a glyph.
748
749 This function converts input Hangul choseong, jungseong, and jongseong
750 Unicode code triplets into a Hangul syllable. Any of those with an
751 out of range code point are assigned a blank glyph for combining.
752
753 This function performs the following steps:
754
755 1) Determine the sequence number of choseong, jungseong,
756 and jongseong, from 0 to the total number of choseong,
757 jungseong, or jongseong, respectively, minus one. The
758 sequence for each is as follows:
759
760 a) Choseong: Unicode code points of U+1100..U+115E
761 and then U+A960..U+A97C.
762
763 b) Jungseong: Unicode code points of U+1161..U+11A7
764 and then U+D7B0..U+D7C6.
765
766 c) Jongseong: Unicode code points of U+11A8..U+11FF
767 and then U+D7CB..U+D7FB.
768
769 2) From the choseong, jungseong, and jongseong sequence number,
770 determine the variation of choseong and jungseong (there is
771 only one jongseong variation, although it is shifted right
772 by one column for some vowels with a pair of long vertical
773 strokes on the right side).
774
775 3) Convert the variation numbers for the three syllable
776 components to index locations in the glyph array.
777
778 4) Combine the glyph array glyphs into a syllable.
779
780 @param[in] glyph_table The collection of all jamo glyphs.
781 @param[in] cho The choseong Unicode code point, 0 or 0x1100..0x115F.
782 @param[in] jung The jungseong Unicode code point, 0 or 0x1160..0x11A7.
783 @param[in] jong The jongseong Unicode code point, 0 or 0x11A8..0x11FF.
784 @param[out] combined_glyph The output glyph, 16 columns in each of 16 rows.
785*/
786 void
787 combined_jamo (unsigned glyph_table [MAX_GLYPHS][16],
788 unsigned cho, unsigned jung, unsigned jong,
789 unsigned *combined_glyph) {
790
791 int i; /* Loop variable. */
792 int cho_num, jung_num, jong_num;
793 int cho_group, jung_group, jong_group;
794 int cho_index, jung_index, jong_index;
795
796 unsigned tmp_glyph[16]; /* Hold shifted jongsung for wide vertical vowel. */
797
798 int cho_variation (int choseong, int jungseong, int jongseong);
799
800 void combine_glyphs (unsigned *glyph1, unsigned *glyph2,
801 unsigned *combined_glyph);
802
803
804 /* Choose a blank glyph for each syllalbe by default. */
805 cho_index = jung_index = jong_index = 0x000;
806
807 /*
808 Convert Unicode code points to jamo sequence number
809 of each letter, or -1 if letter is not in valid range.
810 */
811 if (cho >= 0x1100 && cho <= 0x115E)
812 cho_num = cho - CHO_UNICODE_START;
813 else if (cho >= CHO_EXTA_UNICODE_START &&
814 cho < (CHO_EXTA_UNICODE_START + NCHO_EXTA))
815 cho_num = cho - CHO_EXTA_UNICODE_START + NCHO_MODERN + NJONG_ANCIENT;
816 else
817 cho_num = -1;
818
819 if (jung >= 0x1161 && jung <= 0x11A7)
820 jung_num = jung - JUNG_UNICODE_START;
821 else if (jung >= JUNG_EXTB_UNICODE_START &&
822 jung < (JUNG_EXTB_UNICODE_START + NJUNG_EXTB))
823 jung_num = jung - JUNG_EXTB_UNICODE_START + NJUNG_MODERN + NJUNG_ANCIENT;
824 else
825 jung_num = -1;
826
827 if (jong >= 0x11A8 && jong <= 0x11FF)
828 jong_num = jong - JONG_UNICODE_START;
829 else if (jong >= JONG_EXTB_UNICODE_START &&
830 jong < (JONG_EXTB_UNICODE_START + NJONG_EXTB))
831 jong_num = jong - JONG_EXTB_UNICODE_START + NJONG_MODERN + NJONG_ANCIENT;
832 else
833 jong_num = -1;
834
835 /*
836 Choose initial consonant (choseong) variation based upon
837 the vowel (jungseong) if both are specified.
838 */
839 if (cho_num < 0) {
840 cho_index = cho_group = 0; /* Use blank glyph for choseong. */
841 }
842 else {
843 if (jung_num < 0 && jong_num < 0) { /* Choseong is by itself. */
844 cho_group = 0;
845 if (cho_index < (NCHO_MODERN + NCHO_ANCIENT))
846 cho_index = cho_num + JAMO_HEX;
847 else /* Choseong is in Hangul Jamo Extended-A range. */
848 cho_index = cho_num - (NCHO_MODERN + NCHO_ANCIENT)
849 + JAMO_EXTA_HEX;
850 }
851 else {
852 if (jung_num >= 0) { /* Valid jungseong with choseong. */
853 cho_group = cho_variation (cho_num, jung_num, jong_num);
854 }
855 else { /* Invalid vowel; see if final consonant is valid. */
856 /*
857 If initial consonant and final consonant are specified,
858 set cho_group to 4, which is the group tha would apply
859 to a horizontal-only vowel such as Hangul "O", so the
860 consonant appears full-width.
861 */
862 cho_group = 0;
863 if (jong_num >= 0) {
864 cho_group = 4;
865 }
866 }
867 cho_index = CHO_HEX + CHO_VARIATIONS * cho_num +
868 cho_group;
869 } /* Choseong combined with jungseong and/or jongseong. */
870 } /* Valid choseong. */
871
872 /*
873 Choose vowel (jungseong) variation based upon the choseong
874 and jungseong.
875 */
876 jung_index = jung_group = 0; /* Use blank glyph for jungseong. */
877
878 if (jung_num >= 0) {
879 if (cho_num < 0 && jong_num < 0) { /* Jungseong is by itself. */
880 jung_group = 0;
881 jung_index = jung_num + JUNG_UNICODE_START;
882 }
883 else {
884 if (jong_num >= 0) { /* If there is a final consonant. */
885 if (jong_num == 3) /* Nieun; choose variation 3. */
886 jung_group = 2;
887 else
888 jung_group = 1;
889 } /* Valid jongseong. */
890 /* If valid choseong but no jongseong, choose jungseong variation 0. */
891 else if (cho_num >= 0)
892 jung_group = 0;
893 }
894 jung_index = JUNG_HEX + JUNG_VARIATIONS * jung_num + jung_group;
895 }
896
897 /*
898 Choose final consonant (jongseong) based upon whether choseong
899 and/or jungseong are present.
900 */
901 if (jong_num < 0) {
902 jong_index = jong_group = 0; /* Use blank glyph for jongseong. */
903 }
904 else { /* Valid jongseong. */
905 if (cho_num < 0 && jung_num < 0) { /* Jongseong is by itself. */
906 jong_group = 0;
907 jong_index = jung_num + 0x4A8;
908 }
909 else { /* There is only one jongseong variation if combined. */
910 jong_group = 0;
911 jong_index = JONG_HEX + JONG_VARIATIONS * jong_num +
912 jong_group;
913 }
914 }
915
916 /*
917 Now that we know the index locations for choseong, jungseong, and
918 jongseong glyphs, combine them into one glyph.
919 */
920 combine_glyphs (glyph_table [cho_index], glyph_table [jung_index],
921 combined_glyph);
922
923 if (jong_index > 0) {
924 /*
925 If the vowel has a vertical stroke that is one column
926 away from the right border, shift this jongseung right
927 by one column to line up with the rightmost vertical
928 stroke in the vowel.
929 */
930 if (is_wide_vowel (jung_num)) {
931 for (i = 0; i < 16; i++) {
932 tmp_glyph [i] = glyph_table [jong_index] [i] >> 1;
933 }
934 combine_glyphs (combined_glyph, tmp_glyph,
935 combined_glyph);
936 }
937 else {
938 combine_glyphs (combined_glyph, glyph_table [jong_index],
939 combined_glyph);
940 }
941 }
942
943 return;
944}
945
hangul.h
Define constants and function prototypes for using Hangul glyphs.
NJONG_EXTB
#define NJONG_EXTB
Hangul Extended-B jongseong.
Definition: hangul.h:81
NCHO_EXTA
#define NCHO_EXTA
Hangul Extended-A choseong.
Definition: hangul.h:71
CHO_VARIATIONS
#define CHO_VARIATIONS
6 choseong variations
Definition: hangul.h:88
JONG_VARIATIONS
#define JONG_VARIATIONS
1 jongseong variation
Definition: hangul.h:90
NJONG_MODERN
#define NJONG_MODERN
28 modern Hangul Jamo jongseong
Definition: hangul.h:79
JAMO_EXTB_HEX
#define JAMO_EXTB_HEX
Start of U+D7B0..U+D7FF glyphs.
Definition: hangul.h:140
CHO_UNICODE_START
#define CHO_UNICODE_START
Modern Hangul choseong start.
Definition: hangul.h:50
JAMO_EXTA_HEX
#define JAMO_EXTA_HEX
Start of U+A960..U+A97F glyphs.
Definition: hangul.h:136
JUNG_EXTB_UNICODE_START
#define JUNG_EXTB_UNICODE_START
Hangul Extended-B jungseong start.
Definition: hangul.h:57
JUNG_HEX
#define JUNG_HEX
Location of first jungseong (will be 0x2FB)
Definition: hangul.h:108
NCHO_ANCIENT
#define NCHO_ANCIENT
ancient Hangul Jamo choseong
Definition: hangul.h:70
MAXLINE
#define MAXLINE
Length of maximum file input line.
Definition: hangul.h:33
CHO_EXTA_UNICODE_START
#define CHO_EXTA_UNICODE_START
Hangul Extended-A choseong start.
Definition: hangul.h:52
NCHO_MODERN
#define NCHO_MODERN
19 modern Hangul Jamo choseong
Definition: hangul.h:69
JAMO_HEX
#define JAMO_HEX
Start of U+1100..U+11FF glyphs.
Definition: hangul.h:132
JONG_UNICODE_START
#define JONG_UNICODE_START
Modern Hangul jongseong start.
Definition: hangul.h:60
NJUNG_MODERN
#define NJUNG_MODERN
21 modern Hangul Jamo jungseong
Definition: hangul.h:74
JUNG_UNICODE_START
#define JUNG_UNICODE_START
Modern Hangul jungseong start.
Definition: hangul.h:55
JUNG_VARIATIONS
#define JUNG_VARIATIONS
3 jungseong variations
Definition: hangul.h:89
NJONG_ANCIENT
#define NJONG_ANCIENT
ancient Hangul Jamo jongseong
Definition: hangul.h:80
NJUNG_ANCIENT
#define NJUNG_ANCIENT
ancient Hangul Jamo jungseong
Definition: hangul.h:75
CHO_HEX
#define CHO_HEX
Location of first choseong (location 0x0000 is a blank glyph)
Definition: hangul.h:96
JONG_EXTB_UNICODE_START
#define JONG_EXTB_UNICODE_START
Hangul Extended-B jongseong start.
Definition: hangul.h:62
NJUNG_EXTB
#define NJUNG_EXTB
Hangul Extended-B jungseong.
Definition: hangul.h:76
JONG_HEX
#define JONG_HEX
Location of first jongseong (will be 0x421)
Definition: hangul.h:120
MAX_GLYPHS
#define MAX_GLYPHS
An OpenType font has at most 65536 glyphs.
Definition: hex2otf.c:85
print_glyph_hex
void print_glyph_hex(FILE *fp, unsigned codept, unsigned *this_glyph)
Print one glyph in Unifont hexdraw hexadecimal string style.
Definition: unihangul-support.c:692
one_jamo
void one_jamo(unsigned glyph_table[MAX_GLYPHS][16], unsigned jamo, unsigned *jamo_glyph)
Convert Hangul Jamo choseong, jungseong, and jongseong into a glyph.
Definition: unihangul-support.c:717
combined_jamo
void combined_jamo(unsigned glyph_table[MAX_GLYPHS][16], unsigned cho, unsigned jung, unsigned jong, unsigned *combined_glyph)
Convert Hangul Jamo choseong, jungseong, and jongseong into a glyph.
Definition: unihangul-support.c:787
print_glyph_txt
void print_glyph_txt(FILE *fp, unsigned codept, unsigned *this_glyph)
Print one glyph in Unifont hexdraw plain text style.
Definition: unihangul-support.c:656
hangul_read_base8
unsigned hangul_read_base8(FILE *infp, unsigned char base[][32])
Read hangul-base.hex file into a unsigned char array.
Definition: unihangul-support.c:63
is_wide_vowel
int is_wide_vowel(int vowel)
Whether vowel has rightmost vertical stroke to the right.
Definition: unihangul-support.c:434
hangul_hex_indices
void hangul_hex_indices(int choseong, int jungseong, int jongseong, int *cho_index, int *jung_index, int *jong_index)
Determine index values to the bitmaps for a syllable's components.
Definition: unihangul-support.c:249
hangul_decompose
void hangul_decompose(unsigned codept, int *initial, int *medial, int *final)
Decompose a Hangul Syllables code point into three letters.
Definition: unihangul-support.c:167
glyph_overlap
int glyph_overlap(unsigned *glyph1, unsigned *glyph2)
See if two glyphs overlap.
Definition: unihangul-support.c:613
hangul_variations
void hangul_variations(int choseong, int jungseong, int jongseong, int *cho_var, int *jung_var, int *jong_var)
Determine the variations of each letter in a Hangul syllable.
Definition: unihangul-support.c:298
combine_glyphs
void combine_glyphs(unsigned *glyph1, unsigned *glyph2, unsigned *combined_glyph)
Combine two glyphs into one glyph.
Definition: unihangul-support.c:637
jong_variation
int jong_variation(int choseong, int jungseong, int jongseong)
Return the Johab 6/3/1 jongseong variation.
Definition: unihangul-support.c:558
cho_variation
int cho_variation(int choseong, int jungseong, int jongseong)
Return the Johab 6/3/1 choseong variation for a syllable.
Definition: unihangul-support.c:350
jung_variation
int jung_variation(int choseong, int jungseong, int jongseong)
Return the Johab 6/3/1 jungseong variation.
Definition: unihangul-support.c:524
hangul_syllable
void hangul_syllable(int choseong, int jungseong, int jongseong, unsigned char hangul_base[][32], unsigned char *syllable)
Given letters in a Hangul syllable, return a glyph.
Definition: unihangul-support.c:583
hangul_compose
unsigned hangul_compose(int initial, int medial, int final)
Compose a Hangul syllable into a code point, or 0 if none exists.
Definition: unihangul-support.c:201
hangul_read_base16
unsigned hangul_read_base16(FILE *infp, unsigned base[][16])
Read hangul-base.hex file into a unsigned array.
Definition: unihangul-support.c:116