tegaki-tools-0.3.1/0000755000175000017500000000000011352066723013774 5ustar mathieumathieutegaki-tools-0.3.1/AUTHORS0000644000175000017500000000005711342122364015037 0ustar mathieumathieuMathieu Blondel tegaki-tools-0.3.1/src/0000755000175000017500000000000011352066723014563 5ustar mathieumathieutegaki-tools-0.3.1/src/tegaki-stats0000755000175000017500000001651111352064314017107 0ustar mathieumathieu#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (C) 2009 The Tegaki project contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # Contributors to this file: # - Mathieu Blondel import sys import os from optparse import OptionParser from tegaki.charcol import CharacterCollection from tegakitools.charcol import * VERSION = '0.3.1' class TegakiStatsError(Exception): pass class TegakiStats(object): """ Show various statistics about a character collection. """ def __init__(self, options, args): self._directories = options.directories self._charcols = options.charcols self._databases = options.databases self._tomoe = options.tomoe self._kuchibue = options.kuchibue self._include = options.include self._exclude = options.exclude self._max_samples = options.max_samples self._verbosity_level = options.verbosity_level def run(self): charcol = get_aggregated_charcol( ((TYPE_CHARCOL, self._charcols), (TYPE_CHARCOL_DB, self._databases), (TYPE_DIRECTORY, self._directories), (TYPE_TOMOE, self._tomoe), (TYPE_KUCHIBUE, self._kuchibue))) charcol.include_characters_from_files(self._include) charcol.exclude_characters_from_files(self._exclude) # max samples if self._max_samples: charcol.remove_samples(keep_at_most=self._max_samples) if charcol.get_total_n_characters() == 0: raise TegakiStatsError, "No character collection provided " + \ "or character collections are empty!" print "Number of sets: %d" % charcol.get_n_sets() samp_by_class = self._get_samples_by_class(charcol) # the number of sets and the number of different characters (classes) # are the same if sets are used to group characters by class print "Number of different characters: ", len(samp_by_class) print "Total number of samples: ", charcol.get_total_n_characters() print "Total number of strokes: ", charcol.get_total_n_strokes() n_samples = samp_by_class.values() avg = float(sum(n_samples)) / len(n_samples) print "Average number of samples per character/class: %0.2f" % avg if self._verbosity_level >= 2: print "\nNumber of samples for each character:" for utf8, n_chars in samp_by_class.items(): print "%s: %d" % (utf8, n_chars) print "\n" classes_by_sc = self._get_classes_by_stroke_count(charcol) n_classes = [len(classes_by_sc[k]) for k in classes_by_sc.keys()] avg = float(sum(n_classes)) / len(n_classes) print "Average number of chars/classes per stroke count: %0.2f" % avg if self._verbosity_level >= 1: print "\nCharacters found for each stroke count:" for sc in sorted(classes_by_sc.keys()): print "%d: %s" % (sc, ", ".join(classes_by_sc[sc])) print "\n" sc_by_class = self._get_stroke_counts_by_class(charcol) n_sc = [len(sc_by_class[k]) for k in sc_by_class.keys()] avg = float(sum(n_sc)) / len(n_sc) print "Average number of stroke counts per char/class: %0.2f" % avg if self._verbosity_level >= 2: print "\nDifferent stroke counts for each character:" for utf8, stroke_counts in sc_by_class.items(): stroke_counts = [str(i) for i in sorted(stroke_counts)] print "%s: %s" % (utf8, ", ".join(stroke_counts)) print "\n" def _get_samples_by_class(self, charcol): d = {} for set_name in charcol.get_set_list(): for row in charcol.get_character_rows(set_name): utf8 = row['utf8'].encode("utf8") d[utf8] = d.get(utf8, 0) + 1 return d def _get_classes_by_stroke_count(self, charcol): d = {} for set_name in charcol.get_set_list(): for row in charcol.get_character_rows(set_name): n_strokes = row['n_strokes'] utf8 = row['utf8'].encode("utf8") d[n_strokes] = d.get(n_strokes, []) if not utf8 in d[n_strokes]: d[n_strokes].append(utf8) return d def _get_stroke_counts_by_class(self, charcol): d = {} for set_name in charcol.get_set_list(): for row in charcol.get_character_rows(set_name): n_strokes = row['n_strokes'] utf8 = row['utf8'].encode("utf8") d[utf8] = d.get(utf8, []) if not n_strokes in d[utf8]: d[utf8].append(n_strokes) return d parser = OptionParser(usage="usage: %prog [options]", version="%prog " + VERSION) parser.add_option("-d", "--directory", action="append", type="string", dest="directories", default=[], help="Directory containing individual XML character files") parser.add_option("-c", "--charcol", action="append", type="string", dest="charcols", default=[], help="character collection XML files") parser.add_option("-b", "--db", action="append", type="string", dest="databases", default=[], help="character collection XML files") parser.add_option("-t", "--tomoe-dict", action="append", type="string", dest="tomoe", default=[], help="Tomoe XML dictionary files") parser.add_option("-k", "--kuchibue", action="append", type="string", dest="kuchibue", default=[], help="Kuchibue unipen database") parser.add_option("-i", "--include", action="append", type="string", dest="include", default=[], help="File containing characters to include") parser.add_option("-e", "--exclude", action="append", type="string", dest="exclude", default=[], help="File containing characters to exclude") parser.add_option("-m", "--max-samples", type="int", dest="max_samples", help="Maximum number of samples per character") parser.add_option("-v", "--verbosity-level", type="int", dest="verbosity_level", default=0, help="verbosity level between 0 and 2") (options, args) = parser.parse_args() try: TegakiStats(options, args).run() except TegakiStatsError, e: sys.stderr.write(str(e) + "\n\n") parser.print_help() sys.exit(1) tegaki-tools-0.3.1/src/tegaki-convert0000755000175000017500000001037611352064314017434 0ustar mathieumathieu#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (C) 2009 The Tegaki project contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # Contributors to this file: # - Mathieu Blondel import sys import os from optparse import OptionParser from tegaki.charcol import CharacterCollection from tegakitools.charcol import * VERSION = '0.3.1' class TegakiConvertError(Exception): pass class TegakiConvert(object): def __init__(self, options, args): self._directories = options.directories self._charcols = options.charcols self._databases = options.databases self._tomoe = options.tomoe self._kuchibue = options.kuchibue self._include = options.include self._exclude = options.exclude self._max_samples = options.max_samples if len(args) > 1: raise TegakiConvertError, "tegaki-convert needs only 1 argument" elif len(args) == 1: self._output_path = args[0] else: self._output_path = None def run(self): charcol = get_aggregated_charcol( ((TYPE_CHARCOL, self._charcols), (TYPE_CHARCOL_DB, self._databases), (TYPE_DIRECTORY, self._directories), (TYPE_TOMOE, self._tomoe), (TYPE_KUCHIBUE, self._kuchibue)), self._output_path) charcol.include_characters_from_files(self._include) charcol.exclude_characters_from_files(self._exclude) # max samples if self._max_samples: charcol.remove_samples(keep_at_most=self._max_samples) # output if not self._output_path: # outputs to stdout if not output path specified print charcol.to_xml() else: charcol.save(self._output_path) parser = OptionParser(usage="usage: %prog [options] [output-path]", version="%prog " + VERSION) parser.add_option("-d", "--directory", action="append", type="string", dest="directories", default=[], help="Directory containing individual XML character files") parser.add_option("-c", "--charcol", action="append", type="string", dest="charcols", default=[], help="character collection XML files") parser.add_option("-b", "--db", action="append", type="string", dest="databases", default=[], help="character collection XML files") parser.add_option("-t", "--tomoe-dict", action="append", type="string", dest="tomoe", default=[], help="Tomoe XML dictionary files") parser.add_option("-k", "--kuchibue", action="append", type="string", dest="kuchibue", default=[], help="Kuchibue unipen database") parser.add_option("-i", "--include", action="append", type="string", dest="include", default=[], help="File containing characters to include") parser.add_option("-e", "--exclude", action="append", type="string", dest="exclude", default=[], help="File containing characters to exclude") parser.add_option("-m", "--max-samples", type="int", dest="max_samples", help="Maximum number of samples per character") (options, args) = parser.parse_args() try: TegakiConvert(options, args).run() except TegakiConvertError, e: sys.stderr.write(str(e) + "\n\n") parser.print_help() sys.exit(1) tegaki-tools-0.3.1/src/tegaki-bootstrap0000755000175000017500000005504011342122364017765 0ustar mathieumathieu#!/usr/bin/python # -*- coding: utf-8 -*- # Copyright (C) 2009 The Tegaki project contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # Contributors to this file: # - Christoph Burgmer, cburgmer ÂT ira DÔT uka DÔT de (main author) # - Mathieu Blondel """ Tries to bootstrap a character collection using similar collections and knowledge about the characters shape data. Basically all characters whose components have data, can be interpolated by scaling and shifting the components data and merging them together. Example: 黴 is made up from the component structure ⿲彳⿳山一黑攵 or graphically  山 彳一攵  黑 If we have handwriting data of the five components, we can easily integrate that into the character in question. To bootstrap a Traditional Chinese collection run: $ tegaki-bootstrap --domain=BIG5 --locale=T --max-samples=1 \ handwriting-zh_TW.xml -d ~/xml/ \ -t tegaki-zinnia-simplified-chinese/handwriting-zh_CN.xml \ -t tegaki-zinnia-japanese/handwriting-ja.xml TODO: - Use bounding box when merging of components. For example above 彳 probably has a bounding box of witdth=0.5, which only needs to be scaled by 3/5, and 一 has a bounding box of height=0.2, which allows to scale the upper and lower components less aggressivly. - Map collection sources to a character locale, so we can exclude data that does not fit to the target locale. Furthermore instead of doing exact transformations for source characters from the wrong locale, try using component data. - Try similar characters if no exact character can be found? - Offer easy way to provide additional variations, e.g. stroke order """ import sys import locale import random random.seed(12345) # provide deterministic results from optparse import OptionParser from tegaki.character import CharacterCollection, Writing, Character from tegakitools.charcol import * try: from cjklib.characterlookup import CharacterLookup from cjklib.exception import UnsupportedError except ImportError: print "Please install cjklib (http://code.google.com/p/cjklib)" sys.exit(1) VERSION = '0.3' class TegakiBootstrapError(Exception): pass class TegakiBootstrap(object): # xrate, yrate, dx, dy COMPONENT_TRANSFORMATION = { u'⿰': [(0.5, 1, 0, 0), (0.5, 1, 0.5, 0)], u'⿱': [(1, 0.5, 0, 0), (1, 0.5, 0, 0.5)], #u'⿴': [(1, 1, 0, 0), (0.5, 0.5, 0.25, 0.25)], u'⿵': [(1, 1, 0, 0), (0.5, 0.75, 0.25, 0.25)], u'⿶': [(1, 1, 0, 0), (0.5, 0.75, 0.25, 0)], #u'⿷': [(1, 1, 0, 0), (0.75, 0.5, 0.25, 0.25)], u'⿸': [(1, 1, 0, 0), (0.75, 0.75, 0.25, 0.25)], u'⿹': [(1, 1, 0, 0), (0.75, 0.75, 0, 0.25)], u'⿺': [(1, 1, 0, 0), (0.75, 0.75, 0.25, 0)], u'⿲': [(0.33, 1, 0, 0), (0.33, 1, 0.33, 0), (0.33, 1, 0.66, 0)], u'⿳': [(1, 0.33, 0, 0), (1, 0.33, 0, 0.33), (1, 0.33, 0, 0.66)], } RADICALS_NON_VISUAL_EQUIVALENCE = set([u'⺄', u'⺆', u'⺇', u'⺈', u'⺊', u'⺌', u'⺍', u'⺎', u'⺑', u'⺗', u'⺜', u'⺥', u'⺧', u'⺪', u'⺫', u'⺮', u'⺳', u'⺴', u'⺶', u'⺷', u'⺻', u'⺼', u'⻏', u'⻕']) """ Radical forms that have a equivalent character form with no visual resemblance. """ MIN_COMPONENT_PRODUCTIVITY = 2 """ Min productivity when reporting out-domain components that could help boost the in-domain set. """ def __init__(self, options, args): self._directories = options.directories self._charcols = options.charcols self._tomoe = options.tomoe self._kuchibue = options.kuchibue self._include = options.include self._exclude = options.exclude self._max_samples = options.max_samples assert self._max_samples self._locale = options.locale self._character_domain = options.character_domain self._no_exact_transformation = options.no_exact_transformation self._quiet = options.quiet try: self._output_path = args[0] except: self._output_path = None self._cjk = CharacterLookup(self._locale, self._character_domain) def _get_charcol(self): _charcol = get_aggregated_charcol(((TYPE_CHARCOL, self._charcols), (TYPE_DIRECTORY, self._directories), (TYPE_TOMOE, self._tomoe), (TYPE_KUCHIBUE, self._kuchibue))) _charcol.include_characters_from_files(self._include) _charcol.exclude_characters_from_files(self._exclude) # max samples _charcol.remove_samples(keep_at_most=self._max_samples) return _charcol def run(self): # do the bootstrapping to_charcol = self.bootstrap() # max samples #to_charcol.remove_samples(keep_at_most=self._max_samples) # output if not self._output_path: # outputs to stdout if no output path specified print to_charcol.to_xml() else: gzip = False; bz2 = False if self._output_path.endswith(".gz"): gzip = True if self._output_path.endswith(".bz2"): bz2 = True to_charcol.write(self._output_path, gzip=gzip, bz2=bz2) def bootstrap(self): n_chars = 0 n_exact_transformations = 0 char_n_exact_transformations = 0 n_decomposition_transformations = 0 char_n_decomposition_transformations = 0 char_n_missing_transformations = 0 char_n_underrepresented = 0 to_charcol = CharacterCollection() missing_char_dict = {} missing_single_characters = [] # iterate through all characters of the target character set for target_char in self._cjk.getDomainCharacterIterator(): #for target_char in iter([u'亄', u'乿', u'仜', u'伳']): # DEBUG n_chars += 1 if n_chars % 100 == 0: sys.stdout.write('.') sys.stdout.flush() char_set = target_char.encode('utf8') source_character_lookup = self._get_source_character_lookup() exact_transformations = 0 if (target_char in source_character_lookup and not self._no_exact_transformation): char_n_exact_transformations += 1 to_charcol.add_set(char_set) source_chars = source_character_lookup[target_char] for character in source_chars[:self._max_samples]: exact_transformations += 1 to_charcol.append_character(char_set, character) n_exact_transformations += exact_transformations n_total_transformation = exact_transformations # fill up with decomposition transformations? need_n_chars = self._max_samples - exact_transformations decomposition_transformations = 0 if need_n_chars > 0: writing_objects, missing_chars \ = self.get_writings_from_decomposition(target_char, force_decomposition=True) if writing_objects: char_n_decomposition_transformations += 1 writing_objects = writing_objects[:need_n_chars] for writing in writing_objects: decomposition_transformations += 1 character = Character() character.set_writing(writing) character.set_unicode(target_char) to_charcol.append_character(char_set, character) n_total_transformation += decomposition_transformations if n_total_transformation == 0: if missing_chars: # list components that can help us build this transform. for missing in missing_chars: if missing not in missing_char_dict: missing_char_dict[missing] = [] missing_char_dict[missing].append(target_char) else: missing_single_characters.append(target_char) n_decomposition_transformations += decomposition_transformations # if no direct transformation exists we have no data at all if n_total_transformation == 0: char_n_missing_transformations += 1 elif n_total_transformation < self._max_samples: # we have data, just not enough char_n_underrepresented += 1 sys.stdout.write('\n') if not self._quiet: _, default_encoding = locale.getdefaultlocale() total = n_exact_transformations + n_decomposition_transformations print 'Total characters: %d' % n_chars print 'Total transformation (instances): %d' % total print 'Characters with exact transformations: %d (%d%%)' \ % (char_n_exact_transformations, 100 * char_n_exact_transformations / n_chars) print 'Total exact transformations: %d (%d%%)' \ % (n_exact_transformations, 100 * n_exact_transformations / total) print 'Average exact transformations: %f' \ % (1. * n_exact_transformations / n_chars) print 'Characters with decomposition transformations: %d (%d%%)' \ % (char_n_decomposition_transformations, 100 * char_n_decomposition_transformations / n_chars) print 'Total decomposition transformations: %d (%d%%)' \ % (n_decomposition_transformations, 100 * n_decomposition_transformations / total) print 'Average decomposition transformations: %f' \ % (1. * n_decomposition_transformations / n_chars) print 'Characters missing transformations: %d (%d%%)' \ % (char_n_missing_transformations, 100 * char_n_missing_transformations / n_chars) if self._max_samples > 1: print 'Characters with less than %d instances: %d (%d%%)' \ % (self._max_samples, char_n_underrepresented, 100 * char_n_underrepresented / n_chars) # missing single characters # Extend by those with components, that have a component with low # productivity. in_domain_components = set( self._cjk.filterDomainCharacters(missing_char_dict.keys())) low_productivity_component_chars = [] for component, chars in missing_char_dict.items(): if component not in in_domain_components \ and len(chars) < self.MIN_COMPONENT_PRODUCTIVITY: low_productivity_component_chars.extend(chars) del missing_char_dict[component] missing_single_characters.extend(low_productivity_component_chars) print 'Missing single characters:', print ''.join(missing_single_characters).encode(default_encoding) # remove characters that we already placed in "single" _missing_single_characters = set(missing_single_characters) for component, chars in missing_char_dict.items(): missing_char_dict[component] = list( set(chars) - _missing_single_characters) if not missing_char_dict[component]: del missing_char_dict[component] # missing components missingComponents = sorted(missing_char_dict.items(), key=lambda (x,y): len(y)) missingComponents.reverse() in_domain_component_list = [(component, chars) \ for component, chars in missingComponents \ if component in in_domain_components] # only show "out-domain" components if they have productivity > 1 out_domain_component_list = [(component, chars) \ for component, chars in missingComponents \ if component not in in_domain_components and len(chars) > 1] print 'Missing components: %d' % (len(in_domain_component_list) \ + len(out_domain_component_list)) print 'Missing in-domain components:', print ', '.join(['%s (%s)' % (component, ''.join(chars)) \ for component, chars in in_domain_component_list])\ .encode(default_encoding) print 'Missing out-domain components:', print ', '.join(['%s (%s)' % (component, ''.join(chars)) \ for component, chars in out_domain_component_list])\ .encode(default_encoding) return to_charcol def _get_source_character_lookup(self): if not hasattr(self, '_source_character_lookup'): self._source_character_lookup = {} charcol = self._get_charcol() if charcol.get_total_n_characters() == 0: raise TegakiBootstrapError("Empty input collection provided") for character in charcol.get_all_characters(): char = character.get_utf8().decode('utf8') if char not in self._source_character_lookup: self._source_character_lookup[char] = [] self._source_character_lookup[char].append(character) return self._source_character_lookup def get_writings_from_decomposition(self, char, force_decomposition=False): writing_objects = [] source_char_lookup = self._get_source_character_lookup() exact_transformations = 0 if (not force_decomposition and char in source_char_lookup): writing_objects.extend([character.get_writing() \ for character in source_char_lookup[char]]) if (CharacterLookup.isRadicalChar(char) and char not in self.RADICALS_NON_VISUAL_EQUIVALENCE): try: equivChar = self._cjk.getRadicalFormEquivalentCharacter(char) if equivChar in source_char_lookup: writing_objects.extend([character.get_writing() for character in source_char_lookup[equivChar]]) except UnsupportedError: pass # add decompositions, limit to upper bound max_samples missing_chars = [] if len(writing_objects) < self._max_samples: decompositions = self._cjk.getDecompositionEntries(char) for decomposition in decompositions: writing_objs, _, missing = self._get_writing_from_entry( decomposition) if not writing_objs: missing_chars.extend(missing) writing_objects.extend(writing_objs) if len(writing_objects) >= self._max_samples: break writing_objects = writing_objects[:self._max_samples] return writing_objects, missing_chars def _get_writing_from_entry(self, decomposition, index=0): """Goes through a decomposition""" if type(decomposition[index]) != type(()): # IDS operator character = decomposition[index] writing_objects_list = [] missing_chars = [] if CharacterLookup.isBinaryIDSOperator(character): # check for IDS operators we can't make any order # assumption about if character in [u'⿴', u'⿻', u'⿷']: return [], index, [] else: # Get stroke order for both components for _ in range(0, 2): writing_objs, index, missing \ = self._get_writing_from_entry(decomposition, index+1) if not writing_objs: missing_chars.extend(missing) #return [], index writing_objects_list.append(writing_objs) elif CharacterLookup.isTrinaryIDSOperator(character): # Get stroke order for three components for _ in range(0, 3): writing_objs, index, missing = self._get_writing_from_entry( decomposition, index+1) if not writing_objs: missing_chars.extend(missing) #return [], index writing_objects_list.append(writing_objs) else: assert False, 'not an IDS character' # merge writing_objects = [] if not missing_chars: compound_writings = TegakiBootstrap.cross(*writing_objects_list) # shuffle to provide more variation random.shuffle(compound_writings) compound_writings = compound_writings[:self._max_samples] for writing_objs in compound_writings: writing = self.merge_writing_objects(character, writing_objs) writing_objects.append(writing) return writing_objects, index, missing_chars else: # no IDS operator but character char, _ = decomposition[index] # if the character is unknown or there is none raise if char == u'?': return [], index, [] else: # recursion writing_objs, missing_chars \ = self.get_writings_from_decomposition(char) if not writing_objs and not missing_chars: if (CharacterLookup.isRadicalChar(char) and char not in self.RADICALS_NON_VISUAL_EQUIVALENCE): try: char = self._cjk.getRadicalFormEquivalentCharacter( char) except UnsupportedError: pass missing_chars = [char] return writing_objs, index, missing_chars assert False @classmethod def merge_writing_objects(cls, ids_char, writing_objects): if ids_char not in cls.COMPONENT_TRANSFORMATION: raise ValueError("Not supported") # [u'⿴', u'⿻', u'⿷'] assert (CharacterLookup.isBinaryIDSOperator(ids_char) \ and len(writing_objects) == 2) \ or (CharacterLookup.isTrinaryIDSOperator(ids_char) \ and len(writing_objects) == 3) assert len(cls.COMPONENT_TRANSFORMATION[ids_char]) \ == len(writing_objects) transformations = cls.COMPONENT_TRANSFORMATION[ids_char] # reverse transformations where inner part is written first if ids_char in [u'⿺', u'⿶']: writing_objects.reverse() transformations = transformations[:] transformations.reverse() resultingWriting = Writing() for idx, transformation in enumerate(transformations): xrate, yrate, dx, dy = transformation obj = writing_objects[idx].copy() obj.resize(xrate, yrate) obj.move_rel(dx * obj.get_width(), dy * obj.get_height()) obj.resize(resultingWriting.get_width() / obj.get_width(), resultingWriting.get_height() / obj.get_height()) for s in obj.get_strokes(True): resultingWriting.append_stroke(s) return resultingWriting @staticmethod def cross(*args): ans = [[]] for arg in args: ans = [x+[y] for x in ans for y in arg] return ans parser = OptionParser(usage="usage: %prog [options] [output-path]", version="%prog " + VERSION) parser.add_option("-d", "--directory", action="append", type="string", dest="directories", default=[], help="Directory containing individual XML character files") parser.add_option("-c", "--charcol", action="append", type="string", dest="charcols", default=[], help="character collection XML files") parser.add_option("-t", "--tomoe-dict", action="append", type="string", dest="tomoe", default=[], help="Tomoe XML dictionary files") parser.add_option("-k", "--kuchibue", action="append", type="string", dest="kuchibue", default=[], help="Kuchibue unipen database") parser.add_option("-i", "--include", action="append", type="string", dest="include", default=[], help="File containing characters to include") parser.add_option("-e", "--exclude", action="append", type="string", dest="exclude", default=[], help="File containing characters to exclude") parser.add_option("-m", "--max-samples", type="int", dest="max_samples", default=1, help="Maximum number of samples per character") parser.add_option("-l", "--locale", type="string", dest="locale", default='T', help="Character locale of target characters") parser.add_option("--domain", type="string", dest="character_domain", default='Unicode', help="Character domain of target characters") parser.add_option("-x", "--no-exact", dest="no_exact_transformation", action="store_true", help="Don't use exact transformations" \ + ", use only decompositions") parser.add_option("-q", "--quiet", dest="quiet", action="store_true", help="Don't print any statistics") (options, args) = parser.parse_args() try: TegakiBootstrap(options, args).run() except TegakiBootstrapError, e: sys.stderr.write(str(e) + "\n\n") parser.print_help() sys.exit(1) tegaki-tools-0.3.1/src/tegaki-render0000755000175000017500000002704611342122364017234 0ustar mathieumathieu#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (C) 2009 The Tegaki project contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # Contributors to this file: # - Mathieu Blondel VERSION = '0.3' import sys from optparse import OptionParser, OptionGroup from tegaki.character import Character from tegakigtk.renderers import * try: from tegakigifenc import GifEncoder FORMATS = ["gif"] except ImportError: FORMATS = [] FORMATS += ["png", "svg", "pdf"] class TegakiRenderError(Exception): pass class TegakiRender(object): def __init__(self, options, args): char = Character() char.read(args[0]) self._writing = char.get_writing() self._output = args[1] for o in options.__dict__.keys(): setattr(self, "_" + o, getattr(options, o)) if not options.width and not options.height: self._width, self._height = self._get_default_size() elif not options.width: self._width = self._height else: self._height = self._width def _preprocessing(self): if self._normalize: self._writing.normalize() if self._center: self._writing.normalize_position() if self._smooth: self._writing.smooth() def _draw_init(self, renderer): renderer.set_stroke_width(self._stroke_width) renderer.set_draw_circles(self._circles) renderer.draw_background() if not self._steps: if self._axis: renderer.draw_axis() renderer.set_draw_annotations(self._annot) def _get_default_size(self): if self._cm: return [20, 20] elif self._inch: return [8, 8] else: return [400, 400] def _get_size(self): if self._cm: return cm_to_pt(self._width, self._height) elif self._inch: return inch_to_pt(self._width, self._height) else: return [self._width, self._height] def _get_stroke_groups(self): if self._steps_groups: try: return [int(n) for n in self._steps_groups.split(",")] except ValueError: raise TegakiRenderError, \ "--steps-groups must be a comma separated list " " of group stroke numbers, e.g. 1,1,3,1,4,2,2" else: return None def _gen_png(self): if self._steps: png_renderer = WritingStepsImageRenderer(self._writing, height=self._get_size()[1], stroke_groups=self._get_stroke_groups(), start=self._steps_start, length=self._steps_length, n_chars_per_row=self._steps_n_chars_per_row) self._draw_init(png_renderer) png_renderer.draw_writing_steps() else: png_renderer = WritingImageRenderer(self._writing, *self._get_size()) self._draw_init(png_renderer) png_renderer.draw_writing() png_renderer.write_to_png(self._output) def _gen_svg(self): if self._steps: svg_renderer = WritingStepsSVGRenderer(self._writing, self._output, height=self._get_size()[1], stroke_groups=self._get_stroke_groups(), start=self._steps_start, length=self._steps_length, n_chars_per_row=self._steps_n_chars_per_row) self._draw_init(svg_renderer) svg_renderer.draw_writing_steps() else: svg_renderer = WritingSVGRenderer(self._writing, self._output, *self._get_size()) self._draw_init(svg_renderer) svg_renderer.draw_writing() def _gen_pdf(self): if self._steps: pdf_renderer = WritingStepsPDFRenderer(self._writing, self._output, height=self._get_size()[1], stroke_groups=self._get_stroke_groups(), start=self._steps_start, length=self._steps_length, n_chars_per_row=self._steps_n_chars_per_row) self._draw_init(pdf_renderer) pdf_renderer.draw_writing_steps() else: pdf_renderer = WritingSVGRenderer(self._writing, self._output, *self._get_size()) self._draw_init(pdf_renderer) pdf_renderer.draw_writing() def _get_default_frame_duration(self): if self._stroke_by_stroke: return 500 else: return 100 def _gen_animated_gif(self): w, h = self._get_size() enc = GifEncoder() rend = WritingImageRenderer(self._writing, w, h) if self._stroke_by_stroke: def _write_frame(): buf = str(rend.get_data()) if self._frame_duration: delay_ms = self._frame_duration else: delay_ms = self._get_default_frame_duration() enc.add_image(0, 0, w, h, delay_ms, buf, rend.get_stride()) else: def _write_frame(x, y, width, height, delay_ms): if self._frame_duration: delay_ms = self._frame_duration elif not delay_ms: delay_ms = self._get_default_frame_duration() buf = str(rend.get_area_data(x, y, width, height)) assert(len(buf) == width * height * 4) enc.add_image(x, y, width, height, delay_ms, buf, width*4) self._draw_init(rend) rend.draw_writing() # set_palette_for_image(img_data, width, height, # number of bytes per line, alpha, num colors) enc.set_palette_for_image(str(rend.get_data()), w, h, rend.get_stride(), True, 255) enc.open(self._output, w, h, True, self._loop) # set the entire image as first frame for the first 2000 milliseconds enc.add_image(0, 0, w, h, 2000, str(rend.get_data()), rend.get_stride()) self._draw_init(rend) # set a blank drawing area as second frame enc.add_image(0, 0, w, h, 0, str(rend.get_data()), rend.get_stride()) if self._stroke_by_stroke: rend.set_stroke_added_callback(_write_frame) else: rend.set_area_changed_callback(_write_frame) rend.draw_writing() enc.close() def run(self): self._preprocessing() if self._output.endswith("png"): self._gen_png() elif self._output.endswith("svg"): self._gen_svg() elif self._output.endswith("pdf"): self._gen_pdf() elif self._output.endswith("gif") and "gif" in FORMATS: self._gen_animated_gif() else: raise TegakiRenderError, "Output format not supported!" usage = "usage: %prog [options] input.xml " + "output.(%s)" % "|".join(FORMATS) parser = OptionParser(usage=usage, version="%prog " + VERSION) group = OptionGroup(parser, "Size options") group.add_option("", "--width", type="int", dest="width", help="output image width") group.add_option("", "--height", type="int", dest="height", help="output image height") group.add_option("", "--cm", action="store_true", dest="cm", default=False, help="width and height are defined in centimeters") group.add_option("", "--inch", action="store_true", dest="inch", default=False, help="width and height are defined in inches") parser.add_option_group(group) ##### group = OptionGroup(parser, "Preprocessing options") group.add_option("", "--without-smoothing", action="store_false", dest="smooth", default=True, help="don't smooth strokes") group.add_option("", "--without-normalizing", action="store_false", dest="normalize", default=True, help="don't normalize character") group.add_option("", "--without-centering", action="store_false", dest="center", default=True, help="don't center character") parser.add_option_group(group) ##### group = OptionGroup(parser, "Drawing options") group.add_option("", "--without-axis", action="store_false", dest="axis", default=True, help="don't draw axis") group.add_option("", "--without-annot", action="store_false", dest="annot", default=True, help="don't draw stroke number annotations") group.add_option("", "--without-circles", action="store_false", dest="circles", default=True, help="don't draw circles") group.add_option("", "--stroke-width", type="int", dest="stroke_width", default=16, help="stroke_width") parser.add_option_group(group) ##### group = OptionGroup(parser, "Step-by-step options") group.add_option("", "--steps", action="store_true", dest="steps", default=False, help="draw the character step-by-step") group.add_option("", "--steps-start", type="int", dest="steps_start", default=0, help="step start index (starts at 0)") group.add_option("", "--steps-length", type="int", dest="steps_length", help="number of steps") group.add_option("", "--steps-groups", type="string", dest="steps_groups", help="comma-separated list of group stroke numbers") group.add_option("", "--steps-n-chars-per-row", type="int", dest="steps_n_chars_per_row", help="number of characters to display per row") parser.add_option_group(group) ##### group = OptionGroup(parser, "GIF options") group.add_option("", "--loop", action="store_true", dest="loop", default=False, help="Make the GIF loops") group.add_option("", "--stroke-by-stroke", action="store_true", dest="stroke_by_stroke", default=False, help="display entire strokes in one frame") group.add_option("", "--frame-duration", type="int", dest="frame_duration", help="frame duration in milliseconds") parser.add_option_group(group) (options, args) = parser.parse_args() try: if len(args) < 2: raise TegakiRenderError, "Needs an input and an output file!" TegakiRender(options, args).run() except TegakiRenderError, e: sys.stderr.write(str(e) + "\n\n") parser.print_help() sys.exit(1) tegaki-tools-0.3.1/src/tegaki-build0000755000175000017500000001306611352064314017052 0ustar mathieumathieu#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (C) 2009 The Tegaki project contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # Contributors to this file: # - Mathieu Blondel import sys import os from optparse import OptionParser from tegaki.charcol import CharacterCollection from tegaki.trainer import Trainer, TrainerError from tegakitools.charcol import * VERSION = '0.3.1' class TegakiBuildError(Exception): pass class TegakiBuild(object): def __init__(self, options, args): self._directories = options.directories self._charcols = options.charcols self._databases = options.databases self._tomoe = options.tomoe self._kuchibue = options.kuchibue self._include = options.include self._exclude = options.exclude self._max_samples = options.max_samples self._list = options.list if not self._list: self._trainer = args[0] self._meta = args[1] def run(self): if self._list: self._list_trainers() else: self._train() def _list_trainers(self): avail_trainers = Trainer.get_available_trainers() print "\n".join(["- " + key for key in avail_trainers.keys()]) def _train(self): charcol = CharacterCollection() # read meta file try: meta = Trainer.read_meta_file(self._meta) except IOError, e: raise TegakiBuildError, str(e) charcol = get_aggregated_charcol( ((TYPE_CHARCOL, self._charcols), (TYPE_CHARCOL_DB, self._databases), (TYPE_DIRECTORY, self._directories), (TYPE_TOMOE, self._tomoe), (TYPE_KUCHIBUE, self._kuchibue))) charcol.include_characters_from_files(self._include) charcol.exclude_characters_from_files(self._exclude) # max samples if self._max_samples: charcol.remove_samples(keep_at_most=self._max_samples) if charcol.get_total_n_characters() == 0: raise TegakiBuildError, "No character samples to train!" trainer = self._get_trainer() path = self._meta.replace(".meta", ".model") if not path.endswith(".model"): path += ".model" trainer.train(charcol, meta, path) print "Training done!" def _get_trainer(self): avail_trainers = Trainer.get_available_trainers() if not self._trainer in avail_trainers: err = "Not an available trainer!\n" err += "Available ones include: %s" % \ ", ".join(avail_trainers.keys()) raise TegakiBuildError, err return avail_trainers[self._trainer]() usage = """usage: %prog [options] trainer meta-file trainer a trainer available on the system meta-file path to a model .meta file""" parser = OptionParser(usage=usage, version="%prog " + VERSION, description="Train a model") parser.add_option("-d", "--directory", action="append", type="string", dest="directories", default=[], help="directory containing individual XML character files") parser.add_option("-c", "--charcol", action="append", type="string", dest="charcols", default=[], help="character collection XML files") parser.add_option("-b", "--db", action="append", type="string", dest="databases", default=[], help="character collection XML files") parser.add_option("-t", "--tomoe-dict", action="append", type="string", dest="tomoe", default=[], help="Tomoe XML dictionary files") parser.add_option("-k", "--kuchibue", action="append", type="string", dest="kuchibue", default=[], help="Kuchibue unipen database") parser.add_option("-l", "--list", action="store_true",dest="list", default=False, help="List available trainers") parser.add_option("-i", "--include", action="append", type="string", dest="include", default=[], help="File containing characters to include") parser.add_option("-e", "--exclude", action="append", type="string", dest="exclude", default=[], help="File containing characters to exclude") parser.add_option("-m", "--max-samples", type="int", dest="max_samples", help="Maximum number of samples per character") (options, args) = parser.parse_args() try: if not options.list and len(args) < 2: raise TegakiBuildError, "Needs a trainer and meta-file!" TegakiBuild(options, args).run() except TegakiBuildError, e: sys.stderr.write(str(e) + "\n\n") parser.print_help() sys.exit(1) tegaki-tools-0.3.1/src/tegakitools/0000755000175000017500000000000011352066723017110 5ustar mathieumathieutegaki-tools-0.3.1/src/tegakitools/charcol.py0000644000175000017500000000640611342122364021074 0ustar mathieumathieu#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (C) 2009 The Tegaki project contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # Contributors to this file: # - Mathieu Blondel import os from tegaki.charcol import CharacterCollection from tegakitools.tomoe import tomoe_dict_to_character_collection from tegakitools.kuchibue import kuchibue_to_character_collection TYPE_CHARCOL, TYPE_CHARCOL_DB, TYPE_DIRECTORY, TYPE_TOMOE, TYPE_KUCHIBUE = \ range(5) def _get_charcol(charcol_type, charcol_path): if charcol_type == TYPE_DIRECTORY: # charcol_path is actually a directory here return CharacterCollection.from_character_directory(charcol_path) elif charcol_type in (TYPE_CHARCOL, TYPE_CHARCOL_DB): return CharacterCollection(charcol_path) elif charcol_type == TYPE_TOMOE: return tomoe_dict_to_character_collection(charcol_path) elif charcol_type == TYPE_KUCHIBUE: return kuchibue_to_character_collection(charcol_path) def get_aggregated_charcol(tuples, dbpath=None): """ Create a character collection out of other character collections, character directories, tomoe dictionaries or kuchibue databases. tuples: a list of tuples (TYPE, path list) """ # number of files for each character collection type n_files = [len(t[1]) for t in tuples] # we don't need to merge character collections if only one is provided # this can save a lot of time for large collections if sum(n_files) == 1 and dbpath is None: idx = n_files.index(1) return _get_charcol(tuples[idx][0], tuples[idx][1][0]) if dbpath is not None and dbpath.endswith(".chardb"): if os.path.exists(dbpath): print "%s exists already." % dbpath print "Continuing will modify it..." answer = raw_input("Continue anyway? (y/N)") if answer == "y": print "Overwrite to concatenate collections together " + \ "in a new database" print "Don't overwrite to append new characters or " + \ "filter (-i,-e,-m) existing database" answer = raw_input("Overwrite it? (y/N)") if answer == "y": os.unlink(dbpath) else: exit() charcol = CharacterCollection(dbpath) #charcol.WRITE_BACK = False #charcol.AUTO_COMMIT = True else: charcol = CharacterCollection() # in memory db charcols = [_get_charcol(typ, path) \ for typ, paths in tuples for path in paths] charcol.merge(charcols) return charcol tegaki-tools-0.3.1/src/tegakitools/__init__.py0000644000175000017500000000000011342122364021200 0ustar mathieumathieutegaki-tools-0.3.1/src/tegakitools/unipen.py0000644000175000017500000001162411342122364020755 0ustar mathieumathieu#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (C) 2009 The Tegaki project contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # Contributors to this file: # - Mathieu Blondel # Incomplete unipen format parser # See http://hwr.nici.kun.nl/unipen/unipen.def for the format specification import re import os from tegaki.character import Point, Stroke, Writing, Character from tegaki.charcol import CharacterCollection class UnipenEventParser(object): """SAX-like event-based parser""" KEYWORD_LINE_REGEXP = re.compile(r"^\.[A-Z]+") def __init__(self): self._parsed_file = None def parse_file(self, path): self._parsed_file = path f = open(path) keyword, args = None, None for line in f.readlines(): if self._is_keyword_line(line): if keyword is not None and args is not None: self.handle_keyword(keyword.strip(), args.strip()) keyword, args = None, None arr = line.split(" ", 1) keyword = arr[0][1:] if len(arr) == 1: args = "" else: args = arr[1] elif keyword is not None and args is not None: args += line if keyword is not None and args is not None: self.handle_keyword(keyword, args) f.close() self.handle_eof() self._parsed_file = None def handle_keyword(self, keyword, args): # default keyword handler print keyword, args def handle_eof(self): # default end-of-file handler print "end of file" def _is_keyword_line(self, line): return (self.KEYWORD_LINE_REGEXP.match(line) is not None) class UnipenProxyParser(UnipenEventParser): def __init__(self, redirect): UnipenEventParser.__init__(self) self._redirect = redirect def handle_keyword(self, keyword, args): self._redirect(keyword, args) def handle_eof(self): pass class UnipenParser(UnipenEventParser): def __init__(self): UnipenEventParser.__init__(self) self._labels = [] self._characters = [] self._char = None def _handle_SEGMENT(self, args): seg_type, delimit, quality, label = args.split(" ") if seg_type == "CHARACTER": label = label.strip()[1:-1] self._labels.append(label) def _handle_START_BOX(self, args): if self._char: self._characters.append(self._char) self._char = Character() def _handle_PEN_DOWN(self, args): writing = self._char.get_writing() points = [[int(p_) for p_ in p.split(" ")] \ for p in args.strip().split("\n")] stroke = Stroke() for x, y in points: stroke.append_point(Point(x,y)) writing.append_stroke(stroke) def _handle_INCLUDE(self, args): if not self._parsed_file: return include_filename = args.upper() currdir = os.path.dirname(os.path.abspath(self._parsed_file)) # FIXME: don't hardcode include paths include1 = os.path.join(currdir, "INCLUDE") include2 = os.path.join(currdir, "..", "INCLUDE") for include in (include1, include2, currdir): path = os.path.join(include, include_filename) if os.path.exists(path): parser = UnipenProxyParser(self.handle_keyword) parser.parse_file(path) break def handle_keyword(self, keyword, args): try: func = getattr(self, "_handle_" + keyword) except AttributeError: pass else: func(args) def get_character_collection(self): charcol = CharacterCollection() assert(len(self._labels) == len(self._characters)) # group characters with the same label into sets sets = {} for i in range(len(self._characters)): utf8 = self._labels[i] self._characters[i].set_utf8(utf8) sets[utf8] = sets.get(utf8, []) + [self._characters[i]] charcol.add_sets(sets.keys()) for set_name, characters in sets.items(): charcol.append_characters(set_name, characters) return charcol tegaki-tools-0.3.1/src/tegakitools/shiftjis.py0000644000175000017500000032262011342122364021303 0ustar mathieumathieu# -*- coding: utf-8 -*- SHIFT_JIS_TABLE = { 0x8140 : " ", 0x8141 : "、", 0x8142 : "。", 0x8143 : ",", 0x8144 : ".", 0x8145 : "・", 0x8146 : ":", 0x8147 : ";", 0x8148 : "?", 0x8149 : "!", 0x814a : "゛", 0x814b : "゜", 0x814c : "´", 0x814d : "`", 0x814e : "¨", 0x814f : "^", 0x8150 : " ̄", 0x8151 : "_", 0x8152 : "ヽ", 0x8153 : "ヾ", 0x8154 : "ゝ", 0x8155 : "ゞ", 0x8156 : "〃", 0x8157 : "仝", 0x8158 : "々", 0x8159 : "〆", 0x815a : "〇", 0x815b : "ー", 0x815c : "―", 0x815d : "‐", 0x815e : "/", 0x815f : "\", 0x8160 : "〜", 0x8161 : "‖", 0x8162 : "|", 0x8163 : "…", 0x8164 : "‥", 0x8165 : "‘", 0x8166 : "’", 0x8167 : "“", 0x8168 : "”", 0x8169 : "(", 0x816a : ")", 0x816b : "〔", 0x816c : "〕", 0x816d : "[", 0x816e : "]", 0x816f : "{", 0x8170 : "}", 0x8171 : "〈", 0x8172 : "〉", 0x8173 : "《", 0x8174 : "》", 0x8175 : "「", 0x8176 : "」", 0x8177 : "『", 0x8178 : "』", 0x8179 : "【", 0x817a : "】", 0x817b : "+", 0x817c : "−", 0x817d : "±", 0x817e : "×", 0x8180 : "÷", 0x8181 : "=", 0x8182 : "≠", 0x8183 : "<", 0x8184 : ">", 0x8185 : "≦", 0x8186 : "≧", 0x8187 : "∞", 0x8188 : "∴", 0x8189 : "♂", 0x818a : "♀", 0x818b : "°", 0x818c : "′", 0x818d : "″", 0x818e : "℃", 0x818f : "¥", 0x8190 : "$", 0x8191 : "¢", 0x8192 : "£", 0x8193 : "%", 0x8194 : "#", 0x8195 : "&", 0x8196 : "*", 0x8197 : "@", 0x8198 : "§", 0x8199 : "☆", 0x819a : "★", 0x819b : "○", 0x819c : "●", 0x819d : "◎", 0x819e : "◇", 0x819f : "◆", 0x81a0 : "□", 0x81a1 : "■", 0x81a2 : "△", 0x81a3 : "▲", 0x81a4 : "▽", 0x81a5 : "▼", 0x81a6 : "※", 0x81a7 : "〒", 0x81a8 : "→", 0x81a9 : "←", 0x81aa : "↑", 0x81ab : "↓", 0x81ac : "〓", 0x81b8 : "∈", 0x81b9 : "∋", 0x81ba : "⊆", 0x81bb : "⊇", 0x81bc : "⊂", 0x81bd : "⊃", 0x81be : "∪", 0x81bf : "∩", 0x81c8 : "∧", 0x81c9 : "∨", 0x81ca : "¬", 0x81cb : "⇒", 0x81cc : "⇔", 0x81cd : "∀", 0x81ce : "∃", 0x81da : "∠", 0x81db : "⊥", 0x81dc : "⌒", 0x81dd : "∂", 0x81de : "∇", 0x81df : "≡", 0x81e0 : "≒", 0x81e1 : "≪", 0x81e2 : "≫", 0x81e3 : "√", 0x81e4 : "∽", 0x81e5 : "∝", 0x81e6 : "∵", 0x81e7 : "∫", 0x81e8 : "∬", 0x81f0 : "Å", 0x81f1 : "‰", 0x81f2 : "♯", 0x81f3 : "♭", 0x81f4 : "♪", 0x81f5 : "†", 0x81f6 : "‡", 0x81f7 : "¶", 0x81fc : "◯", 0x824f : "0", 0x8250 : "1", 0x8251 : "2", 0x8252 : "3", 0x8253 : "4", 0x8254 : "5", 0x8255 : "6", 0x8256 : "7", 0x8257 : "8", 0x8258 : "9", 0x8260 : "A", 0x8261 : "B", 0x8262 : "C", 0x8263 : "D", 0x8264 : "E", 0x8265 : "F", 0x8266 : "G", 0x8267 : "H", 0x8268 : "I", 0x8269 : "J", 0x826a : "K", 0x826b : "L", 0x826c : "M", 0x826d : "N", 0x826e : "O", 0x826f : "P", 0x8270 : "Q", 0x8271 : "R", 0x8272 : "S", 0x8273 : "T", 0x8274 : "U", 0x8275 : "V", 0x8276 : "W", 0x8277 : "X", 0x8278 : "Y", 0x8279 : "Z", 0x8281 : "a", 0x8282 : "b", 0x8283 : "c", 0x8284 : "d", 0x8285 : "e", 0x8286 : "f", 0x8287 : "g", 0x8288 : "h", 0x8289 : "i", 0x828a : "j", 0x828b : "k", 0x828c : "l", 0x828d : "m", 0x828e : "n", 0x828f : "o", 0x8290 : "p", 0x8291 : "q", 0x8292 : "r", 0x8293 : "s", 0x8294 : "t", 0x8295 : "u", 0x8296 : "v", 0x8297 : "w", 0x8298 : "x", 0x8299 : "y", 0x829a : "z", 0x829f : "ぁ", 0x82a0 : "あ", 0x82a1 : "ぃ", 0x82a2 : "い", 0x82a3 : "ぅ", 0x82a4 : "う", 0x82a5 : "ぇ", 0x82a6 : "え", 0x82a7 : "ぉ", 0x82a8 : "お", 0x82a9 : "か", 0x82aa : "が", 0x82ab : "き", 0x82ac : "ぎ", 0x82ad : "く", 0x82ae : "ぐ", 0x82af : "け", 0x82b0 : "げ", 0x82b1 : "こ", 0x82b2 : "ご", 0x82b3 : "さ", 0x82b4 : "ざ", 0x82b5 : "し", 0x82b6 : "じ", 0x82b7 : "す", 0x82b8 : "ず", 0x82b9 : "せ", 0x82ba : "ぜ", 0x82bb : "そ", 0x82bc : "ぞ", 0x82bd : "た", 0x82be : "だ", 0x82bf : "ち", 0x82c0 : "ぢ", 0x82c1 : "っ", 0x82c2 : "つ", 0x82c3 : "づ", 0x82c4 : "て", 0x82c5 : "で", 0x82c6 : "と", 0x82c7 : "ど", 0x82c8 : "な", 0x82c9 : "に", 0x82ca : "ぬ", 0x82cb : "ね", 0x82cc : "の", 0x82cd : "は", 0x82ce : "ば", 0x82cf : "ぱ", 0x82d0 : "ひ", 0x82d1 : "び", 0x82d2 : "ぴ", 0x82d3 : "ふ", 0x82d4 : "ぶ", 0x82d5 : "ぷ", 0x82d6 : "へ", 0x82d7 : "べ", 0x82d8 : "ぺ", 0x82d9 : "ほ", 0x82da : "ぼ", 0x82db : "ぽ", 0x82dc : "ま", 0x82dd : "み", 0x82de : "む", 0x82df : "め", 0x82e0 : "も", 0x82e1 : "ゃ", 0x82e2 : "や", 0x82e3 : "ゅ", 0x82e4 : "ゆ", 0x82e5 : "ょ", 0x82e6 : "よ", 0x82e7 : "ら", 0x82e8 : "り", 0x82e9 : "る", 0x82ea : "れ", 0x82eb : "ろ", 0x82ec : "ゎ", 0x82ed : "わ", 0x82ee : "ゐ", 0x82ef : "ゑ", 0x82f0 : "を", 0x82f1 : "ん", 0x8340 : "ァ", 0x8341 : "ア", 0x8342 : "ィ", 0x8343 : "イ", 0x8344 : "ゥ", 0x8345 : "ウ", 0x8346 : "ェ", 0x8347 : "エ", 0x8348 : "ォ", 0x8349 : "オ", 0x834a : "カ", 0x834b : "ガ", 0x834c : "キ", 0x834d : "ギ", 0x834e : "ク", 0x834f : "グ", 0x8350 : "ケ", 0x8351 : "ゲ", 0x8352 : "コ", 0x8353 : "ゴ", 0x8354 : "サ", 0x8355 : "ザ", 0x8356 : "シ", 0x8357 : "ジ", 0x8358 : "ス", 0x8359 : "ズ", 0x835a : "セ", 0x835b : "ゼ", 0x835c : "ソ", 0x835d : "ゾ", 0x835e : "タ", 0x835f : "ダ", 0x8360 : "チ", 0x8361 : "ヂ", 0x8362 : "ッ", 0x8363 : "ツ", 0x8364 : "ヅ", 0x8365 : "テ", 0x8366 : "デ", 0x8367 : "ト", 0x8368 : "ド", 0x8369 : "ナ", 0x836a : "ニ", 0x836b : "ヌ", 0x836c : "ネ", 0x836d : "ノ", 0x836e : "ハ", 0x836f : "バ", 0x8370 : "パ", 0x8371 : "ヒ", 0x8372 : "ビ", 0x8373 : "ピ", 0x8374 : "フ", 0x8375 : "ブ", 0x8376 : "プ", 0x8377 : "ヘ", 0x8378 : "ベ", 0x8379 : "ペ", 0x837a : "ホ", 0x837b : "ボ", 0x837c : "ポ", 0x837d : "マ", 0x837e : "ミ", 0x8380 : "ム", 0x8381 : "メ", 0x8382 : "モ", 0x8383 : "ャ", 0x8384 : "ヤ", 0x8385 : "ュ", 0x8386 : "ユ", 0x8387 : "ョ", 0x8388 : "ヨ", 0x8389 : "ラ", 0x838a : "リ", 0x838b : "ル", 0x838c : "レ", 0x838d : "ロ", 0x838e : "ヮ", 0x838f : "ワ", 0x8390 : "ヰ", 0x8391 : "ヱ", 0x8392 : "ヲ", 0x8393 : "ン", 0x8394 : "ヴ", 0x8395 : "ヵ", 0x8396 : "ヶ", 0x839f : "Α", 0x83a0 : "Β", 0x83a1 : "Γ", 0x83a2 : "Δ", 0x83a3 : "Ε", 0x83a4 : "Ζ", 0x83a5 : "Η", 0x83a6 : "Θ", 0x83a7 : "Ι", 0x83a8 : "Κ", 0x83a9 : "Λ", 0x83aa : "Μ", 0x83ab : "Ν", 0x83ac : "Ξ", 0x83ad : "Ο", 0x83ae : "Π", 0x83af : "Ρ", 0x83b0 : "Σ", 0x83b1 : "Τ", 0x83b2 : "Υ", 0x83b3 : "Φ", 0x83b4 : "Χ", 0x83b5 : "Ψ", 0x83b6 : "Ω", 0x83bf : "α", 0x83c0 : "β", 0x83c1 : "γ", 0x83c2 : "δ", 0x83c3 : "ε", 0x83c4 : "ζ", 0x83c5 : "η", 0x83c6 : "θ", 0x83c7 : "ι", 0x83c8 : "κ", 0x83c9 : "λ", 0x83ca : "μ", 0x83cb : "ν", 0x83cc : "ξ", 0x83cd : "ο", 0x83ce : "π", 0x83cf : "ρ", 0x83d0 : "σ", 0x83d1 : "τ", 0x83d2 : "υ", 0x83d3 : "φ", 0x83d4 : "χ", 0x83d5 : "ψ", 0x83d6 : "ω", 0x8440 : "А", 0x8441 : "Б", 0x8442 : "В", 0x8443 : "Г", 0x8444 : "Д", 0x8445 : "Е", 0x8446 : "Ё", 0x8447 : "Ж", 0x8448 : "З", 0x8449 : "И", 0x844a : "Й", 0x844b : "К", 0x844c : "Л", 0x844d : "М", 0x844e : "Н", 0x844f : "О", 0x8450 : "П", 0x8451 : "Р", 0x8452 : "С", 0x8453 : "Т", 0x8454 : "У", 0x8455 : "Ф", 0x8456 : "Х", 0x8457 : "Ц", 0x8458 : "Ч", 0x8459 : "Ш", 0x845a : "Щ", 0x845b : "Ъ", 0x845c : "Ы", 0x845d : "Ь", 0x845e : "Э", 0x845f : "Ю", 0x8460 : "Я", 0x8470 : "а", 0x8471 : "б", 0x8472 : "в", 0x8473 : "г", 0x8474 : "д", 0x8475 : "е", 0x8476 : "ё", 0x8477 : "ж", 0x8478 : "з", 0x8479 : "и", 0x847a : "й", 0x847b : "к", 0x847c : "л", 0x847d : "м", 0x847e : "н", 0x8480 : "о", 0x8481 : "п", 0x8482 : "р", 0x8483 : "с", 0x8484 : "т", 0x8485 : "у", 0x8486 : "ф", 0x8487 : "х", 0x8488 : "ц", 0x8489 : "ч", 0x848a : "ш", 0x848b : "щ", 0x848c : "ъ", 0x848d : "ы", 0x848e : "ь", 0x848f : "э", 0x8490 : "ю", 0x8491 : "я", 0x849f : "─", 0x84a0 : "│", 0x84a1 : "┌", 0x84a2 : "┐", 0x84a3 : "┘", 0x84a4 : "└", 0x84a5 : "├", 0x84a6 : "┬", 0x84a7 : "┤", 0x84a8 : "┴", 0x84a9 : "┼", 0x84aa : "━", 0x84ab : "┃", 0x84ac : "┏", 0x84ad : "┓", 0x84ae : "┛", 0x84af : "┗", 0x84b0 : "┣", 0x84b1 : "┳", 0x84b2 : "┫", 0x84b3 : "┻", 0x84b4 : "╋", 0x84b5 : "┠", 0x84b6 : "┯", 0x84b7 : "┨", 0x84b8 : "┷", 0x84b9 : "┿", 0x84ba : "┝", 0x84bb : "┰", 0x84bc : "┥", 0x84bd : "┸", 0x84be : "╂", 0x889f : "亜", 0x88a0 : "唖", 0x88a1 : "娃", 0x88a2 : "阿", 0x88a3 : "哀", 0x88a4 : "愛", 0x88a5 : "挨", 0x88a6 : "姶", 0x88a7 : "逢", 0x88a8 : "葵", 0x88a9 : "茜", 0x88aa : "穐", 0x88ab : "悪", 0x88ac : "握", 0x88ad : "渥", 0x88ae : "旭", 0x88af : "葦", 0x88b0 : "芦", 0x88b1 : "鯵", 0x88b2 : "梓", 0x88b3 : "圧", 0x88b4 : "斡", 0x88b5 : "扱", 0x88b6 : "宛", 0x88b7 : "姐", 0x88b8 : "虻", 0x88b9 : "飴", 0x88ba : "絢", 0x88bb : "綾", 0x88bc : "鮎", 0x88bd : "或", 0x88be : "粟", 0x88bf : "袷", 0x88c0 : "安", 0x88c1 : "庵", 0x88c2 : "按", 0x88c3 : "暗", 0x88c4 : "案", 0x88c5 : "闇", 0x88c6 : "鞍", 0x88c7 : "杏", 0x88c8 : "以", 0x88c9 : "伊", 0x88ca : "位", 0x88cb : "依", 0x88cc : "偉", 0x88cd : "囲", 0x88ce : "夷", 0x88cf : "委", 0x88d0 : "威", 0x88d1 : "尉", 0x88d2 : "惟", 0x88d3 : "意", 0x88d4 : "慰", 0x88d5 : "易", 0x88d6 : "椅", 0x88d7 : "為", 0x88d8 : "畏", 0x88d9 : "異", 0x88da : "移", 0x88db : "維", 0x88dc : "緯", 0x88dd : "胃", 0x88de : "萎", 0x88df : "衣", 0x88e0 : "謂", 0x88e1 : "違", 0x88e2 : "遺", 0x88e3 : "医", 0x88e4 : "井", 0x88e5 : "亥", 0x88e6 : "域", 0x88e7 : "育", 0x88e8 : "郁", 0x88e9 : "磯", 0x88ea : "一", 0x88eb : "壱", 0x88ec : "溢", 0x88ed : "逸", 0x88ee : "稲", 0x88ef : "茨", 0x88f0 : "芋", 0x88f1 : "鰯", 0x88f2 : "允", 0x88f3 : "印", 0x88f4 : "咽", 0x88f5 : "員", 0x88f6 : "因", 0x88f7 : "姻", 0x88f8 : "引", 0x88f9 : "飲", 0x88fa : "淫", 0x88fb : "胤", 0x88fc : "蔭", 0x8940 : "院", 0x8941 : "陰", 0x8942 : "隠", 0x8943 : "韻", 0x8944 : "吋", 0x8945 : "右", 0x8946 : "宇", 0x8947 : "烏", 0x8948 : "羽", 0x8949 : "迂", 0x894a : "雨", 0x894b : "卯", 0x894c : "鵜", 0x894d : "窺", 0x894e : "丑", 0x894f : "碓", 0x8950 : "臼", 0x8951 : "渦", 0x8952 : "嘘", 0x8953 : "唄", 0x8954 : "欝", 0x8955 : "蔚", 0x8956 : "鰻", 0x8957 : "姥", 0x8958 : "厩", 0x8959 : "浦", 0x895a : "瓜", 0x895b : "閏", 0x895c : "噂", 0x895d : "云", 0x895e : "運", 0x895f : "雲", 0x8960 : "荏", 0x8961 : "餌", 0x8962 : "叡", 0x8963 : "営", 0x8964 : "嬰", 0x8965 : "影", 0x8966 : "映", 0x8967 : "曳", 0x8968 : "栄", 0x8969 : "永", 0x896a : "泳", 0x896b : "洩", 0x896c : "瑛", 0x896d : "盈", 0x896e : "穎", 0x896f : "頴", 0x8970 : "英", 0x8971 : "衛", 0x8972 : "詠", 0x8973 : "鋭", 0x8974 : "液", 0x8975 : "疫", 0x8976 : "益", 0x8977 : "駅", 0x8978 : "悦", 0x8979 : "謁", 0x897a : "越", 0x897b : "閲", 0x897c : "榎", 0x897d : "厭", 0x897e : "円", 0x8980 : "園", 0x8981 : "堰", 0x8982 : "奄", 0x8983 : "宴", 0x8984 : "延", 0x8985 : "怨", 0x8986 : "掩", 0x8987 : "援", 0x8988 : "沿", 0x8989 : "演", 0x898a : "炎", 0x898b : "焔", 0x898c : "煙", 0x898d : "燕", 0x898e : "猿", 0x898f : "縁", 0x8990 : "艶", 0x8991 : "苑", 0x8992 : "薗", 0x8993 : "遠", 0x8994 : "鉛", 0x8995 : "鴛", 0x8996 : "塩", 0x8997 : "於", 0x8998 : "汚", 0x8999 : "甥", 0x899a : "凹", 0x899b : "央", 0x899c : "奥", 0x899d : "往", 0x899e : "応", 0x899f : "押", 0x89a0 : "旺", 0x89a1 : "横", 0x89a2 : "欧", 0x89a3 : "殴", 0x89a4 : "王", 0x89a5 : "翁", 0x89a6 : "襖", 0x89a7 : "鴬", 0x89a8 : "鴎", 0x89a9 : "黄", 0x89aa : "岡", 0x89ab : "沖", 0x89ac : "荻", 0x89ad : "億", 0x89ae : "屋", 0x89af : "憶", 0x89b0 : "臆", 0x89b1 : "桶", 0x89b2 : "牡", 0x89b3 : "乙", 0x89b4 : "俺", 0x89b5 : "卸", 0x89b6 : "恩", 0x89b7 : "温", 0x89b8 : "穏", 0x89b9 : "音", 0x89ba : "下", 0x89bb : "化", 0x89bc : "仮", 0x89bd : "何", 0x89be : "伽", 0x89bf : "価", 0x89c0 : "佳", 0x89c1 : "加", 0x89c2 : "可", 0x89c3 : "嘉", 0x89c4 : "夏", 0x89c5 : "嫁", 0x89c6 : "家", 0x89c7 : "寡", 0x89c8 : "科", 0x89c9 : "暇", 0x89ca : "果", 0x89cb : "架", 0x89cc : "歌", 0x89cd : "河", 0x89ce : "火", 0x89cf : "珂", 0x89d0 : "禍", 0x89d1 : "禾", 0x89d2 : "稼", 0x89d3 : "箇", 0x89d4 : "花", 0x89d5 : "苛", 0x89d6 : "茄", 0x89d7 : "荷", 0x89d8 : "華", 0x89d9 : "菓", 0x89da : "蝦", 0x89db : "課", 0x89dc : "嘩", 0x89dd : "貨", 0x89de : "迦", 0x89df : "過", 0x89e0 : "霞", 0x89e1 : "蚊", 0x89e2 : "俄", 0x89e3 : "峨", 0x89e4 : "我", 0x89e5 : "牙", 0x89e6 : "画", 0x89e7 : "臥", 0x89e8 : "芽", 0x89e9 : "蛾", 0x89ea : "賀", 0x89eb : "雅", 0x89ec : "餓", 0x89ed : "駕", 0x89ee : "介", 0x89ef : "会", 0x89f0 : "解", 0x89f1 : "回", 0x89f2 : "塊", 0x89f3 : "壊", 0x89f4 : "廻", 0x89f5 : "快", 0x89f6 : "怪", 0x89f7 : "悔", 0x89f8 : "恢", 0x89f9 : "懐", 0x89fa : "戒", 0x89fb : "拐", 0x89fc : "改", 0x8a40 : "魁", 0x8a41 : "晦", 0x8a42 : "械", 0x8a43 : "海", 0x8a44 : "灰", 0x8a45 : "界", 0x8a46 : "皆", 0x8a47 : "絵", 0x8a48 : "芥", 0x8a49 : "蟹", 0x8a4a : "開", 0x8a4b : "階", 0x8a4c : "貝", 0x8a4d : "凱", 0x8a4e : "劾", 0x8a4f : "外", 0x8a50 : "咳", 0x8a51 : "害", 0x8a52 : "崖", 0x8a53 : "慨", 0x8a54 : "概", 0x8a55 : "涯", 0x8a56 : "碍", 0x8a57 : "蓋", 0x8a58 : "街", 0x8a59 : "該", 0x8a5a : "鎧", 0x8a5b : "骸", 0x8a5c : "浬", 0x8a5d : "馨", 0x8a5e : "蛙", 0x8a5f : "垣", 0x8a60 : "柿", 0x8a61 : "蛎", 0x8a62 : "鈎", 0x8a63 : "劃", 0x8a64 : "嚇", 0x8a65 : "各", 0x8a66 : "廓", 0x8a67 : "拡", 0x8a68 : "撹", 0x8a69 : "格", 0x8a6a : "核", 0x8a6b : "殻", 0x8a6c : "獲", 0x8a6d : "確", 0x8a6e : "穫", 0x8a6f : "覚", 0x8a70 : "角", 0x8a71 : "赫", 0x8a72 : "較", 0x8a73 : "郭", 0x8a74 : "閣", 0x8a75 : "隔", 0x8a76 : "革", 0x8a77 : "学", 0x8a78 : "岳", 0x8a79 : "楽", 0x8a7a : "額", 0x8a7b : "顎", 0x8a7c : "掛", 0x8a7d : "笠", 0x8a7e : "樫", 0x8a80 : "橿", 0x8a81 : "梶", 0x8a82 : "鰍", 0x8a83 : "潟", 0x8a84 : "割", 0x8a85 : "喝", 0x8a86 : "恰", 0x8a87 : "括", 0x8a88 : "活", 0x8a89 : "渇", 0x8a8a : "滑", 0x8a8b : "葛", 0x8a8c : "褐", 0x8a8d : "轄", 0x8a8e : "且", 0x8a8f : "鰹", 0x8a90 : "叶", 0x8a91 : "椛", 0x8a92 : "樺", 0x8a93 : "鞄", 0x8a94 : "株", 0x8a95 : "兜", 0x8a96 : "竃", 0x8a97 : "蒲", 0x8a98 : "釜", 0x8a99 : "鎌", 0x8a9a : "噛", 0x8a9b : "鴨", 0x8a9c : "栢", 0x8a9d : "茅", 0x8a9e : "萱", 0x8a9f : "粥", 0x8aa0 : "刈", 0x8aa1 : "苅", 0x8aa2 : "瓦", 0x8aa3 : "乾", 0x8aa4 : "侃", 0x8aa5 : "冠", 0x8aa6 : "寒", 0x8aa7 : "刊", 0x8aa8 : "勘", 0x8aa9 : "勧", 0x8aaa : "巻", 0x8aab : "喚", 0x8aac : "堪", 0x8aad : "姦", 0x8aae : "完", 0x8aaf : "官", 0x8ab0 : "寛", 0x8ab1 : "干", 0x8ab2 : "幹", 0x8ab3 : "患", 0x8ab4 : "感", 0x8ab5 : "慣", 0x8ab6 : "憾", 0x8ab7 : "換", 0x8ab8 : "敢", 0x8ab9 : "柑", 0x8aba : "桓", 0x8abb : "棺", 0x8abc : "款", 0x8abd : "歓", 0x8abe : "汗", 0x8abf : "漢", 0x8ac0 : "澗", 0x8ac1 : "潅", 0x8ac2 : "環", 0x8ac3 : "甘", 0x8ac4 : "監", 0x8ac5 : "看", 0x8ac6 : "竿", 0x8ac7 : "管", 0x8ac8 : "簡", 0x8ac9 : "緩", 0x8aca : "缶", 0x8acb : "翰", 0x8acc : "肝", 0x8acd : "艦", 0x8ace : "莞", 0x8acf : "観", 0x8ad0 : "諌", 0x8ad1 : "貫", 0x8ad2 : "還", 0x8ad3 : "鑑", 0x8ad4 : "間", 0x8ad5 : "閑", 0x8ad6 : "関", 0x8ad7 : "陥", 0x8ad8 : "韓", 0x8ad9 : "館", 0x8ada : "舘", 0x8adb : "丸", 0x8adc : "含", 0x8add : "岸", 0x8ade : "巌", 0x8adf : "玩", 0x8ae0 : "癌", 0x8ae1 : "眼", 0x8ae2 : "岩", 0x8ae3 : "翫", 0x8ae4 : "贋", 0x8ae5 : "雁", 0x8ae6 : "頑", 0x8ae7 : "顔", 0x8ae8 : "願", 0x8ae9 : "企", 0x8aea : "伎", 0x8aeb : "危", 0x8aec : "喜", 0x8aed : "器", 0x8aee : "基", 0x8aef : "奇", 0x8af0 : "嬉", 0x8af1 : "寄", 0x8af2 : "岐", 0x8af3 : "希", 0x8af4 : "幾", 0x8af5 : "忌", 0x8af6 : "揮", 0x8af7 : "机", 0x8af8 : "旗", 0x8af9 : "既", 0x8afa : "期", 0x8afb : "棋", 0x8afc : "棄", 0x8b40 : "機", 0x8b41 : "帰", 0x8b42 : "毅", 0x8b43 : "気", 0x8b44 : "汽", 0x8b45 : "畿", 0x8b46 : "祈", 0x8b47 : "季", 0x8b48 : "稀", 0x8b49 : "紀", 0x8b4a : "徽", 0x8b4b : "規", 0x8b4c : "記", 0x8b4d : "貴", 0x8b4e : "起", 0x8b4f : "軌", 0x8b50 : "輝", 0x8b51 : "飢", 0x8b52 : "騎", 0x8b53 : "鬼", 0x8b54 : "亀", 0x8b55 : "偽", 0x8b56 : "儀", 0x8b57 : "妓", 0x8b58 : "宜", 0x8b59 : "戯", 0x8b5a : "技", 0x8b5b : "擬", 0x8b5c : "欺", 0x8b5d : "犠", 0x8b5e : "疑", 0x8b5f : "祇", 0x8b60 : "義", 0x8b61 : "蟻", 0x8b62 : "誼", 0x8b63 : "議", 0x8b64 : "掬", 0x8b65 : "菊", 0x8b66 : "鞠", 0x8b67 : "吉", 0x8b68 : "吃", 0x8b69 : "喫", 0x8b6a : "桔", 0x8b6b : "橘", 0x8b6c : "詰", 0x8b6d : "砧", 0x8b6e : "杵", 0x8b6f : "黍", 0x8b70 : "却", 0x8b71 : "客", 0x8b72 : "脚", 0x8b73 : "虐", 0x8b74 : "逆", 0x8b75 : "丘", 0x8b76 : "久", 0x8b77 : "仇", 0x8b78 : "休", 0x8b79 : "及", 0x8b7a : "吸", 0x8b7b : "宮", 0x8b7c : "弓", 0x8b7d : "急", 0x8b7e : "救", 0x8b80 : "朽", 0x8b81 : "求", 0x8b82 : "汲", 0x8b83 : "泣", 0x8b84 : "灸", 0x8b85 : "球", 0x8b86 : "究", 0x8b87 : "窮", 0x8b88 : "笈", 0x8b89 : "級", 0x8b8a : "糾", 0x8b8b : "給", 0x8b8c : "旧", 0x8b8d : "牛", 0x8b8e : "去", 0x8b8f : "居", 0x8b90 : "巨", 0x8b91 : "拒", 0x8b92 : "拠", 0x8b93 : "挙", 0x8b94 : "渠", 0x8b95 : "虚", 0x8b96 : "許", 0x8b97 : "距", 0x8b98 : "鋸", 0x8b99 : "漁", 0x8b9a : "禦", 0x8b9b : "魚", 0x8b9c : "亨", 0x8b9d : "享", 0x8b9e : "京", 0x8b9f : "供", 0x8ba0 : "侠", 0x8ba1 : "僑", 0x8ba2 : "兇", 0x8ba3 : "競", 0x8ba4 : "共", 0x8ba5 : "凶", 0x8ba6 : "協", 0x8ba7 : "匡", 0x8ba8 : "卿", 0x8ba9 : "叫", 0x8baa : "喬", 0x8bab : "境", 0x8bac : "峡", 0x8bad : "強", 0x8bae : "彊", 0x8baf : "怯", 0x8bb0 : "恐", 0x8bb1 : "恭", 0x8bb2 : "挟", 0x8bb3 : "教", 0x8bb4 : "橋", 0x8bb5 : "況", 0x8bb6 : "狂", 0x8bb7 : "狭", 0x8bb8 : "矯", 0x8bb9 : "胸", 0x8bba : "脅", 0x8bbb : "興", 0x8bbc : "蕎", 0x8bbd : "郷", 0x8bbe : "鏡", 0x8bbf : "響", 0x8bc0 : "饗", 0x8bc1 : "驚", 0x8bc2 : "仰", 0x8bc3 : "凝", 0x8bc4 : "尭", 0x8bc5 : "暁", 0x8bc6 : "業", 0x8bc7 : "局", 0x8bc8 : "曲", 0x8bc9 : "極", 0x8bca : "玉", 0x8bcb : "桐", 0x8bcc : "粁", 0x8bcd : "僅", 0x8bce : "勤", 0x8bcf : "均", 0x8bd0 : "巾", 0x8bd1 : "錦", 0x8bd2 : "斤", 0x8bd3 : "欣", 0x8bd4 : "欽", 0x8bd5 : "琴", 0x8bd6 : "禁", 0x8bd7 : "禽", 0x8bd8 : "筋", 0x8bd9 : "緊", 0x8bda : "芹", 0x8bdb : "菌", 0x8bdc : "衿", 0x8bdd : "襟", 0x8bde : "謹", 0x8bdf : "近", 0x8be0 : "金", 0x8be1 : "吟", 0x8be2 : "銀", 0x8be3 : "九", 0x8be4 : "倶", 0x8be5 : "句", 0x8be6 : "区", 0x8be7 : "狗", 0x8be8 : "玖", 0x8be9 : "矩", 0x8bea : "苦", 0x8beb : "躯", 0x8bec : "駆", 0x8bed : "駈", 0x8bee : "駒", 0x8bef : "具", 0x8bf0 : "愚", 0x8bf1 : "虞", 0x8bf2 : "喰", 0x8bf3 : "空", 0x8bf4 : "偶", 0x8bf5 : "寓", 0x8bf6 : "遇", 0x8bf7 : "隅", 0x8bf8 : "串", 0x8bf9 : "櫛", 0x8bfa : "釧", 0x8bfb : "屑", 0x8bfc : "屈", 0x8c40 : "掘", 0x8c41 : "窟", 0x8c42 : "沓", 0x8c43 : "靴", 0x8c44 : "轡", 0x8c45 : "窪", 0x8c46 : "熊", 0x8c47 : "隈", 0x8c48 : "粂", 0x8c49 : "栗", 0x8c4a : "繰", 0x8c4b : "桑", 0x8c4c : "鍬", 0x8c4d : "勲", 0x8c4e : "君", 0x8c4f : "薫", 0x8c50 : "訓", 0x8c51 : "群", 0x8c52 : "軍", 0x8c53 : "郡", 0x8c54 : "卦", 0x8c55 : "袈", 0x8c56 : "祁", 0x8c57 : "係", 0x8c58 : "傾", 0x8c59 : "刑", 0x8c5a : "兄", 0x8c5b : "啓", 0x8c5c : "圭", 0x8c5d : "珪", 0x8c5e : "型", 0x8c5f : "契", 0x8c60 : "形", 0x8c61 : "径", 0x8c62 : "恵", 0x8c63 : "慶", 0x8c64 : "慧", 0x8c65 : "憩", 0x8c66 : "掲", 0x8c67 : "携", 0x8c68 : "敬", 0x8c69 : "景", 0x8c6a : "桂", 0x8c6b : "渓", 0x8c6c : "畦", 0x8c6d : "稽", 0x8c6e : "系", 0x8c6f : "経", 0x8c70 : "継", 0x8c71 : "繋", 0x8c72 : "罫", 0x8c73 : "茎", 0x8c74 : "荊", 0x8c75 : "蛍", 0x8c76 : "計", 0x8c77 : "詣", 0x8c78 : "警", 0x8c79 : "軽", 0x8c7a : "頚", 0x8c7b : "鶏", 0x8c7c : "芸", 0x8c7d : "迎", 0x8c7e : "鯨", 0x8c80 : "劇", 0x8c81 : "戟", 0x8c82 : "撃", 0x8c83 : "激", 0x8c84 : "隙", 0x8c85 : "桁", 0x8c86 : "傑", 0x8c87 : "欠", 0x8c88 : "決", 0x8c89 : "潔", 0x8c8a : "穴", 0x8c8b : "結", 0x8c8c : "血", 0x8c8d : "訣", 0x8c8e : "月", 0x8c8f : "件", 0x8c90 : "倹", 0x8c91 : "倦", 0x8c92 : "健", 0x8c93 : "兼", 0x8c94 : "券", 0x8c95 : "剣", 0x8c96 : "喧", 0x8c97 : "圏", 0x8c98 : "堅", 0x8c99 : "嫌", 0x8c9a : "建", 0x8c9b : "憲", 0x8c9c : "懸", 0x8c9d : "拳", 0x8c9e : "捲", 0x8c9f : "検", 0x8ca0 : "権", 0x8ca1 : "牽", 0x8ca2 : "犬", 0x8ca3 : "献", 0x8ca4 : "研", 0x8ca5 : "硯", 0x8ca6 : "絹", 0x8ca7 : "県", 0x8ca8 : "肩", 0x8ca9 : "見", 0x8caa : "謙", 0x8cab : "賢", 0x8cac : "軒", 0x8cad : "遣", 0x8cae : "鍵", 0x8caf : "険", 0x8cb0 : "顕", 0x8cb1 : "験", 0x8cb2 : "鹸", 0x8cb3 : "元", 0x8cb4 : "原", 0x8cb5 : "厳", 0x8cb6 : "幻", 0x8cb7 : "弦", 0x8cb8 : "減", 0x8cb9 : "源", 0x8cba : "玄", 0x8cbb : "現", 0x8cbc : "絃", 0x8cbd : "舷", 0x8cbe : "言", 0x8cbf : "諺", 0x8cc0 : "限", 0x8cc1 : "乎", 0x8cc2 : "個", 0x8cc3 : "古", 0x8cc4 : "呼", 0x8cc5 : "固", 0x8cc6 : "姑", 0x8cc7 : "孤", 0x8cc8 : "己", 0x8cc9 : "庫", 0x8cca : "弧", 0x8ccb : "戸", 0x8ccc : "故", 0x8ccd : "枯", 0x8cce : "湖", 0x8ccf : "狐", 0x8cd0 : "糊", 0x8cd1 : "袴", 0x8cd2 : "股", 0x8cd3 : "胡", 0x8cd4 : "菰", 0x8cd5 : "虎", 0x8cd6 : "誇", 0x8cd7 : "跨", 0x8cd8 : "鈷", 0x8cd9 : "雇", 0x8cda : "顧", 0x8cdb : "鼓", 0x8cdc : "五", 0x8cdd : "互", 0x8cde : "伍", 0x8cdf : "午", 0x8ce0 : "呉", 0x8ce1 : "吾", 0x8ce2 : "娯", 0x8ce3 : "後", 0x8ce4 : "御", 0x8ce5 : "悟", 0x8ce6 : "梧", 0x8ce7 : "檎", 0x8ce8 : "瑚", 0x8ce9 : "碁", 0x8cea : "語", 0x8ceb : "誤", 0x8cec : "護", 0x8ced : "醐", 0x8cee : "乞", 0x8cef : "鯉", 0x8cf0 : "交", 0x8cf1 : "佼", 0x8cf2 : "侯", 0x8cf3 : "候", 0x8cf4 : "倖", 0x8cf5 : "光", 0x8cf6 : "公", 0x8cf7 : "功", 0x8cf8 : "効", 0x8cf9 : "勾", 0x8cfa : "厚", 0x8cfb : "口", 0x8cfc : "向", 0x8d40 : "后", 0x8d41 : "喉", 0x8d42 : "坑", 0x8d43 : "垢", 0x8d44 : "好", 0x8d45 : "孔", 0x8d46 : "孝", 0x8d47 : "宏", 0x8d48 : "工", 0x8d49 : "巧", 0x8d4a : "巷", 0x8d4b : "幸", 0x8d4c : "広", 0x8d4d : "庚", 0x8d4e : "康", 0x8d4f : "弘", 0x8d50 : "恒", 0x8d51 : "慌", 0x8d52 : "抗", 0x8d53 : "拘", 0x8d54 : "控", 0x8d55 : "攻", 0x8d56 : "昂", 0x8d57 : "晃", 0x8d58 : "更", 0x8d59 : "杭", 0x8d5a : "校", 0x8d5b : "梗", 0x8d5c : "構", 0x8d5d : "江", 0x8d5e : "洪", 0x8d5f : "浩", 0x8d60 : "港", 0x8d61 : "溝", 0x8d62 : "甲", 0x8d63 : "皇", 0x8d64 : "硬", 0x8d65 : "稿", 0x8d66 : "糠", 0x8d67 : "紅", 0x8d68 : "紘", 0x8d69 : "絞", 0x8d6a : "綱", 0x8d6b : "耕", 0x8d6c : "考", 0x8d6d : "肯", 0x8d6e : "肱", 0x8d6f : "腔", 0x8d70 : "膏", 0x8d71 : "航", 0x8d72 : "荒", 0x8d73 : "行", 0x8d74 : "衡", 0x8d75 : "講", 0x8d76 : "貢", 0x8d77 : "購", 0x8d78 : "郊", 0x8d79 : "酵", 0x8d7a : "鉱", 0x8d7b : "砿", 0x8d7c : "鋼", 0x8d7d : "閤", 0x8d7e : "降", 0x8d80 : "項", 0x8d81 : "香", 0x8d82 : "高", 0x8d83 : "鴻", 0x8d84 : "剛", 0x8d85 : "劫", 0x8d86 : "号", 0x8d87 : "合", 0x8d88 : "壕", 0x8d89 : "拷", 0x8d8a : "濠", 0x8d8b : "豪", 0x8d8c : "轟", 0x8d8d : "麹", 0x8d8e : "克", 0x8d8f : "刻", 0x8d90 : "告", 0x8d91 : "国", 0x8d92 : "穀", 0x8d93 : "酷", 0x8d94 : "鵠", 0x8d95 : "黒", 0x8d96 : "獄", 0x8d97 : "漉", 0x8d98 : "腰", 0x8d99 : "甑", 0x8d9a : "忽", 0x8d9b : "惚", 0x8d9c : "骨", 0x8d9d : "狛", 0x8d9e : "込", 0x8d9f : "此", 0x8da0 : "頃", 0x8da1 : "今", 0x8da2 : "困", 0x8da3 : "坤", 0x8da4 : "墾", 0x8da5 : "婚", 0x8da6 : "恨", 0x8da7 : "懇", 0x8da8 : "昏", 0x8da9 : "昆", 0x8daa : "根", 0x8dab : "梱", 0x8dac : "混", 0x8dad : "痕", 0x8dae : "紺", 0x8daf : "艮", 0x8db0 : "魂", 0x8db1 : "些", 0x8db2 : "佐", 0x8db3 : "叉", 0x8db4 : "唆", 0x8db5 : "嵯", 0x8db6 : "左", 0x8db7 : "差", 0x8db8 : "査", 0x8db9 : "沙", 0x8dba : "瑳", 0x8dbb : "砂", 0x8dbc : "詐", 0x8dbd : "鎖", 0x8dbe : "裟", 0x8dbf : "坐", 0x8dc0 : "座", 0x8dc1 : "挫", 0x8dc2 : "債", 0x8dc3 : "催", 0x8dc4 : "再", 0x8dc5 : "最", 0x8dc6 : "哉", 0x8dc7 : "塞", 0x8dc8 : "妻", 0x8dc9 : "宰", 0x8dca : "彩", 0x8dcb : "才", 0x8dcc : "採", 0x8dcd : "栽", 0x8dce : "歳", 0x8dcf : "済", 0x8dd0 : "災", 0x8dd1 : "采", 0x8dd2 : "犀", 0x8dd3 : "砕", 0x8dd4 : "砦", 0x8dd5 : "祭", 0x8dd6 : "斎", 0x8dd7 : "細", 0x8dd8 : "菜", 0x8dd9 : "裁", 0x8dda : "載", 0x8ddb : "際", 0x8ddc : "剤", 0x8ddd : "在", 0x8dde : "材", 0x8ddf : "罪", 0x8de0 : "財", 0x8de1 : "冴", 0x8de2 : "坂", 0x8de3 : "阪", 0x8de4 : "堺", 0x8de5 : "榊", 0x8de6 : "肴", 0x8de7 : "咲", 0x8de8 : "崎", 0x8de9 : "埼", 0x8dea : "碕", 0x8deb : "鷺", 0x8dec : "作", 0x8ded : "削", 0x8dee : "咋", 0x8def : "搾", 0x8df0 : "昨", 0x8df1 : "朔", 0x8df2 : "柵", 0x8df3 : "窄", 0x8df4 : "策", 0x8df5 : "索", 0x8df6 : "錯", 0x8df7 : "桜", 0x8df8 : "鮭", 0x8df9 : "笹", 0x8dfa : "匙", 0x8dfb : "冊", 0x8dfc : "刷", 0x8e40 : "察", 0x8e41 : "拶", 0x8e42 : "撮", 0x8e43 : "擦", 0x8e44 : "札", 0x8e45 : "殺", 0x8e46 : "薩", 0x8e47 : "雑", 0x8e48 : "皐", 0x8e49 : "鯖", 0x8e4a : "捌", 0x8e4b : "錆", 0x8e4c : "鮫", 0x8e4d : "皿", 0x8e4e : "晒", 0x8e4f : "三", 0x8e50 : "傘", 0x8e51 : "参", 0x8e52 : "山", 0x8e53 : "惨", 0x8e54 : "撒", 0x8e55 : "散", 0x8e56 : "桟", 0x8e57 : "燦", 0x8e58 : "珊", 0x8e59 : "産", 0x8e5a : "算", 0x8e5b : "纂", 0x8e5c : "蚕", 0x8e5d : "讃", 0x8e5e : "賛", 0x8e5f : "酸", 0x8e60 : "餐", 0x8e61 : "斬", 0x8e62 : "暫", 0x8e63 : "残", 0x8e64 : "仕", 0x8e65 : "仔", 0x8e66 : "伺", 0x8e67 : "使", 0x8e68 : "刺", 0x8e69 : "司", 0x8e6a : "史", 0x8e6b : "嗣", 0x8e6c : "四", 0x8e6d : "士", 0x8e6e : "始", 0x8e6f : "姉", 0x8e70 : "姿", 0x8e71 : "子", 0x8e72 : "屍", 0x8e73 : "市", 0x8e74 : "師", 0x8e75 : "志", 0x8e76 : "思", 0x8e77 : "指", 0x8e78 : "支", 0x8e79 : "孜", 0x8e7a : "斯", 0x8e7b : "施", 0x8e7c : "旨", 0x8e7d : "枝", 0x8e7e : "止", 0x8e80 : "死", 0x8e81 : "氏", 0x8e82 : "獅", 0x8e83 : "祉", 0x8e84 : "私", 0x8e85 : "糸", 0x8e86 : "紙", 0x8e87 : "紫", 0x8e88 : "肢", 0x8e89 : "脂", 0x8e8a : "至", 0x8e8b : "視", 0x8e8c : "詞", 0x8e8d : "詩", 0x8e8e : "試", 0x8e8f : "誌", 0x8e90 : "諮", 0x8e91 : "資", 0x8e92 : "賜", 0x8e93 : "雌", 0x8e94 : "飼", 0x8e95 : "歯", 0x8e96 : "事", 0x8e97 : "似", 0x8e98 : "侍", 0x8e99 : "児", 0x8e9a : "字", 0x8e9b : "寺", 0x8e9c : "慈", 0x8e9d : "持", 0x8e9e : "時", 0x8e9f : "次", 0x8ea0 : "滋", 0x8ea1 : "治", 0x8ea2 : "爾", 0x8ea3 : "璽", 0x8ea4 : "痔", 0x8ea5 : "磁", 0x8ea6 : "示", 0x8ea7 : "而", 0x8ea8 : "耳", 0x8ea9 : "自", 0x8eaa : "蒔", 0x8eab : "辞", 0x8eac : "汐", 0x8ead : "鹿", 0x8eae : "式", 0x8eaf : "識", 0x8eb0 : "鴫", 0x8eb1 : "竺", 0x8eb2 : "軸", 0x8eb3 : "宍", 0x8eb4 : "雫", 0x8eb5 : "七", 0x8eb6 : "叱", 0x8eb7 : "執", 0x8eb8 : "失", 0x8eb9 : "嫉", 0x8eba : "室", 0x8ebb : "悉", 0x8ebc : "湿", 0x8ebd : "漆", 0x8ebe : "疾", 0x8ebf : "質", 0x8ec0 : "実", 0x8ec1 : "蔀", 0x8ec2 : "篠", 0x8ec3 : "偲", 0x8ec4 : "柴", 0x8ec5 : "芝", 0x8ec6 : "屡", 0x8ec7 : "蕊", 0x8ec8 : "縞", 0x8ec9 : "舎", 0x8eca : "写", 0x8ecb : "射", 0x8ecc : "捨", 0x8ecd : "赦", 0x8ece : "斜", 0x8ecf : "煮", 0x8ed0 : "社", 0x8ed1 : "紗", 0x8ed2 : "者", 0x8ed3 : "謝", 0x8ed4 : "車", 0x8ed5 : "遮", 0x8ed6 : "蛇", 0x8ed7 : "邪", 0x8ed8 : "借", 0x8ed9 : "勺", 0x8eda : "尺", 0x8edb : "杓", 0x8edc : "灼", 0x8edd : "爵", 0x8ede : "酌", 0x8edf : "釈", 0x8ee0 : "錫", 0x8ee1 : "若", 0x8ee2 : "寂", 0x8ee3 : "弱", 0x8ee4 : "惹", 0x8ee5 : "主", 0x8ee6 : "取", 0x8ee7 : "守", 0x8ee8 : "手", 0x8ee9 : "朱", 0x8eea : "殊", 0x8eeb : "狩", 0x8eec : "珠", 0x8eed : "種", 0x8eee : "腫", 0x8eef : "趣", 0x8ef0 : "酒", 0x8ef1 : "首", 0x8ef2 : "儒", 0x8ef3 : "受", 0x8ef4 : "呪", 0x8ef5 : "寿", 0x8ef6 : "授", 0x8ef7 : "樹", 0x8ef8 : "綬", 0x8ef9 : "需", 0x8efa : "囚", 0x8efb : "収", 0x8efc : "周", 0x8f40 : "宗", 0x8f41 : "就", 0x8f42 : "州", 0x8f43 : "修", 0x8f44 : "愁", 0x8f45 : "拾", 0x8f46 : "洲", 0x8f47 : "秀", 0x8f48 : "秋", 0x8f49 : "終", 0x8f4a : "繍", 0x8f4b : "習", 0x8f4c : "臭", 0x8f4d : "舟", 0x8f4e : "蒐", 0x8f4f : "衆", 0x8f50 : "襲", 0x8f51 : "讐", 0x8f52 : "蹴", 0x8f53 : "輯", 0x8f54 : "週", 0x8f55 : "酋", 0x8f56 : "酬", 0x8f57 : "集", 0x8f58 : "醜", 0x8f59 : "什", 0x8f5a : "住", 0x8f5b : "充", 0x8f5c : "十", 0x8f5d : "従", 0x8f5e : "戎", 0x8f5f : "柔", 0x8f60 : "汁", 0x8f61 : "渋", 0x8f62 : "獣", 0x8f63 : "縦", 0x8f64 : "重", 0x8f65 : "銃", 0x8f66 : "叔", 0x8f67 : "夙", 0x8f68 : "宿", 0x8f69 : "淑", 0x8f6a : "祝", 0x8f6b : "縮", 0x8f6c : "粛", 0x8f6d : "塾", 0x8f6e : "熟", 0x8f6f : "出", 0x8f70 : "術", 0x8f71 : "述", 0x8f72 : "俊", 0x8f73 : "峻", 0x8f74 : "春", 0x8f75 : "瞬", 0x8f76 : "竣", 0x8f77 : "舜", 0x8f78 : "駿", 0x8f79 : "准", 0x8f7a : "循", 0x8f7b : "旬", 0x8f7c : "楯", 0x8f7d : "殉", 0x8f7e : "淳", 0x8f80 : "準", 0x8f81 : "潤", 0x8f82 : "盾", 0x8f83 : "純", 0x8f84 : "巡", 0x8f85 : "遵", 0x8f86 : "醇", 0x8f87 : "順", 0x8f88 : "処", 0x8f89 : "初", 0x8f8a : "所", 0x8f8b : "暑", 0x8f8c : "曙", 0x8f8d : "渚", 0x8f8e : "庶", 0x8f8f : "緒", 0x8f90 : "署", 0x8f91 : "書", 0x8f92 : "薯", 0x8f93 : "藷", 0x8f94 : "諸", 0x8f95 : "助", 0x8f96 : "叙", 0x8f97 : "女", 0x8f98 : "序", 0x8f99 : "徐", 0x8f9a : "恕", 0x8f9b : "鋤", 0x8f9c : "除", 0x8f9d : "傷", 0x8f9e : "償", 0x8f9f : "勝", 0x8fa0 : "匠", 0x8fa1 : "升", 0x8fa2 : "召", 0x8fa3 : "哨", 0x8fa4 : "商", 0x8fa5 : "唱", 0x8fa6 : "嘗", 0x8fa7 : "奨", 0x8fa8 : "妾", 0x8fa9 : "娼", 0x8faa : "宵", 0x8fab : "将", 0x8fac : "小", 0x8fad : "少", 0x8fae : "尚", 0x8faf : "庄", 0x8fb0 : "床", 0x8fb1 : "廠", 0x8fb2 : "彰", 0x8fb3 : "承", 0x8fb4 : "抄", 0x8fb5 : "招", 0x8fb6 : "掌", 0x8fb7 : "捷", 0x8fb8 : "昇", 0x8fb9 : "昌", 0x8fba : "昭", 0x8fbb : "晶", 0x8fbc : "松", 0x8fbd : "梢", 0x8fbe : "樟", 0x8fbf : "樵", 0x8fc0 : "沼", 0x8fc1 : "消", 0x8fc2 : "渉", 0x8fc3 : "湘", 0x8fc4 : "焼", 0x8fc5 : "焦", 0x8fc6 : "照", 0x8fc7 : "症", 0x8fc8 : "省", 0x8fc9 : "硝", 0x8fca : "礁", 0x8fcb : "祥", 0x8fcc : "称", 0x8fcd : "章", 0x8fce : "笑", 0x8fcf : "粧", 0x8fd0 : "紹", 0x8fd1 : "肖", 0x8fd2 : "菖", 0x8fd3 : "蒋", 0x8fd4 : "蕉", 0x8fd5 : "衝", 0x8fd6 : "裳", 0x8fd7 : "訟", 0x8fd8 : "証", 0x8fd9 : "詔", 0x8fda : "詳", 0x8fdb : "象", 0x8fdc : "賞", 0x8fdd : "醤", 0x8fde : "鉦", 0x8fdf : "鍾", 0x8fe0 : "鐘", 0x8fe1 : "障", 0x8fe2 : "鞘", 0x8fe3 : "上", 0x8fe4 : "丈", 0x8fe5 : "丞", 0x8fe6 : "乗", 0x8fe7 : "冗", 0x8fe8 : "剰", 0x8fe9 : "城", 0x8fea : "場", 0x8feb : "壌", 0x8fec : "嬢", 0x8fed : "常", 0x8fee : "情", 0x8fef : "擾", 0x8ff0 : "条", 0x8ff1 : "杖", 0x8ff2 : "浄", 0x8ff3 : "状", 0x8ff4 : "畳", 0x8ff5 : "穣", 0x8ff6 : "蒸", 0x8ff7 : "譲", 0x8ff8 : "醸", 0x8ff9 : "錠", 0x8ffa : "嘱", 0x8ffb : "埴", 0x8ffc : "飾", 0x9040 : "拭", 0x9041 : "植", 0x9042 : "殖", 0x9043 : "燭", 0x9044 : "織", 0x9045 : "職", 0x9046 : "色", 0x9047 : "触", 0x9048 : "食", 0x9049 : "蝕", 0x904a : "辱", 0x904b : "尻", 0x904c : "伸", 0x904d : "信", 0x904e : "侵", 0x904f : "唇", 0x9050 : "娠", 0x9051 : "寝", 0x9052 : "審", 0x9053 : "心", 0x9054 : "慎", 0x9055 : "振", 0x9056 : "新", 0x9057 : "晋", 0x9058 : "森", 0x9059 : "榛", 0x905a : "浸", 0x905b : "深", 0x905c : "申", 0x905d : "疹", 0x905e : "真", 0x905f : "神", 0x9060 : "秦", 0x9061 : "紳", 0x9062 : "臣", 0x9063 : "芯", 0x9064 : "薪", 0x9065 : "親", 0x9066 : "診", 0x9067 : "身", 0x9068 : "辛", 0x9069 : "進", 0x906a : "針", 0x906b : "震", 0x906c : "人", 0x906d : "仁", 0x906e : "刃", 0x906f : "塵", 0x9070 : "壬", 0x9071 : "尋", 0x9072 : "甚", 0x9073 : "尽", 0x9074 : "腎", 0x9075 : "訊", 0x9076 : "迅", 0x9077 : "陣", 0x9078 : "靭", 0x9079 : "笥", 0x907a : "諏", 0x907b : "須", 0x907c : "酢", 0x907d : "図", 0x907e : "厨", 0x9080 : "逗", 0x9081 : "吹", 0x9082 : "垂", 0x9083 : "帥", 0x9084 : "推", 0x9085 : "水", 0x9086 : "炊", 0x9087 : "睡", 0x9088 : "粋", 0x9089 : "翠", 0x908a : "衰", 0x908b : "遂", 0x908c : "酔", 0x908d : "錐", 0x908e : "錘", 0x908f : "随", 0x9090 : "瑞", 0x9091 : "髄", 0x9092 : "崇", 0x9093 : "嵩", 0x9094 : "数", 0x9095 : "枢", 0x9096 : "趨", 0x9097 : "雛", 0x9098 : "据", 0x9099 : "杉", 0x909a : "椙", 0x909b : "菅", 0x909c : "頗", 0x909d : "雀", 0x909e : "裾", 0x909f : "澄", 0x90a0 : "摺", 0x90a1 : "寸", 0x90a2 : "世", 0x90a3 : "瀬", 0x90a4 : "畝", 0x90a5 : "是", 0x90a6 : "凄", 0x90a7 : "制", 0x90a8 : "勢", 0x90a9 : "姓", 0x90aa : "征", 0x90ab : "性", 0x90ac : "成", 0x90ad : "政", 0x90ae : "整", 0x90af : "星", 0x90b0 : "晴", 0x90b1 : "棲", 0x90b2 : "栖", 0x90b3 : "正", 0x90b4 : "清", 0x90b5 : "牲", 0x90b6 : "生", 0x90b7 : "盛", 0x90b8 : "精", 0x90b9 : "聖", 0x90ba : "声", 0x90bb : "製", 0x90bc : "西", 0x90bd : "誠", 0x90be : "誓", 0x90bf : "請", 0x90c0 : "逝", 0x90c1 : "醒", 0x90c2 : "青", 0x90c3 : "静", 0x90c4 : "斉", 0x90c5 : "税", 0x90c6 : "脆", 0x90c7 : "隻", 0x90c8 : "席", 0x90c9 : "惜", 0x90ca : "戚", 0x90cb : "斥", 0x90cc : "昔", 0x90cd : "析", 0x90ce : "石", 0x90cf : "積", 0x90d0 : "籍", 0x90d1 : "績", 0x90d2 : "脊", 0x90d3 : "責", 0x90d4 : "赤", 0x90d5 : "跡", 0x90d6 : "蹟", 0x90d7 : "碩", 0x90d8 : "切", 0x90d9 : "拙", 0x90da : "接", 0x90db : "摂", 0x90dc : "折", 0x90dd : "設", 0x90de : "窃", 0x90df : "節", 0x90e0 : "説", 0x90e1 : "雪", 0x90e2 : "絶", 0x90e3 : "舌", 0x90e4 : "蝉", 0x90e5 : "仙", 0x90e6 : "先", 0x90e7 : "千", 0x90e8 : "占", 0x90e9 : "宣", 0x90ea : "専", 0x90eb : "尖", 0x90ec : "川", 0x90ed : "戦", 0x90ee : "扇", 0x90ef : "撰", 0x90f0 : "栓", 0x90f1 : "栴", 0x90f2 : "泉", 0x90f3 : "浅", 0x90f4 : "洗", 0x90f5 : "染", 0x90f6 : "潜", 0x90f7 : "煎", 0x90f8 : "煽", 0x90f9 : "旋", 0x90fa : "穿", 0x90fb : "箭", 0x90fc : "線", 0x9140 : "繊", 0x9141 : "羨", 0x9142 : "腺", 0x9143 : "舛", 0x9144 : "船", 0x9145 : "薦", 0x9146 : "詮", 0x9147 : "賎", 0x9148 : "践", 0x9149 : "選", 0x914a : "遷", 0x914b : "銭", 0x914c : "銑", 0x914d : "閃", 0x914e : "鮮", 0x914f : "前", 0x9150 : "善", 0x9151 : "漸", 0x9152 : "然", 0x9153 : "全", 0x9154 : "禅", 0x9155 : "繕", 0x9156 : "膳", 0x9157 : "糎", 0x9158 : "噌", 0x9159 : "塑", 0x915a : "岨", 0x915b : "措", 0x915c : "曾", 0x915d : "曽", 0x915e : "楚", 0x915f : "狙", 0x9160 : "疏", 0x9161 : "疎", 0x9162 : "礎", 0x9163 : "祖", 0x9164 : "租", 0x9165 : "粗", 0x9166 : "素", 0x9167 : "組", 0x9168 : "蘇", 0x9169 : "訴", 0x916a : "阻", 0x916b : "遡", 0x916c : "鼠", 0x916d : "僧", 0x916e : "創", 0x916f : "双", 0x9170 : "叢", 0x9171 : "倉", 0x9172 : "喪", 0x9173 : "壮", 0x9174 : "奏", 0x9175 : "爽", 0x9176 : "宋", 0x9177 : "層", 0x9178 : "匝", 0x9179 : "惣", 0x917a : "想", 0x917b : "捜", 0x917c : "掃", 0x917d : "挿", 0x917e : "掻", 0x9180 : "操", 0x9181 : "早", 0x9182 : "曹", 0x9183 : "巣", 0x9184 : "槍", 0x9185 : "槽", 0x9186 : "漕", 0x9187 : "燥", 0x9188 : "争", 0x9189 : "痩", 0x918a : "相", 0x918b : "窓", 0x918c : "糟", 0x918d : "総", 0x918e : "綜", 0x918f : "聡", 0x9190 : "草", 0x9191 : "荘", 0x9192 : "葬", 0x9193 : "蒼", 0x9194 : "藻", 0x9195 : "装", 0x9196 : "走", 0x9197 : "送", 0x9198 : "遭", 0x9199 : "鎗", 0x919a : "霜", 0x919b : "騒", 0x919c : "像", 0x919d : "増", 0x919e : "憎", 0x919f : "臓", 0x91a0 : "蔵", 0x91a1 : "贈", 0x91a2 : "造", 0x91a3 : "促", 0x91a4 : "側", 0x91a5 : "則", 0x91a6 : "即", 0x91a7 : "息", 0x91a8 : "捉", 0x91a9 : "束", 0x91aa : "測", 0x91ab : "足", 0x91ac : "速", 0x91ad : "俗", 0x91ae : "属", 0x91af : "賊", 0x91b0 : "族", 0x91b1 : "続", 0x91b2 : "卒", 0x91b3 : "袖", 0x91b4 : "其", 0x91b5 : "揃", 0x91b6 : "存", 0x91b7 : "孫", 0x91b8 : "尊", 0x91b9 : "損", 0x91ba : "村", 0x91bb : "遜", 0x91bc : "他", 0x91bd : "多", 0x91be : "太", 0x91bf : "汰", 0x91c0 : "詑", 0x91c1 : "唾", 0x91c2 : "堕", 0x91c3 : "妥", 0x91c4 : "惰", 0x91c5 : "打", 0x91c6 : "柁", 0x91c7 : "舵", 0x91c8 : "楕", 0x91c9 : "陀", 0x91ca : "駄", 0x91cb : "騨", 0x91cc : "体", 0x91cd : "堆", 0x91ce : "対", 0x91cf : "耐", 0x91d0 : "岱", 0x91d1 : "帯", 0x91d2 : "待", 0x91d3 : "怠", 0x91d4 : "態", 0x91d5 : "戴", 0x91d6 : "替", 0x91d7 : "泰", 0x91d8 : "滞", 0x91d9 : "胎", 0x91da : "腿", 0x91db : "苔", 0x91dc : "袋", 0x91dd : "貸", 0x91de : "退", 0x91df : "逮", 0x91e0 : "隊", 0x91e1 : "黛", 0x91e2 : "鯛", 0x91e3 : "代", 0x91e4 : "台", 0x91e5 : "大", 0x91e6 : "第", 0x91e7 : "醍", 0x91e8 : "題", 0x91e9 : "鷹", 0x91ea : "滝", 0x91eb : "瀧", 0x91ec : "卓", 0x91ed : "啄", 0x91ee : "宅", 0x91ef : "托", 0x91f0 : "択", 0x91f1 : "拓", 0x91f2 : "沢", 0x91f3 : "濯", 0x91f4 : "琢", 0x91f5 : "託", 0x91f6 : "鐸", 0x91f7 : "濁", 0x91f8 : "諾", 0x91f9 : "茸", 0x91fa : "凧", 0x91fb : "蛸", 0x91fc : "只", 0x9240 : "叩", 0x9241 : "但", 0x9242 : "達", 0x9243 : "辰", 0x9244 : "奪", 0x9245 : "脱", 0x9246 : "巽", 0x9247 : "竪", 0x9248 : "辿", 0x9249 : "棚", 0x924a : "谷", 0x924b : "狸", 0x924c : "鱈", 0x924d : "樽", 0x924e : "誰", 0x924f : "丹", 0x9250 : "単", 0x9251 : "嘆", 0x9252 : "坦", 0x9253 : "担", 0x9254 : "探", 0x9255 : "旦", 0x9256 : "歎", 0x9257 : "淡", 0x9258 : "湛", 0x9259 : "炭", 0x925a : "短", 0x925b : "端", 0x925c : "箪", 0x925d : "綻", 0x925e : "耽", 0x925f : "胆", 0x9260 : "蛋", 0x9261 : "誕", 0x9262 : "鍛", 0x9263 : "団", 0x9264 : "壇", 0x9265 : "弾", 0x9266 : "断", 0x9267 : "暖", 0x9268 : "檀", 0x9269 : "段", 0x926a : "男", 0x926b : "談", 0x926c : "値", 0x926d : "知", 0x926e : "地", 0x926f : "弛", 0x9270 : "恥", 0x9271 : "智", 0x9272 : "池", 0x9273 : "痴", 0x9274 : "稚", 0x9275 : "置", 0x9276 : "致", 0x9277 : "蜘", 0x9278 : "遅", 0x9279 : "馳", 0x927a : "築", 0x927b : "畜", 0x927c : "竹", 0x927d : "筑", 0x927e : "蓄", 0x9280 : "逐", 0x9281 : "秩", 0x9282 : "窒", 0x9283 : "茶", 0x9284 : "嫡", 0x9285 : "着", 0x9286 : "中", 0x9287 : "仲", 0x9288 : "宙", 0x9289 : "忠", 0x928a : "抽", 0x928b : "昼", 0x928c : "柱", 0x928d : "注", 0x928e : "虫", 0x928f : "衷", 0x9290 : "註", 0x9291 : "酎", 0x9292 : "鋳", 0x9293 : "駐", 0x9294 : "樗", 0x9295 : "瀦", 0x9296 : "猪", 0x9297 : "苧", 0x9298 : "著", 0x9299 : "貯", 0x929a : "丁", 0x929b : "兆", 0x929c : "凋", 0x929d : "喋", 0x929e : "寵", 0x929f : "帖", 0x92a0 : "帳", 0x92a1 : "庁", 0x92a2 : "弔", 0x92a3 : "張", 0x92a4 : "彫", 0x92a5 : "徴", 0x92a6 : "懲", 0x92a7 : "挑", 0x92a8 : "暢", 0x92a9 : "朝", 0x92aa : "潮", 0x92ab : "牒", 0x92ac : "町", 0x92ad : "眺", 0x92ae : "聴", 0x92af : "脹", 0x92b0 : "腸", 0x92b1 : "蝶", 0x92b2 : "調", 0x92b3 : "諜", 0x92b4 : "超", 0x92b5 : "跳", 0x92b6 : "銚", 0x92b7 : "長", 0x92b8 : "頂", 0x92b9 : "鳥", 0x92ba : "勅", 0x92bb : "捗", 0x92bc : "直", 0x92bd : "朕", 0x92be : "沈", 0x92bf : "珍", 0x92c0 : "賃", 0x92c1 : "鎮", 0x92c2 : "陳", 0x92c3 : "津", 0x92c4 : "墜", 0x92c5 : "椎", 0x92c6 : "槌", 0x92c7 : "追", 0x92c8 : "鎚", 0x92c9 : "痛", 0x92ca : "通", 0x92cb : "塚", 0x92cc : "栂", 0x92cd : "掴", 0x92ce : "槻", 0x92cf : "佃", 0x92d0 : "漬", 0x92d1 : "柘", 0x92d2 : "辻", 0x92d3 : "蔦", 0x92d4 : "綴", 0x92d5 : "鍔", 0x92d6 : "椿", 0x92d7 : "潰", 0x92d8 : "坪", 0x92d9 : "壷", 0x92da : "嬬", 0x92db : "紬", 0x92dc : "爪", 0x92dd : "吊", 0x92de : "釣", 0x92df : "鶴", 0x92e0 : "亭", 0x92e1 : "低", 0x92e2 : "停", 0x92e3 : "偵", 0x92e4 : "剃", 0x92e5 : "貞", 0x92e6 : "呈", 0x92e7 : "堤", 0x92e8 : "定", 0x92e9 : "帝", 0x92ea : "底", 0x92eb : "庭", 0x92ec : "廷", 0x92ed : "弟", 0x92ee : "悌", 0x92ef : "抵", 0x92f0 : "挺", 0x92f1 : "提", 0x92f2 : "梯", 0x92f3 : "汀", 0x92f4 : "碇", 0x92f5 : "禎", 0x92f6 : "程", 0x92f7 : "締", 0x92f8 : "艇", 0x92f9 : "訂", 0x92fa : "諦", 0x92fb : "蹄", 0x92fc : "逓", 0x9340 : "邸", 0x9341 : "鄭", 0x9342 : "釘", 0x9343 : "鼎", 0x9344 : "泥", 0x9345 : "摘", 0x9346 : "擢", 0x9347 : "敵", 0x9348 : "滴", 0x9349 : "的", 0x934a : "笛", 0x934b : "適", 0x934c : "鏑", 0x934d : "溺", 0x934e : "哲", 0x934f : "徹", 0x9350 : "撤", 0x9351 : "轍", 0x9352 : "迭", 0x9353 : "鉄", 0x9354 : "典", 0x9355 : "填", 0x9356 : "天", 0x9357 : "展", 0x9358 : "店", 0x9359 : "添", 0x935a : "纏", 0x935b : "甜", 0x935c : "貼", 0x935d : "転", 0x935e : "顛", 0x935f : "点", 0x9360 : "伝", 0x9361 : "殿", 0x9362 : "澱", 0x9363 : "田", 0x9364 : "電", 0x9365 : "兎", 0x9366 : "吐", 0x9367 : "堵", 0x9368 : "塗", 0x9369 : "妬", 0x936a : "屠", 0x936b : "徒", 0x936c : "斗", 0x936d : "杜", 0x936e : "渡", 0x936f : "登", 0x9370 : "菟", 0x9371 : "賭", 0x9372 : "途", 0x9373 : "都", 0x9374 : "鍍", 0x9375 : "砥", 0x9376 : "砺", 0x9377 : "努", 0x9378 : "度", 0x9379 : "土", 0x937a : "奴", 0x937b : "怒", 0x937c : "倒", 0x937d : "党", 0x937e : "冬", 0x9380 : "凍", 0x9381 : "刀", 0x9382 : "唐", 0x9383 : "塔", 0x9384 : "塘", 0x9385 : "套", 0x9386 : "宕", 0x9387 : "島", 0x9388 : "嶋", 0x9389 : "悼", 0x938a : "投", 0x938b : "搭", 0x938c : "東", 0x938d : "桃", 0x938e : "梼", 0x938f : "棟", 0x9390 : "盗", 0x9391 : "淘", 0x9392 : "湯", 0x9393 : "涛", 0x9394 : "灯", 0x9395 : "燈", 0x9396 : "当", 0x9397 : "痘", 0x9398 : "祷", 0x9399 : "等", 0x939a : "答", 0x939b : "筒", 0x939c : "糖", 0x939d : "統", 0x939e : "到", 0x939f : "董", 0x93a0 : "蕩", 0x93a1 : "藤", 0x93a2 : "討", 0x93a3 : "謄", 0x93a4 : "豆", 0x93a5 : "踏", 0x93a6 : "逃", 0x93a7 : "透", 0x93a8 : "鐙", 0x93a9 : "陶", 0x93aa : "頭", 0x93ab : "騰", 0x93ac : "闘", 0x93ad : "働", 0x93ae : "動", 0x93af : "同", 0x93b0 : "堂", 0x93b1 : "導", 0x93b2 : "憧", 0x93b3 : "撞", 0x93b4 : "洞", 0x93b5 : "瞳", 0x93b6 : "童", 0x93b7 : "胴", 0x93b8 : "萄", 0x93b9 : "道", 0x93ba : "銅", 0x93bb : "峠", 0x93bc : "鴇", 0x93bd : "匿", 0x93be : "得", 0x93bf : "徳", 0x93c0 : "涜", 0x93c1 : "特", 0x93c2 : "督", 0x93c3 : "禿", 0x93c4 : "篤", 0x93c5 : "毒", 0x93c6 : "独", 0x93c7 : "読", 0x93c8 : "栃", 0x93c9 : "橡", 0x93ca : "凸", 0x93cb : "突", 0x93cc : "椴", 0x93cd : "届", 0x93ce : "鳶", 0x93cf : "苫", 0x93d0 : "寅", 0x93d1 : "酉", 0x93d2 : "瀞", 0x93d3 : "噸", 0x93d4 : "屯", 0x93d5 : "惇", 0x93d6 : "敦", 0x93d7 : "沌", 0x93d8 : "豚", 0x93d9 : "遁", 0x93da : "頓", 0x93db : "呑", 0x93dc : "曇", 0x93dd : "鈍", 0x93de : "奈", 0x93df : "那", 0x93e0 : "内", 0x93e1 : "乍", 0x93e2 : "凪", 0x93e3 : "薙", 0x93e4 : "謎", 0x93e5 : "灘", 0x93e6 : "捺", 0x93e7 : "鍋", 0x93e8 : "楢", 0x93e9 : "馴", 0x93ea : "縄", 0x93eb : "畷", 0x93ec : "南", 0x93ed : "楠", 0x93ee : "軟", 0x93ef : "難", 0x93f0 : "汝", 0x93f1 : "二", 0x93f2 : "尼", 0x93f3 : "弐", 0x93f4 : "迩", 0x93f5 : "匂", 0x93f6 : "賑", 0x93f7 : "肉", 0x93f8 : "虹", 0x93f9 : "廿", 0x93fa : "日", 0x93fb : "乳", 0x93fc : "入", 0x9440 : "如", 0x9441 : "尿", 0x9442 : "韮", 0x9443 : "任", 0x9444 : "妊", 0x9445 : "忍", 0x9446 : "認", 0x9447 : "濡", 0x9448 : "禰", 0x9449 : "祢", 0x944a : "寧", 0x944b : "葱", 0x944c : "猫", 0x944d : "熱", 0x944e : "年", 0x944f : "念", 0x9450 : "捻", 0x9451 : "撚", 0x9452 : "燃", 0x9453 : "粘", 0x9454 : "乃", 0x9455 : "廼", 0x9456 : "之", 0x9457 : "埜", 0x9458 : "嚢", 0x9459 : "悩", 0x945a : "濃", 0x945b : "納", 0x945c : "能", 0x945d : "脳", 0x945e : "膿", 0x945f : "農", 0x9460 : "覗", 0x9461 : "蚤", 0x9462 : "巴", 0x9463 : "把", 0x9464 : "播", 0x9465 : "覇", 0x9466 : "杷", 0x9467 : "波", 0x9468 : "派", 0x9469 : "琶", 0x946a : "破", 0x946b : "婆", 0x946c : "罵", 0x946d : "芭", 0x946e : "馬", 0x946f : "俳", 0x9470 : "廃", 0x9471 : "拝", 0x9472 : "排", 0x9473 : "敗", 0x9474 : "杯", 0x9475 : "盃", 0x9476 : "牌", 0x9477 : "背", 0x9478 : "肺", 0x9479 : "輩", 0x947a : "配", 0x947b : "倍", 0x947c : "培", 0x947d : "媒", 0x947e : "梅", 0x9480 : "楳", 0x9481 : "煤", 0x9482 : "狽", 0x9483 : "買", 0x9484 : "売", 0x9485 : "賠", 0x9486 : "陪", 0x9487 : "這", 0x9488 : "蝿", 0x9489 : "秤", 0x948a : "矧", 0x948b : "萩", 0x948c : "伯", 0x948d : "剥", 0x948e : "博", 0x948f : "拍", 0x9490 : "柏", 0x9491 : "泊", 0x9492 : "白", 0x9493 : "箔", 0x9494 : "粕", 0x9495 : "舶", 0x9496 : "薄", 0x9497 : "迫", 0x9498 : "曝", 0x9499 : "漠", 0x949a : "爆", 0x949b : "縛", 0x949c : "莫", 0x949d : "駁", 0x949e : "麦", 0x949f : "函", 0x94a0 : "箱", 0x94a1 : "硲", 0x94a2 : "箸", 0x94a3 : "肇", 0x94a4 : "筈", 0x94a5 : "櫨", 0x94a6 : "幡", 0x94a7 : "肌", 0x94a8 : "畑", 0x94a9 : "畠", 0x94aa : "八", 0x94ab : "鉢", 0x94ac : "溌", 0x94ad : "発", 0x94ae : "醗", 0x94af : "髪", 0x94b0 : "伐", 0x94b1 : "罰", 0x94b2 : "抜", 0x94b3 : "筏", 0x94b4 : "閥", 0x94b5 : "鳩", 0x94b6 : "噺", 0x94b7 : "塙", 0x94b8 : "蛤", 0x94b9 : "隼", 0x94ba : "伴", 0x94bb : "判", 0x94bc : "半", 0x94bd : "反", 0x94be : "叛", 0x94bf : "帆", 0x94c0 : "搬", 0x94c1 : "斑", 0x94c2 : "板", 0x94c3 : "氾", 0x94c4 : "汎", 0x94c5 : "版", 0x94c6 : "犯", 0x94c7 : "班", 0x94c8 : "畔", 0x94c9 : "繁", 0x94ca : "般", 0x94cb : "藩", 0x94cc : "販", 0x94cd : "範", 0x94ce : "釆", 0x94cf : "煩", 0x94d0 : "頒", 0x94d1 : "飯", 0x94d2 : "挽", 0x94d3 : "晩", 0x94d4 : "番", 0x94d5 : "盤", 0x94d6 : "磐", 0x94d7 : "蕃", 0x94d8 : "蛮", 0x94d9 : "匪", 0x94da : "卑", 0x94db : "否", 0x94dc : "妃", 0x94dd : "庇", 0x94de : "彼", 0x94df : "悲", 0x94e0 : "扉", 0x94e1 : "批", 0x94e2 : "披", 0x94e3 : "斐", 0x94e4 : "比", 0x94e5 : "泌", 0x94e6 : "疲", 0x94e7 : "皮", 0x94e8 : "碑", 0x94e9 : "秘", 0x94ea : "緋", 0x94eb : "罷", 0x94ec : "肥", 0x94ed : "被", 0x94ee : "誹", 0x94ef : "費", 0x94f0 : "避", 0x94f1 : "非", 0x94f2 : "飛", 0x94f3 : "樋", 0x94f4 : "簸", 0x94f5 : "備", 0x94f6 : "尾", 0x94f7 : "微", 0x94f8 : "枇", 0x94f9 : "毘", 0x94fa : "琵", 0x94fb : "眉", 0x94fc : "美", 0x9540 : "鼻", 0x9541 : "柊", 0x9542 : "稗", 0x9543 : "匹", 0x9544 : "疋", 0x9545 : "髭", 0x9546 : "彦", 0x9547 : "膝", 0x9548 : "菱", 0x9549 : "肘", 0x954a : "弼", 0x954b : "必", 0x954c : "畢", 0x954d : "筆", 0x954e : "逼", 0x954f : "桧", 0x9550 : "姫", 0x9551 : "媛", 0x9552 : "紐", 0x9553 : "百", 0x9554 : "謬", 0x9555 : "俵", 0x9556 : "彪", 0x9557 : "標", 0x9558 : "氷", 0x9559 : "漂", 0x955a : "瓢", 0x955b : "票", 0x955c : "表", 0x955d : "評", 0x955e : "豹", 0x955f : "廟", 0x9560 : "描", 0x9561 : "病", 0x9562 : "秒", 0x9563 : "苗", 0x9564 : "錨", 0x9565 : "鋲", 0x9566 : "蒜", 0x9567 : "蛭", 0x9568 : "鰭", 0x9569 : "品", 0x956a : "彬", 0x956b : "斌", 0x956c : "浜", 0x956d : "瀕", 0x956e : "貧", 0x956f : "賓", 0x9570 : "頻", 0x9571 : "敏", 0x9572 : "瓶", 0x9573 : "不", 0x9574 : "付", 0x9575 : "埠", 0x9576 : "夫", 0x9577 : "婦", 0x9578 : "富", 0x9579 : "冨", 0x957a : "布", 0x957b : "府", 0x957c : "怖", 0x957d : "扶", 0x957e : "敷", 0x9580 : "斧", 0x9581 : "普", 0x9582 : "浮", 0x9583 : "父", 0x9584 : "符", 0x9585 : "腐", 0x9586 : "膚", 0x9587 : "芙", 0x9588 : "譜", 0x9589 : "負", 0x958a : "賦", 0x958b : "赴", 0x958c : "阜", 0x958d : "附", 0x958e : "侮", 0x958f : "撫", 0x9590 : "武", 0x9591 : "舞", 0x9592 : "葡", 0x9593 : "蕪", 0x9594 : "部", 0x9595 : "封", 0x9596 : "楓", 0x9597 : "風", 0x9598 : "葺", 0x9599 : "蕗", 0x959a : "伏", 0x959b : "副", 0x959c : "復", 0x959d : "幅", 0x959e : "服", 0x959f : "福", 0x95a0 : "腹", 0x95a1 : "複", 0x95a2 : "覆", 0x95a3 : "淵", 0x95a4 : "弗", 0x95a5 : "払", 0x95a6 : "沸", 0x95a7 : "仏", 0x95a8 : "物", 0x95a9 : "鮒", 0x95aa : "分", 0x95ab : "吻", 0x95ac : "噴", 0x95ad : "墳", 0x95ae : "憤", 0x95af : "扮", 0x95b0 : "焚", 0x95b1 : "奮", 0x95b2 : "粉", 0x95b3 : "糞", 0x95b4 : "紛", 0x95b5 : "雰", 0x95b6 : "文", 0x95b7 : "聞", 0x95b8 : "丙", 0x95b9 : "併", 0x95ba : "兵", 0x95bb : "塀", 0x95bc : "幣", 0x95bd : "平", 0x95be : "弊", 0x95bf : "柄", 0x95c0 : "並", 0x95c1 : "蔽", 0x95c2 : "閉", 0x95c3 : "陛", 0x95c4 : "米", 0x95c5 : "頁", 0x95c6 : "僻", 0x95c7 : "壁", 0x95c8 : "癖", 0x95c9 : "碧", 0x95ca : "別", 0x95cb : "瞥", 0x95cc : "蔑", 0x95cd : "箆", 0x95ce : "偏", 0x95cf : "変", 0x95d0 : "片", 0x95d1 : "篇", 0x95d2 : "編", 0x95d3 : "辺", 0x95d4 : "返", 0x95d5 : "遍", 0x95d6 : "便", 0x95d7 : "勉", 0x95d8 : "娩", 0x95d9 : "弁", 0x95da : "鞭", 0x95db : "保", 0x95dc : "舗", 0x95dd : "鋪", 0x95de : "圃", 0x95df : "捕", 0x95e0 : "歩", 0x95e1 : "甫", 0x95e2 : "補", 0x95e3 : "輔", 0x95e4 : "穂", 0x95e5 : "募", 0x95e6 : "墓", 0x95e7 : "慕", 0x95e8 : "戊", 0x95e9 : "暮", 0x95ea : "母", 0x95eb : "簿", 0x95ec : "菩", 0x95ed : "倣", 0x95ee : "俸", 0x95ef : "包", 0x95f0 : "呆", 0x95f1 : "報", 0x95f2 : "奉", 0x95f3 : "宝", 0x95f4 : "峰", 0x95f5 : "峯", 0x95f6 : "崩", 0x95f7 : "庖", 0x95f8 : "抱", 0x95f9 : "捧", 0x95fa : "放", 0x95fb : "方", 0x95fc : "朋", 0x9640 : "法", 0x9641 : "泡", 0x9642 : "烹", 0x9643 : "砲", 0x9644 : "縫", 0x9645 : "胞", 0x9646 : "芳", 0x9647 : "萌", 0x9648 : "蓬", 0x9649 : "蜂", 0x964a : "褒", 0x964b : "訪", 0x964c : "豊", 0x964d : "邦", 0x964e : "鋒", 0x964f : "飽", 0x9650 : "鳳", 0x9651 : "鵬", 0x9652 : "乏", 0x9653 : "亡", 0x9654 : "傍", 0x9655 : "剖", 0x9656 : "坊", 0x9657 : "妨", 0x9658 : "帽", 0x9659 : "忘", 0x965a : "忙", 0x965b : "房", 0x965c : "暴", 0x965d : "望", 0x965e : "某", 0x965f : "棒", 0x9660 : "冒", 0x9661 : "紡", 0x9662 : "肪", 0x9663 : "膨", 0x9664 : "謀", 0x9665 : "貌", 0x9666 : "貿", 0x9667 : "鉾", 0x9668 : "防", 0x9669 : "吠", 0x966a : "頬", 0x966b : "北", 0x966c : "僕", 0x966d : "卜", 0x966e : "墨", 0x966f : "撲", 0x9670 : "朴", 0x9671 : "牧", 0x9672 : "睦", 0x9673 : "穆", 0x9674 : "釦", 0x9675 : "勃", 0x9676 : "没", 0x9677 : "殆", 0x9678 : "堀", 0x9679 : "幌", 0x967a : "奔", 0x967b : "本", 0x967c : "翻", 0x967d : "凡", 0x967e : "盆", 0x9680 : "摩", 0x9681 : "磨", 0x9682 : "魔", 0x9683 : "麻", 0x9684 : "埋", 0x9685 : "妹", 0x9686 : "昧", 0x9687 : "枚", 0x9688 : "毎", 0x9689 : "哩", 0x968a : "槙", 0x968b : "幕", 0x968c : "膜", 0x968d : "枕", 0x968e : "鮪", 0x968f : "柾", 0x9690 : "鱒", 0x9691 : "桝", 0x9692 : "亦", 0x9693 : "俣", 0x9694 : "又", 0x9695 : "抹", 0x9696 : "末", 0x9697 : "沫", 0x9698 : "迄", 0x9699 : "侭", 0x969a : "繭", 0x969b : "麿", 0x969c : "万", 0x969d : "慢", 0x969e : "満", 0x969f : "漫", 0x96a0 : "蔓", 0x96a1 : "味", 0x96a2 : "未", 0x96a3 : "魅", 0x96a4 : "巳", 0x96a5 : "箕", 0x96a6 : "岬", 0x96a7 : "密", 0x96a8 : "蜜", 0x96a9 : "湊", 0x96aa : "蓑", 0x96ab : "稔", 0x96ac : "脈", 0x96ad : "妙", 0x96ae : "粍", 0x96af : "民", 0x96b0 : "眠", 0x96b1 : "務", 0x96b2 : "夢", 0x96b3 : "無", 0x96b4 : "牟", 0x96b5 : "矛", 0x96b6 : "霧", 0x96b7 : "鵡", 0x96b8 : "椋", 0x96b9 : "婿", 0x96ba : "娘", 0x96bb : "冥", 0x96bc : "名", 0x96bd : "命", 0x96be : "明", 0x96bf : "盟", 0x96c0 : "迷", 0x96c1 : "銘", 0x96c2 : "鳴", 0x96c3 : "姪", 0x96c4 : "牝", 0x96c5 : "滅", 0x96c6 : "免", 0x96c7 : "棉", 0x96c8 : "綿", 0x96c9 : "緬", 0x96ca : "面", 0x96cb : "麺", 0x96cc : "摸", 0x96cd : "模", 0x96ce : "茂", 0x96cf : "妄", 0x96d0 : "孟", 0x96d1 : "毛", 0x96d2 : "猛", 0x96d3 : "盲", 0x96d4 : "網", 0x96d5 : "耗", 0x96d6 : "蒙", 0x96d7 : "儲", 0x96d8 : "木", 0x96d9 : "黙", 0x96da : "目", 0x96db : "杢", 0x96dc : "勿", 0x96dd : "餅", 0x96de : "尤", 0x96df : "戻", 0x96e0 : "籾", 0x96e1 : "貰", 0x96e2 : "問", 0x96e3 : "悶", 0x96e4 : "紋", 0x96e5 : "門", 0x96e6 : "匁", 0x96e7 : "也", 0x96e8 : "冶", 0x96e9 : "夜", 0x96ea : "爺", 0x96eb : "耶", 0x96ec : "野", 0x96ed : "弥", 0x96ee : "矢", 0x96ef : "厄", 0x96f0 : "役", 0x96f1 : "約", 0x96f2 : "薬", 0x96f3 : "訳", 0x96f4 : "躍", 0x96f5 : "靖", 0x96f6 : "柳", 0x96f7 : "薮", 0x96f8 : "鑓", 0x96f9 : "愉", 0x96fa : "愈", 0x96fb : "油", 0x96fc : "癒", 0x9740 : "諭", 0x9741 : "輸", 0x9742 : "唯", 0x9743 : "佑", 0x9744 : "優", 0x9745 : "勇", 0x9746 : "友", 0x9747 : "宥", 0x9748 : "幽", 0x9749 : "悠", 0x974a : "憂", 0x974b : "揖", 0x974c : "有", 0x974d : "柚", 0x974e : "湧", 0x974f : "涌", 0x9750 : "猶", 0x9751 : "猷", 0x9752 : "由", 0x9753 : "祐", 0x9754 : "裕", 0x9755 : "誘", 0x9756 : "遊", 0x9757 : "邑", 0x9758 : "郵", 0x9759 : "雄", 0x975a : "融", 0x975b : "夕", 0x975c : "予", 0x975d : "余", 0x975e : "与", 0x975f : "誉", 0x9760 : "輿", 0x9761 : "預", 0x9762 : "傭", 0x9763 : "幼", 0x9764 : "妖", 0x9765 : "容", 0x9766 : "庸", 0x9767 : "揚", 0x9768 : "揺", 0x9769 : "擁", 0x976a : "曜", 0x976b : "楊", 0x976c : "様", 0x976d : "洋", 0x976e : "溶", 0x976f : "熔", 0x9770 : "用", 0x9771 : "窯", 0x9772 : "羊", 0x9773 : "耀", 0x9774 : "葉", 0x9775 : "蓉", 0x9776 : "要", 0x9777 : "謡", 0x9778 : "踊", 0x9779 : "遥", 0x977a : "陽", 0x977b : "養", 0x977c : "慾", 0x977d : "抑", 0x977e : "欲", 0x9780 : "沃", 0x9781 : "浴", 0x9782 : "翌", 0x9783 : "翼", 0x9784 : "淀", 0x9785 : "羅", 0x9786 : "螺", 0x9787 : "裸", 0x9788 : "来", 0x9789 : "莱", 0x978a : "頼", 0x978b : "雷", 0x978c : "洛", 0x978d : "絡", 0x978e : "落", 0x978f : "酪", 0x9790 : "乱", 0x9791 : "卵", 0x9792 : "嵐", 0x9793 : "欄", 0x9794 : "濫", 0x9795 : "藍", 0x9796 : "蘭", 0x9797 : "覧", 0x9798 : "利", 0x9799 : "吏", 0x979a : "履", 0x979b : "李", 0x979c : "梨", 0x979d : "理", 0x979e : "璃", 0x979f : "痢", 0x97a0 : "裏", 0x97a1 : "裡", 0x97a2 : "里", 0x97a3 : "離", 0x97a4 : "陸", 0x97a5 : "律", 0x97a6 : "率", 0x97a7 : "立", 0x97a8 : "葎", 0x97a9 : "掠", 0x97aa : "略", 0x97ab : "劉", 0x97ac : "流", 0x97ad : "溜", 0x97ae : "琉", 0x97af : "留", 0x97b0 : "硫", 0x97b1 : "粒", 0x97b2 : "隆", 0x97b3 : "竜", 0x97b4 : "龍", 0x97b5 : "侶", 0x97b6 : "慮", 0x97b7 : "旅", 0x97b8 : "虜", 0x97b9 : "了", 0x97ba : "亮", 0x97bb : "僚", 0x97bc : "両", 0x97bd : "凌", 0x97be : "寮", 0x97bf : "料", 0x97c0 : "梁", 0x97c1 : "涼", 0x97c2 : "猟", 0x97c3 : "療", 0x97c4 : "瞭", 0x97c5 : "稜", 0x97c6 : "糧", 0x97c7 : "良", 0x97c8 : "諒", 0x97c9 : "遼", 0x97ca : "量", 0x97cb : "陵", 0x97cc : "領", 0x97cd : "力", 0x97ce : "緑", 0x97cf : "倫", 0x97d0 : "厘", 0x97d1 : "林", 0x97d2 : "淋", 0x97d3 : "燐", 0x97d4 : "琳", 0x97d5 : "臨", 0x97d6 : "輪", 0x97d7 : "隣", 0x97d8 : "鱗", 0x97d9 : "麟", 0x97da : "瑠", 0x97db : "塁", 0x97dc : "涙", 0x97dd : "累", 0x97de : "類", 0x97df : "令", 0x97e0 : "伶", 0x97e1 : "例", 0x97e2 : "冷", 0x97e3 : "励", 0x97e4 : "嶺", 0x97e5 : "怜", 0x97e6 : "玲", 0x97e7 : "礼", 0x97e8 : "苓", 0x97e9 : "鈴", 0x97ea : "隷", 0x97eb : "零", 0x97ec : "霊", 0x97ed : "麗", 0x97ee : "齢", 0x97ef : "暦", 0x97f0 : "歴", 0x97f1 : "列", 0x97f2 : "劣", 0x97f3 : "烈", 0x97f4 : "裂", 0x97f5 : "廉", 0x97f6 : "恋", 0x97f7 : "憐", 0x97f8 : "漣", 0x97f9 : "煉", 0x97fa : "簾", 0x97fb : "練", 0x97fc : "聯", 0x9840 : "蓮", 0x9841 : "連", 0x9842 : "錬", 0x9843 : "呂", 0x9844 : "魯", 0x9845 : "櫓", 0x9846 : "炉", 0x9847 : "賂", 0x9848 : "路", 0x9849 : "露", 0x984a : "労", 0x984b : "婁", 0x984c : "廊", 0x984d : "弄", 0x984e : "朗", 0x984f : "楼", 0x9850 : "榔", 0x9851 : "浪", 0x9852 : "漏", 0x9853 : "牢", 0x9854 : "狼", 0x9855 : "篭", 0x9856 : "老", 0x9857 : "聾", 0x9858 : "蝋", 0x9859 : "郎", 0x985a : "六", 0x985b : "麓", 0x985c : "禄", 0x985d : "肋", 0x985e : "録", 0x985f : "論", 0x9860 : "倭", 0x9861 : "和", 0x9862 : "話", 0x9863 : "歪", 0x9864 : "賄", 0x9865 : "脇", 0x9866 : "惑", 0x9867 : "枠", 0x9868 : "鷲", 0x9869 : "亙", 0x986a : "亘", 0x986b : "鰐", 0x986c : "詫", 0x986d : "藁", 0x986e : "蕨", 0x986f : "椀", 0x9870 : "湾", 0x9871 : "碗", 0x9872 : "腕", 0x989f : "弌", 0x98a0 : "丐", 0x98a1 : "丕", 0x98a2 : "个", 0x98a3 : "丱", 0x98a4 : "丶", 0x98a5 : "丼", 0x98a6 : "丿", 0x98a7 : "乂", 0x98a8 : "乖", 0x98a9 : "乘", 0x98aa : "亂", 0x98ab : "亅", 0x98ac : "豫", 0x98ad : "亊", 0x98ae : "舒", 0x98af : "弍", 0x98b0 : "于", 0x98b1 : "亞", 0x98b2 : "亟", 0x98b3 : "亠", 0x98b4 : "亢", 0x98b5 : "亰", 0x98b6 : "亳", 0x98b7 : "亶", 0x98b8 : "从", 0x98b9 : "仍", 0x98ba : "仄", 0x98bb : "仆", 0x98bc : "仂", 0x98bd : "仗", 0x98be : "仞", 0x98bf : "仭", 0x98c0 : "仟", 0x98c1 : "价", 0x98c2 : "伉", 0x98c3 : "佚", 0x98c4 : "估", 0x98c5 : "佛", 0x98c6 : "佝", 0x98c7 : "佗", 0x98c8 : "佇", 0x98c9 : "佶", 0x98ca : "侈", 0x98cb : "侏", 0x98cc : "侘", 0x98cd : "佻", 0x98ce : "佩", 0x98cf : "佰", 0x98d0 : "侑", 0x98d1 : "佯", 0x98d2 : "來", 0x98d3 : "侖", 0x98d4 : "儘", 0x98d5 : "俔", 0x98d6 : "俟", 0x98d7 : "俎", 0x98d8 : "俘", 0x98d9 : "俛", 0x98da : "俑", 0x98db : "俚", 0x98dc : "俐", 0x98dd : "俤", 0x98de : "俥", 0x98df : "倚", 0x98e0 : "倨", 0x98e1 : "倔", 0x98e2 : "倪", 0x98e3 : "倥", 0x98e4 : "倅", 0x98e5 : "伜", 0x98e6 : "俶", 0x98e7 : "倡", 0x98e8 : "倩", 0x98e9 : "倬", 0x98ea : "俾", 0x98eb : "俯", 0x98ec : "們", 0x98ed : "倆", 0x98ee : "偃", 0x98ef : "假", 0x98f0 : "會", 0x98f1 : "偕", 0x98f2 : "偐", 0x98f3 : "偈", 0x98f4 : "做", 0x98f5 : "偖", 0x98f6 : "偬", 0x98f7 : "偸", 0x98f8 : "傀", 0x98f9 : "傚", 0x98fa : "傅", 0x98fb : "傴", 0x98fc : "傲", 0x9940 : "僉", 0x9941 : "僊", 0x9942 : "傳", 0x9943 : "僂", 0x9944 : "僖", 0x9945 : "僞", 0x9946 : "僥", 0x9947 : "僭", 0x9948 : "僣", 0x9949 : "僮", 0x994a : "價", 0x994b : "僵", 0x994c : "儉", 0x994d : "儁", 0x994e : "儂", 0x994f : "儖", 0x9950 : "儕", 0x9951 : "儔", 0x9952 : "儚", 0x9953 : "儡", 0x9954 : "儺", 0x9955 : "儷", 0x9956 : "儼", 0x9957 : "儻", 0x9958 : "儿", 0x9959 : "兀", 0x995a : "兒", 0x995b : "兌", 0x995c : "兔", 0x995d : "兢", 0x995e : "竸", 0x995f : "兩", 0x9960 : "兪", 0x9961 : "兮", 0x9962 : "冀", 0x9963 : "冂", 0x9964 : "囘", 0x9965 : "册", 0x9966 : "冉", 0x9967 : "冏", 0x9968 : "冑", 0x9969 : "冓", 0x996a : "冕", 0x996b : "冖", 0x996c : "冤", 0x996d : "冦", 0x996e : "冢", 0x996f : "冩", 0x9970 : "冪", 0x9971 : "冫", 0x9972 : "决", 0x9973 : "冱", 0x9974 : "冲", 0x9975 : "冰", 0x9976 : "况", 0x9977 : "冽", 0x9978 : "凅", 0x9979 : "凉", 0x997a : "凛", 0x997b : "几", 0x997c : "處", 0x997d : "凩", 0x997e : "凭", 0x9980 : "凰", 0x9981 : "凵", 0x9982 : "凾", 0x9983 : "刄", 0x9984 : "刋", 0x9985 : "刔", 0x9986 : "刎", 0x9987 : "刧", 0x9988 : "刪", 0x9989 : "刮", 0x998a : "刳", 0x998b : "刹", 0x998c : "剏", 0x998d : "剄", 0x998e : "剋", 0x998f : "剌", 0x9990 : "剞", 0x9991 : "剔", 0x9992 : "剪", 0x9993 : "剴", 0x9994 : "剩", 0x9995 : "剳", 0x9996 : "剿", 0x9997 : "剽", 0x9998 : "劍", 0x9999 : "劔", 0x999a : "劒", 0x999b : "剱", 0x999c : "劈", 0x999d : "劑", 0x999e : "辨", 0x999f : "辧", 0x99a0 : "劬", 0x99a1 : "劭", 0x99a2 : "劼", 0x99a3 : "劵", 0x99a4 : "勁", 0x99a5 : "勍", 0x99a6 : "勗", 0x99a7 : "勞", 0x99a8 : "勣", 0x99a9 : "勦", 0x99aa : "飭", 0x99ab : "勠", 0x99ac : "勳", 0x99ad : "勵", 0x99ae : "勸", 0x99af : "勹", 0x99b0 : "匆", 0x99b1 : "匈", 0x99b2 : "甸", 0x99b3 : "匍", 0x99b4 : "匐", 0x99b5 : "匏", 0x99b6 : "匕", 0x99b7 : "匚", 0x99b8 : "匣", 0x99b9 : "匯", 0x99ba : "匱", 0x99bb : "匳", 0x99bc : "匸", 0x99bd : "區", 0x99be : "卆", 0x99bf : "卅", 0x99c0 : "丗", 0x99c1 : "卉", 0x99c2 : "卍", 0x99c3 : "凖", 0x99c4 : "卞", 0x99c5 : "卩", 0x99c6 : "卮", 0x99c7 : "夘", 0x99c8 : "卻", 0x99c9 : "卷", 0x99ca : "厂", 0x99cb : "厖", 0x99cc : "厠", 0x99cd : "厦", 0x99ce : "厥", 0x99cf : "厮", 0x99d0 : "厰", 0x99d1 : "厶", 0x99d2 : "參", 0x99d3 : "簒", 0x99d4 : "雙", 0x99d5 : "叟", 0x99d6 : "曼", 0x99d7 : "燮", 0x99d8 : "叮", 0x99d9 : "叨", 0x99da : "叭", 0x99db : "叺", 0x99dc : "吁", 0x99dd : "吽", 0x99de : "呀", 0x99df : "听", 0x99e0 : "吭", 0x99e1 : "吼", 0x99e2 : "吮", 0x99e3 : "吶", 0x99e4 : "吩", 0x99e5 : "吝", 0x99e6 : "呎", 0x99e7 : "咏", 0x99e8 : "呵", 0x99e9 : "咎", 0x99ea : "呟", 0x99eb : "呱", 0x99ec : "呷", 0x99ed : "呰", 0x99ee : "咒", 0x99ef : "呻", 0x99f0 : "咀", 0x99f1 : "呶", 0x99f2 : "咄", 0x99f3 : "咐", 0x99f4 : "咆", 0x99f5 : "哇", 0x99f6 : "咢", 0x99f7 : "咸", 0x99f8 : "咥", 0x99f9 : "咬", 0x99fa : "哄", 0x99fb : "哈", 0x99fc : "咨", 0x9a40 : "咫", 0x9a41 : "哂", 0x9a42 : "咤", 0x9a43 : "咾", 0x9a44 : "咼", 0x9a45 : "哘", 0x9a46 : "哥", 0x9a47 : "哦", 0x9a48 : "唏", 0x9a49 : "唔", 0x9a4a : "哽", 0x9a4b : "哮", 0x9a4c : "哭", 0x9a4d : "哺", 0x9a4e : "哢", 0x9a4f : "唹", 0x9a50 : "啀", 0x9a51 : "啣", 0x9a52 : "啌", 0x9a53 : "售", 0x9a54 : "啜", 0x9a55 : "啅", 0x9a56 : "啖", 0x9a57 : "啗", 0x9a58 : "唸", 0x9a59 : "唳", 0x9a5a : "啝", 0x9a5b : "喙", 0x9a5c : "喀", 0x9a5d : "咯", 0x9a5e : "喊", 0x9a5f : "喟", 0x9a60 : "啻", 0x9a61 : "啾", 0x9a62 : "喘", 0x9a63 : "喞", 0x9a64 : "單", 0x9a65 : "啼", 0x9a66 : "喃", 0x9a67 : "喩", 0x9a68 : "喇", 0x9a69 : "喨", 0x9a6a : "嗚", 0x9a6b : "嗅", 0x9a6c : "嗟", 0x9a6d : "嗄", 0x9a6e : "嗜", 0x9a6f : "嗤", 0x9a70 : "嗔", 0x9a71 : "嘔", 0x9a72 : "嗷", 0x9a73 : "嘖", 0x9a74 : "嗾", 0x9a75 : "嗽", 0x9a76 : "嘛", 0x9a77 : "嗹", 0x9a78 : "噎", 0x9a79 : "噐", 0x9a7a : "營", 0x9a7b : "嘴", 0x9a7c : "嘶", 0x9a7d : "嘲", 0x9a7e : "嘸", 0x9a80 : "噫", 0x9a81 : "噤", 0x9a82 : "嘯", 0x9a83 : "噬", 0x9a84 : "噪", 0x9a85 : "嚆", 0x9a86 : "嚀", 0x9a87 : "嚊", 0x9a88 : "嚠", 0x9a89 : "嚔", 0x9a8a : "嚏", 0x9a8b : "嚥", 0x9a8c : "嚮", 0x9a8d : "嚶", 0x9a8e : "嚴", 0x9a8f : "囂", 0x9a90 : "嚼", 0x9a91 : "囁", 0x9a92 : "囃", 0x9a93 : "囀", 0x9a94 : "囈", 0x9a95 : "囎", 0x9a96 : "囑", 0x9a97 : "囓", 0x9a98 : "囗", 0x9a99 : "囮", 0x9a9a : "囹", 0x9a9b : "圀", 0x9a9c : "囿", 0x9a9d : "圄", 0x9a9e : "圉", 0x9a9f : "圈", 0x9aa0 : "國", 0x9aa1 : "圍", 0x9aa2 : "圓", 0x9aa3 : "團", 0x9aa4 : "圖", 0x9aa5 : "嗇", 0x9aa6 : "圜", 0x9aa7 : "圦", 0x9aa8 : "圷", 0x9aa9 : "圸", 0x9aaa : "坎", 0x9aab : "圻", 0x9aac : "址", 0x9aad : "坏", 0x9aae : "坩", 0x9aaf : "埀", 0x9ab0 : "垈", 0x9ab1 : "坡", 0x9ab2 : "坿", 0x9ab3 : "垉", 0x9ab4 : "垓", 0x9ab5 : "垠", 0x9ab6 : "垳", 0x9ab7 : "垤", 0x9ab8 : "垪", 0x9ab9 : "垰", 0x9aba : "埃", 0x9abb : "埆", 0x9abc : "埔", 0x9abd : "埒", 0x9abe : "埓", 0x9abf : "堊", 0x9ac0 : "埖", 0x9ac1 : "埣", 0x9ac2 : "堋", 0x9ac3 : "堙", 0x9ac4 : "堝", 0x9ac5 : "塲", 0x9ac6 : "堡", 0x9ac7 : "塢", 0x9ac8 : "塋", 0x9ac9 : "塰", 0x9aca : "毀", 0x9acb : "塒", 0x9acc : "堽", 0x9acd : "塹", 0x9ace : "墅", 0x9acf : "墹", 0x9ad0 : "墟", 0x9ad1 : "墫", 0x9ad2 : "墺", 0x9ad3 : "壞", 0x9ad4 : "墻", 0x9ad5 : "墸", 0x9ad6 : "墮", 0x9ad7 : "壅", 0x9ad8 : "壓", 0x9ad9 : "壑", 0x9ada : "壗", 0x9adb : "壙", 0x9adc : "壘", 0x9add : "壥", 0x9ade : "壜", 0x9adf : "壤", 0x9ae0 : "壟", 0x9ae1 : "壯", 0x9ae2 : "壺", 0x9ae3 : "壹", 0x9ae4 : "壻", 0x9ae5 : "壼", 0x9ae6 : "壽", 0x9ae7 : "夂", 0x9ae8 : "夊", 0x9ae9 : "夐", 0x9aea : "夛", 0x9aeb : "梦", 0x9aec : "夥", 0x9aed : "夬", 0x9aee : "夭", 0x9aef : "夲", 0x9af0 : "夸", 0x9af1 : "夾", 0x9af2 : "竒", 0x9af3 : "奕", 0x9af4 : "奐", 0x9af5 : "奎", 0x9af6 : "奚", 0x9af7 : "奘", 0x9af8 : "奢", 0x9af9 : "奠", 0x9afa : "奧", 0x9afb : "奬", 0x9afc : "奩", 0x9b40 : "奸", 0x9b41 : "妁", 0x9b42 : "妝", 0x9b43 : "佞", 0x9b44 : "侫", 0x9b45 : "妣", 0x9b46 : "妲", 0x9b47 : "姆", 0x9b48 : "姨", 0x9b49 : "姜", 0x9b4a : "妍", 0x9b4b : "姙", 0x9b4c : "姚", 0x9b4d : "娥", 0x9b4e : "娟", 0x9b4f : "娑", 0x9b50 : "娜", 0x9b51 : "娉", 0x9b52 : "娚", 0x9b53 : "婀", 0x9b54 : "婬", 0x9b55 : "婉", 0x9b56 : "娵", 0x9b57 : "娶", 0x9b58 : "婢", 0x9b59 : "婪", 0x9b5a : "媚", 0x9b5b : "媼", 0x9b5c : "媾", 0x9b5d : "嫋", 0x9b5e : "嫂", 0x9b5f : "媽", 0x9b60 : "嫣", 0x9b61 : "嫗", 0x9b62 : "嫦", 0x9b63 : "嫩", 0x9b64 : "嫖", 0x9b65 : "嫺", 0x9b66 : "嫻", 0x9b67 : "嬌", 0x9b68 : "嬋", 0x9b69 : "嬖", 0x9b6a : "嬲", 0x9b6b : "嫐", 0x9b6c : "嬪", 0x9b6d : "嬶", 0x9b6e : "嬾", 0x9b6f : "孃", 0x9b70 : "孅", 0x9b71 : "孀", 0x9b72 : "孑", 0x9b73 : "孕", 0x9b74 : "孚", 0x9b75 : "孛", 0x9b76 : "孥", 0x9b77 : "孩", 0x9b78 : "孰", 0x9b79 : "孳", 0x9b7a : "孵", 0x9b7b : "學", 0x9b7c : "斈", 0x9b7d : "孺", 0x9b7e : "宀", 0x9b80 : "它", 0x9b81 : "宦", 0x9b82 : "宸", 0x9b83 : "寃", 0x9b84 : "寇", 0x9b85 : "寉", 0x9b86 : "寔", 0x9b87 : "寐", 0x9b88 : "寤", 0x9b89 : "實", 0x9b8a : "寢", 0x9b8b : "寞", 0x9b8c : "寥", 0x9b8d : "寫", 0x9b8e : "寰", 0x9b8f : "寶", 0x9b90 : "寳", 0x9b91 : "尅", 0x9b92 : "將", 0x9b93 : "專", 0x9b94 : "對", 0x9b95 : "尓", 0x9b96 : "尠", 0x9b97 : "尢", 0x9b98 : "尨", 0x9b99 : "尸", 0x9b9a : "尹", 0x9b9b : "屁", 0x9b9c : "屆", 0x9b9d : "屎", 0x9b9e : "屓", 0x9b9f : "屐", 0x9ba0 : "屏", 0x9ba1 : "孱", 0x9ba2 : "屬", 0x9ba3 : "屮", 0x9ba4 : "乢", 0x9ba5 : "屶", 0x9ba6 : "屹", 0x9ba7 : "岌", 0x9ba8 : "岑", 0x9ba9 : "岔", 0x9baa : "妛", 0x9bab : "岫", 0x9bac : "岻", 0x9bad : "岶", 0x9bae : "岼", 0x9baf : "岷", 0x9bb0 : "峅", 0x9bb1 : "岾", 0x9bb2 : "峇", 0x9bb3 : "峙", 0x9bb4 : "峩", 0x9bb5 : "峽", 0x9bb6 : "峺", 0x9bb7 : "峭", 0x9bb8 : "嶌", 0x9bb9 : "峪", 0x9bba : "崋", 0x9bbb : "崕", 0x9bbc : "崗", 0x9bbd : "嵜", 0x9bbe : "崟", 0x9bbf : "崛", 0x9bc0 : "崑", 0x9bc1 : "崔", 0x9bc2 : "崢", 0x9bc3 : "崚", 0x9bc4 : "崙", 0x9bc5 : "崘", 0x9bc6 : "嵌", 0x9bc7 : "嵒", 0x9bc8 : "嵎", 0x9bc9 : "嵋", 0x9bca : "嵬", 0x9bcb : "嵳", 0x9bcc : "嵶", 0x9bcd : "嶇", 0x9bce : "嶄", 0x9bcf : "嶂", 0x9bd0 : "嶢", 0x9bd1 : "嶝", 0x9bd2 : "嶬", 0x9bd3 : "嶮", 0x9bd4 : "嶽", 0x9bd5 : "嶐", 0x9bd6 : "嶷", 0x9bd7 : "嶼", 0x9bd8 : "巉", 0x9bd9 : "巍", 0x9bda : "巓", 0x9bdb : "巒", 0x9bdc : "巖", 0x9bdd : "巛", 0x9bde : "巫", 0x9bdf : "已", 0x9be0 : "巵", 0x9be1 : "帋", 0x9be2 : "帚", 0x9be3 : "帙", 0x9be4 : "帑", 0x9be5 : "帛", 0x9be6 : "帶", 0x9be7 : "帷", 0x9be8 : "幄", 0x9be9 : "幃", 0x9bea : "幀", 0x9beb : "幎", 0x9bec : "幗", 0x9bed : "幔", 0x9bee : "幟", 0x9bef : "幢", 0x9bf0 : "幤", 0x9bf1 : "幇", 0x9bf2 : "幵", 0x9bf3 : "并", 0x9bf4 : "幺", 0x9bf5 : "麼", 0x9bf6 : "广", 0x9bf7 : "庠", 0x9bf8 : "廁", 0x9bf9 : "廂", 0x9bfa : "廈", 0x9bfb : "廐", 0x9bfc : "廏", 0x9c40 : "廖", 0x9c41 : "廣", 0x9c42 : "廝", 0x9c43 : "廚", 0x9c44 : "廛", 0x9c45 : "廢", 0x9c46 : "廡", 0x9c47 : "廨", 0x9c48 : "廩", 0x9c49 : "廬", 0x9c4a : "廱", 0x9c4b : "廳", 0x9c4c : "廰", 0x9c4d : "廴", 0x9c4e : "廸", 0x9c4f : "廾", 0x9c50 : "弃", 0x9c51 : "弉", 0x9c52 : "彝", 0x9c53 : "彜", 0x9c54 : "弋", 0x9c55 : "弑", 0x9c56 : "弖", 0x9c57 : "弩", 0x9c58 : "弭", 0x9c59 : "弸", 0x9c5a : "彁", 0x9c5b : "彈", 0x9c5c : "彌", 0x9c5d : "彎", 0x9c5e : "弯", 0x9c5f : "彑", 0x9c60 : "彖", 0x9c61 : "彗", 0x9c62 : "彙", 0x9c63 : "彡", 0x9c64 : "彭", 0x9c65 : "彳", 0x9c66 : "彷", 0x9c67 : "徃", 0x9c68 : "徂", 0x9c69 : "彿", 0x9c6a : "徊", 0x9c6b : "很", 0x9c6c : "徑", 0x9c6d : "徇", 0x9c6e : "從", 0x9c6f : "徙", 0x9c70 : "徘", 0x9c71 : "徠", 0x9c72 : "徨", 0x9c73 : "徭", 0x9c74 : "徼", 0x9c75 : "忖", 0x9c76 : "忻", 0x9c77 : "忤", 0x9c78 : "忸", 0x9c79 : "忱", 0x9c7a : "忝", 0x9c7b : "悳", 0x9c7c : "忿", 0x9c7d : "怡", 0x9c7e : "恠", 0x9c80 : "怙", 0x9c81 : "怐", 0x9c82 : "怩", 0x9c83 : "怎", 0x9c84 : "怱", 0x9c85 : "怛", 0x9c86 : "怕", 0x9c87 : "怫", 0x9c88 : "怦", 0x9c89 : "怏", 0x9c8a : "怺", 0x9c8b : "恚", 0x9c8c : "恁", 0x9c8d : "恪", 0x9c8e : "恷", 0x9c8f : "恟", 0x9c90 : "恊", 0x9c91 : "恆", 0x9c92 : "恍", 0x9c93 : "恣", 0x9c94 : "恃", 0x9c95 : "恤", 0x9c96 : "恂", 0x9c97 : "恬", 0x9c98 : "恫", 0x9c99 : "恙", 0x9c9a : "悁", 0x9c9b : "悍", 0x9c9c : "惧", 0x9c9d : "悃", 0x9c9e : "悚", 0x9c9f : "悄", 0x9ca0 : "悛", 0x9ca1 : "悖", 0x9ca2 : "悗", 0x9ca3 : "悒", 0x9ca4 : "悧", 0x9ca5 : "悋", 0x9ca6 : "惡", 0x9ca7 : "悸", 0x9ca8 : "惠", 0x9ca9 : "惓", 0x9caa : "悴", 0x9cab : "忰", 0x9cac : "悽", 0x9cad : "惆", 0x9cae : "悵", 0x9caf : "惘", 0x9cb0 : "慍", 0x9cb1 : "愕", 0x9cb2 : "愆", 0x9cb3 : "惶", 0x9cb4 : "惷", 0x9cb5 : "愀", 0x9cb6 : "惴", 0x9cb7 : "惺", 0x9cb8 : "愃", 0x9cb9 : "愡", 0x9cba : "惻", 0x9cbb : "惱", 0x9cbc : "愍", 0x9cbd : "愎", 0x9cbe : "慇", 0x9cbf : "愾", 0x9cc0 : "愨", 0x9cc1 : "愧", 0x9cc2 : "慊", 0x9cc3 : "愿", 0x9cc4 : "愼", 0x9cc5 : "愬", 0x9cc6 : "愴", 0x9cc7 : "愽", 0x9cc8 : "慂", 0x9cc9 : "慄", 0x9cca : "慳", 0x9ccb : "慷", 0x9ccc : "慘", 0x9ccd : "慙", 0x9cce : "慚", 0x9ccf : "慫", 0x9cd0 : "慴", 0x9cd1 : "慯", 0x9cd2 : "慥", 0x9cd3 : "慱", 0x9cd4 : "慟", 0x9cd5 : "慝", 0x9cd6 : "慓", 0x9cd7 : "慵", 0x9cd8 : "憙", 0x9cd9 : "憖", 0x9cda : "憇", 0x9cdb : "憬", 0x9cdc : "憔", 0x9cdd : "憚", 0x9cde : "憊", 0x9cdf : "憑", 0x9ce0 : "憫", 0x9ce1 : "憮", 0x9ce2 : "懌", 0x9ce3 : "懊", 0x9ce4 : "應", 0x9ce5 : "懷", 0x9ce6 : "懈", 0x9ce7 : "懃", 0x9ce8 : "懆", 0x9ce9 : "憺", 0x9cea : "懋", 0x9ceb : "罹", 0x9cec : "懍", 0x9ced : "懦", 0x9cee : "懣", 0x9cef : "懶", 0x9cf0 : "懺", 0x9cf1 : "懴", 0x9cf2 : "懿", 0x9cf3 : "懽", 0x9cf4 : "懼", 0x9cf5 : "懾", 0x9cf6 : "戀", 0x9cf7 : "戈", 0x9cf8 : "戉", 0x9cf9 : "戍", 0x9cfa : "戌", 0x9cfb : "戔", 0x9cfc : "戛", 0x9d40 : "戞", 0x9d41 : "戡", 0x9d42 : "截", 0x9d43 : "戮", 0x9d44 : "戰", 0x9d45 : "戲", 0x9d46 : "戳", 0x9d47 : "扁", 0x9d48 : "扎", 0x9d49 : "扞", 0x9d4a : "扣", 0x9d4b : "扛", 0x9d4c : "扠", 0x9d4d : "扨", 0x9d4e : "扼", 0x9d4f : "抂", 0x9d50 : "抉", 0x9d51 : "找", 0x9d52 : "抒", 0x9d53 : "抓", 0x9d54 : "抖", 0x9d55 : "拔", 0x9d56 : "抃", 0x9d57 : "抔", 0x9d58 : "拗", 0x9d59 : "拑", 0x9d5a : "抻", 0x9d5b : "拏", 0x9d5c : "拿", 0x9d5d : "拆", 0x9d5e : "擔", 0x9d5f : "拈", 0x9d60 : "拜", 0x9d61 : "拌", 0x9d62 : "拊", 0x9d63 : "拂", 0x9d64 : "拇", 0x9d65 : "抛", 0x9d66 : "拉", 0x9d67 : "挌", 0x9d68 : "拮", 0x9d69 : "拱", 0x9d6a : "挧", 0x9d6b : "挂", 0x9d6c : "挈", 0x9d6d : "拯", 0x9d6e : "拵", 0x9d6f : "捐", 0x9d70 : "挾", 0x9d71 : "捍", 0x9d72 : "搜", 0x9d9f : "據", 0x9da0 : "擒", 0x9da1 : "擅", 0x9da2 : "擇", 0x9da3 : "撻", 0x9da4 : "擘", 0x9da5 : "擂", 0x9da6 : "擱", 0x9da7 : "擧", 0x9da8 : "舉", 0x9da9 : "擠", 0x9daa : "擡", 0x9dab : "抬", 0x9dac : "擣", 0x9dad : "擯", 0x9dae : "攬", 0x9daf : "擶", 0x9db0 : "擴", 0x9db1 : "擲", 0x9db2 : "擺", 0x9db3 : "攀", 0x9db4 : "擽", 0x9db5 : "攘", 0x9db6 : "攜", 0x9db7 : "攅", 0x9db8 : "攤", 0x9db9 : "攣", 0x9dba : "攫", 0x9dbb : "攴", 0x9dbc : "攵", 0x9dbd : "攷", 0x9dbe : "收", 0x9dbf : "攸", 0x9dc0 : "畋", 0x9dc1 : "效", 0x9dc2 : "敖", 0x9dc3 : "敕", 0x9dc4 : "敍", 0x9dc5 : "敘", 0x9dc6 : "敞", 0x9dc7 : "敝", 0x9dc8 : "敲", 0x9dc9 : "數", 0x9dca : "斂", 0x9dcb : "斃", 0x9dcc : "變", 0x9dcd : "斛", 0x9dce : "斟", 0x9dcf : "斫", 0x9dd0 : "斷", 0x9dd1 : "旃", 0x9dd2 : "旆", 0x9dd3 : "旁", 0x9dd4 : "旄", 0x9dd5 : "旌", 0x9dd6 : "旒", 0x9dd7 : "旛", 0x9dd8 : "旙", 0x9dd9 : "无", 0x9dda : "旡", 0x9ddb : "旱", 0x9ddc : "杲", 0x9ddd : "昊", 0x9dde : "昃", 0x9ddf : "旻", 0x9de0 : "杳", 0x9de1 : "昵", 0x9de2 : "昶", 0x9de3 : "昴", 0x9de4 : "昜", 0x9de5 : "晏", 0x9de6 : "晄", 0x9de7 : "晉", 0x9de8 : "晁", 0x9de9 : "晞", 0x9dea : "晝", 0x9deb : "晤", 0x9dec : "晧", 0x9ded : "晨", 0x9dee : "晟", 0x9def : "晢", 0x9df0 : "晰", 0x9df1 : "暃", 0x9df2 : "暈", 0x9df3 : "暎", 0x9df4 : "暉", 0x9df5 : "暄", 0x9df6 : "暘", 0x9df7 : "暝", 0x9df8 : "曁", 0x9df9 : "暹", 0x9dfa : "曉", 0x9dfb : "暾", 0x9dfc : "暼", 0x9e40 : "曄", 0x9e41 : "暸", 0x9e42 : "曖", 0x9e43 : "曚", 0x9e44 : "曠", 0x9e45 : "昿", 0x9e46 : "曦", 0x9e47 : "曩", 0x9e48 : "曰", 0x9e49 : "曵", 0x9e4a : "曷", 0x9e4b : "朏", 0x9e4c : "朖", 0x9e4d : "朞", 0x9e4e : "朦", 0x9e4f : "朧", 0x9e50 : "霸", 0x9e51 : "朮", 0x9e52 : "朿", 0x9e53 : "朶", 0x9e54 : "杁", 0x9e55 : "朸", 0x9e56 : "朷", 0x9e57 : "杆", 0x9e58 : "杞", 0x9e59 : "杠", 0x9e5a : "杙", 0x9e5b : "杣", 0x9e5c : "杤", 0x9e5d : "枉", 0x9e5e : "杰", 0x9e5f : "枩", 0x9e60 : "杼", 0x9e61 : "杪", 0x9e62 : "枌", 0x9e63 : "枋", 0x9e64 : "枦", 0x9e65 : "枡", 0x9e66 : "枅", 0x9e67 : "枷", 0x9e68 : "柯", 0x9e69 : "枴", 0x9e6a : "柬", 0x9e6b : "枳", 0x9e6c : "柩", 0x9e6d : "枸", 0x9e6e : "柤", 0x9e6f : "柞", 0x9e70 : "柝", 0x9e71 : "柢", 0x9e72 : "柮", 0x9e73 : "枹", 0x9e74 : "柎", 0x9e75 : "柆", 0x9e76 : "柧", 0x9e77 : "檜", 0x9e78 : "栞", 0x9e79 : "框", 0x9e7a : "栩", 0x9e7b : "桀", 0x9e7c : "桍", 0x9e7d : "栲", 0x9e7e : "桎", 0x9e80 : "梳", 0x9e81 : "栫", 0x9e82 : "桙", 0x9e83 : "档", 0x9e84 : "桷", 0x9e85 : "桿", 0x9e86 : "梟", 0x9e87 : "梏", 0x9e88 : "梭", 0x9e89 : "梔", 0x9e8a : "條", 0x9e8b : "梛", 0x9e8c : "梃", 0x9e8d : "檮", 0x9e8e : "梹", 0x9e8f : "桴", 0x9e90 : "梵", 0x9e91 : "梠", 0x9e92 : "梺", 0x9e93 : "椏", 0x9e94 : "梍", 0x9e95 : "桾", 0x9e96 : "椁", 0x9e97 : "棊", 0x9e98 : "椈", 0x9e99 : "棘", 0x9e9a : "椢", 0x9e9b : "椦", 0x9e9c : "棡", 0x9e9d : "椌", 0x9e9e : "棍", 0x9e9f : "棔", 0x9ea0 : "棧", 0x9ea1 : "棕", 0x9ea2 : "椶", 0x9ea3 : "椒", 0x9ea4 : "椄", 0x9ea5 : "棗", 0x9ea6 : "棣", 0x9ea7 : "椥", 0x9ea8 : "棹", 0x9ea9 : "棠", 0x9eaa : "棯", 0x9eab : "椨", 0x9eac : "椪", 0x9ead : "椚", 0x9eae : "椣", 0x9eaf : "椡", 0x9eb0 : "棆", 0x9eb1 : "楹", 0x9eb2 : "楷", 0x9eb3 : "楜", 0x9eb4 : "楸", 0x9eb5 : "楫", 0x9eb6 : "楔", 0x9eb7 : "楾", 0x9eb8 : "楮", 0x9eb9 : "椹", 0x9eba : "楴", 0x9ebb : "椽", 0x9ebc : "楙", 0x9ebd : "椰", 0x9ebe : "楡", 0x9ebf : "楞", 0x9ec0 : "楝", 0x9ec1 : "榁", 0x9ec2 : "楪", 0x9ec3 : "榲", 0x9ec4 : "榮", 0x9ec5 : "槐", 0x9ec6 : "榿", 0x9ec7 : "槁", 0x9ec8 : "槓", 0x9ec9 : "榾", 0x9eca : "槎", 0x9ecb : "寨", 0x9ecc : "槊", 0x9ecd : "槝", 0x9ece : "榻", 0x9ecf : "槃", 0x9ed0 : "榧", 0x9ed1 : "樮", 0x9ed2 : "榑", 0x9ed3 : "榠", 0x9ed4 : "榜", 0x9ed5 : "榕", 0x9ed6 : "榴", 0x9ed7 : "槞", 0x9ed8 : "槨", 0x9ed9 : "樂", 0x9eda : "樛", 0x9edb : "槿", 0x9edc : "權", 0x9edd : "槹", 0x9ede : "槲", 0x9edf : "槧", 0x9ee0 : "樅", 0x9ee1 : "榱", 0x9ee2 : "樞", 0x9ee3 : "槭", 0x9ee4 : "樔", 0x9ee5 : "槫", 0x9ee6 : "樊", 0x9ee7 : "樒", 0x9ee8 : "櫁", 0x9ee9 : "樣", 0x9eea : "樓", 0x9eeb : "橄", 0x9eec : "樌", 0x9eed : "橲", 0x9eee : "樶", 0x9eef : "橸", 0x9ef0 : "橇", 0x9ef1 : "橢", 0x9ef2 : "橙", 0x9ef3 : "橦", 0x9ef4 : "橈", 0x9ef5 : "樸", 0x9ef6 : "樢", 0x9ef7 : "檐", 0x9ef8 : "檍", 0x9ef9 : "檠", 0x9efa : "檄", 0x9efb : "檢", 0x9efc : "檣", 0x9f40 : "檗", 0x9f41 : "蘗", 0x9f42 : "檻", 0x9f43 : "櫃", 0x9f44 : "櫂", 0x9f45 : "檸", 0x9f46 : "檳", 0x9f47 : "檬", 0x9f48 : "櫞", 0x9f49 : "櫑", 0x9f4a : "櫟", 0x9f4b : "檪", 0x9f4c : "櫚", 0x9f4d : "櫪", 0x9f4e : "櫻", 0x9f4f : "欅", 0x9f50 : "蘖", 0x9f51 : "櫺", 0x9f52 : "欒", 0x9f53 : "欖", 0x9f54 : "鬱", 0x9f55 : "欟", 0x9f56 : "欸", 0x9f57 : "欷", 0x9f58 : "盜", 0x9f59 : "欹", 0x9f5a : "飮", 0x9f5b : "歇", 0x9f5c : "歃", 0x9f5d : "歉", 0x9f5e : "歐", 0x9f5f : "歙", 0x9f60 : "歔", 0x9f61 : "歛", 0x9f62 : "歟", 0x9f63 : "歡", 0x9f64 : "歸", 0x9f65 : "歹", 0x9f66 : "歿", 0x9f67 : "殀", 0x9f68 : "殄", 0x9f69 : "殃", 0x9f6a : "殍", 0x9f6b : "殘", 0x9f6c : "殕", 0x9f6d : "殞", 0x9f6e : "殤", 0x9f6f : "殪", 0x9f70 : "殫", 0x9f71 : "殯", 0x9f72 : "殲", 0x9f73 : "殱", 0x9f74 : "殳", 0x9f75 : "殷", 0x9f76 : "殼", 0x9f77 : "毆", 0x9f78 : "毋", 0x9f79 : "毓", 0x9f7a : "毟", 0x9f7b : "毬", 0x9f7c : "毫", 0x9f7d : "毳", 0x9f7e : "毯", 0x9f80 : "麾", 0x9f81 : "氈", 0x9f82 : "氓", 0x9f83 : "气", 0x9f84 : "氛", 0x9f85 : "氤", 0x9f86 : "氣", 0x9f87 : "汞", 0x9f88 : "汕", 0x9f89 : "汢", 0x9f8a : "汪", 0x9f8b : "沂", 0x9f8c : "沍", 0x9f8d : "沚", 0x9f8e : "沁", 0x9f8f : "沛", 0x9f90 : "汾", 0x9f91 : "汨", 0x9f92 : "汳", 0x9f93 : "沒", 0x9f94 : "沐", 0x9f95 : "泄", 0x9f96 : "泱", 0x9f97 : "泓", 0x9f98 : "沽", 0x9f99 : "泗", 0x9f9a : "泅", 0x9f9b : "泝", 0x9f9c : "沮", 0x9f9d : "沱", 0x9f9e : "沾", 0x9f9f : "沺", 0x9fa0 : "泛", 0x9fa1 : "泯", 0x9fa2 : "泙", 0x9fa3 : "泪", 0x9fa4 : "洟", 0x9fa5 : "衍", 0x9fa6 : "洶", 0x9fa7 : "洫", 0x9fa8 : "洽", 0x9fa9 : "洸", 0x9faa : "洙", 0x9fab : "洵", 0x9fac : "洳", 0x9fad : "洒", 0x9fae : "洌", 0x9faf : "浣", 0x9fb0 : "涓", 0x9fb1 : "浤", 0x9fb2 : "浚", 0x9fb3 : "浹", 0x9fb4 : "浙", 0x9fb5 : "涎", 0x9fb6 : "涕", 0x9fb7 : "濤", 0x9fb8 : "涅", 0x9fb9 : "淹", 0x9fba : "渕", 0x9fbb : "渊", 0x9fbc : "涵", 0x9fbd : "淇", 0x9fbe : "淦", 0x9fbf : "涸", 0x9fc0 : "淆", 0x9fc1 : "淬", 0x9fc2 : "淞", 0x9fc3 : "淌", 0x9fc4 : "淨", 0x9fc5 : "淒", 0x9fc6 : "淅", 0x9fc7 : "淺", 0x9fc8 : "淙", 0x9fc9 : "淤", 0x9fca : "淕", 0x9fcb : "淪", 0x9fcc : "淮", 0x9fcd : "渭", 0x9fce : "湮", 0x9fcf : "渮", 0x9fd0 : "渙", 0x9fd1 : "湲", 0x9fd2 : "湟", 0x9fd3 : "渾", 0x9fd4 : "渣", 0x9fd5 : "湫", 0x9fd6 : "渫", 0x9fd7 : "湶", 0x9fd8 : "湍", 0x9fd9 : "渟", 0x9fda : "湃", 0x9fdb : "渺", 0x9fdc : "湎", 0x9fdd : "渤", 0x9fde : "滿", 0x9fdf : "渝", 0x9fe0 : "游", 0x9fe1 : "溂", 0x9fe2 : "溪", 0x9fe3 : "溘", 0x9fe4 : "滉", 0x9fe5 : "溷", 0x9fe6 : "滓", 0x9fe7 : "溽", 0x9fe8 : "溯", 0x9fe9 : "滄", 0x9fea : "溲", 0x9feb : "滔", 0x9fec : "滕", 0x9fed : "溏", 0x9fee : "溥", 0x9fef : "滂", 0x9ff0 : "溟", 0x9ff1 : "潁", 0x9ff2 : "漑", 0x9ff3 : "灌", 0x9ff4 : "滬", 0x9ff5 : "滸", 0x9ff6 : "滾", 0x9ff7 : "漿", 0x9ff8 : "滲", 0x9ff9 : "漱", 0x9ffa : "滯", 0x9ffb : "漲", 0x9ffc : "滌", 0xe040 : "漾", 0xe041 : "漓", 0xe042 : "滷", 0xe043 : "澆", 0xe044 : "潺", 0xe045 : "潸", 0xe046 : "澁", 0xe047 : "澀", 0xe048 : "潯", 0xe049 : "潛", 0xe04a : "濳", 0xe04b : "潭", 0xe04c : "澂", 0xe04d : "潼", 0xe04e : "潘", 0xe04f : "澎", 0xe050 : "澑", 0xe051 : "濂", 0xe052 : "潦", 0xe053 : "澳", 0xe054 : "澣", 0xe055 : "澡", 0xe056 : "澤", 0xe057 : "澹", 0xe058 : "濆", 0xe059 : "澪", 0xe05a : "濟", 0xe05b : "濕", 0xe05c : "濬", 0xe05d : "濔", 0xe05e : "濘", 0xe05f : "濱", 0xe060 : "濮", 0xe061 : "濛", 0xe062 : "瀉", 0xe063 : "瀋", 0xe064 : "濺", 0xe065 : "瀑", 0xe066 : "瀁", 0xe067 : "瀏", 0xe068 : "濾", 0xe069 : "瀛", 0xe06a : "瀚", 0xe06b : "潴", 0xe06c : "瀝", 0xe06d : "瀘", 0xe06e : "瀟", 0xe06f : "瀰", 0xe070 : "瀾", 0xe071 : "瀲", 0xe072 : "灑", 0xe073 : "灣", 0xe074 : "炙", 0xe075 : "炒", 0xe076 : "炯", 0xe077 : "烱", 0xe078 : "炬", 0xe079 : "炸", 0xe07a : "炳", 0xe07b : "炮", 0xe07c : "烟", 0xe07d : "烋", 0xe07e : "烝", 0xe080 : "烙", 0xe081 : "焉", 0xe082 : "烽", 0xe083 : "焜", 0xe084 : "焙", 0xe085 : "煥", 0xe086 : "煕", 0xe087 : "熈", 0xe088 : "煦", 0xe089 : "煢", 0xe08a : "煌", 0xe08b : "煖", 0xe08c : "煬", 0xe08d : "熏", 0xe08e : "燻", 0xe08f : "熄", 0xe090 : "熕", 0xe091 : "熨", 0xe092 : "熬", 0xe093 : "燗", 0xe094 : "熹", 0xe095 : "熾", 0xe096 : "燒", 0xe097 : "燉", 0xe098 : "燔", 0xe099 : "燎", 0xe09a : "燠", 0xe09b : "燬", 0xe09c : "燧", 0xe09d : "燵", 0xe09e : "燼", 0xe09f : "燹", 0xe0a0 : "燿", 0xe0a1 : "爍", 0xe0a2 : "爐", 0xe0a3 : "爛", 0xe0a4 : "爨", 0xe0a5 : "爭", 0xe0a6 : "爬", 0xe0a7 : "爰", 0xe0a8 : "爲", 0xe0a9 : "爻", 0xe0aa : "爼", 0xe0ab : "爿", 0xe0ac : "牀", 0xe0ad : "牆", 0xe0ae : "牋", 0xe0af : "牘", 0xe0b0 : "牴", 0xe0b1 : "牾", 0xe0b2 : "犂", 0xe0b3 : "犁", 0xe0b4 : "犇", 0xe0b5 : "犒", 0xe0b6 : "犖", 0xe0b7 : "犢", 0xe0b8 : "犧", 0xe0b9 : "犹", 0xe0ba : "犲", 0xe0bb : "狃", 0xe0bc : "狆", 0xe0bd : "狄", 0xe0be : "狎", 0xe0bf : "狒", 0xe0c0 : "狢", 0xe0c1 : "狠", 0xe0c2 : "狡", 0xe0c3 : "狹", 0xe0c4 : "狷", 0xe0c5 : "倏", 0xe0c6 : "猗", 0xe0c7 : "猊", 0xe0c8 : "猜", 0xe0c9 : "猖", 0xe0ca : "猝", 0xe0cb : "猴", 0xe0cc : "猯", 0xe0cd : "猩", 0xe0ce : "猥", 0xe0cf : "猾", 0xe0d0 : "獎", 0xe0d1 : "獏", 0xe0d2 : "默", 0xe0d3 : "獗", 0xe0d4 : "獪", 0xe0d5 : "獨", 0xe0d6 : "獰", 0xe0d7 : "獸", 0xe0d8 : "獵", 0xe0d9 : "獻", 0xe0da : "獺", 0xe0db : "珈", 0xe0dc : "玳", 0xe0dd : "珎", 0xe0de : "玻", 0xe0df : "珀", 0xe0e0 : "珥", 0xe0e1 : "珮", 0xe0e2 : "珞", 0xe0e3 : "璢", 0xe0e4 : "琅", 0xe0e5 : "瑯", 0xe0e6 : "琥", 0xe0e7 : "珸", 0xe0e8 : "琲", 0xe0e9 : "琺", 0xe0ea : "瑕", 0xe0eb : "琿", 0xe0ec : "瑟", 0xe0ed : "瑙", 0xe0ee : "瑁", 0xe0ef : "瑜", 0xe0f0 : "瑩", 0xe0f1 : "瑰", 0xe0f2 : "瑣", 0xe0f3 : "瑪", 0xe0f4 : "瑶", 0xe0f5 : "瑾", 0xe0f6 : "璋", 0xe0f7 : "璞", 0xe0f8 : "璧", 0xe0f9 : "瓊", 0xe0fa : "瓏", 0xe0fb : "瓔", 0xe0fc : "珱", 0xe140 : "瓠", 0xe141 : "瓣", 0xe142 : "瓧", 0xe143 : "瓩", 0xe144 : "瓮", 0xe145 : "瓲", 0xe146 : "瓰", 0xe147 : "瓱", 0xe148 : "瓸", 0xe149 : "瓷", 0xe14a : "甄", 0xe14b : "甃", 0xe14c : "甅", 0xe14d : "甌", 0xe14e : "甎", 0xe14f : "甍", 0xe150 : "甕", 0xe151 : "甓", 0xe152 : "甞", 0xe153 : "甦", 0xe154 : "甬", 0xe155 : "甼", 0xe156 : "畄", 0xe157 : "畍", 0xe158 : "畊", 0xe159 : "畉", 0xe15a : "畛", 0xe15b : "畆", 0xe15c : "畚", 0xe15d : "畩", 0xe15e : "畤", 0xe15f : "畧", 0xe160 : "畫", 0xe161 : "畭", 0xe162 : "畸", 0xe163 : "當", 0xe164 : "疆", 0xe165 : "疇", 0xe166 : "畴", 0xe167 : "疊", 0xe168 : "疉", 0xe169 : "疂", 0xe16a : "疔", 0xe16b : "疚", 0xe16c : "疝", 0xe16d : "疥", 0xe16e : "疣", 0xe16f : "痂", 0xe170 : "疳", 0xe171 : "痃", 0xe172 : "疵", 0xe173 : "疽", 0xe174 : "疸", 0xe175 : "疼", 0xe176 : "疱", 0xe177 : "痍", 0xe178 : "痊", 0xe179 : "痒", 0xe17a : "痙", 0xe17b : "痣", 0xe17c : "痞", 0xe17d : "痾", 0xe17e : "痿", 0xe180 : "痼", 0xe181 : "瘁", 0xe182 : "痰", 0xe183 : "痺", 0xe184 : "痲", 0xe185 : "痳", 0xe186 : "瘋", 0xe187 : "瘍", 0xe188 : "瘉", 0xe189 : "瘟", 0xe18a : "瘧", 0xe18b : "瘠", 0xe18c : "瘡", 0xe18d : "瘢", 0xe18e : "瘤", 0xe18f : "瘴", 0xe190 : "瘰", 0xe191 : "瘻", 0xe192 : "癇", 0xe193 : "癈", 0xe194 : "癆", 0xe195 : "癜", 0xe196 : "癘", 0xe197 : "癡", 0xe198 : "癢", 0xe199 : "癨", 0xe19a : "癩", 0xe19b : "癪", 0xe19c : "癧", 0xe19d : "癬", 0xe19e : "癰", 0xe19f : "癲", 0xe1a0 : "癶", 0xe1a1 : "癸", 0xe1a2 : "發", 0xe1a3 : "皀", 0xe1a4 : "皃", 0xe1a5 : "皈", 0xe1a6 : "皋", 0xe1a7 : "皎", 0xe1a8 : "皖", 0xe1a9 : "皓", 0xe1aa : "皙", 0xe1ab : "皚", 0xe1ac : "皰", 0xe1ad : "皴", 0xe1ae : "皸", 0xe1af : "皹", 0xe1b0 : "皺", 0xe1b1 : "盂", 0xe1b2 : "盍", 0xe1b3 : "盖", 0xe1b4 : "盒", 0xe1b5 : "盞", 0xe1b6 : "盡", 0xe1b7 : "盥", 0xe1b8 : "盧", 0xe1b9 : "盪", 0xe1ba : "蘯", 0xe1bb : "盻", 0xe1bc : "眈", 0xe1bd : "眇", 0xe1be : "眄", 0xe1bf : "眩", 0xe1c0 : "眤", 0xe1c1 : "眞", 0xe1c2 : "眥", 0xe1c3 : "眦", 0xe1c4 : "眛", 0xe1c5 : "眷", 0xe1c6 : "眸", 0xe1c7 : "睇", 0xe1c8 : "睚", 0xe1c9 : "睨", 0xe1ca : "睫", 0xe1cb : "睛", 0xe1cc : "睥", 0xe1cd : "睿", 0xe1ce : "睾", 0xe1cf : "睹", 0xe1d0 : "瞎", 0xe1d1 : "瞋", 0xe1d2 : "瞑", 0xe1d3 : "瞠", 0xe1d4 : "瞞", 0xe1d5 : "瞰", 0xe1d6 : "瞶", 0xe1d7 : "瞹", 0xe1d8 : "瞿", 0xe1d9 : "瞼", 0xe1da : "瞽", 0xe1db : "瞻", 0xe1dc : "矇", 0xe1dd : "矍", 0xe1de : "矗", 0xe1df : "矚", 0xe1e0 : "矜", 0xe1e1 : "矣", 0xe1e2 : "矮", 0xe1e3 : "矼", 0xe1e4 : "砌", 0xe1e5 : "砒", 0xe1e6 : "礦", 0xe1e7 : "砠", 0xe1e8 : "礪", 0xe1e9 : "硅", 0xe1ea : "碎", 0xe1eb : "硴", 0xe1ec : "碆", 0xe1ed : "硼", 0xe1ee : "碚", 0xe1ef : "碌", 0xe1f0 : "碣", 0xe1f1 : "碵", 0xe1f2 : "碪", 0xe1f3 : "碯", 0xe1f4 : "磑", 0xe1f5 : "磆", 0xe1f6 : "磋", 0xe1f7 : "磔", 0xe1f8 : "碾", 0xe1f9 : "碼", 0xe1fa : "磅", 0xe1fb : "磊", 0xe1fc : "磬", 0xe240 : "磧", 0xe241 : "磚", 0xe242 : "磽", 0xe243 : "磴", 0xe244 : "礇", 0xe245 : "礒", 0xe246 : "礑", 0xe247 : "礙", 0xe248 : "礬", 0xe249 : "礫", 0xe24a : "祀", 0xe24b : "祠", 0xe24c : "祗", 0xe24d : "祟", 0xe24e : "祚", 0xe24f : "祕", 0xe250 : "祓", 0xe251 : "祺", 0xe252 : "祿", 0xe253 : "禊", 0xe254 : "禝", 0xe255 : "禧", 0xe256 : "齋", 0xe257 : "禪", 0xe258 : "禮", 0xe259 : "禳", 0xe25a : "禹", 0xe25b : "禺", 0xe25c : "秉", 0xe25d : "秕", 0xe25e : "秧", 0xe25f : "秬", 0xe260 : "秡", 0xe261 : "秣", 0xe262 : "稈", 0xe263 : "稍", 0xe264 : "稘", 0xe265 : "稙", 0xe266 : "稠", 0xe267 : "稟", 0xe268 : "禀", 0xe269 : "稱", 0xe26a : "稻", 0xe26b : "稾", 0xe26c : "稷", 0xe26d : "穃", 0xe26e : "穗", 0xe26f : "穉", 0xe270 : "穡", 0xe271 : "穢", 0xe272 : "穩", 0xe29f : "筺", 0xe2a0 : "笄", 0xe2a1 : "筍", 0xe2a2 : "笋", 0xe2a3 : "筌", 0xe2a4 : "筅", 0xe2a5 : "筵", 0xe2a6 : "筥", 0xe2a7 : "筴", 0xe2a8 : "筧", 0xe2a9 : "筰", 0xe2aa : "筱", 0xe2ab : "筬", 0xe2ac : "筮", 0xe2ad : "箝", 0xe2ae : "箘", 0xe2af : "箟", 0xe2b0 : "箍", 0xe2b1 : "箜", 0xe2b2 : "箚", 0xe2b3 : "箋", 0xe2b4 : "箒", 0xe2b5 : "箏", 0xe2b6 : "筝", 0xe2b7 : "箙", 0xe2b8 : "篋", 0xe2b9 : "篁", 0xe2ba : "篌", 0xe2bb : "篏", 0xe2bc : "箴", 0xe2bd : "篆", 0xe2be : "篝", 0xe2bf : "篩", 0xe2c0 : "簑", 0xe2c1 : "簔", 0xe2c2 : "篦", 0xe2c3 : "篥", 0xe2c4 : "籠", 0xe2c5 : "簀", 0xe2c6 : "簇", 0xe2c7 : "簓", 0xe2c8 : "篳", 0xe2c9 : "篷", 0xe2ca : "簗", 0xe2cb : "簍", 0xe2cc : "篶", 0xe2cd : "簣", 0xe2ce : "簧", 0xe2cf : "簪", 0xe2d0 : "簟", 0xe2d1 : "簷", 0xe2d2 : "簫", 0xe2d3 : "簽", 0xe2d4 : "籌", 0xe2d5 : "籃", 0xe2d6 : "籔", 0xe2d7 : "籏", 0xe2d8 : "籀", 0xe2d9 : "籐", 0xe2da : "籘", 0xe2db : "籟", 0xe2dc : "籤", 0xe2dd : "籖", 0xe2de : "籥", 0xe2df : "籬", 0xe2e0 : "籵", 0xe2e1 : "粃", 0xe2e2 : "粐", 0xe2e3 : "粤", 0xe2e4 : "粭", 0xe2e5 : "粢", 0xe2e6 : "粫", 0xe2e7 : "粡", 0xe2e8 : "粨", 0xe2e9 : "粳", 0xe2ea : "粲", 0xe2eb : "粱", 0xe2ec : "粮", 0xe2ed : "粹", 0xe2ee : "粽", 0xe2ef : "糀", 0xe2f0 : "糅", 0xe2f1 : "糂", 0xe2f2 : "糘", 0xe2f3 : "糒", 0xe2f4 : "糜", 0xe2f5 : "糢", 0xe2f6 : "鬻", 0xe2f7 : "糯", 0xe2f8 : "糲", 0xe2f9 : "糴", 0xe2fa : "糶", 0xe2fb : "糺", 0xe2fc : "紆", 0xe340 : "紂", 0xe341 : "紜", 0xe342 : "紕", 0xe343 : "紊", 0xe344 : "絅", 0xe345 : "絋", 0xe346 : "紮", 0xe347 : "紲", 0xe348 : "紿", 0xe349 : "紵", 0xe34a : "絆", 0xe34b : "絳", 0xe34c : "絖", 0xe34d : "絎", 0xe34e : "絲", 0xe34f : "絨", 0xe350 : "絮", 0xe351 : "絏", 0xe352 : "絣", 0xe353 : "經", 0xe354 : "綉", 0xe355 : "絛", 0xe356 : "綏", 0xe357 : "絽", 0xe358 : "綛", 0xe359 : "綺", 0xe35a : "綮", 0xe35b : "綣", 0xe35c : "綵", 0xe35d : "緇", 0xe35e : "綽", 0xe35f : "綫", 0xe360 : "總", 0xe361 : "綢", 0xe362 : "綯", 0xe363 : "緜", 0xe364 : "綸", 0xe365 : "綟", 0xe366 : "綰", 0xe367 : "緘", 0xe368 : "緝", 0xe369 : "緤", 0xe36a : "緞", 0xe36b : "緻", 0xe36c : "緲", 0xe36d : "緡", 0xe36e : "縅", 0xe36f : "縊", 0xe370 : "縣", 0xe371 : "縡", 0xe372 : "縒", 0xe373 : "縱", 0xe374 : "縟", 0xe375 : "縉", 0xe376 : "縋", 0xe377 : "縢", 0xe378 : "繆", 0xe379 : "繦", 0xe37a : "縻", 0xe37b : "縵", 0xe37c : "縹", 0xe37d : "繃", 0xe37e : "縷", 0xe380 : "縲", 0xe381 : "縺", 0xe382 : "繧", 0xe383 : "繝", 0xe384 : "繖", 0xe385 : "繞", 0xe386 : "繙", 0xe387 : "繚", 0xe388 : "繹", 0xe389 : "繪", 0xe38a : "繩", 0xe38b : "繼", 0xe38c : "繻", 0xe38d : "纃", 0xe38e : "緕", 0xe38f : "繽", 0xe390 : "辮", 0xe391 : "繿", 0xe392 : "纈", 0xe393 : "纉", 0xe394 : "續", 0xe395 : "纒", 0xe396 : "纐", 0xe397 : "纓", 0xe398 : "纔", 0xe399 : "纖", 0xe39a : "纎", 0xe39b : "纛", 0xe39c : "纜", 0xe39d : "缸", 0xe39e : "缺", 0xe39f : "罅", 0xe3a0 : "罌", 0xe3a1 : "罍", 0xe3a2 : "罎", 0xe3a3 : "罐", 0xe3a4 : "网", 0xe3a5 : "罕", 0xe3a6 : "罔", 0xe3a7 : "罘", 0xe3a8 : "罟", 0xe3a9 : "罠", 0xe3aa : "罨", 0xe3ab : "罩", 0xe3ac : "罧", 0xe3ad : "罸", 0xe3ae : "羂", 0xe3af : "羆", 0xe3b0 : "羃", 0xe3b1 : "羈", 0xe3b2 : "羇", 0xe3b3 : "羌", 0xe3b4 : "羔", 0xe3b5 : "羞", 0xe3b6 : "羝", 0xe3b7 : "羚", 0xe3b8 : "羣", 0xe3b9 : "羯", 0xe3ba : "羲", 0xe3bb : "羹", 0xe3bc : "羮", 0xe3bd : "羶", 0xe3be : "羸", 0xe3bf : "譱", 0xe3c0 : "翅", 0xe3c1 : "翆", 0xe3c2 : "翊", 0xe3c3 : "翕", 0xe3c4 : "翔", 0xe3c5 : "翡", 0xe3c6 : "翦", 0xe3c7 : "翩", 0xe3c8 : "翳", 0xe3c9 : "翹", 0xe3ca : "飜", 0xe3cb : "耆", 0xe3cc : "耄", 0xe3cd : "耋", 0xe3ce : "耒", 0xe3cf : "耘", 0xe3d0 : "耙", 0xe3d1 : "耜", 0xe3d2 : "耡", 0xe3d3 : "耨", 0xe3d4 : "耿", 0xe3d5 : "耻", 0xe3d6 : "聊", 0xe3d7 : "聆", 0xe3d8 : "聒", 0xe3d9 : "聘", 0xe3da : "聚", 0xe3db : "聟", 0xe3dc : "聢", 0xe3dd : "聨", 0xe3de : "聳", 0xe3df : "聲", 0xe3e0 : "聰", 0xe3e1 : "聶", 0xe3e2 : "聹", 0xe3e3 : "聽", 0xe3e4 : "聿", 0xe3e5 : "肄", 0xe3e6 : "肆", 0xe3e7 : "肅", 0xe3e8 : "肛", 0xe3e9 : "肓", 0xe3ea : "肚", 0xe3eb : "肭", 0xe3ec : "冐", 0xe3ed : "肬", 0xe3ee : "胛", 0xe3ef : "胥", 0xe3f0 : "胙", 0xe3f1 : "胝", 0xe3f2 : "胄", 0xe3f3 : "胚", 0xe3f4 : "胖", 0xe3f5 : "脉", 0xe3f6 : "胯", 0xe3f7 : "胱", 0xe3f8 : "脛", 0xe3f9 : "脩", 0xe3fa : "脣", 0xe3fb : "脯", 0xe3fc : "腋", 0xe440 : "隋", 0xe441 : "腆", 0xe442 : "脾", 0xe443 : "腓", 0xe444 : "腑", 0xe445 : "胼", 0xe446 : "腱", 0xe447 : "腮", 0xe448 : "腥", 0xe449 : "腦", 0xe44a : "腴", 0xe44b : "膃", 0xe44c : "膈", 0xe44d : "膊", 0xe44e : "膀", 0xe44f : "膂", 0xe450 : "膠", 0xe451 : "膕", 0xe452 : "膤", 0xe453 : "膣", 0xe454 : "腟", 0xe455 : "膓", 0xe456 : "膩", 0xe457 : "膰", 0xe458 : "膵", 0xe459 : "膾", 0xe45a : "膸", 0xe45b : "膽", 0xe45c : "臀", 0xe45d : "臂", 0xe45e : "膺", 0xe45f : "臉", 0xe460 : "臍", 0xe461 : "臑", 0xe462 : "臙", 0xe463 : "臘", 0xe464 : "臈", 0xe465 : "臚", 0xe466 : "臟", 0xe467 : "臠", 0xe468 : "臧", 0xe469 : "臺", 0xe46a : "臻", 0xe46b : "臾", 0xe46c : "舁", 0xe46d : "舂", 0xe46e : "舅", 0xe46f : "與", 0xe470 : "舊", 0xe471 : "舍", 0xe472 : "舐", 0xe473 : "舖", 0xe474 : "舩", 0xe475 : "舫", 0xe476 : "舸", 0xe477 : "舳", 0xe478 : "艀", 0xe479 : "艙", 0xe47a : "艘", 0xe47b : "艝", 0xe47c : "艚", 0xe47d : "艟", 0xe47e : "艤", 0xe480 : "艢", 0xe481 : "艨", 0xe482 : "艪", 0xe483 : "艫", 0xe484 : "舮", 0xe485 : "艱", 0xe486 : "艷", 0xe487 : "艸", 0xe488 : "艾", 0xe489 : "芍", 0xe48a : "芒", 0xe48b : "芫", 0xe48c : "芟", 0xe48d : "芻", 0xe48e : "芬", 0xe48f : "苡", 0xe490 : "苣", 0xe491 : "苟", 0xe492 : "苒", 0xe493 : "苴", 0xe494 : "苳", 0xe495 : "苺", 0xe496 : "莓", 0xe497 : "范", 0xe498 : "苻", 0xe499 : "苹", 0xe49a : "苞", 0xe49b : "茆", 0xe49c : "苜", 0xe49d : "茉", 0xe49e : "苙", 0xe49f : "茵", 0xe4a0 : "茴", 0xe4a1 : "茖", 0xe4a2 : "茲", 0xe4a3 : "茱", 0xe4a4 : "荀", 0xe4a5 : "茹", 0xe4a6 : "荐", 0xe4a7 : "荅", 0xe4a8 : "茯", 0xe4a9 : "茫", 0xe4aa : "茗", 0xe4ab : "茘", 0xe4ac : "莅", 0xe4ad : "莚", 0xe4ae : "莪", 0xe4af : "莟", 0xe4b0 : "莢", 0xe4b1 : "莖", 0xe4b2 : "茣", 0xe4b3 : "莎", 0xe4b4 : "莇", 0xe4b5 : "莊", 0xe4b6 : "荼", 0xe4b7 : "莵", 0xe4b8 : "荳", 0xe4b9 : "荵", 0xe4ba : "莠", 0xe4bb : "莉", 0xe4bc : "莨", 0xe4bd : "菴", 0xe4be : "萓", 0xe4bf : "菫", 0xe4c0 : "菎", 0xe4c1 : "菽", 0xe4c2 : "萃", 0xe4c3 : "菘", 0xe4c4 : "萋", 0xe4c5 : "菁", 0xe4c6 : "菷", 0xe4c7 : "萇", 0xe4c8 : "菠", 0xe4c9 : "菲", 0xe4ca : "萍", 0xe4cb : "萢", 0xe4cc : "萠", 0xe4cd : "莽", 0xe4ce : "萸", 0xe4cf : "蔆", 0xe4d0 : "菻", 0xe4d1 : "葭", 0xe4d2 : "萪", 0xe4d3 : "萼", 0xe4d4 : "蕚", 0xe4d5 : "蒄", 0xe4d6 : "葷", 0xe4d7 : "葫", 0xe4d8 : "蒭", 0xe4d9 : "葮", 0xe4da : "蒂", 0xe4db : "葩", 0xe4dc : "葆", 0xe4dd : "萬", 0xe4de : "葯", 0xe4df : "葹", 0xe4e0 : "萵", 0xe4e1 : "蓊", 0xe4e2 : "葢", 0xe4e3 : "蒹", 0xe4e4 : "蒿", 0xe4e5 : "蒟", 0xe4e6 : "蓙", 0xe4e7 : "蓍", 0xe4e8 : "蒻", 0xe4e9 : "蓚", 0xe4ea : "蓐", 0xe4eb : "蓁", 0xe4ec : "蓆", 0xe4ed : "蓖", 0xe4ee : "蒡", 0xe4ef : "蔡", 0xe4f0 : "蓿", 0xe4f1 : "蓴", 0xe4f2 : "蔗", 0xe4f3 : "蔘", 0xe4f4 : "蔬", 0xe4f5 : "蔟", 0xe4f6 : "蔕", 0xe4f7 : "蔔", 0xe4f8 : "蓼", 0xe4f9 : "蕀", 0xe4fa : "蕣", 0xe4fb : "蕘", 0xe4fc : "蕈", 0xe540 : "蕁", 0xe541 : "蘂", 0xe542 : "蕋", 0xe543 : "蕕", 0xe544 : "薀", 0xe545 : "薤", 0xe546 : "薈", 0xe547 : "薑", 0xe548 : "薊", 0xe549 : "薨", 0xe54a : "蕭", 0xe54b : "薔", 0xe54c : "薛", 0xe54d : "藪", 0xe54e : "薇", 0xe54f : "薜", 0xe550 : "蕷", 0xe551 : "蕾", 0xe552 : "薐", 0xe553 : "藉", 0xe554 : "薺", 0xe555 : "藏", 0xe556 : "薹", 0xe557 : "藐", 0xe558 : "藕", 0xe559 : "藝", 0xe55a : "藥", 0xe55b : "藜", 0xe55c : "藹", 0xe55d : "蘊", 0xe55e : "蘓", 0xe55f : "蘋", 0xe560 : "藾", 0xe561 : "藺", 0xe562 : "蘆", 0xe563 : "蘢", 0xe564 : "蘚", 0xe565 : "蘰", 0xe566 : "蘿", 0xe567 : "虍", 0xe568 : "乕", 0xe569 : "虔", 0xe56a : "號", 0xe56b : "虧", 0xe56c : "虱", 0xe56d : "蚓", 0xe56e : "蚣", 0xe56f : "蚩", 0xe570 : "蚪", 0xe571 : "蚋", 0xe572 : "蚌", 0xe573 : "蚶", 0xe574 : "蚯", 0xe575 : "蛄", 0xe576 : "蛆", 0xe577 : "蚰", 0xe578 : "蛉", 0xe579 : "蠣", 0xe57a : "蚫", 0xe57b : "蛔", 0xe57c : "蛞", 0xe57d : "蛩", 0xe57e : "蛬", 0xe580 : "蛟", 0xe581 : "蛛", 0xe582 : "蛯", 0xe583 : "蜒", 0xe584 : "蜆", 0xe585 : "蜈", 0xe586 : "蜀", 0xe587 : "蜃", 0xe588 : "蛻", 0xe589 : "蜑", 0xe58a : "蜉", 0xe58b : "蜍", 0xe58c : "蛹", 0xe58d : "蜊", 0xe58e : "蜴", 0xe58f : "蜿", 0xe590 : "蜷", 0xe591 : "蜻", 0xe592 : "蜥", 0xe593 : "蜩", 0xe594 : "蜚", 0xe595 : "蝠", 0xe596 : "蝟", 0xe597 : "蝸", 0xe598 : "蝌", 0xe599 : "蝎", 0xe59a : "蝴", 0xe59b : "蝗", 0xe59c : "蝨", 0xe59d : "蝮", 0xe59e : "蝙", 0xe59f : "蝓", 0xe5a0 : "蝣", 0xe5a1 : "蝪", 0xe5a2 : "蠅", 0xe5a3 : "螢", 0xe5a4 : "螟", 0xe5a5 : "螂", 0xe5a6 : "螯", 0xe5a7 : "蟋", 0xe5a8 : "螽", 0xe5a9 : "蟀", 0xe5aa : "蟐", 0xe5ab : "雖", 0xe5ac : "螫", 0xe5ad : "蟄", 0xe5ae : "螳", 0xe5af : "蟇", 0xe5b0 : "蟆", 0xe5b1 : "螻", 0xe5b2 : "蟯", 0xe5b3 : "蟲", 0xe5b4 : "蟠", 0xe5b5 : "蠏", 0xe5b6 : "蠍", 0xe5b7 : "蟾", 0xe5b8 : "蟶", 0xe5b9 : "蟷", 0xe5ba : "蠎", 0xe5bb : "蟒", 0xe5bc : "蠑", 0xe5bd : "蠖", 0xe5be : "蠕", 0xe5bf : "蠢", 0xe5c0 : "蠡", 0xe5c1 : "蠱", 0xe5c2 : "蠶", 0xe5c3 : "蠹", 0xe5c4 : "蠧", 0xe5c5 : "蠻", 0xe5c6 : "衄", 0xe5c7 : "衂", 0xe5c8 : "衒", 0xe5c9 : "衙", 0xe5ca : "衞", 0xe5cb : "衢", 0xe5cc : "衫", 0xe5cd : "袁", 0xe5ce : "衾", 0xe5cf : "袞", 0xe5d0 : "衵", 0xe5d1 : "衽", 0xe5d2 : "袵", 0xe5d3 : "衲", 0xe5d4 : "袂", 0xe5d5 : "袗", 0xe5d6 : "袒", 0xe5d7 : "袮", 0xe5d8 : "袙", 0xe5d9 : "袢", 0xe5da : "袍", 0xe5db : "袤", 0xe5dc : "袰", 0xe5dd : "袿", 0xe5de : "袱", 0xe5df : "裃", 0xe5e0 : "裄", 0xe5e1 : "裔", 0xe5e2 : "裘", 0xe5e3 : "裙", 0xe5e4 : "裝", 0xe5e5 : "裹", 0xe5e6 : "褂", 0xe5e7 : "裼", 0xe5e8 : "裴", 0xe5e9 : "裨", 0xe5ea : "裲", 0xe5eb : "褄", 0xe5ec : "褌", 0xe5ed : "褊", 0xe5ee : "褓", 0xe5ef : "襃", 0xe5f0 : "褞", 0xe5f1 : "褥", 0xe5f2 : "褪", 0xe5f3 : "褫", 0xe5f4 : "襁", 0xe5f5 : "襄", 0xe5f6 : "褻", 0xe5f7 : "褶", 0xe5f8 : "褸", 0xe5f9 : "襌", 0xe5fa : "褝", 0xe5fb : "襠", 0xe5fc : "襞", 0xe640 : "襦", 0xe641 : "襤", 0xe642 : "襭", 0xe643 : "襪", 0xe644 : "襯", 0xe645 : "襴", 0xe646 : "襷", 0xe647 : "襾", 0xe648 : "覃", 0xe649 : "覈", 0xe64a : "覊", 0xe64b : "覓", 0xe64c : "覘", 0xe64d : "覡", 0xe64e : "覩", 0xe64f : "覦", 0xe650 : "覬", 0xe651 : "覯", 0xe652 : "覲", 0xe653 : "覺", 0xe654 : "覽", 0xe655 : "覿", 0xe656 : "觀", 0xe657 : "觚", 0xe658 : "觜", 0xe659 : "觝", 0xe65a : "觧", 0xe65b : "觴", 0xe65c : "觸", 0xe65d : "訃", 0xe65e : "訖", 0xe65f : "訐", 0xe660 : "訌", 0xe661 : "訛", 0xe662 : "訝", 0xe663 : "訥", 0xe664 : "訶", 0xe665 : "詁", 0xe666 : "詛", 0xe667 : "詒", 0xe668 : "詆", 0xe669 : "詈", 0xe66a : "詼", 0xe66b : "詭", 0xe66c : "詬", 0xe66d : "詢", 0xe66e : "誅", 0xe66f : "誂", 0xe670 : "誄", 0xe671 : "誨", 0xe672 : "誡", 0xe673 : "誑", 0xe674 : "誥", 0xe675 : "誦", 0xe676 : "誚", 0xe677 : "誣", 0xe678 : "諄", 0xe679 : "諍", 0xe67a : "諂", 0xe67b : "諚", 0xe67c : "諫", 0xe67d : "諳", 0xe67e : "諧", 0xe680 : "諤", 0xe681 : "諱", 0xe682 : "謔", 0xe683 : "諠", 0xe684 : "諢", 0xe685 : "諷", 0xe686 : "諞", 0xe687 : "諛", 0xe688 : "謌", 0xe689 : "謇", 0xe68a : "謚", 0xe68b : "諡", 0xe68c : "謖", 0xe68d : "謐", 0xe68e : "謗", 0xe68f : "謠", 0xe690 : "謳", 0xe691 : "鞫", 0xe692 : "謦", 0xe693 : "謫", 0xe694 : "謾", 0xe695 : "謨", 0xe696 : "譁", 0xe697 : "譌", 0xe698 : "譏", 0xe699 : "譎", 0xe69a : "證", 0xe69b : "譖", 0xe69c : "譛", 0xe69d : "譚", 0xe69e : "譫", 0xe69f : "譟", 0xe6a0 : "譬", 0xe6a1 : "譯", 0xe6a2 : "譴", 0xe6a3 : "譽", 0xe6a4 : "讀", 0xe6a5 : "讌", 0xe6a6 : "讎", 0xe6a7 : "讒", 0xe6a8 : "讓", 0xe6a9 : "讖", 0xe6aa : "讙", 0xe6ab : "讚", 0xe6ac : "谺", 0xe6ad : "豁", 0xe6ae : "谿", 0xe6af : "豈", 0xe6b0 : "豌", 0xe6b1 : "豎", 0xe6b2 : "豐", 0xe6b3 : "豕", 0xe6b4 : "豢", 0xe6b5 : "豬", 0xe6b6 : "豸", 0xe6b7 : "豺", 0xe6b8 : "貂", 0xe6b9 : "貉", 0xe6ba : "貅", 0xe6bb : "貊", 0xe6bc : "貍", 0xe6bd : "貎", 0xe6be : "貔", 0xe6bf : "豼", 0xe6c0 : "貘", 0xe6c1 : "戝", 0xe6c2 : "貭", 0xe6c3 : "貪", 0xe6c4 : "貽", 0xe6c5 : "貲", 0xe6c6 : "貳", 0xe6c7 : "貮", 0xe6c8 : "貶", 0xe6c9 : "賈", 0xe6ca : "賁", 0xe6cb : "賤", 0xe6cc : "賣", 0xe6cd : "賚", 0xe6ce : "賽", 0xe6cf : "賺", 0xe6d0 : "賻", 0xe6d1 : "贄", 0xe6d2 : "贅", 0xe6d3 : "贊", 0xe6d4 : "贇", 0xe6d5 : "贏", 0xe6d6 : "贍", 0xe6d7 : "贐", 0xe6d8 : "齎", 0xe6d9 : "贓", 0xe6da : "賍", 0xe6db : "贔", 0xe6dc : "贖", 0xe6dd : "赧", 0xe6de : "赭", 0xe6df : "赱", 0xe6e0 : "赳", 0xe6e1 : "趁", 0xe6e2 : "趙", 0xe6e3 : "跂", 0xe6e4 : "趾", 0xe6e5 : "趺", 0xe6e6 : "跏", 0xe6e7 : "跚", 0xe6e8 : "跖", 0xe6e9 : "跌", 0xe6ea : "跛", 0xe6eb : "跋", 0xe6ec : "跪", 0xe6ed : "跫", 0xe6ee : "跟", 0xe6ef : "跣", 0xe6f0 : "跼", 0xe6f1 : "踈", 0xe6f2 : "踉", 0xe6f3 : "跿", 0xe6f4 : "踝", 0xe6f5 : "踞", 0xe6f6 : "踐", 0xe6f7 : "踟", 0xe6f8 : "蹂", 0xe6f9 : "踵", 0xe6fa : "踰", 0xe6fb : "踴", 0xe6fc : "蹊", 0xe740 : "蹇", 0xe741 : "蹉", 0xe742 : "蹌", 0xe743 : "蹐", 0xe744 : "蹈", 0xe745 : "蹙", 0xe746 : "蹤", 0xe747 : "蹠", 0xe748 : "踪", 0xe749 : "蹣", 0xe74a : "蹕", 0xe74b : "蹶", 0xe74c : "蹲", 0xe74d : "蹼", 0xe74e : "躁", 0xe74f : "躇", 0xe750 : "躅", 0xe751 : "躄", 0xe752 : "躋", 0xe753 : "躊", 0xe754 : "躓", 0xe755 : "躑", 0xe756 : "躔", 0xe757 : "躙", 0xe758 : "躪", 0xe759 : "躡", 0xe75a : "躬", 0xe75b : "躰", 0xe75c : "軆", 0xe75d : "躱", 0xe75e : "躾", 0xe75f : "軅", 0xe760 : "軈", 0xe761 : "軋", 0xe762 : "軛", 0xe763 : "軣", 0xe764 : "軼", 0xe765 : "軻", 0xe766 : "軫", 0xe767 : "軾", 0xe768 : "輊", 0xe769 : "輅", 0xe76a : "輕", 0xe76b : "輒", 0xe76c : "輙", 0xe76d : "輓", 0xe76e : "輜", 0xe76f : "輟", 0xe770 : "輛", 0xe771 : "輌", 0xe772 : "輦", 0xe79f : "遏", 0xe7a0 : "遐", 0xe7a1 : "遑", 0xe7a2 : "遒", 0xe7a3 : "逎", 0xe7a4 : "遉", 0xe7a5 : "逾", 0xe7a6 : "遖", 0xe7a7 : "遘", 0xe7a8 : "遞", 0xe7a9 : "遨", 0xe7aa : "遯", 0xe7ab : "遶", 0xe7ac : "隨", 0xe7ad : "遲", 0xe7ae : "邂", 0xe7af : "遽", 0xe7b0 : "邁", 0xe7b1 : "邀", 0xe7b2 : "邊", 0xe7b3 : "邉", 0xe7b4 : "邏", 0xe7b5 : "邨", 0xe7b6 : "邯", 0xe7b7 : "邱", 0xe7b8 : "邵", 0xe7b9 : "郢", 0xe7ba : "郤", 0xe7bb : "扈", 0xe7bc : "郛", 0xe7bd : "鄂", 0xe7be : "鄒", 0xe7bf : "鄙", 0xe7c0 : "鄲", 0xe7c1 : "鄰", 0xe7c2 : "酊", 0xe7c3 : "酖", 0xe7c4 : "酘", 0xe7c5 : "酣", 0xe7c6 : "酥", 0xe7c7 : "酩", 0xe7c8 : "酳", 0xe7c9 : "酲", 0xe7ca : "醋", 0xe7cb : "醉", 0xe7cc : "醂", 0xe7cd : "醢", 0xe7ce : "醫", 0xe7cf : "醯", 0xe7d0 : "醪", 0xe7d1 : "醵", 0xe7d2 : "醴", 0xe7d3 : "醺", 0xe7d4 : "釀", 0xe7d5 : "釁", 0xe7d6 : "釉", 0xe7d7 : "釋", 0xe7d8 : "釐", 0xe7d9 : "釖", 0xe7da : "釟", 0xe7db : "釡", 0xe7dc : "釛", 0xe7dd : "釼", 0xe7de : "釵", 0xe7df : "釶", 0xe7e0 : "鈞", 0xe7e1 : "釿", 0xe7e2 : "鈔", 0xe7e3 : "鈬", 0xe7e4 : "鈕", 0xe7e5 : "鈑", 0xe7e6 : "鉞", 0xe7e7 : "鉗", 0xe7e8 : "鉅", 0xe7e9 : "鉉", 0xe7ea : "鉤", 0xe7eb : "鉈", 0xe7ec : "銕", 0xe7ed : "鈿", 0xe7ee : "鉋", 0xe7ef : "鉐", 0xe7f0 : "銜", 0xe7f1 : "銖", 0xe7f2 : "銓", 0xe7f3 : "銛", 0xe7f4 : "鉚", 0xe7f5 : "鋏", 0xe7f6 : "銹", 0xe7f7 : "銷", 0xe7f8 : "鋩", 0xe7f9 : "錏", 0xe7fa : "鋺", 0xe7fb : "鍄", 0xe7fc : "錮", 0xe840 : "錙", 0xe841 : "錢", 0xe842 : "錚", 0xe843 : "錣", 0xe844 : "錺", 0xe845 : "錵", 0xe846 : "錻", 0xe847 : "鍜", 0xe848 : "鍠", 0xe849 : "鍼", 0xe84a : "鍮", 0xe84b : "鍖", 0xe84c : "鎰", 0xe84d : "鎬", 0xe84e : "鎭", 0xe84f : "鎔", 0xe850 : "鎹", 0xe851 : "鏖", 0xe852 : "鏗", 0xe853 : "鏨", 0xe854 : "鏥", 0xe855 : "鏘", 0xe856 : "鏃", 0xe857 : "鏝", 0xe858 : "鏐", 0xe859 : "鏈", 0xe85a : "鏤", 0xe85b : "鐚", 0xe85c : "鐔", 0xe85d : "鐓", 0xe85e : "鐃", 0xe85f : "鐇", 0xe860 : "鐐", 0xe861 : "鐶", 0xe862 : "鐫", 0xe863 : "鐵", 0xe864 : "鐡", 0xe865 : "鐺", 0xe866 : "鑁", 0xe867 : "鑒", 0xe868 : "鑄", 0xe869 : "鑛", 0xe86a : "鑠", 0xe86b : "鑢", 0xe86c : "鑞", 0xe86d : "鑪", 0xe86e : "鈩", 0xe86f : "鑰", 0xe870 : "鑵", 0xe871 : "鑷", 0xe872 : "鑽", 0xe873 : "鑚", 0xe874 : "鑼", 0xe875 : "鑾", 0xe876 : "钁", 0xe877 : "鑿", 0xe878 : "閂", 0xe879 : "閇", 0xe87a : "閊", 0xe87b : "閔", 0xe87c : "閖", 0xe87d : "閘", 0xe87e : "閙", 0xe880 : "閠", 0xe881 : "閨", 0xe882 : "閧", 0xe883 : "閭", 0xe884 : "閼", 0xe885 : "閻", 0xe886 : "閹", 0xe887 : "閾", 0xe888 : "闊", 0xe889 : "濶", 0xe88a : "闃", 0xe88b : "闍", 0xe88c : "闌", 0xe88d : "闕", 0xe88e : "闔", 0xe88f : "闖", 0xe890 : "關", 0xe891 : "闡", 0xe892 : "闥", 0xe893 : "闢", 0xe894 : "阡", 0xe895 : "阨", 0xe896 : "阮", 0xe897 : "阯", 0xe898 : "陂", 0xe899 : "陌", 0xe89a : "陏", 0xe89b : "陋", 0xe89c : "陷", 0xe89d : "陜", 0xe89e : "陞", 0xe89f : "陝", 0xe8a0 : "陟", 0xe8a1 : "陦", 0xe8a2 : "陲", 0xe8a3 : "陬", 0xe8a4 : "隍", 0xe8a5 : "隘", 0xe8a6 : "隕", 0xe8a7 : "隗", 0xe8a8 : "險", 0xe8a9 : "隧", 0xe8aa : "隱", 0xe8ab : "隲", 0xe8ac : "隰", 0xe8ad : "隴", 0xe8ae : "隶", 0xe8af : "隸", 0xe8b0 : "隹", 0xe8b1 : "雎", 0xe8b2 : "雋", 0xe8b3 : "雉", 0xe8b4 : "雍", 0xe8b5 : "襍", 0xe8b6 : "雜", 0xe8b7 : "霍", 0xe8b8 : "雕", 0xe8b9 : "雹", 0xe8ba : "霄", 0xe8bb : "霆", 0xe8bc : "霈", 0xe8bd : "霓", 0xe8be : "霎", 0xe8bf : "霑", 0xe8c0 : "霏", 0xe8c1 : "霖", 0xe8c2 : "霙", 0xe8c3 : "霤", 0xe8c4 : "霪", 0xe8c5 : "霰", 0xe8c6 : "霹", 0xe8c7 : "霽", 0xe8c8 : "霾", 0xe8c9 : "靄", 0xe8ca : "靆", 0xe8cb : "靈", 0xe8cc : "靂", 0xe8cd : "靉", 0xe8ce : "靜", 0xe8cf : "靠", 0xe8d0 : "靤", 0xe8d1 : "靦", 0xe8d2 : "靨", 0xe8d3 : "勒", 0xe8d4 : "靫", 0xe8d5 : "靱", 0xe8d6 : "靹", 0xe8d7 : "鞅", 0xe8d8 : "靼", 0xe8d9 : "鞁", 0xe8da : "靺", 0xe8db : "鞆", 0xe8dc : "鞋", 0xe8dd : "鞏", 0xe8de : "鞐", 0xe8df : "鞜", 0xe8e0 : "鞨", 0xe8e1 : "鞦", 0xe8e2 : "鞣", 0xe8e3 : "鞳", 0xe8e4 : "鞴", 0xe8e5 : "韃", 0xe8e6 : "韆", 0xe8e7 : "韈", 0xe8e8 : "韋", 0xe8e9 : "韜", 0xe8ea : "韭", 0xe8eb : "齏", 0xe8ec : "韲", 0xe8ed : "竟", 0xe8ee : "韶", 0xe8ef : "韵", 0xe8f0 : "頏", 0xe8f1 : "頌", 0xe8f2 : "頸", 0xe8f3 : "頤", 0xe8f4 : "頡", 0xe8f5 : "頷", 0xe8f6 : "頽", 0xe8f7 : "顆", 0xe8f8 : "顏", 0xe8f9 : "顋", 0xe8fa : "顫", 0xe8fb : "顯", 0xe8fc : "顰", 0xe940 : "顱", 0xe941 : "顴", 0xe942 : "顳", 0xe943 : "颪", 0xe944 : "颯", 0xe945 : "颱", 0xe946 : "颶", 0xe947 : "飄", 0xe948 : "飃", 0xe949 : "飆", 0xe94a : "飩", 0xe94b : "飫", 0xe94c : "餃", 0xe94d : "餉", 0xe94e : "餒", 0xe94f : "餔", 0xe950 : "餘", 0xe951 : "餡", 0xe952 : "餝", 0xe953 : "餞", 0xe954 : "餤", 0xe955 : "餠", 0xe956 : "餬", 0xe957 : "餮", 0xe958 : "餽", 0xe959 : "餾", 0xe95a : "饂", 0xe95b : "饉", 0xe95c : "饅", 0xe95d : "饐", 0xe95e : "饋", 0xe95f : "饑", 0xe960 : "饒", 0xe961 : "饌", 0xe962 : "饕", 0xe963 : "馗", 0xe964 : "馘", 0xe965 : "馥", 0xe966 : "馭", 0xe967 : "馮", 0xe968 : "馼", 0xe969 : "駟", 0xe96a : "駛", 0xe96b : "駝", 0xe96c : "駘", 0xe96d : "駑", 0xe96e : "駭", 0xe96f : "駮", 0xe970 : "駱", 0xe971 : "駲", 0xe972 : "駻", 0xe973 : "駸", 0xe974 : "騁", 0xe975 : "騏", 0xe976 : "騅", 0xe977 : "駢", 0xe978 : "騙", 0xe979 : "騫", 0xe97a : "騷", 0xe97b : "驅", 0xe97c : "驂", 0xe97d : "驀", 0xe97e : "驃", 0xe980 : "騾", 0xe981 : "驕", 0xe982 : "驍", 0xe983 : "驛", 0xe984 : "驗", 0xe985 : "驟", 0xe986 : "驢", 0xe987 : "驥", 0xe988 : "驤", 0xe989 : "驩", 0xe98a : "驫", 0xe98b : "驪", 0xe98c : "骭", 0xe98d : "骰", 0xe98e : "骼", 0xe98f : "髀", 0xe990 : "髏", 0xe991 : "髑", 0xe992 : "髓", 0xe993 : "體", 0xe994 : "髞", 0xe995 : "髟", 0xe996 : "髢", 0xe997 : "髣", 0xe998 : "髦", 0xe999 : "髯", 0xe99a : "髫", 0xe99b : "髮", 0xe99c : "髴", 0xe99d : "髱", 0xe99e : "髷", 0xe99f : "髻", 0xe9a0 : "鬆", 0xe9a1 : "鬘", 0xe9a2 : "鬚", 0xe9a3 : "鬟", 0xe9a4 : "鬢", 0xe9a5 : "鬣", 0xe9a6 : "鬥", 0xe9a7 : "鬧", 0xe9a8 : "鬨", 0xe9a9 : "鬩", 0xe9aa : "鬪", 0xe9ab : "鬮", 0xe9ac : "鬯", 0xe9ad : "鬲", 0xe9ae : "魄", 0xe9af : "魃", 0xe9b0 : "魏", 0xe9b1 : "魍", 0xe9b2 : "魎", 0xe9b3 : "魑", 0xe9b4 : "魘", 0xe9b5 : "魴", 0xe9b6 : "鮓", 0xe9b7 : "鮃", 0xe9b8 : "鮑", 0xe9b9 : "鮖", 0xe9ba : "鮗", 0xe9bb : "鮟", 0xe9bc : "鮠", 0xe9bd : "鮨", 0xe9be : "鮴", 0xe9bf : "鯀", 0xe9c0 : "鯊", 0xe9c1 : "鮹", 0xe9c2 : "鯆", 0xe9c3 : "鯏", 0xe9c4 : "鯑", 0xe9c5 : "鯒", 0xe9c6 : "鯣", 0xe9c7 : "鯢", 0xe9c8 : "鯤", 0xe9c9 : "鯔", 0xe9ca : "鯡", 0xe9cb : "鰺", 0xe9cc : "鯲", 0xe9cd : "鯱", 0xe9ce : "鯰", 0xe9cf : "鰕", 0xe9d0 : "鰔", 0xe9d1 : "鰉", 0xe9d2 : "鰓", 0xe9d3 : "鰌", 0xe9d4 : "鰆", 0xe9d5 : "鰈", 0xe9d6 : "鰒", 0xe9d7 : "鰊", 0xe9d8 : "鰄", 0xe9d9 : "鰮", 0xe9da : "鰛", 0xe9db : "鰥", 0xe9dc : "鰤", 0xe9dd : "鰡", 0xe9de : "鰰", 0xe9df : "鱇", 0xe9e0 : "鰲", 0xe9e1 : "鱆", 0xe9e2 : "鰾", 0xe9e3 : "鱚", 0xe9e4 : "鱠", 0xe9e5 : "鱧", 0xe9e6 : "鱶", 0xe9e7 : "鱸", 0xe9e8 : "鳧", 0xe9e9 : "鳬", 0xe9ea : "鳰", 0xe9eb : "鴉", 0xe9ec : "鴈", 0xe9ed : "鳫", 0xe9ee : "鴃", 0xe9ef : "鴆", 0xe9f0 : "鴪", 0xe9f1 : "鴦", 0xe9f2 : "鶯", 0xe9f3 : "鴣", 0xe9f4 : "鴟", 0xe9f5 : "鵄", 0xe9f6 : "鴕", 0xe9f7 : "鴒", 0xe9f8 : "鵁", 0xe9f9 : "鴿", 0xe9fa : "鴾", 0xe9fb : "鵆", 0xe9fc : "鵈", 0xea40 : "鵝", 0xea41 : "鵞", 0xea42 : "鵤", 0xea43 : "鵑", 0xea44 : "鵐", 0xea45 : "鵙", 0xea46 : "鵲", 0xea47 : "鶉", 0xea48 : "鶇", 0xea49 : "鶫", 0xea4a : "鵯", 0xea4b : "鵺", 0xea4c : "鶚", 0xea4d : "鶤", 0xea4e : "鶩", 0xea4f : "鶲", 0xea50 : "鷄", 0xea51 : "鷁", 0xea52 : "鶻", 0xea53 : "鶸", 0xea54 : "鶺", 0xea55 : "鷆", 0xea56 : "鷏", 0xea57 : "鷂", 0xea58 : "鷙", 0xea59 : "鷓", 0xea5a : "鷸", 0xea5b : "鷦", 0xea5c : "鷭", 0xea5d : "鷯", 0xea5e : "鷽", 0xea5f : "鸚", 0xea60 : "鸛", 0xea61 : "鸞", 0xea62 : "鹵", 0xea63 : "鹹", 0xea64 : "鹽", 0xea65 : "麁", 0xea66 : "麈", 0xea67 : "麋", 0xea68 : "麌", 0xea69 : "麒", 0xea6a : "麕", 0xea6b : "麑", 0xea6c : "麝", 0xea6d : "麥", 0xea6e : "麩", 0xea6f : "麸", 0xea70 : "麪", 0xea71 : "麭", 0xea72 : "靡", 0xea73 : "黌", 0xea74 : "黎", 0xea75 : "黏", 0xea76 : "黐", 0xea77 : "黔", 0xea78 : "黜", 0xea79 : "點", 0xea7a : "黝", 0xea7b : "黠", 0xea7c : "黥", 0xea7d : "黨", 0xea7e : "黯", 0xea80 : "黴", 0xea81 : "黶", 0xea82 : "黷", 0xea83 : "黹", 0xea84 : "黻", 0xea85 : "黼", 0xea86 : "黽", 0xea87 : "鼇", 0xea88 : "鼈", 0xea89 : "皷", 0xea8a : "鼕", 0xea8b : "鼡", 0xea8c : "鼬", 0xea8d : "鼾", 0xea8e : "齊", 0xea8f : "齒", 0xea90 : "齔", 0xea91 : "齣", 0xea92 : "齟", 0xea93 : "齠", 0xea94 : "齡", 0xea95 : "齦", 0xea96 : "齧", 0xea97 : "齬", 0xea98 : "齪", 0xea99 : "齷", 0xea9a : "齲", 0xea9b : "齶", 0xea9c : "龕", 0xea9d : "龜", 0xea9e : "龠", 0xea9f : "堯", 0xeaa0 : "槇", 0xeaa1 : "遙", 0xeaa2 : "瑤", 0xeaa3 : "凜", 0xeaa4 : "熙", }tegaki-tools-0.3.1/src/tegakitools/tomoe.py0000644000175000017500000000627111342122364020604 0ustar mathieumathieu#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (C) 2009 The Tegaki project contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # Contributors to this file: # - Mathieu Blondel from tegaki.character import Point, Stroke, Writing, Character, _XmlBase from tegaki.charcol import CharacterCollection class TomoeXmlDictionaryReader(_XmlBase): def __init__(self): self._charcol = CharacterCollection() def get_character_collection(self): return self._charcol def _start_element(self, name, attrs): self._tag = name if self._first_tag: self._first_tag = False if self._tag != "dictionary": raise ValueError, "The very first tag should be " if self._tag == "character": self._writing = Writing() if self._tag == "stroke": self._stroke = Stroke() elif self._tag == "point": point = Point() for key in ("x", "y", "pressure", "xtilt", "ytilt", "timestamp"): if attrs.has_key(key): value = attrs[key].encode("UTF-8") if key in ("pressure", "xtilt", "ytilt"): value = float(value) else: value = int(float(value)) else: value = None setattr(point, key, value) self._stroke.append_point(point) def _end_element(self, name): if name == "character": char = Character() char.set_utf8(self._utf8) char.set_writing(self._writing) self._charcol.add_set(self._utf8) self._charcol.append_character(self._utf8, char) for s in ["_tag", "_stroke"]: if s in self.__dict__: del self.__dict__[s] if name == "stroke": self._writing.append_stroke(self._stroke) self._stroke = None self._tag = None def _char_data(self, data): if self._tag == "utf8": self._utf8 = data.encode("UTF-8") elif self._tag == "width": self._writing.set_width(int(data)) elif self._tag == "height": self._writing.set_height(int(data)) def tomoe_dict_to_character_collection(path): reader = TomoeXmlDictionaryReader() gzip = False; bz2 = False if path.endswith(".gz"): gzip = True if path.endswith(".bz2"): bz2 = True reader.read(path, gzip=gzip, bz2=bz2) return reader.get_character_collection() tegaki-tools-0.3.1/src/tegakitools/kuchibue.py0000644000175000017500000001331311342122364021253 0ustar mathieumathieu#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (C) 2009 The Tegaki project contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # Contributors to this file: # - Mathieu Blondel # Incomplete parser for the unipen version of the kuchibue database # See http://www.tuat.ac.jp/~nakagawa/database/ import re import os from tegaki.character import Point, Stroke, Writing, Character from tegaki.charcol import CharacterCollection from unipen import UnipenParser from shiftjis import SHIFT_JIS_TABLE class KuchibueParser(UnipenParser): # The Kuchibue database has three major differences with Tegaki # # 1) (0, 0) is the left-bottom corner in the former while it's the top- # left corner in the latter. # 2) the default screen size is 1280*960 for the former while it's # 1000 * 1000 for the latter # 3) the screen contains 152 boxes (19 columns, 8 rows) for the former # while it contains only 1 for the latter def __init__(self): UnipenParser.__init__(self) self._labels = [] self._characters = [] self._char = None self._row = 0 self._col = 0 self._screen = None self._line = None def _handle_SEGMENT(self, args): seg_type, delimit, quality, label = args.split(" ") if seg_type == "SCREEN": self._screen = [] elif seg_type == "LINE": self._screen.append(0) # number of characters in line elif seg_type == "CHARACTER": label = label.strip()[1:-1] if label.startswith("SJIS"): charcode = int("0" + label[4:], 16) try: label = SHIFT_JIS_TABLE[charcode] except KeyError: pass #print "missing character", hex(charcode) self._labels.append(label) self._screen[-1] += 1 def _handle_X_DIM(self, args): self.FRAME_WIDTH = int(args) def _handle_Y_DIM(self, args): self.FRAME_HEIGHT = int(args) def _get_int_pair_from_line(self, line): k, v = line.split(":") return [int(val) for val in v.strip().split(" ")] def _handle_PAD(self, args): lines = [l.strip() for l in args.split("\n")] for line in lines: if line.startswith("Input Resolution"): self.INPUT_RESOLUTION_WIDTH, self.INPUT_RESOLUTION_HEIGHT = \ self._get_int_pair_from_line(line) def _handle_DATA_INFO(self, args): lines = [l.strip() for l in args.split("\n")] for line in lines: if line.startswith("Frame start"): self.FRAME_START_X, self.FRAME_START_Y = \ self._get_int_pair_from_line(line) elif line.startswith("Frame step"): self.FRAME_STEP_X, self.FRAME_STEP_Y = \ self._get_int_pair_from_line(line) elif line.startswith("Frame count"): self.FRAME_COUNT_COL, self.FRAME_COUNT_ROW = \ self._get_int_pair_from_line(line) def _handle_START_BOX(self, args): if self._char: self._characters.append(self._char) if self._col == self.FRAME_COUNT_COL - 1: self._col = 0 if self._row == self.FRAME_COUNT_ROW - 1: self._row = 0 else: self._row += 1 else: self._col += 1 self._char = Character() def handle_eof(self): if self._char: self._characters.append(self._char) def _get_coordinates(self, x, y): y = abs(y - self.INPUT_RESOLUTION_HEIGHT) # change basis x -= self.FRAME_START_X # remove the padding x -= self.FRAME_STEP_X * self._col # translate to the left x *= float(Writing.WIDTH) / self.FRAME_WIDTH # scale for x = 1000 y -= (self.INPUT_RESOLUTION_HEIGHT - self.FRAME_START_Y) # padding y -= self.FRAME_STEP_Y * self._row # translate to the top y *= float(Writing.HEIGHT) / self.FRAME_HEIGHT # scale for y = 1000 return (int(x), int(y)) def _handle_PEN_DOWN(self, args): writing = self._char.get_writing() points = [[int(p_) for p_ in p.split(" ")] \ for p in args.strip().split("\n")] stroke = Stroke() for x, y in points: x, y = self._get_coordinates(x,y) #assert(x >= 0 and x <= 1000) #assert(y >= 0 and y <= 1000) stroke.append_point(Point(x,y)) writing.append_stroke(stroke) def _handle_PEN_UP(self, args): writing = self._char.get_writing() x, y = [int(p) for p in args.strip().split(" ")] x, y = self._get_coordinates(x,y) strokes = writing.get_strokes() strokes[-1].append(Point(x,y)) def kuchibue_to_character_collection(path): parser = KuchibueParser() parser.parse_file(path) return parser.get_character_collection() if __name__ == "__main__": import sys charcol = kuchibue_to_character_collection(sys.argv[1]) print charcol.to_xml() tegaki-tools-0.3.1/src/tegaki-eval0000755000175000017500000002741511352064314016705 0ustar mathieumathieu#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright (C) 2009 The Tegaki project contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # Contributors to this file: # - Mathieu Blondel import sys import os import time from optparse import OptionParser from tegaki.charcol import CharacterCollection from tegaki.recognizer import Recognizer, RecognizerError from tegakitools.charcol import * VERSION = '0.3.1' def harmonic_mean(x1, x2): if x1 == 0.0 and x2 == 0.0: return 0.0 else: return 2 * float(x1 * x2) / float(x1 + x2) class TegakiEvalError(Exception): pass class TegakiEval(object): MATCH_RESULTS = (1, 5, 10) def __init__(self, options, args): self._verbosity_level = options.verbosity_level self._directories = options.directories self._databases = options.databases self._charcols = options.charcols self._tomoe = options.tomoe self._kuchibue = options.kuchibue self._list = options.list self._include = options.include self._exclude = options.exclude self._max_samples = options.max_samples if not self._list: self._recognizer = args[0] self._model = args[1] def run(self): if self._list: self._list_recognizers() else: self._recognize() def _list_recognizers(self): avail_recognizers = Recognizer.get_all_available_models() print "\n".join(["- %s (%s)" % (model, recog) for recog, model, meta \ in avail_recognizers]) def _recognize(self): charcol = get_aggregated_charcol( ((TYPE_CHARCOL, self._charcols), (TYPE_CHARCOL_DB, self._databases), (TYPE_DIRECTORY, self._directories), (TYPE_TOMOE, self._tomoe), (TYPE_KUCHIBUE, self._kuchibue))) charcol.include_characters_from_files(self._include) charcol.exclude_characters_from_files(self._exclude) # max samples if self._max_samples: charcol.remove_samples(keep_at_most=self._max_samples) # FIXME: don't load all characters in memory all_chars = charcol.get_all_characters() if len(all_chars) == 0: raise TegakiEvalError, "No character samples to evaluate!" recognizer_class = self._get_recognizer_class() recognizer = self._get_recognizer(recognizer_class) self._eval(recognizer, all_chars) def _get_recognizer_class(self): avail_recognizers = Recognizer.get_available_recognizers() if not self._recognizer in avail_recognizers: err = "Not an available recognizer!\n" err += "Available ones include: %s" % \ ", ".join(avail_recognizers.keys()) raise TegakiEvalError, err return avail_recognizers[self._recognizer] def _get_recognizer(self, recognizer_class): recognizer = recognizer_class() if os.path.exists(self._model): # the path exists so we consider the parameter to be a model path method = recognizer.open # try to find a .meta file meta_file = self._model.replace(".model", ".meta") if os.path.exists(meta_file) and meta_file.endswith(".meta"): try: meta = Recognizer.read_meta_file(meta_file) except RecognizerError, e: raise TegakiEvalError, str(e) else: meta = {} else: # otherwise we consider the parameter to be a model name avail_models = recognizer_class.get_available_models() if not self._model in avail_models: err = "Not an available model!\n" err += "Available ones include: %s" % \ ", ".join(["\"%s\"" % k for k in avail_models.keys()]) raise TegakiEvalError, err meta = avail_models[self._model] method = recognizer.set_model try: method(self._model) recognizer.set_options(meta) except RecognizerError, e: raise TegakiEvalError, str(e) return recognizer def _eval(self, recognizer, all_chars): # number of samples present per character n_samples = {} # number of correctly predicted samples per character n_corr_pred = {} # number of times a character was predicted (correctly or not) n_pred = {} for n in self.MATCH_RESULTS: n_corr_pred[n] = {} n_pred[n] = {} # calculate our statistics for each character canddict = {} # store ALL the candidate results for verbosity >= 2 start_time = time.time() for char in all_chars: utf8 = char.get_utf8() if not utf8: continue n_samples[utf8] = n_samples.get(utf8, 0) + 1 cand = recognizer.recognize(char.get_writing(), n=max(self.MATCH_RESULTS)) cand = [char for char, prob in cand] # we don't need the probability if self._verbosity_level >= 2: if utf8 not in canddict: canddict[utf8] = [] canddict[utf8].append(cand) for n in self.MATCH_RESULTS: if utf8 in cand[0:n]: n_corr_pred[n][utf8] = n_corr_pred[n].get(utf8, 0) + 1 for c in cand[0:n]: n_pred[n][c] = n_pred[n].get(c, 0) + 1 end_time = time.time() # Calculate accuracy/recall and precision for each character # Print the overall results print "Overall results" print "\tRecognizer: %s" % self._recognizer print "\tNumber of characters evaluated: %d\n" % len(all_chars) total_time = end_time - start_time print "\tTotal time: %0.2f sec" % float(total_time) print "\tAverage time per character: %0.2f sec" % \ (float(total_time) / len(all_chars)) print "\tRecognition speed: %0.2f char/sec\n" % \ (len(all_chars) / float(total_time)) total_samples = sum(n_samples.values()) recall = {} precision = {} for n in self.MATCH_RESULTS: recall[n] = {} precision[n] = {} for n in self.MATCH_RESULTS: total_corr_pred = sum(n_corr_pred[n].values()) #total_pred = sum(n_pred[n].values()) recall_sum = 0 precision_sum = 0 for k in n_samples.keys(): # recall accounts for the recognizer "completeness" # i.e. number of correct predictions / number of samples recall[n][k] = float(n_corr_pred[n].get(k, 0)) / \ float(n_samples[k]) recall_sum += recall[n][k] # i.e. number of correct predictions / number of predictions try: precision[n][k] = float(n_corr_pred[n].get(k, 0)) / \ float(n_pred[n][k]) except KeyError: precision[n][k] = 0 precision_sum += precision[n][k] recall_sum *= 100 / float(len(n_samples)) precision_sum *= 100 / float(len(n_samples)) print "\tmatch%d" % n print "\t\tAccuracy/Recall: %0.2f" % recall_sum if n == 1: # Precision doesn't make sense for n > 1 print "\t\tPrecision: %0.2f" % precision_sum print "\t\tF1 score: %0.2f" % harmonic_mean(recall_sum, precision_sum) print "" # verbosity level 1 if self._verbosity_level < 1: return print "Result details" for k in n_samples.keys(): print "\tCharacter: %s" %k print "\tNumber of samples: %d\n" % n_samples[k] for n in self.MATCH_RESULTS: print "\t\tmatch%d" % n print "\t\tAccuracy/Recall: %0.2f" % (recall[n][k] * 100) if n == 1: # Precision doesn't make sense for n > 1 print "\t\tPrecision: %0.2f" % (precision[n][k] * 100) f1s = harmonic_mean(recall[n][k], precision[n][k]) * 100 print "\t\tF1 score: %0.2f" % f1s print "" if self._verbosity_level < 2: continue # verbosity level 2 print "\tCandidates:" i = 0 for cand in canddict[k]: print "\tsample%d: %s" % (i, ", ".join(cand)) i += 1 print "" usage = """usage: %prog [options] recognizer model recognizer a recognizer available on the system model a model name available for that recognizer on the system OR the direct file path to the model """ parser = OptionParser(usage=usage, version="%prog " + VERSION) parser.add_option("-v", "--verbosity-level", type="int", dest="verbosity_level", default=0, help="verbosity level between 0 and 2") parser.add_option("-d", "--directory", action="append", type="string", dest="directories", default=[], help="directory containing individual XML character files") parser.add_option("-c", "--charcol", action="append", type="string", dest="charcols", default=[], help="character collection XML files") parser.add_option("-b", "--db", action="append", type="string", dest="databases", default=[], help="character collection XML files") parser.add_option("-t", "--tomoe-dict", action="append", type="string", dest="tomoe", default=[], help="Tomoe XML dictionary files") parser.add_option("-k", "--kuchibue", action="append", type="string", dest="kuchibue", default=[], help="Kuchibue unipen database") parser.add_option("-l", "--list", action="store_true",dest="list", default=False, help="List available recognizers and models") parser.add_option("-i", "--include", action="append", type="string", dest="include", default=[], help="File containing characters to include") parser.add_option("-e", "--exclude", action="append", type="string", dest="exclude", default=[], help="File containing characters to exclude") parser.add_option("-m", "--max-samples", type="int", dest="max_samples", help="Maximum number of samples per character") (options, args) = parser.parse_args() try: if not options.list and len(args) < 2: raise TegakiEvalError, "Needs a recognizer and a model!" TegakiEval(options, args).run() except TegakiEvalError, e: sys.stderr.write(str(e) + "\n\n") parser.print_help() sys.exit(1) tegaki-tools-0.3.1/COPYING0000644000175000017500000004326211342122364015027 0ustar mathieumathieu GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. tegaki-tools-0.3.1/PKG-INFO0000644000175000017500000000040211352066723015065 0ustar mathieumathieuMetadata-Version: 1.0 Name: tegaki-tools Version: 0.3.1 Summary: A set of command-line tools for Tegaki. Home-page: http://www.tegaki.org Author: Mathieu Blondel Author-email: mathieu ÂT mblondel DÔT org License: GPL Description: UNKNOWN Platform: UNKNOWN tegaki-tools-0.3.1/README0000644000175000017500000000177611342122364014660 0ustar mathieumathieutegaki-tools ============ A set of command-line tools for Tegaki. Tools ------ * tegaki-boostrap: bootstrap a character collection using similar collections and knowledge about the characters shape data. * tegaki-build: build/train handwriting recognition models. * tegaki-convert: convert and/or concat character collection files. * tegaki-eval: evaluate handwriting recognition models against test data. * tegaki-render: convert character file to an image or video. * tegaki-stats: show various statistics about a character collection. Requirements ------------ tegaki-python 0.3 tegaki-pygtk 0.3 Install ------- ($ su) # python setup.py install Additionally, if you would like GIF support in tegaki-render: $ cd tegaki-gifenc $ python setup.py build ($ su) # python setup.py install License ------- This package is distributed under the terms of the GNU General Public License. See the COPYING file for more information. Homepage -------- http://www.tegaki.org tegaki-tools-0.3.1/tegaki-gifenc/0000755000175000017500000000000011352066723016471 5ustar mathieumathieutegaki-tools-0.3.1/tegaki-gifenc/tegakigifenc.h0000644000175000017500000000334511342122364021260 0ustar mathieumathieu/* * Copyright (C) 2009 The Tegaki project contributors * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* * Contributors to this file: * - Mathieu Blondel */ #ifndef TEGAKIGIFENC_H #define TEGAKIGIFENC_H #include extern "C" { #include "gifenc/gifenc.h" } namespace tegakigifenc { class GifEncoder { public: GifEncoder(); ~GifEncoder(); bool open(char *filename, unsigned int width, unsigned int height, bool alpha, bool loop); void add_image(unsigned int x, unsigned int y, unsigned int width, unsigned int height, unsigned int display_millis, char *data, unsigned int rowstride); void set_palette_for_image(char *data, unsigned int width, unsigned int height, unsigned int rowstride, bool alpha, unsigned int max_colors); void close(); private: Gifenc *enc; GifencPalette *palette; FILE *output; }; } #endif tegaki-tools-0.3.1/tegaki-gifenc/tegakigifenc.cpp0000644000175000017500000000561611342122364021616 0ustar mathieumathieu/* * Copyright (C) 2009 The Tegaki project contributors * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* * Contributors to this file: * - Mathieu Blondel */ #include #include #include #include "tegakigifenc.h" namespace tegakigifenc { static gboolean encoder_write_data (gpointer closure, const guchar * data, gsize len, GError ** error) { FILE *f = (FILE *)closure; fwrite(data, 1, len, f); return 1; } GifEncoder::GifEncoder() { palette = NULL; } void GifEncoder::set_palette_for_image(char *data, unsigned int width, unsigned int height, unsigned int rowstride, bool alpha, unsigned int max_colors) { palette = gifenc_quantize_image ((const guint8 *) data, width, height, rowstride, alpha ? TRUE : FALSE, max_colors); } bool GifEncoder::open(char *filename, unsigned int width, unsigned int height, bool alpha, bool loop) { output = fopen(filename, "w"); if (!output) return false; enc = gifenc_new(width, height, encoder_write_data, output, NULL); if (!palette) palette = gifenc_palette_get_simple(alpha ? TRUE : FALSE); gifenc_initialize (enc, palette, loop ? TRUE : FALSE, NULL); return true; } void GifEncoder::add_image(unsigned int x, unsigned int y, unsigned int width, unsigned int height, unsigned int display_millis, char *data, unsigned int rowstride) { guint8 *target = (guint8 *) malloc(width * height * sizeof(guint8) * 4); gifenc_dither_rgb(target, rowstride, palette, (guint8 *)data, width, height, rowstride); gifenc_add_image(enc, x, y, width, height, display_millis, (guint8 *)target, rowstride, NULL); free(target); } void GifEncoder::close() { gifenc_close(enc, NULL); } GifEncoder::~GifEncoder() { if(enc) gifenc_free(enc); fclose(output); } } tegaki-tools-0.3.1/tegaki-gifenc/tegakigifenc.i0000644000175000017500000000011711342122364021253 0ustar mathieumathieu%module tegakigifenc %{ #include "tegakigifenc.h" %} %include "tegakigifenc.h"tegaki-tools-0.3.1/tegaki-gifenc/setup.py0000644000175000017500000000220411342122364020172 0ustar mathieumathieu# -*- coding: utf-8 -*- import os import re import subprocess from distutils.core import setup, Extension VERSION = "0.3" def pkg_config(package, option): sub = subprocess.Popen(["pkg-config",option,package], stdout=subprocess.PIPE) spaces = re.compile('\s+',re.DOTALL) args = spaces.split(sub.stdout.read().strip()) sub.stdout.close() sub.wait() return [a[2:] for a in args] setup( name="tegaki-gifenc", description = 'GIF encoder for Tegaki', author = 'Mathieu Blondel', author_email = 'mathieu ÂT mblondel DÔT org', url = 'http://www.tegaki.org', version = VERSION, license='GPL', py_modules=['tegakigifenc'], ext_modules=[Extension("_tegakigifenc", ["tegakigifenc.i","tegakigifenc.cpp", "gifenc/gifenc.c", "gifenc/quantize.c"], include_dirs = pkg_config('gtk+-2.0','--cflags'), libraries = pkg_config('gtk+-2.0','--libs'), #library_dirs = pkg_config('glib-2.0','--libs'), swig_opts=['-c++'])], )tegaki-tools-0.3.1/tegaki-gifenc/gifenc/0000755000175000017500000000000011352066723017724 5ustar mathieumathieutegaki-tools-0.3.1/tegaki-gifenc/gifenc/quantize.c0000644000175000017500000002471711342122364021734 0ustar mathieumathieu/* simple gif encoder * Copyright (C) 2005 Benjamin Otte #include #include "gifenc.h" /*** GENERAL ***/ void gifenc_palette_free (GifencPalette *palette) { g_return_if_fail (palette != NULL); if (palette->free) palette->free (palette->data); g_free (palette); } guint gifenc_palette_get_alpha_index (const GifencPalette *palette) { g_return_val_if_fail (palette != NULL, 0); g_return_val_if_fail (palette->alpha, 0); return palette->num_colors; } guint gifenc_palette_get_num_colors (const GifencPalette *palette) { g_return_val_if_fail (palette != NULL, 0); return palette->num_colors + (palette->alpha ? 1 : 0); } guint gifenc_palette_get_color (const GifencPalette *palette, guint id) { g_return_val_if_fail (palette != NULL, 0); g_return_val_if_fail (id < palette->num_colors, 0); return palette->colors[id]; } /*** SIMPLE ***/ static guint gifenc_palette_simple_lookup (gpointer data, guint32 color, guint32 *resulting_color) { color &= 0xC0C0C0; *resulting_color = color + 0x202020; return ((color >> 18) & 0x30) | ((color >> 12) & 0xC) | ((color >> 6) & 0x3); } GifencPalette * gifenc_palette_get_simple (gboolean alpha) { GifencPalette *palette; guint r, g, b, i = 0; palette = g_new (GifencPalette, 1); palette->alpha = alpha; palette->num_colors = 64; palette->colors = g_new (guint, palette->num_colors); for (r = 0; r < 4; r++) { for (g = 0; g < 4; g++) { for (b = 0; b < 4; b++) { palette->colors[i++] = (r << 22) + (g << 14) + (b << 6) + 0x202020; } } } palette->data = GINT_TO_POINTER (alpha ? 1 : 0); palette->lookup = gifenc_palette_simple_lookup; palette->free = NULL; return palette; } /*** OCTREE QUANTIZATION ***/ /* maximum number of leaves before starting color reduction */ #define MAX_LEAVES (12000) /* maximum number of leaves before stopping a running color reduction */ #define STOP_LEAVES (MAX_LEAVES >> 2) typedef struct _GifencOctree GifencOctree; struct _GifencOctree { GifencOctree * children[8]; /* children nodes or NULL */ guint level; /* how deep in tree are we? */ guint red; /* sum of all red pixels */ guint green; /* sum of green pixels */ guint blue; /* sum of blue pixels */ guint count; /* amount of pixels at this node */ guint32 color; /* representations (depending on value): -1: random non-leaf node -2: root node 0x1000000: leaf node with undefined color 0-0xFFFFFF: leaf node with defined color */ guint id; /* color index */ }; typedef struct { GifencOctree * tree; GSList * non_leaves; guint num_leaves; } OctreeInfo; #define OCTREE_IS_LEAF(tree) ((tree)->color <= 0x1000000) static GifencOctree * gifenc_octree_new (void) { GifencOctree *ret = g_new0 (GifencOctree, 1); ret->color = (guint) -1; return ret; } static void gifenc_octree_free (gpointer data) { GifencOctree *tree = data; guint i; for (i = 0; i < 8; i++) { if (tree->children[i]) gifenc_octree_free (tree->children[i]); } g_free (tree); } #if 0 #define PRINT_NON_LEAVES 1 static void gifenc_octree_print (GifencOctree *tree, guint flags) { #define FLAG_SET(flag) (flags & (flag)) if (OCTREE_IS_LEAF (tree)) { g_print ("%*s %6d %2X-%2X-%2X\n", tree->level * 2, "", tree->count, tree->red / tree->count, tree->green / tree->count, tree->blue / tree->count); } else { guint i; if (FLAG_SET(PRINT_NON_LEAVES)) g_print ("%*s %6d\n", tree->level * 2, "", tree->count); g_assert (tree->red == 0); g_assert (tree->green == 0); g_assert (tree->blue == 0); for (i = 0; i < 8; i++) { if (tree->children[i]) gifenc_octree_print (tree->children[i], flags); } } #undef FLAG_SET } #endif static guint color_to_index (guint color, guint level) { guint ret; g_assert (level < 8); color >>= (7 - level); ret = (color & 0x10000) ? 4 : 0; if (color & 0x100) ret += 2; if (color & 0x1) ret ++; return ret; } static void gifenc_octree_add_one (GifencOctree *tree, guint32 color, guint count) { tree->red += ((color >> 16) & 0xFF) * count; tree->green += ((color >> 8) & 0xFF) * count; tree->blue += (color & 0xFF) * count; } static void gifenc_octree_add_color (OctreeInfo *info, guint32 color, guint count) { guint i; GifencOctree *tree = info->tree; color &= 0xFFFFFF; for (;;) { tree->count += count; if (tree->level == 8 || OCTREE_IS_LEAF (tree)) { if (tree->color < 0x1000000 && tree->color != color) { GifencOctree *new = gifenc_octree_new (); new->level = tree->level + 1; new->count = tree->count - count; new->red = tree->red; tree->red = 0; new->green = tree->green; tree->green = 0; new->blue = tree->blue; tree->blue = 0; new->color = tree->color; tree->color = (guint) -1; i = color_to_index (new->color, tree->level); tree->children[i] = new; info->non_leaves = g_slist_prepend (info->non_leaves, tree); } else { gifenc_octree_add_one (tree, color, count); return; } } i = color_to_index (color, tree->level); if (tree->children[i]) { tree = tree->children[i]; } else { GifencOctree *new = gifenc_octree_new (); new->level = tree->level + 1; gifenc_octree_add_one (new, color, count); new->count = count; new->color = color; tree->children[i] = new; info->num_leaves++; return; } } } static int octree_compare_count (gconstpointer a, gconstpointer b) { return ((const GifencOctree *) a)->count - ((const GifencOctree *) b)->count; } static void gifenc_octree_reduce_one (OctreeInfo *info, GifencOctree *tree) { guint i; g_assert (!OCTREE_IS_LEAF (tree)); for (i = 0; i < 8; i++) { if (!tree->children[i]) continue; g_assert (OCTREE_IS_LEAF (tree->children[i])); tree->red += tree->children[i]->red; tree->green += tree->children[i]->green; tree->blue += tree->children[i]->blue; gifenc_octree_free (tree->children[i]); tree->children[i] = NULL; info->num_leaves--; } tree->color = 0x1000000; info->num_leaves++; info->non_leaves = g_slist_remove (info->non_leaves, tree); } static void gifenc_octree_reduce_colors (OctreeInfo *info, guint stop) { info->non_leaves = g_slist_sort (info->non_leaves, octree_compare_count); //g_print ("reducing %u leaves (%u non-leaves)\n", info->num_leaves, // g_slist_length (info->non_leaves)); while (info->num_leaves > stop) { gifenc_octree_reduce_one (info, info->non_leaves->data); } //g_print (" ==> to %u leaves\n", info->num_leaves); } static guint gifenc_octree_finalize (GifencOctree *tree, guint start_id, guint *colors) { if (OCTREE_IS_LEAF (tree)) { if (tree->color > 0xFFFFFF) tree->color = ((tree->red / tree->count) << 16) | ((tree->green / tree->count) << 8) | (tree->blue / tree->count); tree->id = start_id; colors[start_id] = tree->color; return tree->id + 1; } else { guint i; for (i = 0; i < 8; i++) { if (tree->children[i]) start_id = gifenc_octree_finalize (tree->children[i], start_id, colors); } return start_id; } g_assert_not_reached (); return 0; } static guint gifenc_octree_lookup (gpointer data, guint32 color, guint32 *looked_up_color) { GifencOctree *tree = data; guint idx; if (OCTREE_IS_LEAF (tree)) { *looked_up_color = tree->color; return tree->id; } idx = color_to_index (color, tree->level); if (tree->children[idx] == NULL) { static const guint order[8][7] = { { 2, 1, 4, 3, 6, 5, 7 }, { 3, 0, 5, 2, 7, 4, 6 }, { 0, 3, 6, 1, 4, 7, 5 }, { 1, 2, 7, 6, 5, 0, 4 }, { 6, 5, 0, 7, 2, 1, 3 }, { 7, 4, 1, 6, 3, 0, 2 }, { 4, 7, 2, 5, 0, 3, 1 }, { 5, 6, 3, 4, 1, 2, 0 } }; guint i, tmp; for (i = 0; i < 7; i++) { tmp = order[idx][i]; if (!tree->children[tmp]) continue; /* make selection smarter, like using closest match */ return gifenc_octree_lookup ( tree->children[tmp], color, looked_up_color); } g_assert_not_reached (); } return gifenc_octree_lookup ( tree->children[idx], color, looked_up_color); } GifencPalette * gifenc_quantize_image (const guint8 *data, guint width, guint height, guint rowstride, gboolean alpha, guint max_colors) { guint x, y; const guint32 *row; OctreeInfo info = { NULL, NULL, 0 }; GifencPalette *palette; g_return_val_if_fail (width * height <= (G_MAXUINT >> 8), NULL); info.tree = gifenc_octree_new (); info.tree->color = (guint) -2; /* special node */ if (TRUE) { guint r, g, b, count; static const guint8 colors[] = { 0, 85, 170, 255 }; count = (width * height) / (4 * 4 * 4); for (r = 0; r < 4; r++) { for (g = 0; g < 4; g++) { for (b = 0; b < 4; b++) { gifenc_octree_add_color (&info, (colors[r] << 16) + (colors[g] << 8) + colors[b], 1); } } } } for (y = 0; y < height; y++) { row = (const guint32 *) data; for (x = 0; x < width; x++) { gifenc_octree_add_color (&info, row[x] & 0xFFFFFF, 1); } //if (info.num_leaves > MAX_LEAVES) // gifenc_octree_reduce_colors (&info, STOP_LEAVES); data += rowstride; } //gifenc_octree_print (info.tree, 1); gifenc_octree_reduce_colors (&info, max_colors - (alpha ? 1 : 0)); //gifenc_octree_print (info.tree, 1); //g_print ("total: %u colors (%u non-leaves)\n", info.num_leaves, // g_slist_length (info.non_leaves)); palette = g_new (GifencPalette, 1); palette->alpha = alpha; palette->colors = g_new (guint, info.num_leaves); palette->num_colors = info.num_leaves; palette->data = info.tree; palette->lookup = gifenc_octree_lookup; palette->free = gifenc_octree_free; gifenc_octree_finalize (info.tree, 0, palette->colors); g_slist_free (info.non_leaves); return (GifencPalette *) palette; } tegaki-tools-0.3.1/tegaki-gifenc/gifenc/gifenc.h0000644000175000017500000001012311342122364021316 0ustar mathieumathieu/* simple gif encoder * Copyright (C) 2005 Benjamin Otte #include #ifndef __HAVE_GIFENC_H__ #define __HAVE_GIFENC_H__ typedef struct _GifencPalette GifencPalette; typedef struct _GifencColor GifencColor; typedef struct _Gifenc Gifenc; typedef gboolean (* GifencWriteFunc) (gpointer closure, const guchar *data, gsize len, GError **error); typedef enum { GIFENC_STATE_NEW = 0, GIFENC_STATE_INITIALIZED, GIFENC_STATE_CLOSED, } GifencState; struct _GifencPalette { gboolean alpha; guint32 * colors; guint num_colors; guint byte_order; gpointer data; guint (* lookup) (gpointer data, guint32 color, guint32 * resulting_color); void (* free) (gpointer data); }; struct _Gifenc { /* error checking */ GifencState state; /* output */ GifencWriteFunc write_func; gpointer write_data; GDestroyNotify write_destroy; GByteArray * buffer; guint bits; guint n_bits; /* image */ guint width; guint height; guint byte_order; GifencPalette * palette; }; Gifenc * gifenc_new (guint width, guint height, GifencWriteFunc write_func, gpointer write_data, GDestroyNotify write_destroy); gboolean gifenc_free (Gifenc * enc); gboolean gifenc_initialize (Gifenc * enc, GifencPalette * palette, gboolean loop, GError ** error); gboolean gifenc_add_image (Gifenc * enc, guint x, guint y, guint width, guint height, guint display_millis, guint8 * data, guint rowstride, GError ** error); gboolean gifenc_close (Gifenc * gifenc, GError ** error); guint gifenc_get_width (Gifenc * gifenc); guint gifenc_get_height (Gifenc * gifenc); void gifenc_dither_rgb (guint8 * target, guint target_rowstride, const GifencPalette * palette, const guint8 * data, guint width, guint height, guint rowstride); gboolean gifenc_dither_rgb_with_full_image (guint8 * target, guint target_rowstride, guint8 * full, guint full_rowstride, const GifencPalette * palette, const guint8 * data, guint width, guint height, guint rowstride, GdkRectangle * rect_out); /* from quantize.c */ void gifenc_palette_free (GifencPalette * palette); GifencPalette * gifenc_palette_get_simple (gboolean alpha); GifencPalette * gifenc_quantize_image (const guint8 * data, guint width, guint height, guint rowstride, gboolean alpha, guint max_colors); guint gifenc_palette_get_alpha_index (const GifencPalette * palette); guint gifenc_palette_get_num_colors (const GifencPalette * palette); guint32 gifenc_palette_get_color(const GifencPalette * palette, guint id); #endif /* __HAVE_GIFENC_H__ */ tegaki-tools-0.3.1/tegaki-gifenc/gifenc/gifenc.c0000644000175000017500000004162011342122364021317 0ustar mathieumathieu/* simple gif encoder * Copyright (C) 2005 Benjamin Otte #include #include #include #include #include #include "gifenc.h" /*** UTILITIES ***/ static guint log2n (guint number) { guint ret = 0; while (number > 0) { number >>= 1; ret++; } return ret; } #define RED(x) ((guint8) ((x) >> 16)) #define GREEN(x) ((guint8) ((x) >> 8)) #define BLUE(x) ((guint8) (x)) #define COLOR(r, g, b) (((r) << 16) | ((g) << 8) | (b)) /*** WRITE ROUTINES ***/ static gboolean gifenc_flush (Gifenc *enc, GError **error) { gboolean result; if (enc->buffer->len == 0) return TRUE; result = enc->write_func (enc->write_data, enc->buffer->data, enc->buffer->len, error); g_byte_array_set_size (enc->buffer, 0); return result; } static void gifenc_write_uint16 (Gifenc *enc, guint16 value) { g_return_if_fail (enc->n_bits == 0); value = GUINT16_TO_LE (value); g_byte_array_append (enc->buffer, (guint8 *) &value, 2); } static void gifenc_write_byte (Gifenc *enc, guint8 value) { g_return_if_fail (enc->n_bits == 0); g_byte_array_append (enc->buffer, &value, 1); } static void gifenc_write_bits (Gifenc *enc, guint bits, guint nbits) { g_return_if_fail (bits <= 24); g_return_if_fail ((bits & ((1 << nbits) - 1)) == bits); enc->bits <<= nbits; enc->bits |= bits; nbits = enc->n_bits + nbits; enc->n_bits = 0; while (nbits >= 8) { nbits -= 8; gifenc_write_byte (enc, enc->bits >> nbits); } enc->n_bits = nbits; enc->bits &= (1 << nbits) - 1; } /*** FUNCTIONS TO WRITE BLOCKS ***/ static void gifenc_write_header (Gifenc *enc) { g_byte_array_append (enc->buffer, (const guchar *) "GIF89a", 6); } static void gifenc_write_lsd (Gifenc *enc, GifencPalette *palette) { g_assert (palette == NULL || gifenc_palette_get_num_colors (palette) >= 2); gifenc_write_uint16 (enc, enc->width); gifenc_write_uint16 (enc, enc->height); gifenc_write_bits (enc, palette ? 1 : 0, 1); /* global color table flag */ gifenc_write_bits (enc, 0x7, 3); /* color resolution */ gifenc_write_bits (enc, 0, 1); /* sort flag */ gifenc_write_bits (enc, palette ? log2n (gifenc_palette_get_num_colors (palette) - 1) - 1 : 0, 3); /* number of colors */ gifenc_write_byte (enc, 0); /* background color */ gifenc_write_byte (enc, 0); /* pixel aspect ratio */ } static void gifenc_write_color_table (Gifenc *enc, GifencPalette *palette) { guint i, table_size; if (!palette) return; i = gifenc_palette_get_num_colors (palette); table_size = 1 << log2n (i - 1); for (i = 0; i < palette->num_colors; i++) { gifenc_write_byte (enc, RED (palette->colors[i])); gifenc_write_byte (enc, GREEN (palette->colors[i])); gifenc_write_byte (enc, BLUE (palette->colors[i])); } if (palette->alpha) { g_byte_array_append (enc->buffer, (guint8 *) "\272\219\001", 3); i++; } for (; i < table_size; i++) { g_byte_array_append (enc->buffer, (guint8 *) "\0\0\0", 3); } } typedef struct { guint x; guint y; guint width; guint height; GifencPalette *palette; guint8 *data; guint rowstride; } GifencImage; static void gifenc_write_image_description (Gifenc *enc, const GifencImage *image) { gifenc_write_byte (enc, 0x2C); gifenc_write_uint16 (enc, image->x); gifenc_write_uint16 (enc, image->y); gifenc_write_uint16 (enc, image->width); gifenc_write_uint16 (enc, image->height); gifenc_write_bits (enc, image->palette ? 1 : 0, 1); /* local color table flag */ gifenc_write_bits (enc, 0, 1); /* interlace flag */ gifenc_write_bits (enc, 0, 1); /* sort flag */ gifenc_write_bits (enc, 0, 2); /* reserved */ gifenc_write_bits (enc, image->palette ? log2n (gifenc_palette_get_num_colors (image->palette) - 1) - 1 : 0, 3); /* number of palette */ gifenc_write_color_table (enc, image->palette); } typedef struct { guint8 data[255]; guint bytes; guint current_data; guint bits; } EncodeBuffer; static void gifenc_buffer_write (Gifenc *enc, EncodeBuffer *buffer) { if (buffer->bytes == 0) return; gifenc_write_byte (enc, buffer->bytes); g_byte_array_append (enc->buffer, buffer->data, buffer->bytes); buffer->bytes = 0; } static void G_GNUC_UNUSED print_bits (const char *text, guint data, int bits) { int i; g_print ("%s %u (", text, data); for (i = bits - 1; i >= 0; i--) { g_print ("%c", data & (1 << i) ? '1' : '0'); } g_print (")\n"); } #define print_bits(text, data, bits) static void gifenc_buffer_append (Gifenc *enc, EncodeBuffer *buffer, guint data, guint bits) { g_assert (buffer->bits + bits < 24); //g_print ("got code %u (%u)\n", data, bits); print_bits ("appending", data, bits); buffer->current_data |= (data << buffer->bits); buffer->bits += bits; while (buffer->bits >= 8) { if (buffer->bytes == 255) gifenc_buffer_write (enc, buffer); buffer->data[buffer->bytes] = buffer->current_data; print_bits ("got", buffer->data[buffer->bytes], 8); buffer->bits -= 8; buffer->current_data >>= 8; buffer->bytes++; } } static void gifenc_buffer_flush (Gifenc *enc, EncodeBuffer *buffer) { if (buffer->bits) gifenc_buffer_append (enc, buffer, 0, 8 - buffer->bits); gifenc_buffer_write (enc, buffer); gifenc_write_byte (enc, 0); } static void gifenc_write_image_data (Gifenc *enc, const GifencImage *image) { guint codesize, wordsize, x, y; guint next = 0, count = 0, clear, eof, hashcode, hashvalue, cur, codeword; guint8 *data; #define HASH_SIZE (5003) struct { guint value; guint code; } hash[HASH_SIZE]; EncodeBuffer buffer = { { 0, }, 0, 0, 0 }; codesize = log2n (gifenc_palette_get_num_colors (image->palette ? image->palette : enc->palette) - 1); codesize = MAX (codesize, 2); gifenc_write_byte (enc, codesize); //g_print ("codesize with %u palette is %u\n", enc->n_palette, codesize); clear = 1 << codesize; eof = clear + 1; codeword = cur = *image->data; //g_print ("read byte %u\n", cur); wordsize = codesize + 1; gifenc_buffer_append (enc, &buffer, clear, wordsize); if (1 == image->width) { y = 1; x = 0; data = image->data + image->rowstride; } else { y = 0; x = 1; data = image->data; } while (y < image->height) { count = eof + 1; next = (1 << wordsize); /* clear hash */ memset (hash, 0xFF, sizeof (hash)); while (y < image->height) { cur = data[x]; //g_print ("read byte %u\n", cur); x++; if (x >= image->width) { y++; x = 0; data += image->rowstride; } hashcode = codeword ^ (cur << 4); hashvalue = (codeword << 8) | cur; loop: if (hash[hashcode].value == hashvalue) { codeword = hash[hashcode].code; continue; } if (hash[hashcode].value != (guint) -1) { /* not empty */ hashcode = (hashcode + 0xF) % HASH_SIZE; goto loop; } /* found empty slot, put code there */ hash[hashcode].value = hashvalue; hash[hashcode].code = count; //g_print ("saving as %u (%X):", count, count); gifenc_buffer_append (enc, &buffer, codeword, wordsize); count++; codeword = cur; if (count > next) { if (wordsize == 12) { gifenc_buffer_append (enc, &buffer, clear, wordsize); wordsize = codesize + 1; break; } next = MIN (next << 1, 0xFFF); wordsize++; } } } gifenc_buffer_append (enc, &buffer, codeword, wordsize); if (count == next) { wordsize++; if (wordsize > 12) { wordsize = codesize + 1; gifenc_buffer_append (enc, &buffer, clear, wordsize); } } gifenc_buffer_append (enc, &buffer, eof, wordsize); gifenc_buffer_flush (enc, &buffer); } static void gifenc_write_graphic_control (Gifenc *enc, GifencPalette *palette, guint milliseconds) { gifenc_write_byte (enc, 0x21); /* extension */ gifenc_write_byte (enc, 0xF9); /* extension type */ gifenc_write_byte (enc, 0x04); /* size */ gifenc_write_bits (enc, 0, 3); /* reserved */ gifenc_write_bits (enc, 1, 3); /* disposal: do not dispose */ gifenc_write_bits (enc, 0, 1); /* no user input required */ gifenc_write_bits (enc, palette->alpha ? 1 : 0, 1); /* transparent color? */ gifenc_write_uint16 (enc, milliseconds / 10); /* display this long */ gifenc_write_byte (enc, palette->alpha ? palette->num_colors : 0); /* transparent color index */ gifenc_write_byte (enc, 0); /* terminator */ } static void gifenc_write_loop (Gifenc *enc) { gifenc_write_byte (enc, 0x21); /* extension */ gifenc_write_byte (enc, 0xFF); /* application extension */ gifenc_write_byte (enc, 11); /* block size */ g_byte_array_append (enc->buffer, (guint8 *) "NETSCAPE2.0", 11); gifenc_write_byte (enc, 3); /* block size */ gifenc_write_byte (enc, 1); /* ??? */ gifenc_write_byte (enc, 0); /* ??? */ gifenc_write_byte (enc, 0); /* ??? */ gifenc_write_byte (enc, 0); /* block terminator */ } /*** PUBLIC API ***/ Gifenc * gifenc_new (guint width, guint height, GifencWriteFunc write_func, gpointer write_data, GDestroyNotify write_destroy) { Gifenc *enc; g_return_val_if_fail (width <= G_MAXUINT16, NULL); g_return_val_if_fail (height <= G_MAXUINT16, NULL); g_return_val_if_fail (write_func, NULL); enc = g_slice_new0 (Gifenc); enc->width = width; enc->height = height; enc->buffer = g_byte_array_new (); enc->write_func = write_func; enc->write_data = write_data; enc->write_destroy = write_destroy; return enc; } gboolean gifenc_initialize (Gifenc *enc, GifencPalette *palette, gboolean loop, GError **error) { g_return_val_if_fail (enc != NULL, FALSE); g_return_val_if_fail (enc->state == GIFENC_STATE_NEW, FALSE); g_return_val_if_fail (palette != NULL, FALSE); gifenc_write_header (enc); gifenc_write_lsd (enc, palette); gifenc_write_color_table (enc, palette); if (loop) gifenc_write_loop (enc); if (!gifenc_flush (enc, error)) return FALSE; enc->palette = palette; enc->state = GIFENC_STATE_INITIALIZED; return TRUE; } gboolean gifenc_add_image (Gifenc *enc, guint x, guint y, guint width, guint height, guint display_millis, guint8 *data, guint rowstride, GError **error) { GifencImage image = { x, y, width, height, NULL, data, rowstride }; g_return_val_if_fail (enc != NULL, FALSE); g_return_val_if_fail (enc->state == GIFENC_STATE_INITIALIZED, FALSE); g_return_val_if_fail (width > 0, FALSE); g_return_val_if_fail (x + width <= enc->width, FALSE); g_return_val_if_fail (height > 0, FALSE); g_return_val_if_fail (y + height <= enc->height, FALSE); //g_print ("adding image (display time %u)\n", display_millis); gifenc_write_graphic_control (enc, image.palette ? image.palette : enc->palette, display_millis); gifenc_write_image_description (enc, &image); gifenc_write_image_data (enc, &image); return gifenc_flush (enc, error); } gboolean gifenc_close (Gifenc *enc, GError **error) { g_return_val_if_fail (enc != NULL, FALSE); g_return_val_if_fail (enc->state == GIFENC_STATE_INITIALIZED, FALSE); gifenc_write_byte (enc, 0x3B); if (!gifenc_flush (enc, error)) return FALSE; enc->state = GIFENC_STATE_CLOSED; return TRUE; } gboolean gifenc_free (Gifenc *enc) { gboolean success; g_return_val_if_fail (enc != NULL, FALSE); success = enc->state == GIFENC_STATE_CLOSED; if (enc->write_destroy) enc->write_destroy (enc->write_data); if (enc->palette) gifenc_palette_free (enc->palette); //g_byte_array_unref (enc->buffer); g_byte_array_free (enc->buffer, TRUE); g_slice_free (Gifenc, enc); return success; } guint gifenc_get_width (Gifenc *gifenc) { g_return_val_if_fail (gifenc != NULL, 0); return gifenc->width; } guint gifenc_get_height (Gifenc *gifenc) { g_return_val_if_fail (gifenc != NULL, 0); return gifenc->height; } /* Floyd-Steinman factors */ #define FACTOR0 (23) #define FACTOR1 (79) #define FACTOR2 (41) #define FACTOR_FRONT (113) void gifenc_dither_rgb (guint8* target, guint target_rowstride, const GifencPalette *palette, const guint8 *data, guint width, guint height, guint rowstride) { guint x, y, i, c; gint *this_error, *next_error; guint8 this[3]; gint err[3] = { 0, 0, 0 }; guint32 pixel; g_return_if_fail (palette != NULL); this_error = g_new0 (gint, (width + 2) * 3); next_error = g_new (gint, (width + 2) * 3); i = 0; for (y = 0; y < height; y++) { const guint32 *row = (const guint32 *) data; gint *cur_error = this_error + 3; gint *cur_next_error = next_error; err[0] = err[1] = err[2] = 0; memset (cur_next_error, 0, sizeof (gint) * 6); for (x = 0; x < width; x++) { //g_print ("%dx%d %2X%2X%2X %2d %2d %2d", x, y, row[0], row[1], row[2], // (err[0] + cur_error[0]) >> 8, (err[1] + cur_error[1]) >> 8, // (err[2] + cur_error[2]) >> 8); for (c = 0; c < 3; c++) { err[c] = ((err[c] + cur_error[c]) >> 8) + (guint8) (*row >> 8 * c); this[c] = err[c] = CLAMP (err[c], 0, 0xFF); } pixel = COLOR (err[2], err[1], err[0]); //g_print (" %2X%2X%2X =>", this[0], this[1], this[2]); target[x] = palette->lookup (palette->data, pixel, &pixel); //g_print (" %2X%2X%2X (%u) %p\n", this[0], this[1], this[2], (guint) target[x], target + x); for (c = 0; c < 3; c++) { this[c] = *row >> 8 * c; err[c] -= this[c]; cur_next_error[c] += FACTOR0 * err[c]; cur_next_error[c + 3] += FACTOR1 * err[c]; cur_next_error[c + 6] = FACTOR2 * err[c]; err[c] *= FACTOR_FRONT; } row++; cur_error += 3; cur_next_error += 3; } data += rowstride; cur_error = this_error; this_error = next_error; next_error = cur_error; target += target_rowstride; } g_free (this_error); g_free (next_error); } gboolean gifenc_dither_rgb_with_full_image (guint8 *target, guint target_rowstride, guint8 *full, guint full_rowstride, const GifencPalette *palette, const guint8 *data, guint width, guint height, guint rowstride, GdkRectangle *rect_out) { int x, y, i, c; gint *this_error, *next_error; guint8 this[3], alpha; gint err[3] = { 0, 0, 0 }; guint32 pixel; GdkRectangle area = { width, height, 0, 0 }; g_return_val_if_fail (palette != NULL, FALSE); g_return_val_if_fail (palette->alpha, FALSE); alpha = gifenc_palette_get_alpha_index (palette); this_error = g_new0 (gint, (width + 2) * 3); next_error = g_new (gint, (width + 2) * 3); i = 0; for (y = 0; y < (int) height; y++) { const guint32 *row = (const guint32 *) data; gint *cur_error = this_error + 3; gint *cur_next_error = next_error; err[0] = err[1] = err[2] = 0; memset (cur_next_error, 0, sizeof (gint) * 6); for (x = 0; x < (int) width; x++) { //g_print ("%dx%d %2X%2X%2X %2d %2d %2d", x, y, row[0], row[1], row[2], // (err[0] + cur_error[0]) >> 8, (err[1] + cur_error[1]) >> 8, // (err[2] + cur_error[2]) >> 8); for (c = 0; c < 3; c++) { err[c] = ((err[c] + cur_error[c]) >> 8) + (guint8) (*row >> 8 * c); this[c] = err[c] = CLAMP (err[c], 0, 0xFF); } //g_print (" %2X%2X%2X =>", this[0], this[1], this[2]); pixel = COLOR (this[2], this[1], this[0]); target[x] = palette->lookup (palette->data, pixel, &pixel); if (target[x] == full[x]) { target[x] = alpha; } else { area.x = MIN (x, area.x); area.y = MIN (y, area.y); area.width = MAX (x, area.width); area.height = MAX (y, area.height); full[x] = target[x]; } //g_print (" %2X%2X%2X (%u) %p\n", this[0], this[1], this[2], (guint) target[x], target + x); for (c = 0; c < 3; c++) { this[0] = *row >> 8 * c; err[c] -= this[c]; cur_next_error[c] += FACTOR0 * err[c]; cur_next_error[c + 3] += FACTOR1 * err[c]; cur_next_error[c + 6] = FACTOR2 * err[c]; err[c] *= FACTOR_FRONT; } row++; cur_error += 3; cur_next_error += 3; } data += rowstride; cur_error = this_error; this_error = next_error; next_error = cur_error; target += target_rowstride; full += full_rowstride; } g_free (this_error); g_free (next_error); if (area.width < area.x || area.height < area.y) { return FALSE; } else { if (rect_out) { area.width = area.width - area.x + 1; area.height = area.height - area.y + 1; //g_print ("image was %d %d, relevant is %d %d %d %d\n", width, height, // area.x, area.y, area.width, area.height); *rect_out = area; } return TRUE; } } tegaki-tools-0.3.1/ChangeLog0000644000175000017500000002040011352066723015542 0ustar mathieumathieucommit 5b0b86343c91cbf3d7ee683e82f41f9df75edf4d Author: Mathieu Blondel Date: Mon Mar 22 15:32:33 2010 +0900 [all] Set current version to 0.3.1. commit ae808ddbdffa3750a71d2636fe475d5d774516f1 Author: Mathieu Blondel Date: Wed Dec 9 17:16:34 2009 +0900 [tegaki-stats] Display total number of strokes. commit 07a78dd10e599ecbf6d255704551955e0e696a2d Author: Mathieu Blondel Date: Wed Dec 9 16:13:38 2009 +0900 [tegaki-tool] Ask whether to overwrite existing db or not. commit ec14631fab52e09b073e26fd58112e96f5a56d64 Author: Mathieu Blondel Date: Wed Dec 9 14:12:37 2009 +0900 [tegaki-tools] Various optimizations. commit 690a5a89ac2dd301e3efc673912d8ad8c6be0cac Author: Mathieu Blondel Date: Wed Dec 2 20:24:23 2009 +0900 [tegaki-tools] Use CharacterCollection new save method. commit f5fa2429291939d7358a61aeafcd178e5fccd4c4 Author: Mathieu Blondel Date: Tue Dec 1 17:52:55 2009 +0900 [tegaki-build] Don't import Recognizer. commit 90fd8fa22706942945682795acaab65f1280a86c Author: Mathieu Blondel Date: Tue Dec 1 17:30:06 2009 +0900 [tegaki-tools] Support for new CharacterCollection features. commit 4cb5520040c22a617d87dc5b6c26ed1a8c16ad75 Author: Christoph Burgmer Date: Sun Nov 22 12:15:18 2009 +0100 [tegaki-bootstrap] always provide max_samples, mix exact and decomposition transformations; make max_samples default to 1; optimize commit 8a7cbb7c31c6672876d71d9f8915052023036fb8 Author: Christoph Burgmer Date: Fri Nov 20 13:31:37 2009 +0100 [tegaki-bootstrap] Optimize memory footprint. commit 5a73c1b7118429ba59ddeedf3a38dc3b5fb84511 Author: Christoph Burgmer Date: Fri Nov 20 00:55:15 2009 +0100 [tegaki-extractcomponents] Add a tool to extract handwriting of a component. commit 909dac8225b23cddeeb898723a02818f1cac4ea6 Author: Christoph Burgmer Date: Fri Nov 20 00:22:18 2009 +0100 [tegaki-bootstrap] Add option to exclude direct transformations. Also optimize memory useage for 'big' values of "-m". commit 23428970b5125e6effc233ff3261e6cb368ff93d Author: Mathieu Blondel Date: Sun Nov 1 20:56:48 2009 +0900 [all] Include ChangeLog. commit 8fddc2ca2ac023c9b1d6299bb11f7b0b90f04439 Author: Christoph Burgmer Date: Sat Oct 24 02:53:08 2009 +0200 [tegaki-bootstrap] Fix bug introduced through refactoring. commit d398efee65cf4f1b4dfef4846a23f3200579fc38 Author: Christoph Burgmer Date: Tue Oct 20 11:31:45 2009 +0200 [tegaki-bootstrap] Don't build for radical 22 as stroke order is not linear. Also refactor code that got outsourced into a module. commit 14a578c00af3a00a4022d86373f9641813b2e134 Author: Mathieu Blondel Date: Tue Oct 20 13:49:50 2009 +0900 [tegaki-stats] Removed unnecessary code. commit 0a35127481f90449db4e38e1f68f4a7d8c06f28a Author: Mathieu Blondel Date: Mon Oct 19 17:49:58 2009 +0900 [tegaki-stats] Added tool to show statistics about a character collection. commit 84c6b5d90627da576e228ae6de97e87de70ca095 Author: Mathieu Blondel Date: Sun Oct 11 22:31:17 2009 +0900 [tegaki-boostrap] Added to setup.py. commit b5bf3b6056030a3186e434bbb396dec09915f61e Author: Christoph Burgmer Date: Sun Oct 11 13:19:09 2009 +0200 [tegaki-bootstrap] Adding tegaki-bootstrap, a script to bootstrap character collections, using existing ones in conjunction with character component data. Also adding a bootstrapped model covering the BIG5 character set for Traditional Chinese. commit ada0b177aeb4b5ac1c57410cef6e72ae357963f5 Author: Mathieu Blondel Date: Sun Oct 11 08:56:45 2009 +0900 [tegaki-models] Removed binary files, build models from source, added new subset models. commit df142bd26eebb53ad83f867a486013a6cab63fec Author: Mathieu Blondel Date: Fri Sep 18 18:01:25 2009 +0900 [tegaki-convert] Handle pen-up movement in kuchibue data. commit cc91561fc5b2e5db992cc0e7e8b82ec98345790b Author: Mathieu Blondel Date: Fri Sep 18 01:47:47 2009 +0900 [tegaki-convert] Added --max-samples option. commit 16a047cc0961bed958ae53f5545665773d001816 Author: Mathieu Blondel Date: Sat Sep 12 18:08:49 2009 +0900 [tegaki-convert] Added --include and --exclude options. For example, --include data/ja/hiragana.txt will leave hiragana and remove all the rest. On the contrary, --exclude data/ja/hiragana.txt will exclude hiragana and leave all the rest. commit 879f9e40f06450a5e73897212339b780e7100d10 Author: Mathieu Blondel Date: Fri Sep 11 23:16:36 2009 +0900 [tegaki-tools] Fixed a few problems in Kuchibue database import. commit 65b62e6aca2770fafba7587afc7cf70a5a943d24 Author: Mathieu Blondel Date: Tue Sep 8 21:37:29 2009 +0900 [tegaki-tools] Incomplete parsers for the Unipen format and the Kuchibue database. commit fb2601d8e22fa59dcf38fcbef6ba212a82b4c4da Author: Mathieu Blondel Date: Tue Sep 8 10:27:29 2009 +0900 [tegaki-tools] Renamed utils.py to tomoe.py. commit 58bb46005155e6274a783b745d7b21f75a8ede28 Author: Mathieu Blondel Date: Tue Sep 8 10:03:24 2009 +0900 [tegaki-render] Fixes a few mistakes. commit 1bc2ad6af17b3adbb2ee84c6814cb4cf2a77c2f8 Author: Mathieu Blondel Date: Thu Sep 3 18:49:09 2009 +0900 [tegaki-render] Tool to create images (png, svg, pdf) or animations (gif) from character files. commit 8cc58e2d51563a7a390d2a7a0f803e1d455fc30f Author: Mathieu Blondel Date: Fri Aug 28 17:37:04 2009 +0900 [tegaki-eval] Display recognition speed (number of characters / sec). commit 6592d1a94dc89f17e6da6c3b808ee03d479650cf Author: Mathieu Blondel Date: Fri Jul 31 20:46:10 2009 +0900 [tegaki-tools] Support recognizer options. commit 64e9514f48a6f43064d4e65d93a221015adc5b58 Author: Mathieu Blondel Date: Sun Jul 26 16:43:18 2009 +0200 [tegaki-tools] Display running time in tegaki-eval. commit 01bf5873690a7de7c58642c50298f63b2f71f2cc Author: Mathieu Blondel Date: Fri Jul 24 16:43:37 2009 +0200 [tegaki-tools] Fixed bug in tegaki-eval. commit 090b16b1ba9745378558e24640b055dbfecf2fa0 Author: Mathieu Blondel Date: Fri Jul 24 08:41:30 2009 +0200 [tegaki-tools] Added a --list option to tegaki-build and tegaki-eval. commit 072589a2417565b3697ae3abc8e547b06ccde39d Author: Mathieu Blondel Date: Sun Jul 19 11:45:53 2009 +0200 [all] Update project URL. commit 10ea23607f9a0879e1c1c459cf83e763286871da Author: Mathieu Blondel Date: Sun Jul 19 05:23:37 2009 +0200 [tegaki,tegaki-gtk] Renamed the packages to respectively tegaki-python and tegaki-pygtk to make it clear that they are Python packages. commit 73d87a4553427d9c0e1141805adcf0b8887d010d Author: Mathieu Blondel Date: Fri Jul 10 15:01:38 2009 +0200 [tegaki-tools] Added setup.py. commit f5865439890d1671dafa116138157aae4d639bcc Author: Mathieu Blondel Date: Fri Jul 10 14:47:11 2009 +0200 [tegaki-tools] Added tegaki-build. commit 79ec1d5b6c7841df9c499be0fa407fc2babe6f9b Author: Mathieu Blondel Date: Fri Jul 10 13:53:55 2009 +0200 [tegaki,tegaki-tools] Renamed set_model_from_file to open. commit c66e016c6a63617fa1f3e0a1b79a99188fea59df Author: Mathieu Blondel Date: Fri Jul 10 13:09:38 2009 +0200 [all] Added --version option for command line tools. commit d9a05ecefe9f0907f77710313dedbcb15537dc26 Author: Mathieu Blondel Date: Fri Jul 10 12:59:47 2009 +0200 [tegaki-tools] Added native support for Tomoe XML dictionary files. Added tegaki-convert. commit 0f32335a08dc2716f327a4c91ee4b095ba854025 Author: Mathieu Blondel Date: Fri Jul 10 12:15:56 2009 +0200 [tegaki-tools] Added tegaki-eval tool. tegaki-tools-0.3.1/setup.py0000644000175000017500000000236111342122364015501 0ustar mathieumathieu# -*- coding: utf-8 -*- from distutils.core import setup import os def _getversion(path): currdir = os.path.dirname(os.path.abspath(__file__)) path = os.path.join(currdir, path) import re regexp = re.compile(r"VERSION = '([^']*)'") f = open(path) buf = f.read() f.close() return regexp.search(buf).group(1) def getversion(): convert = _getversion('src/tegaki-convert') eval_ = _getversion('src/tegaki-eval') build = _getversion('src/tegaki-build') render = _getversion('src/tegaki-render') bootstrap = _getversion('src/tegaki-bootstrap') stats = _getversion('src/tegaki-stats') return max(convert, eval_, build, render, bootstrap, stats) # Please run # python setup.py install setup( name = 'tegaki-tools', description = 'A set of command-line tools for Tegaki.', author = 'Mathieu Blondel', author_email = 'mathieu ÂT mblondel DÔT org', url = 'http://www.tegaki.org', version = getversion(), license='GPL', scripts = ['src/tegaki-convert', 'src/tegaki-build', 'src/tegaki-eval', 'src/tegaki-render', 'src/tegaki-bootstrap', 'src/tegaki-stats'], packages = ['tegakitools'], package_dir = {'tegakitools':'src/tegakitools'} ) tegaki-tools-0.3.1/MANIFEST.in0000644000175000017500000000022311342122364015520 0ustar mathieumathieuinclude AUTHORS COPYING COPYRIGHT README TODO MANIFEST.in ChangeLog tegaki-gifenc/* tegaki-gifenc/*/* exclude *~ *.orig *.bak *.tmp *.pyc MANIFEST tegaki-tools-0.3.1/COPYRIGHT0000644000175000017500000000027411342122364015263 0ustar mathieumathieuThe code included in this package is copyrighted by Mathieu Blondel : Copyright (C) 2009 Mathieu Blondel. All Rights Reserved. See the COPYING File for the terms of distribution licence.