gdisp: Update font encoder (src)

This commit is contained in:
Joel Bodenmann 2024-09-18 04:29:27 +02:00
parent 44ef4ac25b
commit b48d18c4f9
19 changed files with 1333 additions and 431 deletions

View File

@ -0,0 +1,35 @@
cmake_minimum_required(VERSION 3.13)
project(mfencoder)
find_package(Freetype REQUIRED)
find_package(Threads REQUIRED)
include_directories(${FREETYPE_INCLUDE_DIRS})
set(CMAKE_CXX_STANDARD 14)
include_directories(.)
add_executable(mfencoder
bdf_import.cc
bdf_import.hh
ccfixes.hh
datafile.cc
datafile.hh
encode_rlefont.cc
encode_rlefont.hh
export_bwfont.cc
export_bwfont.hh
export_rlefont.cc
export_rlefont.hh
exporttools.cc
exporttools.hh
freetype_import.cc
freetype_import.hh
gb2312_in_ucs2.h
importtools.cc
importtools.hh
main.cc
optimize_rlefont.cc
optimize_rlefont.hh)
target_link_libraries(mfencoder ${FREETYPE_LIBRARIES} Threads::Threads)

View File

@ -1,10 +1,13 @@
CXXFLAGS = -O2 -Wall -Werror -Wno-unused-function -Wno-sign-compare -std=c++0x CXXFLAGS = -O2 -Wall -Werror -Wno-unused-function -Wno-sign-compare -std=c++0x
CXXFLAGS += -ggdb CXXFLAGS += -ggdb
LDFLAGS += -pthread
ifneq ($(shell uname -s),Darwin)
LDFLAGS += -pthread
endif
# Libfreetype # Libfreetype
CXXFLAGS += $(shell freetype-config --cflags) CXXFLAGS += $(shell pkg-config freetype2 --cflags)
LDFLAGS += $(shell freetype-config --libs) LDFLAGS += $(shell pkg-config freetype2 --libs)
# Class to represent font data internally # Class to represent font data internally
OBJS = datafile.o OBJS = datafile.o

View File

@ -0,0 +1,73 @@
################################################################################
# #
# Requirements: #
# print/freetype2 #
# devel/gmake #
# #
# Notes: #
# Run this makefile using 'gmake', not 'make'. #
# Tested on FreeBSD 10.2 (64-Bit) #
# #
################################################################################
TARGET = mcufont
CPPC = clang++
LD = clang++
RM = rm
SIZE = size
CPPFLAGS = -O2 -Wall -Werror -Wno-unused-function -Wno-sign-compare -std=c++11
CPPFLAGS += -ggdb
LDFLAGS += -pthread
CPPSRCS = \
bdf_import.cc \
datafile.cc \
encode_rlefont.cc \
export_bwfont.cc \
export_rlefont.cc \
exporttools.cc \
freetype_import.cc \
importtools.cc \
optimize_rlefont.cc \
main.cc
INCDIR = .
################################################################################
# Apply some magic where necessary #
################################################################################
CPPFLAGS += $(shell pkg-config freetype2 --cflags)
LDFLAGS += $(shell pkg-config freetype2 --libs)
OBJS += $(addsuffix .o,$(basename $(CPPSRCS:%.cpp=%.o)))
################################################################################
# Rules #
################################################################################
all: $(TARGET) size
clean:
@$(RM) -f mcufont $(OBJS)
@echo Done
$(TARGET): $(OBJS)
@echo Linking $@
@$(LD) $(CPPFLAGS) -o $@ $^ $(LDFLAGS)
%.o: %.cc
@echo Compiling $^
@$(CPPC) $(CPPFLAGS) -c -o $@ $^
size: $(TARGET)
@echo
@echo
$(SIZE) $^
@echo
.PHONY: clean

View File

@ -4,8 +4,8 @@ CXXFLAGS += -ggdb
LDFLAGS += -pthread --static LDFLAGS += -pthread --static
# Libfreetype # Libfreetype
CXXFLAGS += $(shell freetype-config --cflags) CXXFLAGS += $(shell pkg-config freetype2 --cflags)
LDFLAGS += $(shell freetype-config --libs) LDFLAGS += $(shell pkg-config freetype2 --libs)
#FREETYPE2_LIB = ../ugfx/3rdparty/freetype-2.6.1 #FREETYPE2_LIB = ../ugfx/3rdparty/freetype-2.6.1
#CXXFLAGS += -I$(FREETYPE2_LIB)/include #CXXFLAGS += -I$(FREETYPE2_LIB)/include
#LDFLAGS += -I$(FREETYPE2_LIB)/lib -lfreetype #LDFLAGS += -I$(FREETYPE2_LIB)/lib -lfreetype

View File

@ -23,6 +23,9 @@ static int hextoint(char c)
static void parse_fontinfo(std::istream &file, DataFile::fontinfo_t &fontinfo) static void parse_fontinfo(std::istream &file, DataFile::fontinfo_t &fontinfo)
{ {
int font_ascent = 0;
int font_descent = 0;
std::string line; std::string line;
while (std::getline(file, line)) while (std::getline(file, line))
{ {
@ -30,7 +33,7 @@ static void parse_fontinfo(std::istream &file, DataFile::fontinfo_t &fontinfo)
std::string tag; std::string tag;
s >> tag; s >> tag;
tag = toupper(tag); tag = toupper(tag);
if (tag == "FONT") if (tag == "FONT")
{ {
while (isspace(s.peek())) s.get(); while (isspace(s.peek())) s.get();
@ -44,11 +47,27 @@ static void parse_fontinfo(std::istream &file, DataFile::fontinfo_t &fontinfo)
fontinfo.baseline_x = - x; fontinfo.baseline_x = - x;
fontinfo.baseline_y = fontinfo.max_height + y; fontinfo.baseline_y = fontinfo.max_height + y;
} }
else if (tag == "FONT_DESCENT")
{
s >> font_descent;
}
else if (tag == "FONT_ASCENT")
{
s >> font_ascent;
}
else if (tag == "STARTCHAR") else if (tag == "STARTCHAR")
{ {
break; break;
} }
} }
// Fix for fonts edited by Fony (http://hukka.ncn.fi/?fony)
int font_max_height = font_ascent + font_descent;
if (font_max_height != 0)
{
fontinfo.max_height = font_max_height;
fontinfo.baseline_y = font_ascent;
}
} }
static bool parse_glyph(std::istream &file, DataFile::glyphentry_t &glyph, static bool parse_glyph(std::istream &file, DataFile::glyphentry_t &glyph,
@ -56,16 +75,16 @@ static bool parse_glyph(std::istream &file, DataFile::glyphentry_t &glyph,
{ {
glyph.chars.clear(); glyph.chars.clear();
glyph.width = 0; glyph.width = 0;
// Initialize the character contents to all 0 with proper size. // Initialize the character contents to all 0 with proper size.
glyph.data.clear(); glyph.data.clear();
glyph.data.resize(fontinfo.max_width * fontinfo.max_height, 0); glyph.data.resize(fontinfo.max_width * fontinfo.max_height, 0);
int bbx_w = fontinfo.max_width; int bbx_w = fontinfo.max_width;
int bbx_h = fontinfo.max_height; int bbx_h = fontinfo.max_height;
int bbx_x = - fontinfo.baseline_x; int bbx_x = - fontinfo.baseline_x;
int bbx_y = fontinfo.baseline_y - fontinfo.max_height; int bbx_y = fontinfo.baseline_y - fontinfo.max_height;
// Read glyph metadata // Read glyph metadata
std::string line; std::string line;
std::string tag; std::string tag;
@ -74,7 +93,7 @@ static bool parse_glyph(std::istream &file, DataFile::glyphentry_t &glyph,
std::istringstream s(line); std::istringstream s(line);
s >> tag; s >> tag;
tag = toupper(tag); tag = toupper(tag);
if (tag == "ENCODING") if (tag == "ENCODING")
{ {
int c; int c;
@ -94,10 +113,10 @@ static bool parse_glyph(std::istream &file, DataFile::glyphentry_t &glyph,
break; break;
} }
} }
if (tag != "BITMAP") if (tag != "BITMAP")
return false; return false;
// Read glyph bits // Read glyph bits
int x0 = fontinfo.baseline_x + bbx_x; int x0 = fontinfo.baseline_x + bbx_x;
int y = fontinfo.baseline_y - bbx_y - bbx_h; int y = fontinfo.baseline_y - bbx_y - bbx_h;
@ -105,20 +124,20 @@ static bool parse_glyph(std::istream &file, DataFile::glyphentry_t &glyph,
{ {
std::getline(file, line); std::getline(file, line);
line = toupper(line); line = toupper(line);
for (int x = 0; x < bbx_w; x++) for (int x = 0; x < bbx_w; x++)
{ {
int nibble = hextoint(line.at(x / 4)); int nibble = hextoint(line.at(x / 4));
uint8_t pixel = 0; uint8_t pixel = 0;
if (nibble & (8 >> (x % 4))) if (nibble & (8 >> (x % 4)))
pixel = 15; pixel = 15;
glyph.data.at(y * fontinfo.max_width + x0 + x) = pixel; glyph.data.at(y * fontinfo.max_width + x0 + x) = pixel;
} }
y++; y++;
} }
std::getline(file, line); std::getline(file, line);
line = toupper(line); line = toupper(line);
if (line.compare(0, 7, "ENDCHAR") == 0) if (line.compare(0, 7, "ENDCHAR") == 0)
@ -132,22 +151,22 @@ std::unique_ptr<DataFile> LoadBDF(std::istream &file)
DataFile::fontinfo_t fontinfo = {}; DataFile::fontinfo_t fontinfo = {};
std::vector<DataFile::glyphentry_t> glyphtable; std::vector<DataFile::glyphentry_t> glyphtable;
std::vector<DataFile::dictentry_t> dictionary; std::vector<DataFile::dictentry_t> dictionary;
parse_fontinfo(file, fontinfo); parse_fontinfo(file, fontinfo);
while (file) while (file)
{ {
DataFile::glyphentry_t glyph = {}; DataFile::glyphentry_t glyph = {};
if (parse_glyph(file, glyph, fontinfo)) if (parse_glyph(file, glyph, fontinfo))
glyphtable.push_back(glyph); glyphtable.push_back(glyph);
} }
eliminate_duplicates(glyphtable); eliminate_duplicates(glyphtable);
crop_glyphs(glyphtable, fontinfo); crop_glyphs(glyphtable, fontinfo);
detect_flags(glyphtable, fontinfo); detect_flags(glyphtable, fontinfo);
fontinfo.line_height = fontinfo.max_height; fontinfo.line_height = fontinfo.max_height;
std::unique_ptr<DataFile> result(new DataFile( std::unique_ptr<DataFile> result(new DataFile(
dictionary, glyphtable, fontinfo)); dictionary, glyphtable, fontinfo));
return result; return result;

View File

@ -22,16 +22,16 @@ public:
{ {
std::istringstream s(testfile); std::istringstream s(testfile);
std::unique_ptr<DataFile> f = LoadBDF(s); std::unique_ptr<DataFile> f = LoadBDF(s);
TS_ASSERT_EQUALS(f->GetFontInfo().name, "-Misc-Fixed-Medium-R-Normal--14-130-75-75-C-70-ISO8859-15"); TS_ASSERT_EQUALS(f->GetFontInfo().name, "-Misc-Fixed-Medium-R-Normal--14-130-75-75-C-70-ISO8859-15");
TS_ASSERT_EQUALS(f->GetFontInfo().max_width, 6); TS_ASSERT_EQUALS(f->GetFontInfo().max_width, 6);
TS_ASSERT_EQUALS(f->GetFontInfo().max_height, 11); TS_ASSERT_EQUALS(f->GetFontInfo().max_height, 11);
TS_ASSERT_EQUALS(f->GetGlyphCount(), 1); TS_ASSERT_EQUALS(f->GetGlyphCount(), 1);
TS_ASSERT_EQUALS(f->GetGlyphEntry(0).chars.size(), 2); TS_ASSERT_EQUALS(f->GetGlyphEntry(0).chars.size(), 2);
} }
private: private:
static constexpr const char *testfile = static constexpr const char *testfile =
"STARTFONT 2.1\n" "STARTFONT 2.1\n"
"FONT -Misc-Fixed-Medium-R-Normal--14-130-75-75-C-70-ISO8859-15\n" "FONT -Misc-Fixed-Medium-R-Normal--14-130-75-75-C-70-ISO8859-15\n"
"FONTBOUNDINGBOX 7 14 0 -2\n" "FONTBOUNDINGBOX 7 14 0 -2\n"

View File

@ -17,7 +17,7 @@ DataFile::DataFile(const std::vector<dictentry_t> &dictionary,
dictentry_t dummy = {}; dictentry_t dummy = {};
while (m_dictionary.size() < dictionarysize) while (m_dictionary.size() < dictionarysize)
m_dictionary.push_back(dummy); m_dictionary.push_back(dummy);
UpdateLowScoreIndex(); UpdateLowScoreIndex();
} }
@ -32,7 +32,7 @@ void DataFile::Save(std::ostream &file) const
file << "LineHeight " << m_fontinfo.line_height << std::endl; file << "LineHeight " << m_fontinfo.line_height << std::endl;
file << "Flags " << m_fontinfo.flags << std::endl; file << "Flags " << m_fontinfo.flags << std::endl;
file << "RandomSeed " << m_seed << std::endl; file << "RandomSeed " << m_seed << std::endl;
for (const dictentry_t &d : m_dictionary) for (const dictentry_t &d : m_dictionary)
{ {
if (d.replacement.size() != 0) if (d.replacement.size() != 0)
@ -41,7 +41,7 @@ void DataFile::Save(std::ostream &file) const
file << d.ref_encode << " " << d.replacement << std::endl; file << d.ref_encode << " " << d.replacement << std::endl;
} }
} }
for (const glyphentry_t &g : m_glyphtable) for (const glyphentry_t &g : m_glyphtable)
{ {
file << "Glyph "; file << "Glyph ";
@ -61,15 +61,15 @@ std::unique_ptr<DataFile> DataFile::Load(std::istream &file)
std::vector<glyphentry_t> glyphtable; std::vector<glyphentry_t> glyphtable;
uint32_t seed = 1234; uint32_t seed = 1234;
int version = -1; int version = -1;
std::string line; std::string line;
while (std::getline(file, line)) while (std::getline(file, line))
{ {
std::istringstream input(line); std::istringstream input(line);
std::string tag; std::string tag;
input >> tag; input >> tag;
if (tag == "Version") if (tag == "Version")
{ {
input >> version; input >> version;
@ -118,26 +118,26 @@ std::unique_ptr<DataFile> DataFile::Load(std::istream &file)
glyphentry_t g = {}; glyphentry_t g = {};
std::string chars; std::string chars;
input >> chars >> g.width >> g.data; input >> chars >> g.width >> g.data;
if ((int)g.data.size() != fontinfo.max_width * fontinfo.max_height) if ((int)g.data.size() != fontinfo.max_width * fontinfo.max_height)
throw std::runtime_error("wrong glyph data length: " + std::to_string(g.data.size())); throw std::runtime_error("wrong glyph data length: " + std::to_string(g.data.size()));
size_t pos = 0; size_t pos = 0;
while (pos < chars.size()) { while (pos < chars.size()) {
size_t p; size_t p;
g.chars.push_back(std::stoi(chars.substr(pos), &p)); g.chars.push_back(std::stoi(chars.substr(pos), &p));
pos += p + 1; pos += p + 1;
} }
glyphtable.push_back(g); glyphtable.push_back(g);
} }
} }
if (version != DATAFILE_FORMAT_VERSION) if (version != DATAFILE_FORMAT_VERSION)
{ {
return std::unique_ptr<DataFile>(nullptr); return std::unique_ptr<DataFile>(nullptr);
} }
std::unique_ptr<DataFile> result(new DataFile(dictionary, glyphtable, fontinfo)); std::unique_ptr<DataFile> result(new DataFile(dictionary, glyphtable, fontinfo));
result->SetSeed(seed); result->SetSeed(seed);
return result; return result;
@ -146,7 +146,7 @@ std::unique_ptr<DataFile> DataFile::Load(std::istream &file)
void DataFile::SetDictionaryEntry(size_t index, const dictentry_t &value) void DataFile::SetDictionaryEntry(size_t index, const dictentry_t &value)
{ {
m_dictionary.at(index) = value; m_dictionary.at(index) = value;
if (index == m_lowscoreindex || if (index == m_lowscoreindex ||
m_dictionary.at(m_lowscoreindex).score > value.score) m_dictionary.at(m_lowscoreindex).score > value.score)
{ {
@ -157,7 +157,7 @@ void DataFile::SetDictionaryEntry(size_t index, const dictentry_t &value)
std::map<size_t, size_t> DataFile::GetCharToGlyphMap() const std::map<size_t, size_t> DataFile::GetCharToGlyphMap() const
{ {
std::map<size_t, size_t> char_to_glyph; std::map<size_t, size_t> char_to_glyph;
for (size_t i = 0; i < m_glyphtable.size(); i++) for (size_t i = 0; i < m_glyphtable.size(); i++)
{ {
for (size_t c: m_glyphtable[i].chars) for (size_t c: m_glyphtable[i].chars)
@ -165,16 +165,16 @@ std::map<size_t, size_t> DataFile::GetCharToGlyphMap() const
char_to_glyph[c] = i; char_to_glyph[c] = i;
} }
} }
return char_to_glyph; return char_to_glyph;
} }
std::string DataFile::GlyphToText(size_t index) const std::string DataFile::GlyphToText(size_t index) const
{ {
std::ostringstream os; std::ostringstream os;
const char glyphchars[] = "....,,,,----XXXX"; const char glyphchars[] = "....,,,,----XXXX";
for (int y = 0; y < m_fontinfo.max_height; y++) for (int y = 0; y < m_fontinfo.max_height; y++)
{ {
for (int x = 0; x < m_fontinfo.max_width; x++) for (int x = 0; x < m_fontinfo.max_width; x++)
@ -184,7 +184,7 @@ std::string DataFile::GlyphToText(size_t index) const
} }
os << std::endl; os << std::endl;
} }
return os.str(); return os.str();
} }
@ -194,11 +194,11 @@ void DataFile::UpdateLowScoreIndex()
{ {
return a.score < b.score; return a.score < b.score;
}; };
auto iter = std::min_element(m_dictionary.begin(), auto iter = std::min_element(m_dictionary.begin(),
m_dictionary.end(), m_dictionary.end(),
comparison); comparison);
m_lowscoreindex = iter - m_dictionary.begin(); m_lowscoreindex = iter - m_dictionary.begin();
} }
@ -220,9 +220,9 @@ std::istream& operator>>(std::istream& is, DataFile::pixels_t& str)
{ {
char c; char c;
str.clear(); str.clear();
while (isspace(is.peek())) is.get(); while (isspace(is.peek())) is.get();
while (is.get(c)) while (is.get(c))
{ {
if (c >= '0' && c <= '9') if (c >= '0' && c <= '9')
@ -232,7 +232,7 @@ std::istream& operator>>(std::istream& is, DataFile::pixels_t& str)
else else
break; break;
} }
return is; return is;
} }

View File

@ -16,23 +16,23 @@ class DataFile
{ {
public: public:
typedef std::vector<uint8_t> pixels_t; typedef std::vector<uint8_t> pixels_t;
struct dictentry_t struct dictentry_t
{ {
pixels_t replacement; // The expanded version of this block. pixels_t replacement; // The expanded version of this block.
int score; // Number of bytes that having this entry saves. int score; // Number of bytes that having this entry saves.
bool ref_encode; // Encode using references to other dictionary entries. bool ref_encode; // Encode using references to other dictionary entries.
dictentry_t(): score(0), ref_encode(false) {} dictentry_t(): score(0), ref_encode(false) {}
}; };
struct glyphentry_t struct glyphentry_t
{ {
pixels_t data; // The full data of the glyph. pixels_t data; // The full data of the glyph.
std::vector<int> chars; // Characters that this glyph represents. std::vector<int> chars; // Characters that this glyph represents.
int width; // Tracking width of the character. int width; // Tracking width of the character.
}; };
struct fontinfo_t struct fontinfo_t
{ {
std::string name; // Name of the typeface std::string name; // Name of the typeface
@ -43,24 +43,22 @@ public:
int line_height; // Line height (vertical advance). int line_height; // Line height (vertical advance).
int flags; int flags;
}; };
static const int FLAG_MONOSPACE = 0x01; static const int FLAG_MONOSPACE = 0x01;
static const int FLAG_BW = 0x02; static const int FLAG_BW = 0x02;
// Construct from data in memory. // Construct from data in memory.
DataFile(const std::vector<dictentry_t> &dictionary, DataFile(const std::vector<dictentry_t> &dictionary,
const std::vector<glyphentry_t> &glyphs, const std::vector<glyphentry_t> &glyphs,
const fontinfo_t &fontinfo); const fontinfo_t &fontinfo);
inline DataFile * clone() const { return new DataFile(GetDictionary(), GetGlyphTable(), GetFontInfo()); }
// Save to a file (custom format) // Save to a file (custom format)
void Save(std::ostream &file) const; void Save(std::ostream &file) const;
// Load from a file (custom format) // Load from a file (custom format)
// Returns nullptr if load fails. // Returns nullptr if load fails.
static std::unique_ptr<DataFile> Load(std::istream &file); static std::unique_ptr<DataFile> Load(std::istream &file);
// Get or set an entry in the dictionary. The size of the dictionary // Get or set an entry in the dictionary. The size of the dictionary
// is constant. Entries 0 to 23 are reserved for special purposes. // is constant. Entries 0 to 23 are reserved for special purposes.
static const size_t dictionarysize = 256 - 24; static const size_t dictionarysize = 256 - 24;
@ -69,11 +67,11 @@ public:
void SetDictionaryEntry(size_t index, const dictentry_t &value); void SetDictionaryEntry(size_t index, const dictentry_t &value);
const std::vector<dictentry_t> &GetDictionary() const const std::vector<dictentry_t> &GetDictionary() const
{ return m_dictionary; } { return m_dictionary; }
// Get the index of the dictionary entry with the lowest score. // Get the index of the dictionary entry with the lowest score.
size_t GetLowScoreIndex() const size_t GetLowScoreIndex() const
{ return m_lowscoreindex; } { return m_lowscoreindex; }
// Get an entry in the glyph table. // Get an entry in the glyph table.
size_t GetGlyphCount() const size_t GetGlyphCount() const
{ return m_glyphtable.size(); } { return m_glyphtable.size(); }
@ -81,31 +79,31 @@ public:
{ return m_glyphtable.at(index); } { return m_glyphtable.at(index); }
const std::vector<glyphentry_t> &GetGlyphTable() const const std::vector<glyphentry_t> &GetGlyphTable() const
{ return m_glyphtable; } { return m_glyphtable; }
// Create a map of char indices to glyph indices // Create a map of char indices to glyph indices
std::map<size_t, size_t> GetCharToGlyphMap() const; std::map<size_t, size_t> GetCharToGlyphMap() const;
// Get the information that applies to all glyphs. // Get the information that applies to all glyphs.
const fontinfo_t &GetFontInfo() const const fontinfo_t &GetFontInfo() const
{ return m_fontinfo; } { return m_fontinfo; }
// Show a glyph as text. // Show a glyph as text.
std::string GlyphToText(size_t index) const; std::string GlyphToText(size_t index) const;
// Get the random generator seed // Get the random generator seed
// The seed is stored in the datafile to get deterministic behaviour // The seed is stored in the datafile to get deterministic behaviour
// for debugging. // for debugging.
uint32_t GetSeed() const { return m_seed; } uint32_t GetSeed() const { return m_seed; }
void SetSeed(uint32_t seed) { m_seed = seed; } void SetSeed(uint32_t seed) { m_seed = seed; }
private: private:
std::vector<dictentry_t> m_dictionary; std::vector<dictentry_t> m_dictionary;
std::vector<glyphentry_t> m_glyphtable; std::vector<glyphentry_t> m_glyphtable;
fontinfo_t m_fontinfo; fontinfo_t m_fontinfo;
uint32_t m_seed; uint32_t m_seed;
size_t m_lowscoreindex; size_t m_lowscoreindex;
void UpdateLowScoreIndex(); void UpdateLowScoreIndex();
}; };
@ -126,37 +124,37 @@ public:
{ {
std::istringstream s(testfile); std::istringstream s(testfile);
std::unique_ptr<DataFile> f = DataFile::Load(s); std::unique_ptr<DataFile> f = DataFile::Load(s);
TS_ASSERT_EQUALS(f->GetFontInfo().name, "Sans Serif"); TS_ASSERT_EQUALS(f->GetFontInfo().name, "Sans Serif");
TS_ASSERT_EQUALS(f->GetFontInfo().max_width, 4); TS_ASSERT_EQUALS(f->GetFontInfo().max_width, 4);
TS_ASSERT_EQUALS(f->GetFontInfo().max_height, 6); TS_ASSERT_EQUALS(f->GetFontInfo().max_height, 6);
TS_ASSERT_EQUALS(f->GetDictionaryEntry(0).score, 5); TS_ASSERT_EQUALS(f->GetDictionaryEntry(0).score, 5);
TS_ASSERT_EQUALS(f->GetDictionaryEntry(1).score, 13); TS_ASSERT_EQUALS(f->GetDictionaryEntry(1).score, 13);
TS_ASSERT_EQUALS(f->GetGlyphCount(), 3); TS_ASSERT_EQUALS(f->GetGlyphCount(), 3);
DataFile::pixels_t expected = { DataFile::pixels_t expected = {
0,15,0,15, 0,15,0,15, 0,15,0,15, 0,15,0,15, 0,15,0,15, 0,15,0,15 0,15,0,15, 0,15,0,15, 0,15,0,15, 0,15,0,15, 0,15,0,15, 0,15,0,15
}; };
TS_ASSERT_EQUALS(f->GetGlyphEntry(0).data.size(), 24); TS_ASSERT_EQUALS(f->GetGlyphEntry(0).data.size(), 24);
TS_ASSERT(f->GetGlyphEntry(0).data == expected); TS_ASSERT(f->GetGlyphEntry(0).data == expected);
} }
void testFileSave() void testFileSave()
{ {
std::istringstream is1(testfile); std::istringstream is1(testfile);
std::unique_ptr<DataFile> f1 = DataFile::Load(is1); std::unique_ptr<DataFile> f1 = DataFile::Load(is1);
std::ostringstream os; std::ostringstream os;
f1->Save(os); f1->Save(os);
std::string text = os.str(); std::string text = os.str();
std::istringstream is2(text); std::istringstream is2(text);
std::unique_ptr<DataFile> f2 = DataFile::Load(is2); std::unique_ptr<DataFile> f2 = DataFile::Load(is2);
TS_ASSERT_EQUALS(f1->GetFontInfo().name, f2->GetFontInfo().name); TS_ASSERT_EQUALS(f1->GetFontInfo().name, f2->GetFontInfo().name);
TS_ASSERT(f1->GetGlyphEntry(0).data == f2->GetGlyphEntry(0).data); TS_ASSERT(f1->GetGlyphEntry(0).data == f2->GetGlyphEntry(0).data);
} }
private: private:
static constexpr const char *testfile = static constexpr const char *testfile =
"Version 1\n" "Version 1\n"

View File

@ -62,14 +62,14 @@ static size_t prefix_length(const DataFile::pixels_t &pixels, size_t pos)
static encoded_font_t::rlestring_t encode_rle(const DataFile::pixels_t &pixels) static encoded_font_t::rlestring_t encode_rle(const DataFile::pixels_t &pixels)
{ {
encoded_font_t::rlestring_t result; encoded_font_t::rlestring_t result;
size_t pos = 0; size_t pos = 0;
while (pos < pixels.size()) while (pos < pixels.size())
{ {
uint8_t pixel = pixels.at(pos); uint8_t pixel = pixels.at(pos);
size_t count = prefix_length(pixels, pos); size_t count = prefix_length(pixels, pos);
pos += count; pos += count;
if (pixel == 0) if (pixel == 0)
{ {
// Up to 63 zeros can be encoded with RLE_ZEROS. If there are more, // Up to 63 zeros can be encoded with RLE_ZEROS. If there are more,
@ -80,7 +80,7 @@ static encoded_font_t::rlestring_t encode_rle(const DataFile::pixels_t &pixels)
result.push_back(RLE_64ZEROS | (c - 1)); result.push_back(RLE_64ZEROS | (c - 1));
count -= c * 64; count -= c * 64;
} }
if (count) if (count)
{ {
result.push_back(RLE_ZEROS | count); result.push_back(RLE_ZEROS | count);
@ -107,7 +107,7 @@ static encoded_font_t::rlestring_t encode_rle(const DataFile::pixels_t &pixels)
} }
} }
} }
return result; return result;
} }
@ -117,7 +117,7 @@ static encoded_font_t::rlestring_t encode_rle(const DataFile::pixels_t &pixels)
class DictTreeNode class DictTreeNode
{ {
public: public:
constexpr DictTreeNode(): DictTreeNode():
m_index(-1), m_index(-1),
m_ref(false), m_ref(false),
m_length(0), m_length(0),
@ -125,7 +125,7 @@ public:
m_child15(nullptr), m_child15(nullptr),
m_suffix(nullptr) m_suffix(nullptr)
{} {}
void SetChild(uint8_t p, DictTreeNode *child) void SetChild(uint8_t p, DictTreeNode *child)
{ {
if (p == 0) if (p == 0)
@ -143,9 +143,9 @@ public:
m_children[p - 1] = child; m_children[p - 1] = child;
} }
} }
DictTreeNode* GetChild(uint8_t p) const DictTreeNode* GetChild(uint8_t p) const
{ {
if (p == 0) if (p == 0)
return m_child0; return m_child0;
else if (p == 15) else if (p == 15)
@ -157,9 +157,9 @@ public:
else else
return m_children[p - 1]; return m_children[p - 1];
} }
bool HasIntermediateChildren() const { return m_children != nullptr; } bool HasIntermediateChildren() const { return m_children != nullptr; }
int GetIndex() const { return m_index; } int GetIndex() const { return m_index; }
void SetIndex(int index) { m_index = index; } void SetIndex(int index) { m_index = index; }
bool GetRef() const { return m_ref; } bool GetRef() const { return m_ref; }
@ -168,25 +168,25 @@ public:
void SetLength(size_t length) { m_length = length; } void SetLength(size_t length) { m_length = length; }
DictTreeNode *GetSuffix() const { return m_suffix; } DictTreeNode *GetSuffix() const { return m_suffix; }
void SetSuffix(DictTreeNode *suffix) { m_suffix = suffix; } void SetSuffix(DictTreeNode *suffix) { m_suffix = suffix; }
private: private:
// Index of dictionary entry or -1 if just a intermediate node. // Index of dictionary entry or -1 if just a intermediate node.
int m_index; int m_index;
// True for ref-encoded dictionary entries. Used to avoid recursion when // True for ref-encoded dictionary entries. Used to avoid recursion when
// encoding them. // encoding them.
bool m_ref; bool m_ref;
// Length of the corresponding dictionary entry replacement. // Length of the corresponding dictionary entry replacement.
// Equals the distance from the tree root. // Equals the distance from the tree root.
size_t m_length; size_t m_length;
// Most tree nodes will only ever contains children for 0 or 15. // Most tree nodes will only ever contains children for 0 or 15.
// Therefore the array for other nodes is allocated only on demand. // Therefore the array for other nodes is allocated only on demand.
DictTreeNode *m_child0; DictTreeNode *m_child0;
DictTreeNode *m_child15; DictTreeNode *m_child15;
std::unique_ptr<DictTreeNode*[]> m_children; std::unique_ptr<DictTreeNode*[]> m_children;
// Pointer to the longest suffix of this entry that exists in the // Pointer to the longest suffix of this entry that exists in the
// dictionary. // dictionary.
DictTreeNode *m_suffix; DictTreeNode *m_suffix;
@ -202,16 +202,16 @@ public:
m_next = m_storage.get(); m_next = m_storage.get();
m_left = count; m_left = count;
} }
DictTreeNode *allocate() DictTreeNode *allocate()
{ {
if (m_left == 0) if (m_left == 0)
throw std::logic_error("Ran out of preallocated entries"); throw std::logic_error("Ran out of preallocated entries");
m_left--; m_left--;
return m_next++; return m_next++;
} }
private: private:
std::unique_ptr<DictTreeNode[]> m_storage; std::unique_ptr<DictTreeNode[]> m_storage;
DictTreeNode *m_next; DictTreeNode *m_next;
@ -233,10 +233,10 @@ static DictTreeNode* add_tree_entry(const DataFile::pixels_t &entry, int index,
branch = storage.allocate(); branch = storage.allocate();
node->SetChild(p, branch); node->SetChild(p, branch);
} }
node = branch; node = branch;
} }
// Replace the entry if it either does not yet have an encoding, or if // Replace the entry if it either does not yet have an encoding, or if
// the new entry is non-ref (i.e. can be used in more situations). // the new entry is non-ref (i.e. can be used in more situations).
if (node->GetIndex() < 0 || (node->GetRef() && !ref_encoded)) if (node->GetIndex() < 0 || (node->GetRef() && !ref_encoded))
@ -245,7 +245,7 @@ static DictTreeNode* add_tree_entry(const DataFile::pixels_t &entry, int index,
node->SetRef(ref_encoded); node->SetRef(ref_encoded);
node->SetLength(entry.size()); node->SetLength(entry.size());
} }
return node; return node;
} }
@ -260,11 +260,11 @@ static DictTreeNode *find_tree_node(DataFile::pixels_t::const_iterator begin,
{ {
uint8_t pixel = *begin++; uint8_t pixel = *begin++;
node = node->GetChild(pixel); node = node->GetChild(pixel);
if (!node) if (!node)
return nullptr; return nullptr;
} }
return node; return node;
} }
@ -281,10 +281,10 @@ static void fill_tree_suffixes(DictTreeNode *root, DictTreeNode *subtree,
break; break;
} }
} }
if (!subtree->GetSuffix()) if (!subtree->GetSuffix())
subtree->SetSuffix(root); subtree->SetSuffix(root);
DataFile::pixels_t newentry(entry); DataFile::pixels_t newentry(entry);
newentry.resize(entry.size() + 1); newentry.resize(entry.size() + 1);
for (uint8_t i = 0; i < 16; i++) for (uint8_t i = 0; i < 16; i++)
@ -292,7 +292,7 @@ static void fill_tree_suffixes(DictTreeNode *root, DictTreeNode *subtree,
// Speed-up for the common case of 0 and 15 alphas. // Speed-up for the common case of 0 and 15 alphas.
if (i == 1 && !subtree->HasIntermediateChildren()) if (i == 1 && !subtree->HasIntermediateChildren())
i += 14; i += 14;
DictTreeNode *child = subtree->GetChild(i); DictTreeNode *child = subtree->GetChild(i);
if (child) if (child)
{ {
@ -307,7 +307,7 @@ static DictTreeNode* construct_tree(const std::vector<DataFile::dictentry_t> &di
TreeAllocator &storage, bool fast) TreeAllocator &storage, bool fast)
{ {
DictTreeNode* root = storage.allocate(); DictTreeNode* root = storage.allocate();
// Populate the hardcoded entries for 0 to 15 alpha. // Populate the hardcoded entries for 0 to 15 alpha.
for (int j = 0; j < 16; j++) for (int j = 0; j < 16; j++)
{ {
@ -317,18 +317,18 @@ static DictTreeNode* construct_tree(const std::vector<DataFile::dictentry_t> &di
node->SetLength(1); node->SetLength(1);
root->SetChild(j, node); root->SetChild(j, node);
} }
// Populate the actual dictionary entries // Populate the actual dictionary entries
size_t i = DICT_START; size_t i = DICT_START;
for (DataFile::dictentry_t d : dictionary) for (DataFile::dictentry_t d : dictionary)
{ {
if (!d.replacement.size()) if (!d.replacement.size())
break; break;
add_tree_entry(d.replacement, i, d.ref_encode, root, storage); add_tree_entry(d.replacement, i, d.ref_encode, root, storage);
i++; i++;
} }
if (!fast) if (!fast)
{ {
// Populate the fill entries for rest of dictionary // Populate the fill entries for rest of dictionary
@ -342,15 +342,15 @@ static DictTreeNode* construct_tree(const std::vector<DataFile::dictentry_t> &di
uint8_t p = (byte & (1 << j)) ? 15 : 0; uint8_t p = (byte & (1 << j)) ? 15 : 0;
pixels.push_back(p); pixels.push_back(p);
} }
add_tree_entry(pixels, i, false, root, storage); add_tree_entry(pixels, i, false, root, storage);
} }
// Fill in the suffix pointers for optimal encoding // Fill in the suffix pointers for optimal encoding
DataFile::pixels_t nullentry; DataFile::pixels_t nullentry;
fill_tree_suffixes(root, root, nullentry); fill_tree_suffixes(root, root, nullentry);
} }
return root; return root;
} }
@ -360,13 +360,13 @@ struct encoding_link_t
{ {
// Index of the position prior to the last dictionary entry. // Index of the position prior to the last dictionary entry.
size_t previous; size_t previous;
// Index of the dictionary entry that brings us to this point. // Index of the dictionary entry that brings us to this point.
int index; int index;
// Number of links to get here from the start of the string. // Number of links to get here from the start of the string.
size_t length; size_t length;
constexpr encoding_link_t(): previous(0), index(-1), length(9999999) {} constexpr encoding_link_t(): previous(0), index(-1), length(9999999) {}
}; };
@ -380,27 +380,27 @@ static encoded_font_t::refstring_t encode_ref_slow(const DataFile::pixels_t &pix
// Chain of encodings. Each entry in this array corresponds to a position // Chain of encodings. Each entry in this array corresponds to a position
// in the pixel string. // in the pixel string.
std::unique_ptr<encoding_link_t[]> chain(new encoding_link_t[pixels.size() + 1]); std::unique_ptr<encoding_link_t[]> chain(new encoding_link_t[pixels.size() + 1]);
chain[0].previous = 0; chain[0].previous = 0;
chain[0].index = 0; chain[0].index = 0;
chain[0].length = 0; chain[0].length = 0;
// Read the pixels one-by-one and update the encoding links accordingly. // Read the pixels one-by-one and update the encoding links accordingly.
const DictTreeNode *node = root; const DictTreeNode *node = root;
for (size_t pos = 0; pos < pixels.size(); pos++) for (size_t pos = 0; pos < pixels.size(); pos++)
{ {
uint8_t pixel = pixels.at(pos); uint8_t pixel = pixels.at(pos);
const DictTreeNode *branch = node->GetChild(pixel); const DictTreeNode *branch = node->GetChild(pixel);
while (!branch) while (!branch)
{ {
// Cannot expand this sequence, defer to suffix. // Cannot expand this sequence, defer to suffix.
node = node->GetSuffix(); node = node->GetSuffix();
branch = node->GetChild(pixel); branch = node->GetChild(pixel);
} }
node = branch; node = branch;
// We have arrived at a new node, add it and any proper suffixes to // We have arrived at a new node, add it and any proper suffixes to
// the link chain. // the link chain.
const DictTreeNode *suffix = node; const DictTreeNode *suffix = node;
@ -412,14 +412,14 @@ static encoded_font_t::refstring_t encode_ref_slow(const DataFile::pixels_t &pix
link.previous = pos + 1 - suffix->GetLength(); link.previous = pos + 1 - suffix->GetLength();
link.index = suffix->GetIndex(); link.index = suffix->GetIndex();
link.length = chain[link.previous].length + 1; link.length = chain[link.previous].length + 1;
if (link.length < chain[pos + 1].length) if (link.length < chain[pos + 1].length)
chain[pos + 1] = link; chain[pos + 1] = link;
} }
suffix = suffix->GetSuffix(); suffix = suffix->GetSuffix();
} }
} }
// Check if we can shorten the final encoding using REF_FILLZEROS. // Check if we can shorten the final encoding using REF_FILLZEROS.
if (is_glyph) if (is_glyph)
{ {
@ -427,30 +427,30 @@ static encoded_font_t::refstring_t encode_ref_slow(const DataFile::pixels_t &pix
{ {
if (pixels.at(pos) != 0) if (pixels.at(pos) != 0)
break; break;
encoding_link_t link; encoding_link_t link;
link.previous = pos; link.previous = pos;
link.index = REF_FILLZEROS; link.index = REF_FILLZEROS;
link.length = chain[pos].length + 1; link.length = chain[pos].length + 1;
if (link.length <= chain[pixels.size()].length) if (link.length <= chain[pixels.size()].length)
chain[pixels.size()] = link; chain[pixels.size()] = link;
} }
} }
// Backtrack from the final link back to the start and construct the // Backtrack from the final link back to the start and construct the
// encoded string. // encoded string.
encoded_font_t::refstring_t result; encoded_font_t::refstring_t result;
size_t len = chain[pixels.size()].length; size_t len = chain[pixels.size()].length;
result.resize(len); result.resize(len);
size_t pos = pixels.size(); size_t pos = pixels.size();
for (size_t i = len; i > 0; i--) for (size_t i = len; i > 0; i--)
{ {
result.at(i - 1) = chain[pos].index; result.at(i - 1) = chain[pos].index;
pos = chain[pos].previous; pos = chain[pos].previous;
} }
return result; return result;
} }
@ -464,18 +464,18 @@ static size_t walk_tree(const DictTreeNode *tree,
size_t best_length = 0; size_t best_length = 0;
size_t length = 0; size_t length = 0;
index = -1; index = -1;
const DictTreeNode* node = tree; const DictTreeNode* node = tree;
while (pixels != pixelsend) while (pixels != pixelsend)
{ {
uint8_t pixel = *pixels++; uint8_t pixel = *pixels++;
node = node->GetChild(pixel); node = node->GetChild(pixel);
if (!node) if (!node)
break; break;
length++; length++;
if (is_glyph || !node->GetRef()) if (is_glyph || !node->GetRef())
{ {
if (node->GetIndex() >= 0) if (node->GetIndex() >= 0)
@ -485,10 +485,10 @@ static size_t walk_tree(const DictTreeNode *tree,
} }
} }
} }
if (index < 0) if (index < 0)
throw std::logic_error("walk_tree failed to find a valid encoding"); throw std::logic_error("walk_tree failed to find a valid encoding");
return best_length; return best_length;
} }
@ -499,15 +499,15 @@ static encoded_font_t::refstring_t encode_ref_fast(const DataFile::pixels_t &pix
bool is_glyph) bool is_glyph)
{ {
encoded_font_t::refstring_t result; encoded_font_t::refstring_t result;
// Strip any zeroes from end // Strip any zeroes from end
size_t end = pixels.size(); size_t end = pixels.size();
if (is_glyph) if (is_glyph)
{ {
while (end > 0 && pixels.at(end - 1) == 0) end--; while (end > 0 && pixels.at(end - 1) == 0) end--;
} }
size_t i = 0; size_t i = 0;
while (i < end) while (i < end)
{ {
@ -515,10 +515,10 @@ static encoded_font_t::refstring_t encode_ref_fast(const DataFile::pixels_t &pix
i += walk_tree(tree, pixels.begin() + i, pixels.end(), index, is_glyph); i += walk_tree(tree, pixels.begin() + i, pixels.end(), index, is_glyph);
result.push_back(index); result.push_back(index);
} }
if (i < pixels.size()) if (i < pixels.size())
result.push_back(REF_FILLZEROS); result.push_back(REF_FILLZEROS);
return result; return result;
} }
@ -562,17 +562,17 @@ std::unique_ptr<encoded_font_t> encode_font(const DataFile &datafile,
bool fast) bool fast)
{ {
std::unique_ptr<encoded_font_t> result(new encoded_font_t); std::unique_ptr<encoded_font_t> result(new encoded_font_t);
// Sort the dictionary so that RLE-coded entries come first. // Sort the dictionary so that RLE-coded entries come first.
// This way the two are easy to distinguish based on index. // This way the two are easy to distinguish based on index.
std::vector<DataFile::dictentry_t> sorted_dict = datafile.GetDictionary(); std::vector<DataFile::dictentry_t> sorted_dict = datafile.GetDictionary();
std::stable_sort(sorted_dict.begin(), sorted_dict.end(), cmp_dict_coding); std::stable_sort(sorted_dict.begin(), sorted_dict.end(), cmp_dict_coding);
// Build the binary tree for looking up references. // Build the binary tree for looking up references.
size_t count = estimate_tree_node_count(sorted_dict); size_t count = estimate_tree_node_count(sorted_dict);
TreeAllocator allocator(count); TreeAllocator allocator(count);
DictTreeNode* tree = construct_tree(sorted_dict, allocator, fast); DictTreeNode* tree = construct_tree(sorted_dict, allocator, fast);
// Encode the dictionary entries, using either RLE or reference method. // Encode the dictionary entries, using either RLE or reference method.
for (const DataFile::dictentry_t &d : sorted_dict) for (const DataFile::dictentry_t &d : sorted_dict)
{ {
@ -589,19 +589,19 @@ std::unique_ptr<encoded_font_t> encode_font(const DataFile &datafile,
result->rle_dictionary.push_back(encode_rle(d.replacement)); result->rle_dictionary.push_back(encode_rle(d.replacement));
} }
} }
// Then reference-encode the glyphs // Then reference-encode the glyphs
for (const DataFile::glyphentry_t &g : datafile.GetGlyphTable()) for (const DataFile::glyphentry_t &g : datafile.GetGlyphTable())
{ {
result->glyphs.push_back(encode_ref(g.data, tree, true, fast)); result->glyphs.push_back(encode_ref(g.data, tree, true, fast));
} }
// Optionally verify that the encoding was correct. // Optionally verify that the encoding was correct.
if (!fast) if (!fast)
{ {
for (size_t i = 0; i < datafile.GetGlyphCount(); i++) for (size_t i = 0; i < datafile.GetGlyphCount(); i++)
{ {
std::unique_ptr<DataFile::pixels_t> decoded = std::unique_ptr<DataFile::pixels_t> decoded =
decode_glyph(*result, i, datafile.GetFontInfo()); decode_glyph(*result, i, datafile.GetFontInfo());
if (*decoded != datafile.GetGlyphEntry(i).data) if (*decoded != datafile.GetGlyphEntry(i).data)
{ {
@ -613,7 +613,7 @@ std::unique_ptr<encoded_font_t> encode_font(const DataFile &datafile,
} }
} }
} }
return result; return result;
} }
@ -623,14 +623,14 @@ size_t get_encoded_size(const encoded_font_t &encoded)
for (const encoded_font_t::rlestring_t &r : encoded.rle_dictionary) for (const encoded_font_t::rlestring_t &r : encoded.rle_dictionary)
{ {
total += r.size(); total += r.size();
if (r.size() != 0) if (r.size() != 0)
total += 2; // Offset table entry total += 2; // Offset table entry
} }
for (const encoded_font_t::refstring_t &r : encoded.ref_dictionary) for (const encoded_font_t::refstring_t &r : encoded.ref_dictionary)
{ {
total += r.size(); total += r.size();
if (r.size() != 0) if (r.size() != 0)
total += 2; // Offset table entry total += 2; // Offset table entry
} }
@ -649,7 +649,7 @@ std::unique_ptr<DataFile::pixels_t> decode_glyph(
const DataFile::fontinfo_t &fontinfo) const DataFile::fontinfo_t &fontinfo)
{ {
std::unique_ptr<DataFile::pixels_t> result(new DataFile::pixels_t); std::unique_ptr<DataFile::pixels_t> result(new DataFile::pixels_t);
for (uint8_t ref : refstring) for (uint8_t ref : refstring)
{ {
if (ref <= 15) if (ref <= 15)
@ -712,7 +712,7 @@ std::unique_ptr<DataFile::pixels_t> decode_glyph(
else else
{ {
size_t bitcount = fillentry_bitcount(ref); size_t bitcount = fillentry_bitcount(ref);
uint8_t byte = ref - DICT_START7BIT; uint8_t byte = ref - DICT_START7BIT;
for (size_t i = 0; i < bitcount; i++) for (size_t i = 0; i < bitcount; i++)
{ {
@ -721,7 +721,7 @@ std::unique_ptr<DataFile::pixels_t> decode_glyph(
} }
} }
} }
return result; return result;
} }

View File

@ -15,13 +15,13 @@ struct encoded_font_t
// Each item is a byte. Top bit means the value in the original bitstream, // Each item is a byte. Top bit means the value in the original bitstream,
// and the bottom 7 bits store the repetition count. // and the bottom 7 bits store the repetition count.
typedef std::vector<uint8_t> rlestring_t; typedef std::vector<uint8_t> rlestring_t;
// Reference encoded format for storing the glyphs. // Reference encoded format for storing the glyphs.
// Each item is a reference to the dictionary. // Each item is a reference to the dictionary.
// Values 0 and 1 are hardcoded to mean 0 and 1. // Values 0 and 1 are hardcoded to mean 0 and 1.
// All other values mean dictionary entry at (i-2). // All other values mean dictionary entry at (i-2).
typedef std::vector<uint8_t> refstring_t; typedef std::vector<uint8_t> refstring_t;
std::vector<rlestring_t> rle_dictionary; std::vector<rlestring_t> rle_dictionary;
std::vector<refstring_t> ref_dictionary; std::vector<refstring_t> ref_dictionary;
std::vector<refstring_t> glyphs; std::vector<refstring_t> glyphs;
@ -68,45 +68,45 @@ public:
std::istringstream s(testfile); std::istringstream s(testfile);
std::unique_ptr<DataFile> f = DataFile::Load(s); std::unique_ptr<DataFile> f = DataFile::Load(s);
std::unique_ptr<encoded_font_t> e = encode_font(*f, false); std::unique_ptr<encoded_font_t> e = encode_font(*f, false);
TS_ASSERT_EQUALS(e->glyphs.size(), 3); TS_ASSERT_EQUALS(e->glyphs.size(), 3);
// Expected values for dictionary // Expected values for dictionary
encoded_font_t::rlestring_t dict0 = {0x01, 0xCE, 0x01, 0xCE}; encoded_font_t::rlestring_t dict0 = {0x01, 0xCE, 0x01, 0xCE};
encoded_font_t::rlestring_t dict1 = {0x0C}; encoded_font_t::rlestring_t dict1 = {0x0C};
encoded_font_t::rlestring_t dict2 = {0xFE}; encoded_font_t::rlestring_t dict2 = {0xFE};
encoded_font_t::refstring_t dict3 = {24, 24}; encoded_font_t::refstring_t dict3 = {24, 24};
TS_ASSERT(e->rle_dictionary.at(0) == dict0); TS_ASSERT(e->rle_dictionary.at(0) == dict0);
TS_ASSERT(e->rle_dictionary.at(1) == dict1); TS_ASSERT(e->rle_dictionary.at(1) == dict1);
TS_ASSERT(e->rle_dictionary.at(2) == dict2); TS_ASSERT(e->rle_dictionary.at(2) == dict2);
TS_ASSERT(e->ref_dictionary.at(0) == dict3); TS_ASSERT(e->ref_dictionary.at(0) == dict3);
// Expected values for glyphs // Expected values for glyphs
encoded_font_t::refstring_t glyph0 = {27, 27, 27}; encoded_font_t::refstring_t glyph0 = {27, 27, 27};
encoded_font_t::refstring_t glyph1 = {24, 0, 132, 25, 14}; encoded_font_t::refstring_t glyph1 = {24, 0, 132, 25, 14};
encoded_font_t::refstring_t glyph2 = {228, 26, 244, 14, 14, 14, 228, 26, 16}; encoded_font_t::refstring_t glyph2 = {228, 26, 244, 14, 14, 14, 228, 26, 16};
TS_ASSERT_EQUALS(e->glyphs.at(0), glyph0); TS_ASSERT_EQUALS(e->glyphs.at(0), glyph0);
TS_ASSERT_EQUALS(e->glyphs.at(1), glyph1); TS_ASSERT_EQUALS(e->glyphs.at(1), glyph1);
TS_ASSERT_EQUALS(e->glyphs.at(2), glyph2); TS_ASSERT_EQUALS(e->glyphs.at(2), glyph2);
} }
void testDecode() void testDecode()
{ {
std::istringstream s(testfile); std::istringstream s(testfile);
std::unique_ptr<DataFile> f = DataFile::Load(s); std::unique_ptr<DataFile> f = DataFile::Load(s);
std::unique_ptr<encoded_font_t> e = encode_font(*f, false); std::unique_ptr<encoded_font_t> e = encode_font(*f, false);
for (size_t i = 0; i < 3; i++) for (size_t i = 0; i < 3; i++)
{ {
std::unique_ptr<DataFile::pixels_t> dec; std::unique_ptr<DataFile::pixels_t> dec;
dec = decode_glyph(*e, i, f->GetFontInfo()); dec = decode_glyph(*e, i, f->GetFontInfo());
TS_ASSERT_EQUALS(*dec, f->GetGlyphEntry(i).data); TS_ASSERT_EQUALS(*dec, f->GetGlyphEntry(i).data);
} }
} }
private: private:
static constexpr const char *testfile = static constexpr const char *testfile =
"Version 1\n" "Version 1\n"

View File

@ -21,10 +21,10 @@ static void encode_glyph(const DataFile::glyphentry_t &glyph,
int num_cols) int num_cols)
{ {
const int threshold = 8; const int threshold = 8;
if (glyph.data.size() == 0) if (glyph.data.size() == 0)
return; return;
// Find the number of columns in the glyph data // Find the number of columns in the glyph data
if (num_cols == 0) if (num_cols == 0)
{ {
@ -38,7 +38,7 @@ static void encode_glyph(const DataFile::glyphentry_t &glyph,
} }
} }
} }
// Write the bits that compose the glyph // Write the bits that compose the glyph
for (int x = 0; x < num_cols; x++) for (int x = 0; x < num_cols; x++)
{ {
@ -78,7 +78,7 @@ static void encode_character_range(std::ostream &out,
std::vector<DataFile::glyphentry_t> glyphs; std::vector<DataFile::glyphentry_t> glyphs;
bool constant_width = true; bool constant_width = true;
int width = datafile.GetGlyphEntry(range.glyph_indices[0]).width; int width = datafile.GetGlyphEntry(range.glyph_indices[0]).width;
// Copy all the glyphs in this range for the purpose of cropping them. // Copy all the glyphs in this range for the purpose of cropping them.
for (int glyph_index: range.glyph_indices) for (int glyph_index: range.glyph_indices)
{ {
@ -92,7 +92,7 @@ static void encode_character_range(std::ostream &out,
{ {
auto glyph = datafile.GetGlyphEntry(glyph_index); auto glyph = datafile.GetGlyphEntry(glyph_index);
glyphs.push_back(glyph); glyphs.push_back(glyph);
if (glyph.width != width) if (glyph.width != width)
{ {
constant_width = false; constant_width = false;
@ -100,69 +100,69 @@ static void encode_character_range(std::ostream &out,
} }
} }
} }
// Crop the glyphs in this range. Getting rid of a few rows at top // Crop the glyphs in this range. Getting rid of a few rows at top
// or left can save a bunch of bytes with minimal cost. // or left can save a bunch of bytes with minimal cost.
DataFile::fontinfo_t old_fi = datafile.GetFontInfo(); DataFile::fontinfo_t old_fi = datafile.GetFontInfo();
DataFile::fontinfo_t new_fi = old_fi; DataFile::fontinfo_t new_fi = old_fi;
crop_glyphs(glyphs, new_fi); crop_glyphs(glyphs, new_fi);
if (new_fi.max_width != width) if (new_fi.max_width != width)
{ {
constant_width = false; constant_width = false;
width = 0; width = 0;
} }
// Fill in the crop information // Fill in the crop information
cropinfo.offset_x = old_fi.baseline_x - new_fi.baseline_x; cropinfo.offset_x = old_fi.baseline_x - new_fi.baseline_x;
cropinfo.offset_y = old_fi.baseline_y - new_fi.baseline_y; cropinfo.offset_y = old_fi.baseline_y - new_fi.baseline_y;
cropinfo.height_pixels = new_fi.max_height; cropinfo.height_pixels = new_fi.max_height;
cropinfo.height_bytes = (cropinfo.height_pixels + 7) / 8; cropinfo.height_bytes = (cropinfo.height_pixels + 7) / 8;
cropinfo.width = width; cropinfo.width = width;
// Then format and write out the glyph data // Then format and write out the glyph data
std::vector<unsigned> offsets; std::vector<unsigned> offsets;
std::vector<unsigned> data; std::vector<unsigned> data;
std::vector<unsigned> widths; std::vector<unsigned> widths;
size_t stride = cropinfo.height_bytes; size_t stride = cropinfo.height_bytes;
for (const DataFile::glyphentry_t &g : glyphs) for (const DataFile::glyphentry_t &g : glyphs)
{ {
offsets.push_back(data.size() / stride); offsets.push_back(data.size() / stride);
widths.push_back(g.width); widths.push_back(g.width);
encode_glyph(g, new_fi, data, width); encode_glyph(g, new_fi, data, width);
} }
offsets.push_back(data.size() / stride); offsets.push_back(data.size() / stride);
write_const_table(out, data, "gU8", "mf_bwfont_" + name + "_glyph_data_" + std::to_string(range_index)); write_const_table(out, data, "uint8_t", "mf_bwfont_" + name + "_glyph_data_" + std::to_string(range_index), 1);
if (!constant_width) if (!constant_width)
{ {
write_const_table(out, offsets, "gU16", "mf_bwfont_" + name + "_glyph_offsets_" + std::to_string(range_index), 4); write_const_table(out, offsets, "uint16_t", "mf_bwfont_" + name + "_glyph_offsets_" + std::to_string(range_index), 1, 4);
write_const_table(out, widths, "gU8", "mf_bwfont_" + name + "_glyph_widths_" + std::to_string(range_index)); write_const_table(out, widths, "uint8_t", "mf_bwfont_" + name + "_glyph_widths_" + std::to_string(range_index), 1);
} }
} }
void write_source(std::ostream &out, std::string name, const DataFile &datafile) void write_source(std::ostream &out, std::string name, const DataFile &datafile)
{ {
name = filename_to_identifier(name); name = filename_to_identifier(name);
out << std::endl; out << std::endl;
out << std::endl; out << std::endl;
out << "/* Start of automatically generated font definition for " << name << ". */" << std::endl; out << "/* Start of automatically generated font definition for " << name << ". */" << std::endl;
out << std::endl; out << std::endl;
out << "#ifndef MF_BWFONT_INTERNALS" << std::endl; out << "#ifndef MF_BWFONT_INTERNALS" << std::endl;
out << "#define MF_BWFONT_INTERNALS" << std::endl; out << "#define MF_BWFONT_INTERNALS" << std::endl;
out << "#endif" << std::endl; out << "#endif" << std::endl;
out << "#include \"mf_bwfont.h\"" << std::endl; out << "#include \"mf_bwfont.h\"" << std::endl;
out << std::endl; out << std::endl;
out << "#ifndef MF_BWFONT_VERSION_" << BWFONT_FORMAT_VERSION << "_SUPPORTED" << std::endl; out << "#ifndef MF_BWFONT_VERSION_" << BWFONT_FORMAT_VERSION << "_SUPPORTED" << std::endl;
out << "#error The font file is not compatible with this version of mcufont." << std::endl; out << "#error The font file is not compatible with this version of mcufont." << std::endl;
out << "#endif" << std::endl; out << "#endif" << std::endl;
out << std::endl; out << std::endl;
// Split the characters into ranges // Split the characters into ranges
DataFile::fontinfo_t f = datafile.GetFontInfo(); DataFile::fontinfo_t f = datafile.GetFontInfo();
size_t glyph_size = f.max_width * ((f.max_height + 7) / 8); size_t glyph_size = f.max_width * ((f.max_height + 7) / 8);
@ -178,14 +178,14 @@ void write_source(std::ostream &out, std::string name, const DataFile &datafile)
encode_character_range(out, name, datafile, ranges.at(i), i, cropinfo); encode_character_range(out, name, datafile, ranges.at(i), i, cropinfo);
crops.push_back(cropinfo); crops.push_back(cropinfo);
} }
// Write out a table describing the character ranges // Write out a table describing the character ranges
out << "static const struct mf_bwfont_char_range_s mf_bwfont_" + name + "_char_ranges[] = {" << std::endl; out << "static const struct mf_bwfont_char_range_s mf_bwfont_" + name + "_char_ranges[] = {" << std::endl;
for (size_t i = 0; i < ranges.size(); i++) for (size_t i = 0; i < ranges.size(); i++)
{ {
std::string offsets = (crops[i].width) ? "0" : "mf_bwfont_" + name + "_glyph_offsets_" + std::to_string(i); std::string offsets = (crops[i].width) ? "0" : "mf_bwfont_" + name + "_glyph_offsets_" + std::to_string(i);
std::string widths = (crops[i].width) ? "0" : "mf_bwfont_" + name + "_glyph_widths_" + std::to_string(i); std::string widths = (crops[i].width) ? "0" : "mf_bwfont_" + name + "_glyph_widths_" + std::to_string(i);
out << " {" << std::endl; out << " {" << std::endl;
out << " " << ranges.at(i).first_char << ", /* first char */" << std::endl; out << " " << ranges.at(i).first_char << ", /* first char */" << std::endl;
out << " " << ranges.at(i).char_count << ", /* char count */" << std::endl; out << " " << ranges.at(i).char_count << ", /* char count */" << std::endl;
@ -201,10 +201,10 @@ void write_source(std::ostream &out, std::string name, const DataFile &datafile)
} }
out << "};" << std::endl; out << "};" << std::endl;
out << std::endl; out << std::endl;
// Fonts in this format are always black & white // Fonts in this format are always black & white
int flags = datafile.GetFontInfo().flags | DataFile::FLAG_BW; int flags = datafile.GetFontInfo().flags | DataFile::FLAG_BW;
// Pull it all together in the rlefont_s structure. // Pull it all together in the rlefont_s structure.
out << "const struct mf_bwfont_s mf_bwfont_" << name << " = {" << std::endl; out << "const struct mf_bwfont_s mf_bwfont_" << name << " = {" << std::endl;
out << " {" << std::endl; out << " {" << std::endl;
@ -222,12 +222,12 @@ void write_source(std::ostream &out, std::string name, const DataFile &datafile)
out << " " << "&mf_bwfont_character_width," << std::endl; out << " " << "&mf_bwfont_character_width," << std::endl;
out << " " << "&mf_bwfont_render_character," << std::endl; out << " " << "&mf_bwfont_render_character," << std::endl;
out << " }," << std::endl; out << " }," << std::endl;
out << " " << BWFONT_FORMAT_VERSION << ", /* version */" << std::endl; out << " " << BWFONT_FORMAT_VERSION << ", /* version */" << std::endl;
out << " " << ranges.size() << ", /* char range count */" << std::endl; out << " " << ranges.size() << ", /* char range count */" << std::endl;
out << " " << "mf_bwfont_" << name << "_char_ranges," << std::endl; out << " " << "mf_bwfont_" << name << "_char_ranges," << std::endl;
out << "};" << std::endl; out << "};" << std::endl;
// Write the font lookup structure // Write the font lookup structure
out << std::endl; out << std::endl;
out << "#ifdef MF_INCLUDED_FONTS" << std::endl; out << "#ifdef MF_INCLUDED_FONTS" << std::endl;
@ -239,12 +239,12 @@ void write_source(std::ostream &out, std::string name, const DataFile &datafile)
out << "#undef MF_INCLUDED_FONTS" << std::endl; out << "#undef MF_INCLUDED_FONTS" << std::endl;
out << "#define MF_INCLUDED_FONTS (&mf_bwfont_" << name << "_listentry)" << std::endl; out << "#define MF_INCLUDED_FONTS (&mf_bwfont_" << name << "_listentry)" << std::endl;
out << "#endif" << std::endl; out << "#endif" << std::endl;
out << std::endl; out << std::endl;
out << std::endl; out << std::endl;
out << "/* End of automatically generated font definition for " << name << ". */" << std::endl; out << "/* End of automatically generated font definition for " << name << ". */" << std::endl;
out << std::endl; out << std::endl;
} }
}} }}

View File

@ -28,16 +28,16 @@ static void encode_dictionary(std::ostream &out,
offsets.push_back(data.size()); offsets.push_back(data.size());
data.insert(data.end(), r.begin(), r.end()); data.insert(data.end(), r.begin(), r.end());
} }
for (const encoded_font_t::refstring_t &r : encoded.ref_dictionary) for (const encoded_font_t::refstring_t &r : encoded.ref_dictionary)
{ {
offsets.push_back(data.size()); offsets.push_back(data.size());
data.insert(data.end(), r.begin(), r.end()); data.insert(data.end(), r.begin(), r.end());
} }
offsets.push_back(data.size()); offsets.push_back(data.size());
write_const_table(out, data, "gU8", "mf_rlefont_" + name + "_dictionary_data"); write_const_table(out, data, "uint8_t", "mf_rlefont_" + name + "_dictionary_data", 1);
write_const_table(out, offsets, "gU16", "mf_rlefont_" + name + "_dictionary_offsets", 4); write_const_table(out, offsets, "uint16_t", "mf_rlefont_" + name + "_dictionary_offsets", 1, 4);
} }
// Encode the data tables for a single character range. // Encode the data tables for a single character range.
@ -52,7 +52,7 @@ static void encode_character_range(std::ostream &out,
std::vector<unsigned> offsets; std::vector<unsigned> offsets;
std::vector<unsigned> data; std::vector<unsigned> data;
std::map<size_t, unsigned> already_encoded; std::map<size_t, unsigned> already_encoded;
for (int glyph_index : range.glyph_indices) for (int glyph_index : range.glyph_indices)
{ {
if (already_encoded.count(glyph_index)) if (already_encoded.count(glyph_index))
@ -63,49 +63,49 @@ static void encode_character_range(std::ostream &out,
{ {
encoded_font_t::refstring_t r; encoded_font_t::refstring_t r;
int width = 0; int width = 0;
if (glyph_index >= 0) if (glyph_index >= 0)
{ {
r = encoded.glyphs[glyph_index]; r = encoded.glyphs[glyph_index];
width = datafile.GetGlyphEntry(glyph_index).width; width = datafile.GetGlyphEntry(glyph_index).width;
} }
offsets.push_back(data.size()); offsets.push_back(data.size());
already_encoded[glyph_index] = data.size(); already_encoded[glyph_index] = data.size();
data.push_back(width); data.push_back(width);
data.insert(data.end(), r.begin(), r.end()); data.insert(data.end(), r.begin(), r.end());
} }
} }
write_const_table(out, data, "gU8", "mf_rlefont_" + name + "_glyph_data_" + std::to_string(range_index)); write_const_table(out, data, "uint8_t", "mf_rlefont_" + name + "_glyph_data_" + std::to_string(range_index), 1);
write_const_table(out, offsets, "gU16", "mf_rlefont_" + name + "_glyph_offsets_" + std::to_string(range_index), 4); write_const_table(out, offsets, "uint16_t", "mf_rlefont_" + name + "_glyph_offsets_" + std::to_string(range_index), 1, 4);
} }
void write_source(std::ostream &out, std::string name, const DataFile &datafile) void write_source(std::ostream &out, std::string name, const DataFile &datafile)
{ {
name = filename_to_identifier(name); name = filename_to_identifier(name);
std::unique_ptr<encoded_font_t> encoded = encode_font(datafile, false); std::unique_ptr<encoded_font_t> encoded = encode_font(datafile, false);
out << std::endl; out << std::endl;
out << std::endl; out << std::endl;
out << "/* Start of automatically generated font definition for " << name << ". */" << std::endl; out << "/* Start of automatically generated font definition for " << name << ". */" << std::endl;
out << std::endl; out << std::endl;
out << "#ifndef MF_RLEFONT_INTERNALS" << std::endl; out << "#ifndef MF_RLEFONT_INTERNALS" << std::endl;
out << "#define MF_RLEFONT_INTERNALS" << std::endl; out << "#define MF_RLEFONT_INTERNALS" << std::endl;
out << "#endif" << std::endl; out << "#endif" << std::endl;
out << "#include \"mf_rlefont.h\"" << std::endl; out << "#include \"mf_rlefont.h\"" << std::endl;
out << std::endl; out << std::endl;
out << "#ifndef MF_RLEFONT_VERSION_" << RLEFONT_FORMAT_VERSION << "_SUPPORTED" << std::endl; out << "#ifndef MF_RLEFONT_VERSION_" << RLEFONT_FORMAT_VERSION << "_SUPPORTED" << std::endl;
out << "#error The font file is not compatible with this version of mcufont." << std::endl; out << "#error The font file is not compatible with this version of mcufont." << std::endl;
out << "#endif" << std::endl; out << "#endif" << std::endl;
out << std::endl; out << std::endl;
// Write out the dictionary entries // Write out the dictionary entries
encode_dictionary(out, name, datafile, *encoded); encode_dictionary(out, name, datafile, *encoded);
// Split the characters into ranges // Split the characters into ranges
auto get_glyph_size = [&encoded](size_t i) auto get_glyph_size = [&encoded](size_t i)
{ {
@ -119,7 +119,7 @@ void write_source(std::ostream &out, std::string name, const DataFile &datafile)
{ {
encode_character_range(out, name, datafile, *encoded, ranges.at(i), i); encode_character_range(out, name, datafile, *encoded, ranges.at(i), i);
} }
// Write out a table describing the character ranges // Write out a table describing the character ranges
out << "static const struct mf_rlefont_char_range_s mf_rlefont_" << name << "_char_ranges[] = {" << std::endl; out << "static const struct mf_rlefont_char_range_s mf_rlefont_" << name << "_char_ranges[] = {" << std::endl;
for (size_t i = 0; i < ranges.size(); i++) for (size_t i = 0; i < ranges.size(); i++)
@ -127,11 +127,11 @@ void write_source(std::ostream &out, std::string name, const DataFile &datafile)
out << " {" << ranges.at(i).first_char out << " {" << ranges.at(i).first_char
<< ", " << ranges.at(i).char_count << ", " << ranges.at(i).char_count
<< ", mf_rlefont_" << name << "_glyph_offsets_" << i << ", mf_rlefont_" << name << "_glyph_offsets_" << i
<< ", mf_rlefont_" << name << "_glyph_data_" << i << "}," << std::endl; << ", mf_rlefont_" << name << "_glyph_data_" << i << "}," << std::endl;
} }
out << "};" << std::endl; out << "};" << std::endl;
out << std::endl; out << std::endl;
// Pull it all together in the rlefont_s structure. // Pull it all together in the rlefont_s structure.
out << "const struct mf_rlefont_s mf_rlefont_" << name << " = {" << std::endl; out << "const struct mf_rlefont_s mf_rlefont_" << name << " = {" << std::endl;
out << " {" << std::endl; out << " {" << std::endl;
@ -149,7 +149,7 @@ void write_source(std::ostream &out, std::string name, const DataFile &datafile)
out << " " << "&mf_rlefont_character_width," << std::endl; out << " " << "&mf_rlefont_character_width," << std::endl;
out << " " << "&mf_rlefont_render_character," << std::endl; out << " " << "&mf_rlefont_render_character," << std::endl;
out << " }," << std::endl; out << " }," << std::endl;
out << " " << RLEFONT_FORMAT_VERSION << ", /* version */" << std::endl; out << " " << RLEFONT_FORMAT_VERSION << ", /* version */" << std::endl;
out << " " << "mf_rlefont_" << name << "_dictionary_data," << std::endl; out << " " << "mf_rlefont_" << name << "_dictionary_data," << std::endl;
out << " " << "mf_rlefont_" << name << "_dictionary_offsets," << std::endl; out << " " << "mf_rlefont_" << name << "_dictionary_offsets," << std::endl;
@ -158,7 +158,7 @@ void write_source(std::ostream &out, std::string name, const DataFile &datafile)
out << " " << ranges.size() << ", /* char range count */" << std::endl; out << " " << ranges.size() << ", /* char range count */" << std::endl;
out << " " << "mf_rlefont_" << name << "_char_ranges," << std::endl; out << " " << "mf_rlefont_" << name << "_char_ranges," << std::endl;
out << "};" << std::endl; out << "};" << std::endl;
// Write the font lookup structure // Write the font lookup structure
out << std::endl; out << std::endl;
out << "#ifdef MF_INCLUDED_FONTS" << std::endl; out << "#ifdef MF_INCLUDED_FONTS" << std::endl;
@ -170,7 +170,7 @@ void write_source(std::ostream &out, std::string name, const DataFile &datafile)
out << "#undef MF_INCLUDED_FONTS" << std::endl; out << "#undef MF_INCLUDED_FONTS" << std::endl;
out << "#define MF_INCLUDED_FONTS (&mf_rlefont_" << name << "_listentry)" << std::endl; out << "#define MF_INCLUDED_FONTS (&mf_rlefont_" << name << "_listentry)" << std::endl;
out << "#endif" << std::endl; out << "#endif" << std::endl;
out << std::endl; out << std::endl;
out << std::endl; out << std::endl;
out << "/* End of automatically generated font definition for " << name << ". */" << std::endl; out << "/* End of automatically generated font definition for " << name << ". */" << std::endl;

View File

@ -3,8 +3,8 @@
#include <set> #include <set>
namespace mcufont { namespace mcufont {
// Convert a file name to a valid C identifier // Convert a file name to a valid C identifier
std::string filename_to_identifier(std::string name) std::string filename_to_identifier(std::string name)
{ {
@ -12,19 +12,19 @@ std::string filename_to_identifier(std::string name)
size_t pos = name.find_last_of("/\\"); size_t pos = name.find_last_of("/\\");
if (pos != std::string::npos) if (pos != std::string::npos)
name = name.substr(pos + 1); name = name.substr(pos + 1);
// If the name contains a file extension, strip it. // If the name contains a file extension, strip it.
pos = name.find_first_of("."); pos = name.find_first_of(".");
if (pos != std::string::npos) if (pos != std::string::npos)
name = name.substr(0, pos); name = name.substr(0, pos);
// Replace any special characters with _. // Replace any special characters with _.
for (pos = 0; pos < name.size(); pos++) for (pos = 0; pos < name.size(); pos++)
{ {
if (!isalnum(name.at(pos))) if (!isalnum(name.at(pos)))
name.at(pos) = '_'; name.at(pos) = '_';
} }
return name; return name;
} }
@ -33,55 +33,61 @@ void wordwrap_vector(std::ostream &out, const std::vector<unsigned> &data,
const std::string &prefix, size_t width) const std::string &prefix, size_t width)
{ {
int values_per_column = (width <= 2) ? 16 : 8; int values_per_column = (width <= 2) ? 16 : 8;
std::ios::fmtflags flags(out.flags()); std::ios::fmtflags flags(out.flags());
out << prefix; out << prefix;
out << std::hex << std::setfill('0'); out << std::hex << std::setfill('0');
for (size_t i = 0; i < data.size(); i++) for (size_t i = 0; i < data.size(); i++)
{ {
if (i % values_per_column == 0 && i != 0) if (i != 0) {
out << std::endl << prefix; if (i % values_per_column == 0) {
out << std::endl << prefix;
out << "0x" << std::setw(width) << (int)data.at(i) << ", "; }
else {
out << " ";
}
}
out << "0x" << std::setw(width) << (int)data.at(i) << ",";
} }
out.flags(flags); out.flags(flags);
} }
// Write a vector of integers as a C constant array of given datatype. // Write a vector of integers as a C constant array of given datatype.
void write_const_table(std::ostream &out, const std::vector<unsigned> &data, void write_const_table(std::ostream &out, const std::vector<unsigned> &data,
const std::string &datatype, const std::string &tablename, const std::string &datatype, const std::string &tablename, char flg_is_data,
size_t width) size_t width)
{ {
out << "static const " << datatype << " " << tablename; out << "static const " << datatype << " " << tablename;
out << "[" << data.size() << "] = {" << std::endl; out << "[" << data.size() << "]" << ((flg_is_data)?" PROGMEM ":" ") << "= {" << std::endl;
wordwrap_vector(out, data, " ", width); wordwrap_vector(out, data, " ", width);
out << std::endl << "};" << std::endl; out << std::endl << "};" << std::endl;
out << std::endl; out << std::endl;
} }
int get_min_x_advance(const DataFile &datafile) int get_min_x_advance(const DataFile &datafile)
{ {
int min = datafile.GetGlyphEntry(0).width; int min = datafile.GetGlyphEntry(0).width;
for (const DataFile::glyphentry_t &g : datafile.GetGlyphTable()) for (const DataFile::glyphentry_t &g : datafile.GetGlyphTable())
{ {
if (min > g.width) if (min > g.width)
min = g.width; min = g.width;
} }
return min; return min;
} }
int get_max_x_advance(const DataFile &datafile) int get_max_x_advance(const DataFile &datafile)
{ {
int max = 0; int max = 0;
for (const DataFile::glyphentry_t &g : datafile.GetGlyphTable()) for (const DataFile::glyphentry_t &g : datafile.GetGlyphTable())
{ {
if (max < g.width) if (max < g.width)
max = g.width; max = g.width;
} }
return max; return max;
} }
@ -89,26 +95,24 @@ int get_max_x_advance(const DataFile &datafile)
int select_fallback_char(const DataFile &datafile) int select_fallback_char(const DataFile &datafile)
{ {
std::set<int> chars; std::set<int> chars;
size_t i = 0;
for (const DataFile::glyphentry_t &g: datafile.GetGlyphTable()) for (const DataFile::glyphentry_t &g: datafile.GetGlyphTable())
{ {
for (size_t c: g.chars) for (size_t c: g.chars)
{ {
chars.insert(c); chars.insert(c);
} }
i++;
} }
if (chars.count(0xFFFD)) if (chars.count(0xFFFD))
return 0xFFFD; // Unicode replacement character return 0xFFFD; // Unicode replacement character
if (chars.count(0)) if (chars.count(0))
return 0; // Used by many BDF fonts as replacement char return 0; // Used by many BDF fonts as replacement char
if (chars.count('?')) if (chars.count('?'))
return '?'; return '?';
return ' '; return ' ';
} }
@ -124,25 +128,25 @@ std::vector<char_range_t> compute_char_ranges(const DataFile &datafile,
std::vector<char_range_t> result; std::vector<char_range_t> result;
std::map<size_t, size_t> char_to_glyph = datafile.GetCharToGlyphMap(); std::map<size_t, size_t> char_to_glyph = datafile.GetCharToGlyphMap();
std::vector<size_t> chars; std::vector<size_t> chars;
// Get list of all characters in numeric order. // Get list of all characters in numeric order.
for (auto iter : char_to_glyph) for (auto iter : char_to_glyph)
chars.push_back(iter.first); chars.push_back(iter.first);
// Pick out ranges until we have processed all characters // Pick out ranges until we have processed all characters
size_t i = 0; size_t i = 0;
while (i < chars.size()) while (i < chars.size())
{ {
char_range_t range; char_range_t range;
range.first_char = chars.at(i); range.first_char = chars.at(i);
// Find the point where there is a gap larger than minimum_gap. // Find the point where there is a gap larger than minimum_gap.
i++; i++;
while (i < chars.size() && chars.at(i) - chars.at(i - 1) < minimum_gap) while (i < chars.size() && chars.at(i) - chars.at(i - 1) < minimum_gap)
i++; i++;
uint16_t last_char = chars.at(i - 1); uint16_t last_char = chars.at(i - 1);
// Then store the indices of glyphs for each character // Then store the indices of glyphs for each character
size_t data_length = 0; size_t data_length = 0;
for (size_t j = range.first_char; j <= last_char; j++) for (size_t j = range.first_char; j <= last_char; j++)
@ -153,32 +157,32 @@ std::vector<char_range_t> compute_char_ranges(const DataFile &datafile,
range.glyph_indices.push_back(-1); range.glyph_indices.push_back(-1);
continue; continue;
} }
int glyph_index = char_to_glyph[j]; int glyph_index = char_to_glyph[j];
// Monitor the amount of the data in the range and split it // Monitor the amount of the data in the range and split it
// if it grows too large. // if it grows too large.
data_length += get_encoded_glyph_size(glyph_index); data_length += get_encoded_glyph_size(glyph_index);
if (data_length > maximum_size) if (data_length > maximum_size)
{ {
last_char = j - 1; last_char = j - 1;
// Return the rest of characters to be processed by next range. // Return the rest of characters to be processed by next range.
while (chars.at(i-1) > last_char) while (chars.at(i-1) > last_char)
i--; i--;
break; break;
} }
range.glyph_indices.push_back(glyph_index); range.glyph_indices.push_back(glyph_index);
} }
range.char_count = last_char - range.first_char + 1; range.char_count = last_char - range.first_char + 1;
result.push_back(range); result.push_back(range);
} }
return result; return result;
} }
} }

View File

@ -8,7 +8,7 @@
#include "datafile.hh" #include "datafile.hh"
namespace mcufont { namespace mcufont {
// Convert a file name to a valid C identifier // Convert a file name to a valid C identifier
std::string filename_to_identifier(std::string name); std::string filename_to_identifier(std::string name);
@ -18,7 +18,7 @@ void wordwrap_vector(std::ostream &out, const std::vector<unsigned> &data,
// Write a vector of integers as a C constant array of given datatype. // Write a vector of integers as a C constant array of given datatype.
void write_const_table(std::ostream &out, const std::vector<unsigned> &data, void write_const_table(std::ostream &out, const std::vector<unsigned> &data,
const std::string &datatype, const std::string &tablename, const std::string &datatype, const std::string &tablename, char flg_is_data,
size_t width = 2); size_t width = 2);
// Get minimum tracking width of font // Get minimum tracking width of font
@ -36,7 +36,7 @@ struct char_range_t
uint16_t first_char; uint16_t first_char;
uint16_t char_count; uint16_t char_count;
std::vector<int> glyph_indices; std::vector<int> glyph_indices;
char_range_t(): first_char(0), char_count(0) {} char_range_t(): first_char(0), char_count(0) {}
}; };
@ -49,4 +49,4 @@ std::vector<char_range_t> compute_char_ranges(const DataFile &datafile,
size_t maximum_size, size_t maximum_size,
size_t minimum_gap); size_t minimum_gap);
} }

View File

@ -12,7 +12,7 @@
#undef __FTERRORS_H__ #undef __FTERRORS_H__
#define FT_ERRORDEF( e, v, s ) std::make_pair( e, s ), #define FT_ERRORDEF( e, v, s ) std::make_pair( e, s ),
#define FT_ERROR_START_LIST static const std::map<FT_Error, std::string> ft_errors { #define FT_ERROR_START_LIST static const std::map<FT_Error, std::string> ft_errors {
#define FT_ERROR_END_LIST }; #define FT_ERROR_END_LIST };
#include FT_ERRORS_H #include FT_ERRORS_H
namespace mcufont { namespace mcufont {
@ -76,24 +76,24 @@ std::unique_ptr<DataFile> LoadFreetype(std::istream &file, int size, bool bw)
{ {
std::vector<char> data; std::vector<char> data;
readfile(file, data); readfile(file, data);
_FT_Library lib; _FT_Library lib;
_FT_Face face(lib, data); _FT_Face face(lib, data);
checkFT(FT_Set_Pixel_Sizes(face, size, size)); checkFT(FT_Set_Pixel_Sizes(face, size, size));
DataFile::fontinfo_t fontinfo = {}; DataFile::fontinfo_t fontinfo = {};
std::vector<DataFile::glyphentry_t> glyphtable; std::vector<DataFile::glyphentry_t> glyphtable;
std::vector<DataFile::dictentry_t> dictionary; std::vector<DataFile::dictentry_t> dictionary;
// Convert size to pixels and round to nearest. // Convert size to pixels and round to nearest.
int u_per_em = face->units_per_EM; int u_per_em = face->units_per_EM;
auto topx = [size, u_per_em](int s) { return (s * size + u_per_em / 2) / u_per_em; }; auto topx = [size, u_per_em](int s) { return (s * size + u_per_em / 2) / u_per_em; };
fontinfo.name = std::string(face->family_name) + " " + fontinfo.name = std::string(face->family_name) + " " +
std::string(face->style_name) + " " + std::string(face->style_name) + " " +
std::to_string(size); std::to_string(size);
// Reserve 4 pixels on each side for antialiasing + hinting. // Reserve 4 pixels on each side for antialiasing + hinting.
// They will be cropped off later. // They will be cropped off later.
fontinfo.max_width = topx(face->bbox.xMax - face->bbox.xMin) + 8; fontinfo.max_width = topx(face->bbox.xMax - face->bbox.xMin) + 8;
@ -101,12 +101,12 @@ std::unique_ptr<DataFile> LoadFreetype(std::istream &file, int size, bool bw)
fontinfo.baseline_x = topx(-face->bbox.xMin) + 4; fontinfo.baseline_x = topx(-face->bbox.xMin) + 4;
fontinfo.baseline_y = topx(face->bbox.yMax) + 4; fontinfo.baseline_y = topx(face->bbox.yMax) + 4;
fontinfo.line_height = topx(face->height); fontinfo.line_height = topx(face->height);
FT_Int32 loadmode = FT_LOAD_TARGET_NORMAL | FT_LOAD_RENDER; FT_Int32 loadmode = FT_LOAD_TARGET_NORMAL | FT_LOAD_RENDER;
if (bw) if (bw)
loadmode = FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME | FT_LOAD_RENDER; loadmode = FT_LOAD_TARGET_MONO | FT_LOAD_MONOCHROME | FT_LOAD_RENDER;
FT_ULong charcode; FT_ULong charcode;
FT_UInt gindex; FT_UInt gindex;
charcode = FT_Get_First_Char(face, &gindex); charcode = FT_Get_First_Char(face, &gindex);
@ -118,20 +118,20 @@ std::unique_ptr<DataFile> LoadFreetype(std::istream &file, int size, bool bw)
} }
catch (std::runtime_error &e) catch (std::runtime_error &e)
{ {
std::cerr << "Skipping glyph " << gindex << ": " << e.what() << std::endl; std::cerr << "Skipping glyph " << gindex << ": " << e.what() << std::endl;
charcode = FT_Get_Next_Char(face, charcode, &gindex); charcode = FT_Get_Next_Char(face, charcode, &gindex);
} }
DataFile::glyphentry_t glyph; DataFile::glyphentry_t glyph;
glyph.width = (face->glyph->advance.x + 32) / 64; glyph.width = (face->glyph->advance.x + 32) / 64;
glyph.chars.push_back(charcode); glyph.chars.push_back(charcode);
glyph.data.resize(fontinfo.max_width * fontinfo.max_height); glyph.data.resize(fontinfo.max_width * fontinfo.max_height);
int w = face->glyph->bitmap.width; int w = face->glyph->bitmap.width;
int dw = fontinfo.max_width; int dw = fontinfo.max_width;
int dx = fontinfo.baseline_x + face->glyph->bitmap_left; int dx = fontinfo.baseline_x + face->glyph->bitmap_left;
int dy = fontinfo.baseline_y - face->glyph->bitmap_top; int dy = fontinfo.baseline_y - face->glyph->bitmap_top;
/* Some combining diacritics seem to exceed the bounding box. /* Some combining diacritics seem to exceed the bounding box.
* We don't support them all that well anyway, so just move * We don't support them all that well anyway, so just move
* them inside the box in order not to crash.. */ * them inside the box in order not to crash.. */
@ -139,14 +139,14 @@ std::unique_ptr<DataFile> LoadFreetype(std::istream &file, int size, bool bw)
dy = 0; dy = 0;
if (dy + face->glyph->bitmap.rows > fontinfo.max_height) if (dy + face->glyph->bitmap.rows > fontinfo.max_height)
dy = fontinfo.max_height - face->glyph->bitmap.rows; dy = fontinfo.max_height - face->glyph->bitmap.rows;
size_t s = face->glyph->bitmap.pitch; size_t s = face->glyph->bitmap.pitch;
for (int y = 0; y < face->glyph->bitmap.rows; y++) for (int y = 0; y < face->glyph->bitmap.rows; y++)
{ {
for (int x = 0; x < face->glyph->bitmap.width; x++) for (int x = 0; x < face->glyph->bitmap.width; x++)
{ {
size_t index = (y + dy) * dw + x + dx; size_t index = (y + dy) * dw + x + dx;
if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) if (face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO)
{ {
uint8_t byte = face->glyph->bitmap.buffer[s * y + x / 8]; uint8_t byte = face->glyph->bitmap.buffer[s * y + x / 8];
@ -161,24 +161,16 @@ std::unique_ptr<DataFile> LoadFreetype(std::istream &file, int size, bool bw)
} }
} }
glyphtable.push_back(glyph); glyphtable.push_back(glyph);
charcode = FT_Get_Next_Char(face, charcode, &gindex); charcode = FT_Get_Next_Char(face, charcode, &gindex);
if (gindex % 1000 == 0)
std::cout << ".";
} }
std::cout << "\nEliminating duplicates (this may take a while)...";
eliminate_duplicates(glyphtable); eliminate_duplicates(glyphtable);
std::cout << "\nCropping glyphs..."; crop_glyphs(glyphtable, fontinfo);
crop_glyphs(glyphtable, fontinfo); detect_flags(glyphtable, fontinfo);
std::cout << "\nDetecting flags...";
detect_flags(glyphtable, fontinfo); std::unique_ptr<DataFile> result(new DataFile(
std::cout << "\nGenerating datafile...";
std::unique_ptr<DataFile> result(new DataFile(
dictionary, glyphtable, fontinfo)); dictionary, glyphtable, fontinfo));
std::cout << "\n";
return result; return result;
} }

View File

@ -0,0 +1,771 @@
#ifndef __GB2312_IN_UCS2_H__
#define __GB2312_IN_UCS2_H__
const unsigned short gb2312_in_ucs2_codetable[] = { 0x0020,
0x0021,0x0022,0x0023,0x0024,0x0025,0x0026,0x0027,0x0028,0x0029,0x002a,
0x002b,0x002c,0x002d,0x002e,0x002f,0x0030,0x0031,0x0032,0x0033,0x0034,
0x0035,0x0036,0x0037,0x0038,0x0039,0x003a,0x003b,0x003c,0x003d,0x003e,
0x003f,0x0040,0x0041,0x0042,0x0043,0x0044,0x0045,0x0046,0x0047,0x0048,
0x0049,0x004a,0x004b,0x004c,0x004d,0x004e,0x004f,0x0050,0x0051,0x0052,
0x0053,0x0054,0x0055,0x0056,0x0057,0x0058,0x0059,0x005a,0x005b,0x005c,
0x005d,0x005e,0x005f,0x0060,0x0061,0x0062,0x0063,0x0064,0x0065,0x0066,
0x0067,0x0068,0x0069,0x006a,0x006b,0x006c,0x006d,0x006e,0x006f,0x0070,
0x0071,0x0072,0x0073,0x0074,0x0075,0x0076,0x0077,0x0078,0x0079,0x007a,
0x007b,0x007c,0x007d,0x007e,0x00a4,0x00a7,0x00a8,0x00b0,0x00b1,0x00b7,
0x00d7,0x00e0,0x00e1,0x00e8,0x00e9,0x00ea,0x00ec,0x00ed,0x00f2,0x00f3,
0x00f7,0x00f9,0x00fa,0x00fc,0x0101,0x0113,0x011b,0x012b,0x0144,0x0148,
0x014d,0x016b,0x01ce,0x01d0,0x01d2,0x01d4,0x01d6,0x01d8,0x01da,0x01dc,
0x0251,0x0261,0x02c7,0x02c9,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,
0x0397,0x0398,0x0399,0x039a,0x039b,0x039c,0x039d,0x039e,0x039f,0x03a0,
0x03a1,0x03a3,0x03a4,0x03a5,0x03a6,0x03a7,0x03a8,0x03a9,0x03b1,0x03b2,
0x03b3,0x03b4,0x03b5,0x03b6,0x03b7,0x03b8,0x03b9,0x03ba,0x03bb,0x03bc,
0x03bd,0x03be,0x03bf,0x03c0,0x03c1,0x03c3,0x03c4,0x03c5,0x03c6,0x03c7,
0x03c8,0x03c9,0x0401,0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0416,
0x0417,0x0418,0x0419,0x041a,0x041b,0x041c,0x041d,0x041e,0x041f,0x0420,
0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,0x0427,0x0428,0x0429,0x042a,
0x042b,0x042c,0x042d,0x042e,0x042f,0x0430,0x0431,0x0432,0x0433,0x0434,
0x0435,0x0436,0x0437,0x0438,0x0439,0x043a,0x043b,0x043c,0x043d,0x043e,
0x043f,0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,0x0446,0x0447,0x0448,
0x0449,0x044a,0x044b,0x044c,0x044d,0x044e,0x044f,0x0451,0x2014,0x2016,
0x2018,0x2019,0x201c,0x201d,0x2026,0x2030,0x2032,0x2033,0x203b,0x2103,
0x2116,0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,0x2168,
0x2169,0x216a,0x216b,0x2170,0x2171,0x2172,0x2173,0x2174,0x2175,0x2176,
0x2177,0x2178,0x2179,0x2190,0x2191,0x2192,0x2193,0x2208,0x220f,0x2211,
0x221a,0x221d,0x221e,0x2220,0x2225,0x2227,0x2228,0x2229,0x222a,0x222b,
0x222e,0x2234,0x2235,0x2236,0x2237,0x223d,0x2248,0x224c,0x2260,0x2261,
0x2264,0x2265,0x226e,0x226f,0x2299,0x22a5,0x2312,0x2460,0x2461,0x2462,
0x2463,0x2464,0x2465,0x2466,0x2467,0x2468,0x2469,0x2474,0x2475,0x2476,
0x2477,0x2478,0x2479,0x247a,0x247b,0x247c,0x247d,0x247e,0x247f,0x2480,
0x2481,0x2482,0x2483,0x2484,0x2485,0x2486,0x2487,0x2488,0x2489,0x248a,
0x248b,0x248c,0x248d,0x248e,0x248f,0x2490,0x2491,0x2492,0x2493,0x2494,
0x2495,0x2496,0x2497,0x2498,0x2499,0x249a,0x249b,0x2500,0x2501,0x2502,
0x2503,0x2504,0x2505,0x2506,0x2507,0x2508,0x2509,0x250a,0x250b,0x250c,
0x250d,0x250e,0x250f,0x2510,0x2511,0x2512,0x2513,0x2514,0x2515,0x2516,
0x2517,0x2518,0x2519,0x251a,0x251b,0x251c,0x251d,0x251e,0x251f,0x2520,
0x2521,0x2522,0x2523,0x2524,0x2525,0x2526,0x2527,0x2528,0x2529,0x252a,
0x252b,0x252c,0x252d,0x252e,0x252f,0x2530,0x2531,0x2532,0x2533,0x2534,
0x2535,0x2536,0x2537,0x2538,0x2539,0x253a,0x253b,0x253c,0x253d,0x253e,
0x253f,0x2540,0x2541,0x2542,0x2543,0x2544,0x2545,0x2546,0x2547,0x2548,
0x2549,0x254a,0x254b,0x25a0,0x25a1,0x25b2,0x25b3,0x25c6,0x25c7,0x25cb,
0x25ce,0x25cf,0x2605,0x2606,0x2640,0x2642,0x3001,0x3002,0x3003,0x3005,
0x3008,0x3009,0x300a,0x300b,0x300c,0x300d,0x300e,0x300f,0x3010,0x3011,
0x3013,0x3014,0x3015,0x3016,0x3017,0x3041,0x3042,0x3043,0x3044,0x3045,
0x3046,0x3047,0x3048,0x3049,0x304a,0x304b,0x304c,0x304d,0x304e,0x304f,
0x3050,0x3051,0x3052,0x3053,0x3054,0x3055,0x3056,0x3057,0x3058,0x3059,
0x305a,0x305b,0x305c,0x305d,0x305e,0x305f,0x3060,0x3061,0x3062,0x3063,
0x3064,0x3065,0x3066,0x3067,0x3068,0x3069,0x306a,0x306b,0x306c,0x306d,
0x306e,0x306f,0x3070,0x3071,0x3072,0x3073,0x3074,0x3075,0x3076,0x3077,
0x3078,0x3079,0x307a,0x307b,0x307c,0x307d,0x307e,0x307f,0x3080,0x3081,
0x3082,0x3083,0x3084,0x3085,0x3086,0x3087,0x3088,0x3089,0x308a,0x308b,
0x308c,0x308d,0x308e,0x308f,0x3090,0x3091,0x3092,0x3093,0x30a1,0x30a2,
0x30a3,0x30a4,0x30a5,0x30a6,0x30a7,0x30a8,0x30a9,0x30aa,0x30ab,0x30ac,
0x30ad,0x30ae,0x30af,0x30b0,0x30b1,0x30b2,0x30b3,0x30b4,0x30b5,0x30b6,
0x30b7,0x30b8,0x30b9,0x30ba,0x30bb,0x30bc,0x30bd,0x30be,0x30bf,0x30c0,
0x30c1,0x30c2,0x30c3,0x30c4,0x30c5,0x30c6,0x30c7,0x30c8,0x30c9,0x30ca,
0x30cb,0x30cc,0x30cd,0x30ce,0x30cf,0x30d0,0x30d1,0x30d2,0x30d3,0x30d4,
0x30d5,0x30d6,0x30d7,0x30d8,0x30d9,0x30da,0x30db,0x30dc,0x30dd,0x30de,
0x30df,0x30e0,0x30e1,0x30e2,0x30e3,0x30e4,0x30e5,0x30e6,0x30e7,0x30e8,
0x30e9,0x30ea,0x30eb,0x30ec,0x30ed,0x30ee,0x30ef,0x30f0,0x30f1,0x30f2,
0x30f3,0x30f4,0x30f5,0x30f6,0x3105,0x3106,0x3107,0x3108,0x3109,0x310a,
0x310b,0x310c,0x310d,0x310e,0x310f,0x3110,0x3111,0x3112,0x3113,0x3114,
0x3115,0x3116,0x3117,0x3118,0x3119,0x311a,0x311b,0x311c,0x311d,0x311e,
0x311f,0x3120,0x3121,0x3122,0x3123,0x3124,0x3125,0x3126,0x3127,0x3128,
0x3129,0x3220,0x3221,0x3222,0x3223,0x3224,0x3225,0x3226,0x3227,0x3228,
0x3229,0x4e00,0x4e01,0x4e03,0x4e07,0x4e08,0x4e09,0x4e0a,0x4e0b,0x4e0c,
0x4e0d,0x4e0e,0x4e10,0x4e11,0x4e13,0x4e14,0x4e15,0x4e16,0x4e18,0x4e19,
0x4e1a,0x4e1b,0x4e1c,0x4e1d,0x4e1e,0x4e22,0x4e24,0x4e25,0x4e27,0x4e28,
0x4e2a,0x4e2b,0x4e2c,0x4e2d,0x4e30,0x4e32,0x4e34,0x4e36,0x4e38,0x4e39,
0x4e3a,0x4e3b,0x4e3d,0x4e3e,0x4e3f,0x4e43,0x4e45,0x4e47,0x4e48,0x4e49,
0x4e4b,0x4e4c,0x4e4d,0x4e4e,0x4e4f,0x4e50,0x4e52,0x4e53,0x4e54,0x4e56,
0x4e58,0x4e59,0x4e5c,0x4e5d,0x4e5e,0x4e5f,0x4e60,0x4e61,0x4e66,0x4e69,
0x4e70,0x4e71,0x4e73,0x4e7e,0x4e86,0x4e88,0x4e89,0x4e8b,0x4e8c,0x4e8d,
0x4e8e,0x4e8f,0x4e91,0x4e92,0x4e93,0x4e94,0x4e95,0x4e98,0x4e9a,0x4e9b,
0x4e9f,0x4ea0,0x4ea1,0x4ea2,0x4ea4,0x4ea5,0x4ea6,0x4ea7,0x4ea8,0x4ea9,
0x4eab,0x4eac,0x4ead,0x4eae,0x4eb2,0x4eb3,0x4eb5,0x4eba,0x4ebb,0x4ebf,
0x4ec0,0x4ec1,0x4ec2,0x4ec3,0x4ec4,0x4ec5,0x4ec6,0x4ec7,0x4ec9,0x4eca,
0x4ecb,0x4ecd,0x4ece,0x4ed1,0x4ed3,0x4ed4,0x4ed5,0x4ed6,0x4ed7,0x4ed8,
0x4ed9,0x4edd,0x4ede,0x4edf,0x4ee1,0x4ee3,0x4ee4,0x4ee5,0x4ee8,0x4eea,
0x4eeb,0x4eec,0x4ef0,0x4ef2,0x4ef3,0x4ef5,0x4ef6,0x4ef7,0x4efb,0x4efd,
0x4eff,0x4f01,0x4f09,0x4f0a,0x4f0d,0x4f0e,0x4f0f,0x4f10,0x4f11,0x4f17,
0x4f18,0x4f19,0x4f1a,0x4f1b,0x4f1e,0x4f1f,0x4f20,0x4f22,0x4f24,0x4f25,
0x4f26,0x4f27,0x4f2a,0x4f2b,0x4f2f,0x4f30,0x4f32,0x4f34,0x4f36,0x4f38,
0x4f3a,0x4f3c,0x4f3d,0x4f43,0x4f46,0x4f4d,0x4f4e,0x4f4f,0x4f50,0x4f51,
0x4f53,0x4f55,0x4f57,0x4f58,0x4f59,0x4f5a,0x4f5b,0x4f5c,0x4f5d,0x4f5e,
0x4f5f,0x4f60,0x4f63,0x4f64,0x4f65,0x4f67,0x4f69,0x4f6c,0x4f6f,0x4f70,
0x4f73,0x4f74,0x4f76,0x4f7b,0x4f7c,0x4f7e,0x4f7f,0x4f83,0x4f84,0x4f88,
0x4f89,0x4f8b,0x4f8d,0x4f8f,0x4f91,0x4f94,0x4f97,0x4f9b,0x4f9d,0x4fa0,
0x4fa3,0x4fa5,0x4fa6,0x4fa7,0x4fa8,0x4fa9,0x4faa,0x4fac,0x4fae,0x4faf,
0x4fb5,0x4fbf,0x4fc3,0x4fc4,0x4fc5,0x4fca,0x4fce,0x4fcf,0x4fd0,0x4fd1,
0x4fd7,0x4fd8,0x4fda,0x4fdc,0x4fdd,0x4fde,0x4fdf,0x4fe1,0x4fe3,0x4fe6,
0x4fe8,0x4fe9,0x4fea,0x4fed,0x4fee,0x4fef,0x4ff1,0x4ff3,0x4ff8,0x4ffa,
0x4ffe,0x500c,0x500d,0x500f,0x5012,0x5014,0x5018,0x5019,0x501a,0x501c,
0x501f,0x5021,0x5025,0x5026,0x5028,0x5029,0x502a,0x502c,0x502d,0x502e,
0x503a,0x503c,0x503e,0x5043,0x5047,0x5048,0x504c,0x504e,0x504f,0x5055,
0x505a,0x505c,0x5065,0x506c,0x5076,0x5077,0x507b,0x507e,0x507f,0x5080,
0x5085,0x5088,0x508d,0x50a3,0x50a5,0x50a7,0x50a8,0x50a9,0x50ac,0x50b2,
0x50ba,0x50bb,0x50cf,0x50d6,0x50da,0x50e6,0x50e7,0x50ec,0x50ed,0x50ee,
0x50f3,0x50f5,0x50fb,0x5106,0x5107,0x510b,0x5112,0x5121,0x513f,0x5140,
0x5141,0x5143,0x5144,0x5145,0x5146,0x5148,0x5149,0x514b,0x514d,0x5151,
0x5154,0x5155,0x5156,0x515a,0x515c,0x5162,0x5165,0x5168,0x516b,0x516c,
0x516d,0x516e,0x5170,0x5171,0x5173,0x5174,0x5175,0x5176,0x5177,0x5178,
0x5179,0x517b,0x517c,0x517d,0x5180,0x5181,0x5182,0x5185,0x5188,0x5189,
0x518c,0x518d,0x5192,0x5195,0x5196,0x5197,0x5199,0x519b,0x519c,0x51a0,
0x51a2,0x51a4,0x51a5,0x51ab,0x51ac,0x51af,0x51b0,0x51b1,0x51b2,0x51b3,
0x51b5,0x51b6,0x51b7,0x51bb,0x51bc,0x51bd,0x51c0,0x51c4,0x51c6,0x51c7,
0x51c9,0x51cb,0x51cc,0x51cf,0x51d1,0x51db,0x51dd,0x51e0,0x51e1,0x51e4,
0x51eb,0x51ed,0x51ef,0x51f0,0x51f3,0x51f5,0x51f6,0x51f8,0x51f9,0x51fa,
0x51fb,0x51fc,0x51fd,0x51ff,0x5200,0x5201,0x5202,0x5203,0x5206,0x5207,
0x5208,0x520a,0x520d,0x520e,0x5211,0x5212,0x5216,0x5217,0x5218,0x5219,
0x521a,0x521b,0x521d,0x5220,0x5224,0x5228,0x5229,0x522b,0x522d,0x522e,
0x5230,0x5233,0x5236,0x5237,0x5238,0x5239,0x523a,0x523b,0x523d,0x523f,
0x5240,0x5241,0x5242,0x5243,0x524a,0x524c,0x524d,0x5250,0x5251,0x5254,
0x5256,0x525c,0x525e,0x5261,0x5265,0x5267,0x5269,0x526a,0x526f,0x5272,
0x527d,0x527f,0x5281,0x5282,0x5288,0x5290,0x5293,0x529b,0x529d,0x529e,
0x529f,0x52a0,0x52a1,0x52a2,0x52a3,0x52a8,0x52a9,0x52aa,0x52ab,0x52ac,
0x52ad,0x52b1,0x52b2,0x52b3,0x52be,0x52bf,0x52c3,0x52c7,0x52c9,0x52cb,
0x52d0,0x52d2,0x52d6,0x52d8,0x52df,0x52e4,0x52f0,0x52f9,0x52fa,0x52fe,
0x52ff,0x5300,0x5305,0x5306,0x5308,0x530d,0x530f,0x5310,0x5315,0x5316,
0x5317,0x5319,0x531a,0x531d,0x5320,0x5321,0x5323,0x5326,0x532a,0x532e,
0x5339,0x533a,0x533b,0x533e,0x533f,0x5341,0x5343,0x5345,0x5347,0x5348,
0x5349,0x534a,0x534e,0x534f,0x5351,0x5352,0x5353,0x5355,0x5356,0x5357,
0x535a,0x535c,0x535e,0x535f,0x5360,0x5361,0x5362,0x5363,0x5364,0x5366,
0x5367,0x5369,0x536b,0x536e,0x536f,0x5370,0x5371,0x5373,0x5374,0x5375,
0x5377,0x5378,0x537a,0x537f,0x5382,0x5384,0x5385,0x5386,0x5389,0x538b,
0x538c,0x538d,0x5395,0x5398,0x539a,0x539d,0x539f,0x53a2,0x53a3,0x53a5,
0x53a6,0x53a8,0x53a9,0x53ae,0x53b6,0x53bb,0x53bf,0x53c1,0x53c2,0x53c8,
0x53c9,0x53ca,0x53cb,0x53cc,0x53cd,0x53d1,0x53d4,0x53d6,0x53d7,0x53d8,
0x53d9,0x53db,0x53df,0x53e0,0x53e3,0x53e4,0x53e5,0x53e6,0x53e8,0x53e9,
0x53ea,0x53eb,0x53ec,0x53ed,0x53ee,0x53ef,0x53f0,0x53f1,0x53f2,0x53f3,
0x53f5,0x53f6,0x53f7,0x53f8,0x53f9,0x53fb,0x53fc,0x53fd,0x5401,0x5403,
0x5404,0x5406,0x5408,0x5409,0x540a,0x540c,0x540d,0x540e,0x540f,0x5410,
0x5411,0x5412,0x5413,0x5415,0x5416,0x5417,0x541b,0x541d,0x541e,0x541f,
0x5420,0x5421,0x5423,0x5426,0x5427,0x5428,0x5429,0x542b,0x542c,0x542d,
0x542e,0x542f,0x5431,0x5432,0x5434,0x5435,0x5438,0x5439,0x543b,0x543c,
0x543e,0x5440,0x5443,0x5446,0x5448,0x544a,0x544b,0x5450,0x5452,0x5453,
0x5454,0x5455,0x5456,0x5457,0x5458,0x5459,0x545b,0x545c,0x5462,0x5464,
0x5466,0x5468,0x5471,0x5472,0x5473,0x5475,0x5476,0x5477,0x5478,0x547b,
0x547c,0x547d,0x5480,0x5482,0x5484,0x5486,0x548b,0x548c,0x548e,0x548f,
0x5490,0x5492,0x5494,0x5495,0x5496,0x5499,0x549a,0x549b,0x549d,0x54a3,
0x54a4,0x54a6,0x54a7,0x54a8,0x54a9,0x54aa,0x54ab,0x54ac,0x54ad,0x54af,
0x54b1,0x54b3,0x54b4,0x54b8,0x54bb,0x54bd,0x54bf,0x54c0,0x54c1,0x54c2,
0x54c4,0x54c6,0x54c7,0x54c8,0x54c9,0x54cc,0x54cd,0x54ce,0x54cf,0x54d0,
0x54d1,0x54d2,0x54d3,0x54d4,0x54d5,0x54d7,0x54d9,0x54da,0x54dc,0x54dd,
0x54de,0x54df,0x54e5,0x54e6,0x54e7,0x54e8,0x54e9,0x54ea,0x54ed,0x54ee,
0x54f2,0x54f3,0x54fa,0x54fc,0x54fd,0x54ff,0x5501,0x5506,0x5507,0x5509,
0x550f,0x5510,0x5511,0x5514,0x551b,0x5520,0x5522,0x5523,0x5524,0x5527,
0x552a,0x552c,0x552e,0x552f,0x5530,0x5531,0x5533,0x5537,0x553c,0x553e,
0x553f,0x5541,0x5543,0x5544,0x5546,0x5549,0x554a,0x5550,0x5555,0x5556,
0x555c,0x5561,0x5564,0x5565,0x5566,0x5567,0x556a,0x556c,0x556d,0x556e,
0x5575,0x5576,0x5577,0x5578,0x557b,0x557c,0x557e,0x5580,0x5581,0x5582,
0x5583,0x5584,0x5587,0x5588,0x5589,0x558a,0x558b,0x558f,0x5591,0x5594,
0x5598,0x5599,0x559c,0x559d,0x559f,0x55a7,0x55b1,0x55b3,0x55b5,0x55b7,
0x55b9,0x55bb,0x55bd,0x55be,0x55c4,0x55c5,0x55c9,0x55cc,0x55cd,0x55d1,
0x55d2,0x55d3,0x55d4,0x55d6,0x55dc,0x55dd,0x55df,0x55e1,0x55e3,0x55e4,
0x55e5,0x55e6,0x55e8,0x55ea,0x55eb,0x55ec,0x55ef,0x55f2,0x55f3,0x55f5,
0x55f7,0x55fd,0x55fe,0x5600,0x5601,0x5608,0x5609,0x560c,0x560e,0x560f,
0x5618,0x561b,0x561e,0x561f,0x5623,0x5624,0x5627,0x562c,0x562d,0x5631,
0x5632,0x5634,0x5636,0x5639,0x563b,0x563f,0x564c,0x564d,0x564e,0x5654,
0x5657,0x5658,0x5659,0x565c,0x5662,0x5664,0x5668,0x5669,0x566a,0x566b,
0x566c,0x5671,0x5676,0x567b,0x567c,0x5685,0x5686,0x568e,0x568f,0x5693,
0x56a3,0x56af,0x56b7,0x56bc,0x56ca,0x56d4,0x56d7,0x56da,0x56db,0x56dd,
0x56de,0x56df,0x56e0,0x56e1,0x56e2,0x56e4,0x56eb,0x56ed,0x56f0,0x56f1,
0x56f4,0x56f5,0x56f9,0x56fa,0x56fd,0x56fe,0x56ff,0x5703,0x5704,0x5706,
0x5708,0x5709,0x570a,0x571c,0x571f,0x5723,0x5728,0x5729,0x572a,0x572c,
0x572d,0x572e,0x572f,0x5730,0x5733,0x5739,0x573a,0x573b,0x573e,0x5740,
0x5742,0x5747,0x574a,0x574c,0x574d,0x574e,0x574f,0x5750,0x5751,0x5757,
0x575a,0x575b,0x575c,0x575d,0x575e,0x575f,0x5760,0x5761,0x5764,0x5766,
0x5768,0x5769,0x576a,0x576b,0x576d,0x576f,0x5773,0x5776,0x5777,0x577b,
0x577c,0x5782,0x5783,0x5784,0x5785,0x5786,0x578b,0x578c,0x5792,0x5793,
0x579b,0x57a0,0x57a1,0x57a2,0x57a3,0x57a4,0x57a6,0x57a7,0x57a9,0x57ab,
0x57ad,0x57ae,0x57b2,0x57b4,0x57b8,0x57c2,0x57c3,0x57cb,0x57ce,0x57cf,
0x57d2,0x57d4,0x57d5,0x57d8,0x57d9,0x57da,0x57dd,0x57df,0x57e0,0x57e4,
0x57ed,0x57ef,0x57f4,0x57f8,0x57f9,0x57fa,0x57fd,0x5800,0x5802,0x5806,
0x5807,0x580b,0x580d,0x5811,0x5815,0x5819,0x581e,0x5820,0x5821,0x5824,
0x582a,0x5830,0x5835,0x5844,0x584c,0x584d,0x5851,0x5854,0x5858,0x585e,
0x5865,0x586b,0x586c,0x587e,0x5880,0x5881,0x5883,0x5885,0x5889,0x5892,
0x5893,0x5899,0x589a,0x589e,0x589f,0x58a8,0x58a9,0x58bc,0x58c1,0x58c5,
0x58d1,0x58d5,0x58e4,0x58eb,0x58ec,0x58ee,0x58f0,0x58f3,0x58f6,0x58f9,
0x5902,0x5904,0x5907,0x590d,0x590f,0x5914,0x5915,0x5916,0x5919,0x591a,
0x591c,0x591f,0x5924,0x5925,0x5927,0x5929,0x592a,0x592b,0x592d,0x592e,
0x592f,0x5931,0x5934,0x5937,0x5938,0x5939,0x593a,0x593c,0x5941,0x5942,
0x5944,0x5947,0x5948,0x5949,0x594b,0x594e,0x594f,0x5951,0x5954,0x5955,
0x5956,0x5957,0x5958,0x595a,0x5960,0x5962,0x5965,0x5973,0x5974,0x5976,
0x5978,0x5979,0x597d,0x5981,0x5982,0x5983,0x5984,0x5986,0x5987,0x5988,
0x598a,0x598d,0x5992,0x5993,0x5996,0x5997,0x5999,0x599e,0x59a3,0x59a4,
0x59a5,0x59a8,0x59a9,0x59aa,0x59ab,0x59ae,0x59af,0x59b2,0x59b9,0x59bb,
0x59be,0x59c6,0x59ca,0x59cb,0x59d0,0x59d1,0x59d2,0x59d3,0x59d4,0x59d7,
0x59d8,0x59da,0x59dc,0x59dd,0x59e3,0x59e5,0x59e8,0x59ec,0x59f9,0x59fb,
0x59ff,0x5a01,0x5a03,0x5a04,0x5a05,0x5a06,0x5a07,0x5a08,0x5a09,0x5a0c,
0x5a11,0x5a13,0x5a18,0x5a1c,0x5a1f,0x5a20,0x5a23,0x5a25,0x5a29,0x5a31,
0x5a32,0x5a34,0x5a36,0x5a3c,0x5a40,0x5a46,0x5a49,0x5a4a,0x5a55,0x5a5a,
0x5a62,0x5a67,0x5a6a,0x5a74,0x5a75,0x5a76,0x5a77,0x5a7a,0x5a7f,0x5a92,
0x5a9a,0x5a9b,0x5aaa,0x5ab2,0x5ab3,0x5ab5,0x5ab8,0x5abe,0x5ac1,0x5ac2,
0x5ac9,0x5acc,0x5ad2,0x5ad4,0x5ad6,0x5ad8,0x5adc,0x5ae0,0x5ae1,0x5ae3,
0x5ae6,0x5ae9,0x5aeb,0x5af1,0x5b09,0x5b16,0x5b17,0x5b32,0x5b34,0x5b37,
0x5b40,0x5b50,0x5b51,0x5b53,0x5b54,0x5b55,0x5b57,0x5b58,0x5b59,0x5b5a,
0x5b5b,0x5b5c,0x5b5d,0x5b5f,0x5b62,0x5b63,0x5b64,0x5b65,0x5b66,0x5b69,
0x5b6a,0x5b6c,0x5b70,0x5b71,0x5b73,0x5b75,0x5b7a,0x5b7d,0x5b80,0x5b81,
0x5b83,0x5b84,0x5b85,0x5b87,0x5b88,0x5b89,0x5b8b,0x5b8c,0x5b8f,0x5b93,
0x5b95,0x5b97,0x5b98,0x5b99,0x5b9a,0x5b9b,0x5b9c,0x5b9d,0x5b9e,0x5ba0,
0x5ba1,0x5ba2,0x5ba3,0x5ba4,0x5ba5,0x5ba6,0x5baa,0x5bab,0x5bb0,0x5bb3,
0x5bb4,0x5bb5,0x5bb6,0x5bb8,0x5bb9,0x5bbd,0x5bbe,0x5bbf,0x5bc2,0x5bc4,
0x5bc5,0x5bc6,0x5bc7,0x5bcc,0x5bd0,0x5bd2,0x5bd3,0x5bdd,0x5bde,0x5bdf,
0x5be1,0x5be4,0x5be5,0x5be8,0x5bee,0x5bf0,0x5bf8,0x5bf9,0x5bfa,0x5bfb,
0x5bfc,0x5bff,0x5c01,0x5c04,0x5c06,0x5c09,0x5c0a,0x5c0f,0x5c11,0x5c14,
0x5c15,0x5c16,0x5c18,0x5c1a,0x5c1c,0x5c1d,0x5c22,0x5c24,0x5c25,0x5c27,
0x5c2c,0x5c31,0x5c34,0x5c38,0x5c39,0x5c3a,0x5c3b,0x5c3c,0x5c3d,0x5c3e,
0x5c3f,0x5c40,0x5c41,0x5c42,0x5c45,0x5c48,0x5c49,0x5c4a,0x5c4b,0x5c4e,
0x5c4f,0x5c50,0x5c51,0x5c55,0x5c59,0x5c5e,0x5c60,0x5c61,0x5c63,0x5c65,
0x5c66,0x5c6e,0x5c6f,0x5c71,0x5c79,0x5c7a,0x5c7f,0x5c81,0x5c82,0x5c88,
0x5c8c,0x5c8d,0x5c90,0x5c91,0x5c94,0x5c96,0x5c97,0x5c98,0x5c99,0x5c9a,
0x5c9b,0x5c9c,0x5ca2,0x5ca3,0x5ca9,0x5cab,0x5cac,0x5cad,0x5cb1,0x5cb3,
0x5cb5,0x5cb7,0x5cb8,0x5cbd,0x5cbf,0x5cc1,0x5cc4,0x5ccb,0x5cd2,0x5cd9,
0x5ce1,0x5ce4,0x5ce5,0x5ce6,0x5ce8,0x5cea,0x5ced,0x5cf0,0x5cfb,0x5d02,
0x5d03,0x5d06,0x5d07,0x5d0e,0x5d14,0x5d16,0x5d1b,0x5d1e,0x5d24,0x5d26,
0x5d27,0x5d29,0x5d2d,0x5d2e,0x5d34,0x5d3d,0x5d3e,0x5d47,0x5d4a,0x5d4b,
0x5d4c,0x5d58,0x5d5b,0x5d5d,0x5d69,0x5d6b,0x5d6c,0x5d6f,0x5d74,0x5d82,
0x5d99,0x5d9d,0x5db7,0x5dc5,0x5dcd,0x5ddb,0x5ddd,0x5dde,0x5de1,0x5de2,
0x5de5,0x5de6,0x5de7,0x5de8,0x5de9,0x5deb,0x5dee,0x5def,0x5df1,0x5df2,
0x5df3,0x5df4,0x5df7,0x5dfd,0x5dfe,0x5e01,0x5e02,0x5e03,0x5e05,0x5e06,
0x5e08,0x5e0c,0x5e0f,0x5e10,0x5e11,0x5e14,0x5e15,0x5e16,0x5e18,0x5e19,
0x5e1a,0x5e1b,0x5e1c,0x5e1d,0x5e26,0x5e27,0x5e2d,0x5e2e,0x5e31,0x5e37,
0x5e38,0x5e3b,0x5e3c,0x5e3d,0x5e42,0x5e44,0x5e45,0x5e4c,0x5e54,0x5e55,
0x5e5b,0x5e5e,0x5e61,0x5e62,0x5e72,0x5e73,0x5e74,0x5e76,0x5e78,0x5e7a,
0x5e7b,0x5e7c,0x5e7d,0x5e7f,0x5e80,0x5e84,0x5e86,0x5e87,0x5e8a,0x5e8b,
0x5e8f,0x5e90,0x5e91,0x5e93,0x5e94,0x5e95,0x5e96,0x5e97,0x5e99,0x5e9a,
0x5e9c,0x5e9e,0x5e9f,0x5ea0,0x5ea5,0x5ea6,0x5ea7,0x5ead,0x5eb3,0x5eb5,
0x5eb6,0x5eb7,0x5eb8,0x5eb9,0x5ebe,0x5ec9,0x5eca,0x5ed1,0x5ed2,0x5ed3,
0x5ed6,0x5edb,0x5ee8,0x5eea,0x5ef4,0x5ef6,0x5ef7,0x5efa,0x5efe,0x5eff,
0x5f00,0x5f01,0x5f02,0x5f03,0x5f04,0x5f08,0x5f0a,0x5f0b,0x5f0f,0x5f11,
0x5f13,0x5f15,0x5f17,0x5f18,0x5f1b,0x5f1f,0x5f20,0x5f25,0x5f26,0x5f27,
0x5f29,0x5f2a,0x5f2d,0x5f2f,0x5f31,0x5f39,0x5f3a,0x5f3c,0x5f40,0x5f50,
0x5f52,0x5f53,0x5f55,0x5f56,0x5f57,0x5f58,0x5f5d,0x5f61,0x5f62,0x5f64,
0x5f66,0x5f69,0x5f6a,0x5f6c,0x5f6d,0x5f70,0x5f71,0x5f73,0x5f77,0x5f79,
0x5f7b,0x5f7c,0x5f80,0x5f81,0x5f82,0x5f84,0x5f85,0x5f87,0x5f88,0x5f89,
0x5f8a,0x5f8b,0x5f8c,0x5f90,0x5f92,0x5f95,0x5f97,0x5f98,0x5f99,0x5f9c,
0x5fa1,0x5fa8,0x5faa,0x5fad,0x5fae,0x5fb5,0x5fb7,0x5fbc,0x5fbd,0x5fc3,
0x5fc4,0x5fc5,0x5fc6,0x5fc9,0x5fcc,0x5fcd,0x5fcf,0x5fd0,0x5fd1,0x5fd2,
0x5fd6,0x5fd7,0x5fd8,0x5fd9,0x5fdd,0x5fe0,0x5fe1,0x5fe4,0x5fe7,0x5fea,
0x5feb,0x5fed,0x5fee,0x5ff1,0x5ff5,0x5ff8,0x5ffb,0x5ffd,0x5ffe,0x5fff,
0x6000,0x6001,0x6002,0x6003,0x6004,0x6005,0x6006,0x600a,0x600d,0x600e,
0x600f,0x6012,0x6014,0x6015,0x6016,0x6019,0x601b,0x601c,0x601d,0x6020,
0x6021,0x6025,0x6026,0x6027,0x6028,0x6029,0x602a,0x602b,0x602f,0x6035,
0x603b,0x603c,0x603f,0x6041,0x6042,0x6043,0x604b,0x604d,0x6050,0x6052,
0x6055,0x6059,0x605a,0x605d,0x6062,0x6063,0x6064,0x6067,0x6068,0x6069,
0x606a,0x606b,0x606c,0x606d,0x606f,0x6070,0x6073,0x6076,0x6078,0x6079,
0x607a,0x607b,0x607c,0x607d,0x607f,0x6083,0x6084,0x6089,0x608c,0x608d,
0x6092,0x6094,0x6096,0x609a,0x609b,0x609d,0x609f,0x60a0,0x60a3,0x60a6,
0x60a8,0x60ab,0x60ac,0x60ad,0x60af,0x60b1,0x60b2,0x60b4,0x60b8,0x60bb,
0x60bc,0x60c5,0x60c6,0x60ca,0x60cb,0x60d1,0x60d5,0x60d8,0x60da,0x60dc,
0x60dd,0x60df,0x60e0,0x60e6,0x60e7,0x60e8,0x60e9,0x60eb,0x60ec,0x60ed,
0x60ee,0x60ef,0x60f0,0x60f3,0x60f4,0x60f6,0x60f9,0x60fa,0x6100,0x6101,
0x6106,0x6108,0x6109,0x610d,0x610e,0x610f,0x6115,0x611a,0x611f,0x6120,
0x6123,0x6124,0x6126,0x6127,0x612b,0x613f,0x6148,0x614a,0x614c,0x614e,
0x6151,0x6155,0x615d,0x6162,0x6167,0x6168,0x6170,0x6175,0x6177,0x618b,
0x618e,0x6194,0x619d,0x61a7,0x61a8,0x61a9,0x61ac,0x61b7,0x61be,0x61c2,
0x61c8,0x61ca,0x61cb,0x61d1,0x61d2,0x61d4,0x61e6,0x61f5,0x61ff,0x6206,
0x6208,0x620a,0x620b,0x620c,0x620d,0x620e,0x620f,0x6210,0x6211,0x6212,
0x6215,0x6216,0x6217,0x6218,0x621a,0x621b,0x621f,0x6221,0x6222,0x6224,
0x6225,0x622a,0x622c,0x622e,0x6233,0x6234,0x6237,0x623d,0x623e,0x623f,
0x6240,0x6241,0x6243,0x6247,0x6248,0x6249,0x624b,0x624c,0x624d,0x624e,
0x6251,0x6252,0x6253,0x6254,0x6258,0x625b,0x6263,0x6266,0x6267,0x6269,
0x626a,0x626b,0x626c,0x626d,0x626e,0x626f,0x6270,0x6273,0x6276,0x6279,
0x627c,0x627e,0x627f,0x6280,0x6284,0x6289,0x628a,0x6291,0x6292,0x6293,
0x6295,0x6296,0x6297,0x6298,0x629a,0x629b,0x629f,0x62a0,0x62a1,0x62a2,
0x62a4,0x62a5,0x62a8,0x62ab,0x62ac,0x62b1,0x62b5,0x62b9,0x62bb,0x62bc,
0x62bd,0x62bf,0x62c2,0x62c4,0x62c5,0x62c6,0x62c7,0x62c8,0x62c9,0x62ca,
0x62cc,0x62cd,0x62ce,0x62d0,0x62d2,0x62d3,0x62d4,0x62d6,0x62d7,0x62d8,
0x62d9,0x62da,0x62db,0x62dc,0x62df,0x62e2,0x62e3,0x62e5,0x62e6,0x62e7,
0x62e8,0x62e9,0x62ec,0x62ed,0x62ee,0x62ef,0x62f1,0x62f3,0x62f4,0x62f6,
0x62f7,0x62fc,0x62fd,0x62fe,0x62ff,0x6301,0x6302,0x6307,0x6308,0x6309,
0x630e,0x6311,0x6316,0x631a,0x631b,0x631d,0x631e,0x631f,0x6320,0x6321,
0x6322,0x6323,0x6324,0x6325,0x6328,0x632a,0x632b,0x632f,0x6332,0x6339,
0x633a,0x633d,0x6342,0x6343,0x6345,0x6346,0x6349,0x634b,0x634c,0x634d,
0x634e,0x634f,0x6350,0x6355,0x635e,0x635f,0x6361,0x6362,0x6363,0x6367,
0x6369,0x636d,0x636e,0x6371,0x6376,0x6377,0x637a,0x637b,0x6380,0x6382,
0x6387,0x6388,0x6389,0x638a,0x638c,0x638e,0x638f,0x6390,0x6392,0x6396,
0x6398,0x63a0,0x63a2,0x63a3,0x63a5,0x63a7,0x63a8,0x63a9,0x63aa,0x63ac,
0x63ad,0x63ae,0x63b0,0x63b3,0x63b4,0x63b7,0x63b8,0x63ba,0x63bc,0x63be,
0x63c4,0x63c6,0x63c9,0x63cd,0x63ce,0x63cf,0x63d0,0x63d2,0x63d6,0x63de,
0x63e0,0x63e1,0x63e3,0x63e9,0x63ea,0x63ed,0x63f2,0x63f4,0x63f6,0x63f8,
0x63fd,0x63ff,0x6400,0x6401,0x6402,0x6405,0x640b,0x640c,0x640f,0x6410,
0x6413,0x6414,0x641b,0x641c,0x641e,0x6420,0x6421,0x6426,0x642a,0x642c,
0x642d,0x6434,0x643a,0x643d,0x643f,0x6441,0x6444,0x6445,0x6446,0x6447,
0x6448,0x644a,0x6452,0x6454,0x6458,0x645e,0x6467,0x6469,0x646d,0x6478,
0x6479,0x647a,0x6482,0x6484,0x6485,0x6487,0x6491,0x6492,0x6495,0x6496,
0x6499,0x649e,0x64a4,0x64a9,0x64ac,0x64ad,0x64ae,0x64b0,0x64b5,0x64b7,
0x64b8,0x64ba,0x64bc,0x64c0,0x64c2,0x64c5,0x64cd,0x64ce,0x64d0,0x64d2,
0x64d7,0x64d8,0x64de,0x64e2,0x64e4,0x64e6,0x6500,0x6509,0x6512,0x6518,
0x6525,0x652b,0x652e,0x652f,0x6534,0x6535,0x6536,0x6538,0x6539,0x653b,
0x653e,0x653f,0x6545,0x6548,0x6549,0x654c,0x654f,0x6551,0x6555,0x6556,
0x6559,0x655b,0x655d,0x655e,0x6562,0x6563,0x6566,0x656b,0x656c,0x6570,
0x6572,0x6574,0x6577,0x6587,0x658b,0x658c,0x6590,0x6591,0x6593,0x6597,
0x6599,0x659b,0x659c,0x659f,0x65a1,0x65a4,0x65a5,0x65a7,0x65a9,0x65ab,
0x65ad,0x65af,0x65b0,0x65b9,0x65bc,0x65bd,0x65c1,0x65c3,0x65c4,0x65c5,
0x65c6,0x65cb,0x65cc,0x65ce,0x65cf,0x65d2,0x65d6,0x65d7,0x65e0,0x65e2,
0x65e5,0x65e6,0x65e7,0x65e8,0x65e9,0x65ec,0x65ed,0x65ee,0x65ef,0x65f0,
0x65f1,0x65f6,0x65f7,0x65fa,0x6600,0x6602,0x6603,0x6606,0x660a,0x660c,
0x660e,0x660f,0x6613,0x6614,0x6615,0x6619,0x661d,0x661f,0x6620,0x6625,
0x6627,0x6628,0x662d,0x662f,0x6631,0x6634,0x6635,0x6636,0x663c,0x663e,
0x6641,0x6643,0x664b,0x664c,0x664f,0x6652,0x6653,0x6654,0x6655,0x6656,
0x6657,0x665a,0x665f,0x6661,0x6664,0x6666,0x6668,0x666e,0x666f,0x6670,
0x6674,0x6676,0x6677,0x667a,0x667e,0x6682,0x6684,0x6687,0x668c,0x6691,
0x6696,0x6697,0x669d,0x66a7,0x66a8,0x66ae,0x66b4,0x66b9,0x66be,0x66d9,
0x66db,0x66dc,0x66dd,0x66e6,0x66e9,0x66f0,0x66f2,0x66f3,0x66f4,0x66f7,
0x66f9,0x66fc,0x66fe,0x66ff,0x6700,0x6708,0x6709,0x670a,0x670b,0x670d,
0x6710,0x6714,0x6715,0x6717,0x671b,0x671d,0x671f,0x6726,0x6728,0x672a,
0x672b,0x672c,0x672d,0x672f,0x6731,0x6734,0x6735,0x673a,0x673d,0x6740,
0x6742,0x6743,0x6746,0x6748,0x6749,0x674c,0x674e,0x674f,0x6750,0x6751,
0x6753,0x6756,0x675c,0x675e,0x675f,0x6760,0x6761,0x6765,0x6768,0x6769,
0x676a,0x676d,0x676f,0x6770,0x6772,0x6773,0x6775,0x6777,0x677c,0x677e,
0x677f,0x6781,0x6784,0x6787,0x6789,0x678b,0x6790,0x6795,0x6797,0x6798,
0x679a,0x679c,0x679d,0x679e,0x67a2,0x67a3,0x67a5,0x67a7,0x67a8,0x67aa,
0x67ab,0x67ad,0x67af,0x67b0,0x67b3,0x67b5,0x67b6,0x67b7,0x67b8,0x67c1,
0x67c3,0x67c4,0x67cf,0x67d0,0x67d1,0x67d2,0x67d3,0x67d4,0x67d8,0x67d9,
0x67da,0x67dc,0x67dd,0x67de,0x67e0,0x67e2,0x67e5,0x67e9,0x67ec,0x67ef,
0x67f0,0x67f1,0x67f3,0x67f4,0x67fd,0x67ff,0x6800,0x6805,0x6807,0x6808,
0x6809,0x680a,0x680b,0x680c,0x680e,0x680f,0x6811,0x6813,0x6816,0x6817,
0x681d,0x6821,0x6829,0x682a,0x6832,0x6833,0x6837,0x6838,0x6839,0x683c,
0x683d,0x683e,0x6840,0x6841,0x6842,0x6843,0x6844,0x6845,0x6846,0x6848,
0x6849,0x684a,0x684c,0x684e,0x6850,0x6851,0x6853,0x6854,0x6855,0x6860,
0x6861,0x6862,0x6863,0x6864,0x6865,0x6866,0x6867,0x6868,0x6869,0x686b,
0x6874,0x6876,0x6877,0x6881,0x6883,0x6885,0x6886,0x688f,0x6893,0x6897,
0x68a2,0x68a6,0x68a7,0x68a8,0x68ad,0x68af,0x68b0,0x68b3,0x68b5,0x68c0,
0x68c2,0x68c9,0x68cb,0x68cd,0x68d2,0x68d5,0x68d8,0x68da,0x68e0,0x68e3,
0x68ee,0x68f0,0x68f1,0x68f5,0x68f9,0x68fa,0x68fc,0x6901,0x6905,0x690b,
0x690d,0x690e,0x6910,0x6912,0x691f,0x6920,0x6924,0x692d,0x6930,0x6934,
0x6939,0x693d,0x693f,0x6942,0x6954,0x6957,0x695a,0x695d,0x695e,0x6960,
0x6963,0x6966,0x696b,0x696e,0x6971,0x6977,0x6978,0x6979,0x697c,0x6980,
0x6982,0x6984,0x6986,0x6987,0x6988,0x6989,0x698d,0x6994,0x6995,0x6998,
0x699b,0x699c,0x69a7,0x69a8,0x69ab,0x69ad,0x69b1,0x69b4,0x69b7,0x69bb,
0x69c1,0x69ca,0x69cc,0x69ce,0x69d0,0x69d4,0x69db,0x69df,0x69e0,0x69ed,
0x69f2,0x69fd,0x69ff,0x6a0a,0x6a17,0x6a18,0x6a1f,0x6a21,0x6a28,0x6a2a,
0x6a2f,0x6a31,0x6a35,0x6a3d,0x6a3e,0x6a44,0x6a47,0x6a50,0x6a58,0x6a59,
0x6a5b,0x6a61,0x6a65,0x6a71,0x6a79,0x6a7c,0x6a80,0x6a84,0x6a8e,0x6a90,
0x6a91,0x6a97,0x6aa0,0x6aa9,0x6aab,0x6aac,0x6b20,0x6b21,0x6b22,0x6b23,
0x6b24,0x6b27,0x6b32,0x6b37,0x6b39,0x6b3a,0x6b3e,0x6b43,0x6b46,0x6b47,
0x6b49,0x6b4c,0x6b59,0x6b62,0x6b63,0x6b64,0x6b65,0x6b66,0x6b67,0x6b6a,
0x6b79,0x6b7b,0x6b7c,0x6b81,0x6b82,0x6b83,0x6b84,0x6b86,0x6b87,0x6b89,
0x6b8a,0x6b8b,0x6b8d,0x6b92,0x6b93,0x6b96,0x6b9a,0x6b9b,0x6ba1,0x6baa,
0x6bb3,0x6bb4,0x6bb5,0x6bb7,0x6bbf,0x6bc1,0x6bc2,0x6bc5,0x6bcb,0x6bcd,
0x6bcf,0x6bd2,0x6bd3,0x6bd4,0x6bd5,0x6bd6,0x6bd7,0x6bd9,0x6bdb,0x6be1,
0x6bea,0x6beb,0x6bef,0x6bf3,0x6bf5,0x6bf9,0x6bfd,0x6c05,0x6c06,0x6c07,
0x6c0d,0x6c0f,0x6c10,0x6c11,0x6c13,0x6c14,0x6c15,0x6c16,0x6c18,0x6c19,
0x6c1a,0x6c1b,0x6c1f,0x6c21,0x6c22,0x6c24,0x6c26,0x6c27,0x6c28,0x6c29,
0x6c2a,0x6c2e,0x6c2f,0x6c30,0x6c32,0x6c34,0x6c35,0x6c38,0x6c3d,0x6c40,
0x6c41,0x6c42,0x6c46,0x6c47,0x6c49,0x6c4a,0x6c50,0x6c54,0x6c55,0x6c57,
0x6c5b,0x6c5c,0x6c5d,0x6c5e,0x6c5f,0x6c60,0x6c61,0x6c64,0x6c68,0x6c69,
0x6c6a,0x6c70,0x6c72,0x6c74,0x6c76,0x6c79,0x6c7d,0x6c7e,0x6c81,0x6c82,
0x6c83,0x6c85,0x6c86,0x6c88,0x6c89,0x6c8c,0x6c8f,0x6c90,0x6c93,0x6c94,
0x6c99,0x6c9b,0x6c9f,0x6ca1,0x6ca3,0x6ca4,0x6ca5,0x6ca6,0x6ca7,0x6ca9,
0x6caa,0x6cab,0x6cad,0x6cae,0x6cb1,0x6cb2,0x6cb3,0x6cb8,0x6cb9,0x6cbb,
0x6cbc,0x6cbd,0x6cbe,0x6cbf,0x6cc4,0x6cc5,0x6cc9,0x6cca,0x6ccc,0x6cd0,
0x6cd3,0x6cd4,0x6cd5,0x6cd6,0x6cd7,0x6cdb,0x6cde,0x6ce0,0x6ce1,0x6ce2,
0x6ce3,0x6ce5,0x6ce8,0x6cea,0x6ceb,0x6cee,0x6cef,0x6cf0,0x6cf1,0x6cf3,
0x6cf5,0x6cf6,0x6cf7,0x6cf8,0x6cfa,0x6cfb,0x6cfc,0x6cfd,0x6cfe,0x6d01,
0x6d04,0x6d07,0x6d0b,0x6d0c,0x6d0e,0x6d12,0x6d17,0x6d19,0x6d1a,0x6d1b,
0x6d1e,0x6d25,0x6d27,0x6d2a,0x6d2b,0x6d2e,0x6d31,0x6d32,0x6d33,0x6d35,
0x6d39,0x6d3b,0x6d3c,0x6d3d,0x6d3e,0x6d41,0x6d43,0x6d45,0x6d46,0x6d47,
0x6d48,0x6d4a,0x6d4b,0x6d4d,0x6d4e,0x6d4f,0x6d51,0x6d52,0x6d53,0x6d54,
0x6d59,0x6d5a,0x6d5c,0x6d5e,0x6d60,0x6d63,0x6d66,0x6d69,0x6d6a,0x6d6e,
0x6d6f,0x6d74,0x6d77,0x6d78,0x6d7c,0x6d82,0x6d85,0x6d88,0x6d89,0x6d8c,
0x6d8e,0x6d91,0x6d93,0x6d94,0x6d95,0x6d9b,0x6d9d,0x6d9e,0x6d9f,0x6da0,
0x6da1,0x6da3,0x6da4,0x6da6,0x6da7,0x6da8,0x6da9,0x6daa,0x6dab,0x6dae,
0x6daf,0x6db2,0x6db5,0x6db8,0x6dbf,0x6dc0,0x6dc4,0x6dc5,0x6dc6,0x6dc7,
0x6dcb,0x6dcc,0x6dd1,0x6dd6,0x6dd8,0x6dd9,0x6ddd,0x6dde,0x6de0,0x6de1,
0x6de4,0x6de6,0x6deb,0x6dec,0x6dee,0x6df1,0x6df3,0x6df7,0x6df9,0x6dfb,
0x6dfc,0x6e05,0x6e0a,0x6e0c,0x6e0d,0x6e0e,0x6e10,0x6e11,0x6e14,0x6e16,
0x6e17,0x6e1a,0x6e1d,0x6e20,0x6e21,0x6e23,0x6e24,0x6e25,0x6e29,0x6e2b,
0x6e2d,0x6e2f,0x6e32,0x6e34,0x6e38,0x6e3a,0x6e43,0x6e44,0x6e4d,0x6e4e,
0x6e53,0x6e54,0x6e56,0x6e58,0x6e5b,0x6e5f,0x6e6b,0x6e6e,0x6e7e,0x6e7f,
0x6e83,0x6e85,0x6e86,0x6e89,0x6e8f,0x6e90,0x6e98,0x6e9c,0x6e9f,0x6ea2,
0x6ea5,0x6ea7,0x6eaa,0x6eaf,0x6eb1,0x6eb2,0x6eb4,0x6eb6,0x6eb7,0x6eba,
0x6ebb,0x6ebd,0x6ec1,0x6ec2,0x6ec7,0x6ecb,0x6ecf,0x6ed1,0x6ed3,0x6ed4,
0x6ed5,0x6ed7,0x6eda,0x6ede,0x6edf,0x6ee0,0x6ee1,0x6ee2,0x6ee4,0x6ee5,
0x6ee6,0x6ee8,0x6ee9,0x6ef4,0x6ef9,0x6f02,0x6f06,0x6f09,0x6f0f,0x6f13,
0x6f14,0x6f15,0x6f20,0x6f24,0x6f29,0x6f2a,0x6f2b,0x6f2d,0x6f2f,0x6f31,
0x6f33,0x6f36,0x6f3e,0x6f46,0x6f47,0x6f4b,0x6f4d,0x6f58,0x6f5c,0x6f5e,
0x6f62,0x6f66,0x6f6d,0x6f6e,0x6f72,0x6f74,0x6f78,0x6f7a,0x6f7c,0x6f84,
0x6f88,0x6f89,0x6f8c,0x6f8d,0x6f8e,0x6f9c,0x6fa1,0x6fa7,0x6fb3,0x6fb6,
0x6fb9,0x6fc0,0x6fc2,0x6fc9,0x6fd1,0x6fd2,0x6fde,0x6fe0,0x6fe1,0x6fee,
0x6fef,0x7011,0x701a,0x701b,0x7023,0x7035,0x7039,0x704c,0x704f,0x705e,
0x706b,0x706c,0x706d,0x706f,0x7070,0x7075,0x7076,0x7078,0x707c,0x707e,
0x707f,0x7080,0x7085,0x7089,0x708a,0x708e,0x7092,0x7094,0x7095,0x7096,
0x7099,0x709c,0x709d,0x70ab,0x70ac,0x70ad,0x70ae,0x70af,0x70b1,0x70b3,
0x70b7,0x70b8,0x70b9,0x70bb,0x70bc,0x70bd,0x70c0,0x70c1,0x70c2,0x70c3,
0x70c8,0x70ca,0x70d8,0x70d9,0x70db,0x70df,0x70e4,0x70e6,0x70e7,0x70e8,
0x70e9,0x70eb,0x70ec,0x70ed,0x70ef,0x70f7,0x70f9,0x70fd,0x7109,0x710a,
0x7110,0x7113,0x7115,0x7116,0x7118,0x7119,0x711a,0x7126,0x712f,0x7130,
0x7131,0x7136,0x7145,0x714a,0x714c,0x714e,0x715c,0x715e,0x7164,0x7166,
0x7167,0x7168,0x716e,0x7172,0x7173,0x7178,0x717a,0x717d,0x7184,0x718a,
0x718f,0x7194,0x7198,0x7199,0x719f,0x71a0,0x71a8,0x71ac,0x71b3,0x71b5,
0x71b9,0x71c3,0x71ce,0x71d4,0x71d5,0x71e0,0x71e5,0x71e7,0x71ee,0x71f9,
0x7206,0x721d,0x7228,0x722a,0x722c,0x7230,0x7231,0x7235,0x7236,0x7237,
0x7238,0x7239,0x723b,0x723d,0x723f,0x7247,0x7248,0x724c,0x724d,0x7252,
0x7256,0x7259,0x725b,0x725d,0x725f,0x7261,0x7262,0x7266,0x7267,0x7269,
0x726e,0x726f,0x7272,0x7275,0x7279,0x727a,0x727e,0x727f,0x7280,0x7281,
0x7284,0x728a,0x728b,0x728d,0x728f,0x7292,0x729f,0x72ac,0x72ad,0x72af,
0x72b0,0x72b4,0x72b6,0x72b7,0x72b8,0x72b9,0x72c1,0x72c2,0x72c3,0x72c4,
0x72c8,0x72cd,0x72ce,0x72d0,0x72d2,0x72d7,0x72d9,0x72de,0x72e0,0x72e1,
0x72e8,0x72e9,0x72ec,0x72ed,0x72ee,0x72ef,0x72f0,0x72f1,0x72f2,0x72f3,
0x72f4,0x72f7,0x72f8,0x72fa,0x72fb,0x72fc,0x7301,0x7303,0x730a,0x730e,
0x7313,0x7315,0x7316,0x7317,0x731b,0x731c,0x731d,0x731e,0x7321,0x7322,
0x7325,0x7329,0x732a,0x732b,0x732c,0x732e,0x7331,0x7334,0x7337,0x7338,
0x7339,0x733e,0x733f,0x734d,0x7350,0x7352,0x7357,0x7360,0x736c,0x736d,
0x736f,0x737e,0x7384,0x7387,0x7389,0x738b,0x738e,0x7391,0x7396,0x739b,
0x739f,0x73a2,0x73a9,0x73ab,0x73ae,0x73af,0x73b0,0x73b2,0x73b3,0x73b7,
0x73ba,0x73bb,0x73c0,0x73c2,0x73c8,0x73c9,0x73ca,0x73cd,0x73cf,0x73d0,
0x73d1,0x73d9,0x73de,0x73e0,0x73e5,0x73e7,0x73e9,0x73ed,0x73f2,0x7403,
0x7405,0x7406,0x7409,0x740a,0x740f,0x7410,0x741a,0x741b,0x7422,0x7425,
0x7426,0x7428,0x742a,0x742c,0x742e,0x7430,0x7433,0x7434,0x7435,0x7436,
0x743c,0x7441,0x7455,0x7457,0x7459,0x745a,0x745b,0x745c,0x745e,0x745f,
0x746d,0x7470,0x7476,0x7477,0x747e,0x7480,0x7481,0x7483,0x7487,0x748b,
0x748e,0x7490,0x749c,0x749e,0x74a7,0x74a8,0x74a9,0x74ba,0x74d2,0x74dc,
0x74de,0x74e0,0x74e2,0x74e3,0x74e4,0x74e6,0x74ee,0x74ef,0x74f4,0x74f6,
0x74f7,0x74ff,0x7504,0x750d,0x750f,0x7511,0x7513,0x7518,0x7519,0x751a,
0x751c,0x751f,0x7525,0x7528,0x7529,0x752b,0x752c,0x752d,0x752f,0x7530,
0x7531,0x7532,0x7533,0x7535,0x7537,0x7538,0x753a,0x753b,0x753e,0x7540,
0x7545,0x7548,0x754b,0x754c,0x754e,0x754f,0x7554,0x7559,0x755a,0x755b,
0x755c,0x7565,0x7566,0x756a,0x7572,0x7574,0x7578,0x7579,0x757f,0x7583,
0x7586,0x758b,0x758f,0x7591,0x7592,0x7594,0x7596,0x7597,0x7599,0x759a,
0x759d,0x759f,0x75a0,0x75a1,0x75a3,0x75a4,0x75a5,0x75ab,0x75ac,0x75ae,
0x75af,0x75b0,0x75b1,0x75b2,0x75b3,0x75b4,0x75b5,0x75b8,0x75b9,0x75bc,
0x75bd,0x75be,0x75c2,0x75c3,0x75c4,0x75c5,0x75c7,0x75c8,0x75c9,0x75ca,
0x75cd,0x75d2,0x75d4,0x75d5,0x75d6,0x75d8,0x75db,0x75de,0x75e2,0x75e3,
0x75e4,0x75e6,0x75e7,0x75e8,0x75ea,0x75eb,0x75f0,0x75f1,0x75f4,0x75f9,
0x75fc,0x75ff,0x7600,0x7601,0x7603,0x7605,0x760a,0x760c,0x7610,0x7615,
0x7617,0x7618,0x7619,0x761b,0x761f,0x7620,0x7622,0x7624,0x7625,0x7626,
0x7629,0x762a,0x762b,0x762d,0x7630,0x7633,0x7634,0x7635,0x7638,0x763c,
0x763e,0x763f,0x7640,0x7643,0x764c,0x764d,0x7654,0x7656,0x765c,0x765e,
0x7663,0x766b,0x766f,0x7678,0x767b,0x767d,0x767e,0x7682,0x7684,0x7686,
0x7687,0x7688,0x768b,0x768e,0x7691,0x7693,0x7696,0x7699,0x76a4,0x76ae,
0x76b1,0x76b2,0x76b4,0x76bf,0x76c2,0x76c5,0x76c6,0x76c8,0x76ca,0x76cd,
0x76ce,0x76cf,0x76d0,0x76d1,0x76d2,0x76d4,0x76d6,0x76d7,0x76d8,0x76db,
0x76df,0x76e5,0x76ee,0x76ef,0x76f1,0x76f2,0x76f4,0x76f8,0x76f9,0x76fc,
0x76fe,0x7701,0x7704,0x7707,0x7708,0x7709,0x770b,0x770d,0x7719,0x771a,
0x771f,0x7720,0x7722,0x7726,0x7728,0x7729,0x772d,0x772f,0x7735,0x7736,
0x7737,0x7738,0x773a,0x773c,0x7740,0x7741,0x7743,0x7747,0x7750,0x7751,
0x775a,0x775b,0x7761,0x7762,0x7763,0x7765,0x7766,0x7768,0x776b,0x776c,
0x7779,0x777d,0x777e,0x777f,0x7780,0x7784,0x7785,0x778c,0x778d,0x778e,
0x7791,0x7792,0x779f,0x77a0,0x77a2,0x77a5,0x77a7,0x77a9,0x77aa,0x77ac,
0x77b0,0x77b3,0x77b5,0x77bb,0x77bd,0x77bf,0x77cd,0x77d7,0x77db,0x77dc,
0x77e2,0x77e3,0x77e5,0x77e7,0x77e9,0x77eb,0x77ec,0x77ed,0x77ee,0x77f3,
0x77f6,0x77f8,0x77fd,0x77fe,0x77ff,0x7800,0x7801,0x7802,0x7809,0x780c,
0x780d,0x7811,0x7812,0x7814,0x7816,0x7817,0x7818,0x781a,0x781c,0x781d,
0x781f,0x7823,0x7825,0x7826,0x7827,0x7829,0x782c,0x782d,0x7830,0x7834,
0x7837,0x7838,0x7839,0x783a,0x783b,0x783c,0x783e,0x7840,0x7845,0x7847,
0x784c,0x784e,0x7850,0x7852,0x7855,0x7856,0x7857,0x785d,0x786a,0x786b,
0x786c,0x786d,0x786e,0x7877,0x787c,0x7887,0x7889,0x788c,0x788d,0x788e,
0x7891,0x7893,0x7897,0x7898,0x789a,0x789b,0x789c,0x789f,0x78a1,0x78a3,
0x78a5,0x78a7,0x78b0,0x78b1,0x78b2,0x78b3,0x78b4,0x78b9,0x78be,0x78c1,
0x78c5,0x78c9,0x78ca,0x78cb,0x78d0,0x78d4,0x78d5,0x78d9,0x78e8,0x78ec,
0x78f2,0x78f4,0x78f7,0x78fa,0x7901,0x7905,0x7913,0x791e,0x7924,0x7934,
0x793a,0x793b,0x793c,0x793e,0x7940,0x7941,0x7946,0x7948,0x7949,0x7953,
0x7956,0x7957,0x795a,0x795b,0x795c,0x795d,0x795e,0x795f,0x7960,0x7962,
0x7965,0x7967,0x7968,0x796d,0x796f,0x7977,0x7978,0x797a,0x7980,0x7981,
0x7984,0x7985,0x798a,0x798f,0x799a,0x79a7,0x79b3,0x79b9,0x79ba,0x79bb,
0x79bd,0x79be,0x79c0,0x79c1,0x79c3,0x79c6,0x79c9,0x79cb,0x79cd,0x79d1,
0x79d2,0x79d5,0x79d8,0x79df,0x79e3,0x79e4,0x79e6,0x79e7,0x79e9,0x79eb,
0x79ed,0x79ef,0x79f0,0x79f8,0x79fb,0x79fd,0x7a00,0x7a02,0x7a03,0x7a06,
0x7a0b,0x7a0d,0x7a0e,0x7a14,0x7a17,0x7a1a,0x7a1e,0x7a20,0x7a23,0x7a33,
0x7a37,0x7a39,0x7a3b,0x7a3c,0x7a3d,0x7a3f,0x7a46,0x7a51,0x7a57,0x7a70,
0x7a74,0x7a76,0x7a77,0x7a78,0x7a79,0x7a7a,0x7a7f,0x7a80,0x7a81,0x7a83,
0x7a84,0x7a86,0x7a88,0x7a8d,0x7a91,0x7a92,0x7a95,0x7a96,0x7a97,0x7a98,
0x7a9c,0x7a9d,0x7a9f,0x7aa0,0x7aa5,0x7aa6,0x7aa8,0x7aac,0x7aad,0x7ab3,
0x7abf,0x7acb,0x7ad6,0x7ad9,0x7ade,0x7adf,0x7ae0,0x7ae3,0x7ae5,0x7ae6,
0x7aed,0x7aef,0x7af9,0x7afa,0x7afd,0x7aff,0x7b03,0x7b04,0x7b06,0x7b08,
0x7b0a,0x7b0b,0x7b0f,0x7b11,0x7b14,0x7b15,0x7b19,0x7b1b,0x7b1e,0x7b20,
0x7b24,0x7b25,0x7b26,0x7b28,0x7b2a,0x7b2b,0x7b2c,0x7b2e,0x7b31,0x7b33,
0x7b38,0x7b3a,0x7b3c,0x7b3e,0x7b45,0x7b47,0x7b49,0x7b4b,0x7b4c,0x7b4f,
0x7b50,0x7b51,0x7b52,0x7b54,0x7b56,0x7b58,0x7b5a,0x7b5b,0x7b5d,0x7b60,
0x7b62,0x7b6e,0x7b71,0x7b72,0x7b75,0x7b77,0x7b79,0x7b7b,0x7b7e,0x7b80,
0x7b85,0x7b8d,0x7b90,0x7b94,0x7b95,0x7b97,0x7b9c,0x7b9d,0x7ba1,0x7ba2,
0x7ba6,0x7ba7,0x7ba8,0x7ba9,0x7baa,0x7bab,0x7bac,0x7bad,0x7bb1,0x7bb4,
0x7bb8,0x7bc1,0x7bc6,0x7bc7,0x7bcc,0x7bd1,0x7bd3,0x7bd9,0x7bda,0x7bdd,
0x7be1,0x7be5,0x7be6,0x7bea,0x7bee,0x7bf1,0x7bf7,0x7bfc,0x7bfe,0x7c07,
0x7c0b,0x7c0c,0x7c0f,0x7c16,0x7c1f,0x7c26,0x7c27,0x7c2a,0x7c38,0x7c3f,
0x7c40,0x7c41,0x7c4d,0x7c73,0x7c74,0x7c7b,0x7c7c,0x7c7d,0x7c89,0x7c91,
0x7c92,0x7c95,0x7c97,0x7c98,0x7c9c,0x7c9d,0x7c9e,0x7c9f,0x7ca2,0x7ca4,
0x7ca5,0x7caa,0x7cae,0x7cb1,0x7cb2,0x7cb3,0x7cb9,0x7cbc,0x7cbd,0x7cbe,
0x7cc1,0x7cc5,0x7cc7,0x7cc8,0x7cca,0x7ccc,0x7ccd,0x7cd5,0x7cd6,0x7cd7,
0x7cd9,0x7cdc,0x7cdf,0x7ce0,0x7ce8,0x7cef,0x7cf8,0x7cfb,0x7d0a,0x7d20,
0x7d22,0x7d27,0x7d2b,0x7d2f,0x7d6e,0x7d77,0x7da6,0x7dae,0x7e3b,0x7e41,
0x7e47,0x7e82,0x7e9b,0x7e9f,0x7ea0,0x7ea1,0x7ea2,0x7ea3,0x7ea4,0x7ea5,
0x7ea6,0x7ea7,0x7ea8,0x7ea9,0x7eaa,0x7eab,0x7eac,0x7ead,0x7eaf,0x7eb0,
0x7eb1,0x7eb2,0x7eb3,0x7eb5,0x7eb6,0x7eb7,0x7eb8,0x7eb9,0x7eba,0x7ebd,
0x7ebe,0x7ebf,0x7ec0,0x7ec1,0x7ec2,0x7ec3,0x7ec4,0x7ec5,0x7ec6,0x7ec7,
0x7ec8,0x7ec9,0x7eca,0x7ecb,0x7ecc,0x7ecd,0x7ece,0x7ecf,0x7ed0,0x7ed1,
0x7ed2,0x7ed3,0x7ed4,0x7ed5,0x7ed7,0x7ed8,0x7ed9,0x7eda,0x7edb,0x7edc,
0x7edd,0x7ede,0x7edf,0x7ee0,0x7ee1,0x7ee2,0x7ee3,0x7ee5,0x7ee6,0x7ee7,
0x7ee8,0x7ee9,0x7eea,0x7eeb,0x7eed,0x7eee,0x7eef,0x7ef0,0x7ef1,0x7ef2,
0x7ef3,0x7ef4,0x7ef5,0x7ef6,0x7ef7,0x7ef8,0x7efa,0x7efb,0x7efc,0x7efd,
0x7efe,0x7eff,0x7f00,0x7f01,0x7f02,0x7f03,0x7f04,0x7f05,0x7f06,0x7f07,
0x7f08,0x7f09,0x7f0b,0x7f0c,0x7f0d,0x7f0e,0x7f0f,0x7f11,0x7f12,0x7f13,
0x7f14,0x7f15,0x7f16,0x7f17,0x7f18,0x7f19,0x7f1a,0x7f1b,0x7f1c,0x7f1d,
0x7f1f,0x7f20,0x7f21,0x7f22,0x7f23,0x7f24,0x7f25,0x7f26,0x7f27,0x7f28,
0x7f29,0x7f2a,0x7f2b,0x7f2c,0x7f2d,0x7f2e,0x7f2f,0x7f30,0x7f31,0x7f32,
0x7f33,0x7f34,0x7f35,0x7f36,0x7f38,0x7f3a,0x7f42,0x7f44,0x7f45,0x7f50,
0x7f51,0x7f54,0x7f55,0x7f57,0x7f58,0x7f5a,0x7f5f,0x7f61,0x7f62,0x7f68,
0x7f69,0x7f6a,0x7f6e,0x7f71,0x7f72,0x7f74,0x7f79,0x7f7e,0x7f81,0x7f8a,
0x7f8c,0x7f8e,0x7f94,0x7f9a,0x7f9d,0x7f9e,0x7f9f,0x7fa1,0x7fa4,0x7fa7,
0x7faf,0x7fb0,0x7fb2,0x7fb8,0x7fb9,0x7fbc,0x7fbd,0x7fbf,0x7fc1,0x7fc5,
0x7fca,0x7fcc,0x7fce,0x7fd4,0x7fd5,0x7fd8,0x7fdf,0x7fe0,0x7fe1,0x7fe5,
0x7fe6,0x7fe9,0x7fee,0x7ff0,0x7ff1,0x7ff3,0x7ffb,0x7ffc,0x8000,0x8001,
0x8003,0x8004,0x8005,0x8006,0x800b,0x800c,0x800d,0x8010,0x8012,0x8014,
0x8015,0x8016,0x8017,0x8018,0x8019,0x801c,0x8020,0x8022,0x8025,0x8026,
0x8027,0x8028,0x8029,0x802a,0x8031,0x8033,0x8035,0x8036,0x8037,0x8038,
0x803b,0x803d,0x803f,0x8042,0x8043,0x8046,0x804a,0x804b,0x804c,0x804d,
0x8052,0x8054,0x8058,0x805a,0x8069,0x806a,0x8071,0x807f,0x8080,0x8083,
0x8084,0x8086,0x8087,0x8089,0x808b,0x808c,0x8093,0x8096,0x8098,0x809a,
0x809b,0x809c,0x809d,0x809f,0x80a0,0x80a1,0x80a2,0x80a4,0x80a5,0x80a9,
0x80aa,0x80ab,0x80ad,0x80ae,0x80af,0x80b1,0x80b2,0x80b4,0x80b7,0x80ba,
0x80bc,0x80bd,0x80be,0x80bf,0x80c0,0x80c1,0x80c2,0x80c3,0x80c4,0x80c6,
0x80cc,0x80cd,0x80ce,0x80d6,0x80d7,0x80d9,0x80da,0x80db,0x80dc,0x80dd,
0x80de,0x80e1,0x80e4,0x80e5,0x80e7,0x80e8,0x80e9,0x80ea,0x80eb,0x80ec,
0x80ed,0x80ef,0x80f0,0x80f1,0x80f2,0x80f3,0x80f4,0x80f6,0x80f8,0x80fa,
0x80fc,0x80fd,0x8102,0x8106,0x8109,0x810a,0x810d,0x810e,0x810f,0x8110,
0x8111,0x8112,0x8113,0x8114,0x8116,0x8118,0x811a,0x811e,0x812c,0x812f,
0x8131,0x8132,0x8136,0x8138,0x813e,0x8146,0x8148,0x814a,0x814b,0x814c,
0x8150,0x8151,0x8153,0x8154,0x8155,0x8159,0x815a,0x8160,0x8165,0x8167,
0x8169,0x816d,0x816e,0x8170,0x8171,0x8174,0x8179,0x817a,0x817b,0x817c,
0x817d,0x817e,0x817f,0x8180,0x8182,0x8188,0x818a,0x818f,0x8191,0x8198,
0x819b,0x819c,0x819d,0x81a3,0x81a6,0x81a8,0x81aa,0x81b3,0x81ba,0x81bb,
0x81c0,0x81c1,0x81c2,0x81c3,0x81c6,0x81ca,0x81cc,0x81e3,0x81e7,0x81ea,
0x81ec,0x81ed,0x81f3,0x81f4,0x81fb,0x81fc,0x81fe,0x8200,0x8201,0x8202,
0x8204,0x8205,0x8206,0x820c,0x820d,0x8210,0x8212,0x8214,0x821b,0x821c,
0x821e,0x821f,0x8221,0x8222,0x8223,0x8228,0x822a,0x822b,0x822c,0x822d,
0x822f,0x8230,0x8231,0x8233,0x8234,0x8235,0x8236,0x8237,0x8238,0x8239,
0x823b,0x823e,0x8244,0x8247,0x8249,0x824b,0x824f,0x8258,0x825a,0x825f,
0x8268,0x826e,0x826f,0x8270,0x8272,0x8273,0x8274,0x8279,0x827a,0x827d,
0x827e,0x827f,0x8282,0x8284,0x8288,0x828a,0x828b,0x828d,0x828e,0x828f,
0x8291,0x8292,0x8297,0x8298,0x8299,0x829c,0x829d,0x829f,0x82a1,0x82a4,
0x82a5,0x82a6,0x82a8,0x82a9,0x82aa,0x82ab,0x82ac,0x82ad,0x82ae,0x82af,
0x82b0,0x82b1,0x82b3,0x82b4,0x82b7,0x82b8,0x82b9,0x82bd,0x82be,0x82c1,
0x82c4,0x82c7,0x82c8,0x82ca,0x82cb,0x82cc,0x82cd,0x82ce,0x82cf,0x82d1,
0x82d2,0x82d3,0x82d4,0x82d5,0x82d7,0x82d8,0x82db,0x82dc,0x82de,0x82df,
0x82e0,0x82e1,0x82e3,0x82e4,0x82e5,0x82e6,0x82eb,0x82ef,0x82f1,0x82f4,
0x82f7,0x82f9,0x82fb,0x8301,0x8302,0x8303,0x8304,0x8305,0x8306,0x8307,
0x8308,0x8309,0x830c,0x830e,0x830f,0x8311,0x8314,0x8315,0x8317,0x831a,
0x831b,0x831c,0x8327,0x8328,0x832b,0x832c,0x832d,0x832f,0x8331,0x8333,
0x8334,0x8335,0x8336,0x8338,0x8339,0x833a,0x833c,0x8340,0x8343,0x8346,
0x8347,0x8349,0x834f,0x8350,0x8351,0x8352,0x8354,0x835a,0x835b,0x835c,
0x835e,0x835f,0x8360,0x8361,0x8363,0x8364,0x8365,0x8366,0x8367,0x8368,
0x8369,0x836a,0x836b,0x836c,0x836d,0x836e,0x836f,0x8377,0x8378,0x837b,
0x837c,0x837d,0x8385,0x8386,0x8389,0x838e,0x8392,0x8393,0x8398,0x839b,
0x839c,0x839e,0x83a0,0x83a8,0x83a9,0x83aa,0x83ab,0x83b0,0x83b1,0x83b2,
0x83b3,0x83b4,0x83b6,0x83b7,0x83b8,0x83b9,0x83ba,0x83bc,0x83bd,0x83c0,
0x83c1,0x83c5,0x83c7,0x83ca,0x83cc,0x83cf,0x83d4,0x83d6,0x83d8,0x83dc,
0x83dd,0x83df,0x83e0,0x83e1,0x83e5,0x83e9,0x83ea,0x83f0,0x83f1,0x83f2,
0x83f8,0x83f9,0x83fd,0x8401,0x8403,0x8404,0x8406,0x840b,0x840c,0x840d,
0x840e,0x840f,0x8411,0x8418,0x841c,0x841d,0x8424,0x8425,0x8426,0x8427,
0x8428,0x8431,0x8438,0x843c,0x843d,0x8446,0x8451,0x8457,0x8459,0x845a,
0x845b,0x845c,0x8461,0x8463,0x8469,0x846b,0x846c,0x846d,0x8471,0x8473,
0x8475,0x8476,0x8478,0x847a,0x8482,0x8487,0x8488,0x8489,0x848b,0x848c,
0x848e,0x8497,0x8499,0x849c,0x84a1,0x84af,0x84b2,0x84b4,0x84b8,0x84b9,
0x84ba,0x84bd,0x84bf,0x84c1,0x84c4,0x84c9,0x84ca,0x84cd,0x84d0,0x84d1,
0x84d3,0x84d6,0x84dd,0x84df,0x84e0,0x84e3,0x84e5,0x84e6,0x84ec,0x84f0,
0x84fc,0x84ff,0x850c,0x8511,0x8513,0x8517,0x851a,0x851f,0x8521,0x852b,
0x852c,0x8537,0x8538,0x8539,0x853a,0x853b,0x853c,0x853d,0x8543,0x8548,
0x8549,0x854a,0x8556,0x8559,0x855e,0x8564,0x8568,0x8572,0x8574,0x8579,
0x857a,0x857b,0x857e,0x8584,0x8585,0x8587,0x858f,0x859b,0x859c,0x85a4,
0x85a8,0x85aa,0x85ae,0x85af,0x85b0,0x85b7,0x85b9,0x85c1,0x85c9,0x85cf,
0x85d0,0x85d3,0x85d5,0x85dc,0x85e4,0x85e9,0x85fb,0x85ff,0x8605,0x8611,
0x8616,0x8627,0x8629,0x8638,0x863c,0x864d,0x864e,0x864f,0x8650,0x8651,
0x8654,0x865a,0x865e,0x8662,0x866b,0x866c,0x866e,0x8671,0x8679,0x867a,
0x867b,0x867c,0x867d,0x867e,0x867f,0x8680,0x8681,0x8682,0x868a,0x868b,
0x868c,0x868d,0x8693,0x8695,0x869c,0x869d,0x86a3,0x86a4,0x86a7,0x86a8,
0x86a9,0x86aa,0x86ac,0x86af,0x86b0,0x86b1,0x86b4,0x86b5,0x86b6,0x86ba,
0x86c0,0x86c4,0x86c6,0x86c7,0x86c9,0x86ca,0x86cb,0x86ce,0x86cf,0x86d0,
0x86d1,0x86d4,0x86d8,0x86d9,0x86db,0x86de,0x86df,0x86e4,0x86e9,0x86ed,
0x86ee,0x86f0,0x86f1,0x86f2,0x86f3,0x86f4,0x86f8,0x86f9,0x86fe,0x8700,
0x8702,0x8703,0x8707,0x8708,0x8709,0x870a,0x870d,0x8712,0x8713,0x8715,
0x8717,0x8718,0x871a,0x871c,0x871e,0x8721,0x8722,0x8723,0x8725,0x8729,
0x872e,0x8731,0x8734,0x8737,0x873b,0x873e,0x873f,0x8747,0x8748,0x8749,
0x874c,0x874e,0x8753,0x8757,0x8759,0x8760,0x8763,0x8764,0x8765,0x876e,
0x8770,0x8774,0x8776,0x877b,0x877c,0x877d,0x877e,0x8782,0x8783,0x8785,
0x8788,0x878b,0x878d,0x8793,0x8797,0x879f,0x87a8,0x87ab,0x87ac,0x87ad,
0x87af,0x87b3,0x87b5,0x87ba,0x87bd,0x87c0,0x87c6,0x87ca,0x87cb,0x87d1,
0x87d2,0x87d3,0x87db,0x87e0,0x87e5,0x87ea,0x87ee,0x87f9,0x87fe,0x8803,
0x880a,0x8813,0x8815,0x8816,0x881b,0x8821,0x8822,0x8832,0x8839,0x883c,
0x8840,0x8844,0x8845,0x884c,0x884d,0x8854,0x8857,0x8859,0x8861,0x8862,
0x8863,0x8864,0x8865,0x8868,0x8869,0x886b,0x886c,0x886e,0x8870,0x8872,
0x8877,0x887d,0x887e,0x887f,0x8881,0x8882,0x8884,0x8885,0x8888,0x888b,
0x888d,0x8892,0x8896,0x889c,0x88a2,0x88a4,0x88ab,0x88ad,0x88b1,0x88b7,
0x88bc,0x88c1,0x88c2,0x88c5,0x88c6,0x88c9,0x88ce,0x88d2,0x88d4,0x88d5,
0x88d8,0x88d9,0x88df,0x88e2,0x88e3,0x88e4,0x88e5,0x88e8,0x88f0,0x88f1,
0x88f3,0x88f4,0x88f8,0x88f9,0x88fc,0x88fe,0x8902,0x890a,0x8910,0x8912,
0x8913,0x8919,0x891a,0x891b,0x8921,0x8925,0x892a,0x892b,0x8930,0x8934,
0x8936,0x8941,0x8944,0x895e,0x895f,0x8966,0x897b,0x897f,0x8981,0x8983,
0x8986,0x89c1,0x89c2,0x89c4,0x89c5,0x89c6,0x89c7,0x89c8,0x89c9,0x89ca,
0x89cb,0x89cc,0x89ce,0x89cf,0x89d0,0x89d1,0x89d2,0x89d6,0x89da,0x89dc,
0x89de,0x89e3,0x89e5,0x89e6,0x89eb,0x89ef,0x89f3,0x8a00,0x8a07,0x8a3e,
0x8a48,0x8a79,0x8a89,0x8a8a,0x8a93,0x8b07,0x8b26,0x8b66,0x8b6c,0x8ba0,
0x8ba1,0x8ba2,0x8ba3,0x8ba4,0x8ba5,0x8ba6,0x8ba7,0x8ba8,0x8ba9,0x8baa,
0x8bab,0x8bad,0x8bae,0x8baf,0x8bb0,0x8bb2,0x8bb3,0x8bb4,0x8bb5,0x8bb6,
0x8bb7,0x8bb8,0x8bb9,0x8bba,0x8bbc,0x8bbd,0x8bbe,0x8bbf,0x8bc0,0x8bc1,
0x8bc2,0x8bc3,0x8bc4,0x8bc5,0x8bc6,0x8bc8,0x8bc9,0x8bca,0x8bcb,0x8bcc,
0x8bcd,0x8bce,0x8bcf,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,0x8beb,0x8bec,
0x8bed,0x8bee,0x8bef,0x8bf0,0x8bf1,0x8bf2,0x8bf3,0x8bf4,0x8bf5,0x8bf6,
0x8bf7,0x8bf8,0x8bf9,0x8bfa,0x8bfb,0x8bfc,0x8bfd,0x8bfe,0x8bff,0x8c00,
0x8c01,0x8c02,0x8c03,0x8c04,0x8c05,0x8c06,0x8c07,0x8c08,0x8c0a,0x8c0b,
0x8c0c,0x8c0d,0x8c0e,0x8c0f,0x8c10,0x8c11,0x8c12,0x8c13,0x8c14,0x8c15,
0x8c16,0x8c17,0x8c18,0x8c19,0x8c1a,0x8c1b,0x8c1c,0x8c1d,0x8c1f,0x8c20,
0x8c21,0x8c22,0x8c23,0x8c24,0x8c25,0x8c26,0x8c27,0x8c28,0x8c29,0x8c2a,
0x8c2b,0x8c2c,0x8c2d,0x8c2e,0x8c2f,0x8c30,0x8c31,0x8c32,0x8c33,0x8c34,
0x8c35,0x8c36,0x8c37,0x8c41,0x8c46,0x8c47,0x8c49,0x8c4c,0x8c55,0x8c5a,
0x8c61,0x8c62,0x8c6a,0x8c6b,0x8c73,0x8c78,0x8c79,0x8c7a,0x8c82,0x8c85,
0x8c89,0x8c8a,0x8c8c,0x8c94,0x8c98,0x8d1d,0x8d1e,0x8d1f,0x8d21,0x8d22,
0x8d23,0x8d24,0x8d25,0x8d26,0x8d27,0x8d28,0x8d29,0x8d2a,0x8d2b,0x8d2c,
0x8d2d,0x8d2e,0x8d2f,0x8d30,0x8d31,0x8d32,0x8d33,0x8d34,0x8d35,0x8d36,
0x8d37,0x8d38,0x8d39,0x8d3a,0x8d3b,0x8d3c,0x8d3d,0x8d3e,0x8d3f,0x8d40,
0x8d41,0x8d42,0x8d43,0x8d44,0x8d45,0x8d46,0x8d47,0x8d48,0x8d49,0x8d4a,
0x8d4b,0x8d4c,0x8d4d,0x8d4e,0x8d4f,0x8d50,0x8d53,0x8d54,0x8d55,0x8d56,
0x8d58,0x8d59,0x8d5a,0x8d5b,0x8d5c,0x8d5d,0x8d5e,0x8d60,0x8d61,0x8d62,
0x8d63,0x8d64,0x8d66,0x8d67,0x8d6b,0x8d6d,0x8d70,0x8d73,0x8d74,0x8d75,
0x8d76,0x8d77,0x8d81,0x8d84,0x8d85,0x8d8a,0x8d8b,0x8d91,0x8d94,0x8d9f,
0x8da3,0x8db1,0x8db3,0x8db4,0x8db5,0x8db8,0x8dba,0x8dbc,0x8dbe,0x8dbf,
0x8dc3,0x8dc4,0x8dc6,0x8dcb,0x8dcc,0x8dce,0x8dcf,0x8dd1,0x8dd6,0x8dd7,
0x8dda,0x8ddb,0x8ddd,0x8dde,0x8ddf,0x8de3,0x8de4,0x8de8,0x8dea,0x8deb,
0x8dec,0x8def,0x8df3,0x8df5,0x8df7,0x8df8,0x8df9,0x8dfa,0x8dfb,0x8dfd,
0x8e05,0x8e09,0x8e0a,0x8e0c,0x8e0f,0x8e14,0x8e1d,0x8e1e,0x8e1f,0x8e22,
0x8e23,0x8e29,0x8e2a,0x8e2c,0x8e2e,0x8e2f,0x8e31,0x8e35,0x8e39,0x8e3a,
0x8e3d,0x8e40,0x8e41,0x8e42,0x8e44,0x8e47,0x8e48,0x8e49,0x8e4a,0x8e4b,
0x8e51,0x8e52,0x8e59,0x8e66,0x8e69,0x8e6c,0x8e6d,0x8e6f,0x8e70,0x8e72,
0x8e74,0x8e76,0x8e7c,0x8e7f,0x8e81,0x8e85,0x8e87,0x8e8f,0x8e90,0x8e94,
0x8e9c,0x8e9e,0x8eab,0x8eac,0x8eaf,0x8eb2,0x8eba,0x8ece,0x8f66,0x8f67,
0x8f68,0x8f69,0x8f6b,0x8f6c,0x8f6d,0x8f6e,0x8f6f,0x8f70,0x8f71,0x8f72,
0x8f73,0x8f74,0x8f75,0x8f76,0x8f77,0x8f78,0x8f79,0x8f7a,0x8f7b,0x8f7c,
0x8f7d,0x8f7e,0x8f7f,0x8f81,0x8f82,0x8f83,0x8f84,0x8f85,0x8f86,0x8f87,
0x8f88,0x8f89,0x8f8a,0x8f8b,0x8f8d,0x8f8e,0x8f8f,0x8f90,0x8f91,0x8f93,
0x8f94,0x8f95,0x8f96,0x8f97,0x8f98,0x8f99,0x8f9a,0x8f9b,0x8f9c,0x8f9e,
0x8f9f,0x8fa3,0x8fa8,0x8fa9,0x8fab,0x8fb0,0x8fb1,0x8fb6,0x8fb9,0x8fbd,
0x8fbe,0x8fc1,0x8fc2,0x8fc4,0x8fc5,0x8fc7,0x8fc8,0x8fce,0x8fd0,0x8fd1,
0x8fd3,0x8fd4,0x8fd5,0x8fd8,0x8fd9,0x8fdb,0x8fdc,0x8fdd,0x8fde,0x8fdf,
0x8fe2,0x8fe4,0x8fe5,0x8fe6,0x8fe8,0x8fe9,0x8fea,0x8feb,0x8fed,0x8fee,
0x8ff0,0x8ff3,0x8ff7,0x8ff8,0x8ff9,0x8ffd,0x9000,0x9001,0x9002,0x9003,
0x9004,0x9005,0x9006,0x9009,0x900a,0x900b,0x900d,0x900f,0x9010,0x9011,
0x9012,0x9014,0x9016,0x9017,0x901a,0x901b,0x901d,0x901e,0x901f,0x9020,
0x9021,0x9022,0x9026,0x902d,0x902e,0x902f,0x9035,0x9036,0x9038,0x903b,
0x903c,0x903e,0x9041,0x9042,0x9044,0x9047,0x904d,0x904f,0x9050,0x9051,
0x9052,0x9053,0x9057,0x9058,0x905b,0x9062,0x9063,0x9065,0x9068,0x906d,
0x906e,0x9074,0x9075,0x907d,0x907f,0x9080,0x9082,0x9083,0x9088,0x908b,
0x9091,0x9093,0x9095,0x9097,0x9099,0x909b,0x909d,0x90a1,0x90a2,0x90a3,
0x90a6,0x90aa,0x90ac,0x90ae,0x90af,0x90b0,0x90b1,0x90b3,0x90b4,0x90b5,
0x90b6,0x90b8,0x90b9,0x90ba,0x90bb,0x90be,0x90c1,0x90c4,0x90c5,0x90c7,
0x90ca,0x90ce,0x90cf,0x90d0,0x90d1,0x90d3,0x90d7,0x90db,0x90dc,0x90dd,
0x90e1,0x90e2,0x90e6,0x90e7,0x90e8,0x90eb,0x90ed,0x90ef,0x90f4,0x90f8,
0x90fd,0x90fe,0x9102,0x9104,0x9119,0x911e,0x9122,0x9123,0x912f,0x9131,
0x9139,0x9143,0x9146,0x9149,0x914a,0x914b,0x914c,0x914d,0x914e,0x914f,
0x9150,0x9152,0x9157,0x915a,0x915d,0x915e,0x9161,0x9162,0x9163,0x9164,
0x9165,0x9169,0x916a,0x916c,0x916e,0x916f,0x9170,0x9171,0x9172,0x9174,
0x9175,0x9176,0x9177,0x9178,0x9179,0x917d,0x917e,0x917f,0x9185,0x9187,
0x9189,0x918b,0x918c,0x918d,0x9190,0x9191,0x9192,0x919a,0x919b,0x91a2,
0x91a3,0x91aa,0x91ad,0x91ae,0x91af,0x91b4,0x91b5,0x91ba,0x91c7,0x91c9,
0x91ca,0x91cc,0x91cd,0x91ce,0x91cf,0x91d1,0x91dc,0x9274,0x928e,0x92ae,
0x92c8,0x933e,0x936a,0x938f,0x93ca,0x93d6,0x943e,0x946b,0x9485,0x9486,
0x9487,0x9488,0x9489,0x948a,0x948b,0x948c,0x948d,0x948e,0x948f,0x9490,
0x9492,0x9493,0x9494,0x9495,0x9497,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,0x94c8,0x94c9,0x94ca,0x94cb,0x94cc,0x94cd,0x94ce,0x94d0,0x94d1,
0x94d2,0x94d5,0x94d6,0x94d7,0x94d8,0x94d9,0x94db,0x94dc,0x94dd,0x94de,
0x94df,0x94e0,0x94e1,0x94e2,0x94e3,0x94e4,0x94e5,0x94e7,0x94e8,0x94e9,
0x94ea,0x94eb,0x94ec,0x94ed,0x94ee,0x94ef,0x94f0,0x94f1,0x94f2,0x94f3,
0x94f4,0x94f5,0x94f6,0x94f7,0x94f8,0x94f9,0x94fa,0x94fc,0x94fd,0x94fe,
0x94ff,0x9500,0x9501,0x9502,0x9503,0x9504,0x9505,0x9506,0x9507,0x9508,
0x9509,0x950a,0x950b,0x950c,0x950d,0x950e,0x950f,0x9510,0x9511,0x9512,
0x9513,0x9514,0x9515,0x9516,0x9517,0x9518,0x9519,0x951a,0x951b,0x951d,
0x951e,0x951f,0x9521,0x9522,0x9523,0x9524,0x9525,0x9526,0x9528,0x9529,
0x952a,0x952b,0x952c,0x952d,0x952e,0x952f,0x9530,0x9531,0x9532,0x9534,
0x9535,0x9536,0x9537,0x9538,0x9539,0x953a,0x953b,0x953c,0x953e,0x953f,
0x9540,0x9541,0x9542,0x9544,0x9545,0x9546,0x9547,0x9549,0x954a,0x954c,
0x954d,0x954e,0x954f,0x9550,0x9551,0x9552,0x9553,0x9554,0x9556,0x9557,
0x9558,0x9559,0x955b,0x955c,0x955d,0x955e,0x955f,0x9561,0x9562,0x9563,
0x9564,0x9565,0x9566,0x9567,0x9568,0x9569,0x956a,0x956b,0x956c,0x956d,
0x956f,0x9570,0x9571,0x9572,0x9573,0x9576,0x957f,0x95e8,0x95e9,0x95ea,
0x95eb,0x95ed,0x95ee,0x95ef,0x95f0,0x95f1,0x95f2,0x95f3,0x95f4,0x95f5,
0x95f6,0x95f7,0x95f8,0x95f9,0x95fa,0x95fb,0x95fc,0x95fd,0x95fe,0x9600,
0x9601,0x9602,0x9603,0x9604,0x9605,0x9606,0x9608,0x9609,0x960a,0x960b,
0x960c,0x960d,0x960e,0x960f,0x9610,0x9611,0x9612,0x9614,0x9615,0x9616,
0x9617,0x9619,0x961a,0x961c,0x961d,0x961f,0x9621,0x9622,0x962a,0x962e,
0x9631,0x9632,0x9633,0x9634,0x9635,0x9636,0x963b,0x963c,0x963d,0x963f,
0x9640,0x9642,0x9644,0x9645,0x9646,0x9647,0x9648,0x9649,0x964b,0x964c,
0x964d,0x9650,0x9654,0x9655,0x965b,0x965f,0x9661,0x9662,0x9664,0x9667,
0x9668,0x9669,0x966a,0x966c,0x9672,0x9674,0x9675,0x9676,0x9677,0x9685,
0x9686,0x9688,0x968b,0x968d,0x968f,0x9690,0x9694,0x9697,0x9698,0x9699,
0x969c,0x96a7,0x96b0,0x96b3,0x96b6,0x96b9,0x96bc,0x96bd,0x96be,0x96c0,
0x96c1,0x96c4,0x96c5,0x96c6,0x96c7,0x96c9,0x96cc,0x96cd,0x96ce,0x96cf,
0x96d2,0x96d5,0x96e0,0x96e8,0x96e9,0x96ea,0x96ef,0x96f3,0x96f6,0x96f7,
0x96f9,0x96fe,0x9700,0x9701,0x9704,0x9706,0x9707,0x9708,0x9709,0x970d,
0x970e,0x970f,0x9713,0x9716,0x971c,0x971e,0x972a,0x972d,0x9730,0x9732,
0x9738,0x9739,0x973e,0x9752,0x9753,0x9756,0x9759,0x975b,0x975e,0x9760,
0x9761,0x9762,0x9765,0x9769,0x9773,0x9774,0x9776,0x977c,0x9785,0x978b,
0x978d,0x9791,0x9792,0x9794,0x9798,0x97a0,0x97a3,0x97ab,0x97ad,0x97af,
0x97b2,0x97b4,0x97e6,0x97e7,0x97e9,0x97ea,0x97eb,0x97ec,0x97ed,0x97f3,
0x97f5,0x97f6,0x9875,0x9876,0x9877,0x9878,0x9879,0x987a,0x987b,0x987c,
0x987d,0x987e,0x987f,0x9880,0x9881,0x9882,0x9883,0x9884,0x9885,0x9886,
0x9887,0x9888,0x9889,0x988a,0x988c,0x988d,0x988f,0x9890,0x9891,0x9893,
0x9894,0x9896,0x9897,0x9898,0x989a,0x989b,0x989c,0x989d,0x989e,0x989f,
0x98a0,0x98a1,0x98a2,0x98a4,0x98a5,0x98a6,0x98a7,0x98ce,0x98d1,0x98d2,
0x98d3,0x98d5,0x98d8,0x98d9,0x98da,0x98de,0x98df,0x98e7,0x98e8,0x990d,
0x9910,0x992e,0x9954,0x9955,0x9963,0x9965,0x9967,0x9968,0x9969,0x996a,
0x996b,0x996c,0x996d,0x996e,0x996f,0x9970,0x9971,0x9972,0x9974,0x9975,
0x9976,0x9977,0x997a,0x997c,0x997d,0x997f,0x9980,0x9981,0x9984,0x9985,
0x9986,0x9987,0x9988,0x998a,0x998b,0x998d,0x998f,0x9990,0x9991,0x9992,
0x9993,0x9994,0x9995,0x9996,0x9997,0x9998,0x9999,0x99a5,0x99a8,0x9a6c,
0x9a6d,0x9a6e,0x9a6f,0x9a70,0x9a71,0x9a73,0x9a74,0x9a75,0x9a76,0x9a77,
0x9a78,0x9a79,0x9a7a,0x9a7b,0x9a7c,0x9a7d,0x9a7e,0x9a7f,0x9a80,0x9a81,
0x9a82,0x9a84,0x9a85,0x9a86,0x9a87,0x9a88,0x9a8a,0x9a8b,0x9a8c,0x9a8f,
0x9a90,0x9a91,0x9a92,0x9a93,0x9a96,0x9a97,0x9a98,0x9a9a,0x9a9b,0x9a9c,
0x9a9d,0x9a9e,0x9a9f,0x9aa0,0x9aa1,0x9aa2,0x9aa3,0x9aa4,0x9aa5,0x9aa7,
0x9aa8,0x9ab0,0x9ab1,0x9ab6,0x9ab7,0x9ab8,0x9aba,0x9abc,0x9ac0,0x9ac1,
0x9ac2,0x9ac5,0x9acb,0x9acc,0x9ad1,0x9ad3,0x9ad8,0x9adf,0x9ae1,0x9ae6,
0x9aeb,0x9aed,0x9aef,0x9af9,0x9afb,0x9b03,0x9b08,0x9b0f,0x9b13,0x9b1f,
0x9b23,0x9b2f,0x9b32,0x9b3b,0x9b3c,0x9b41,0x9b42,0x9b43,0x9b44,0x9b45,
0x9b47,0x9b48,0x9b49,0x9b4d,0x9b4f,0x9b51,0x9b54,0x9c7c,0x9c7f,0x9c81,
0x9c82,0x9c85,0x9c86,0x9c87,0x9c88,0x9c8b,0x9c8d,0x9c8e,0x9c90,0x9c91,
0x9c92,0x9c94,0x9c95,0x9c9a,0x9c9b,0x9c9c,0x9c9e,0x9c9f,0x9ca0,0x9ca1,
0x9ca2,0x9ca3,0x9ca4,0x9ca5,0x9ca6,0x9ca7,0x9ca8,0x9ca9,0x9cab,0x9cad,
0x9cae,0x9cb0,0x9cb1,0x9cb2,0x9cb3,0x9cb4,0x9cb5,0x9cb6,0x9cb7,0x9cb8,
0x9cba,0x9cbb,0x9cbc,0x9cbd,0x9cc3,0x9cc4,0x9cc5,0x9cc6,0x9cc7,0x9cca,
0x9ccb,0x9ccc,0x9ccd,0x9cce,0x9ccf,0x9cd0,0x9cd3,0x9cd4,0x9cd5,0x9cd6,
0x9cd7,0x9cd8,0x9cd9,0x9cdc,0x9cdd,0x9cde,0x9cdf,0x9ce2,0x9e1f,0x9e20,
0x9e21,0x9e22,0x9e23,0x9e25,0x9e26,0x9e28,0x9e29,0x9e2a,0x9e2b,0x9e2c,
0x9e2d,0x9e2f,0x9e31,0x9e32,0x9e33,0x9e35,0x9e36,0x9e37,0x9e38,0x9e39,
0x9e3a,0x9e3d,0x9e3e,0x9e3f,0x9e41,0x9e42,0x9e43,0x9e44,0x9e45,0x9e46,
0x9e47,0x9e48,0x9e49,0x9e4a,0x9e4b,0x9e4c,0x9e4e,0x9e4f,0x9e51,0x9e55,
0x9e57,0x9e58,0x9e5a,0x9e5b,0x9e5c,0x9e5e,0x9e63,0x9e64,0x9e66,0x9e67,
0x9e68,0x9e69,0x9e6a,0x9e6b,0x9e6c,0x9e6d,0x9e70,0x9e71,0x9e73,0x9e7e,
0x9e7f,0x9e82,0x9e87,0x9e88,0x9e8b,0x9e92,0x9e93,0x9e9d,0x9e9f,0x9ea6,
0x9eb4,0x9eb8,0x9ebb,0x9ebd,0x9ebe,0x9ec4,0x9ec9,0x9ecd,0x9ece,0x9ecf,
0x9ed1,0x9ed4,0x9ed8,0x9edb,0x9edc,0x9edd,0x9edf,0x9ee0,0x9ee2,0x9ee5,
0x9ee7,0x9ee9,0x9eea,0x9eef,0x9ef9,0x9efb,0x9efc,0x9efe,0x9f0b,0x9f0d,
0x9f0e,0x9f10,0x9f13,0x9f17,0x9f19,0x9f20,0x9f22,0x9f2c,0x9f2f,0x9f37,
0x9f39,0x9f3b,0x9f3d,0x9f3e,0x9f44,0x9f50,0x9f51,0x9f7f,0x9f80,0x9f83,
0x9f84,0x9f85,0x9f86,0x9f87,0x9f88,0x9f89,0x9f8a,0x9f8b,0x9f8c,0x9f99,
0x9f9a,0x9f9b,0x9f9f,0x9fa0,0xe7c7,0xe7c8,0xfe31,0xfe33,0xfe34,0xfe35,
0xfe36,0xfe37,0xfe38,0xfe39,0xfe3a,0xfe3b,0xfe3c,0xfe3d,0xfe3e,0xfe3f,
0xfe40,0xfe41,0xfe42,0xfe43,0xfe44,0xff01,0xff02,0xff03,0xff04,0xff05,
0xff06,0xff07,0xff08,0xff09,0xff0a,0xff0b,0xff0c,0xff0d,0xff0e,0xff0f,
0xff10,0xff11,0xff12,0xff13,0xff14,0xff15,0xff16,0xff17,0xff18,0xff19,
0xff1a,0xff1b,0xff1c,0xff1d,0xff1e,0xff1f,0xff20,0xff21,0xff22,0xff23,
0xff24,0xff25,0xff26,0xff27,0xff28,0xff29,0xff2a,0xff2b,0xff2c,0xff2d,
0xff2e,0xff2f,0xff30,0xff31,0xff32,0xff33,0xff34,0xff35,0xff36,0xff37,
0xff38,0xff39,0xff3a,0xff3b,0xff3c,0xff3d,0xff3e,0xff3f,0xff40,0xff41,
0xff42,0xff43,0xff44,0xff45,0xff46,0xff47,0xff48,0xff49,0xff4a,0xff4b,
0xff4c,0xff4d,0xff4e,0xff4f,0xff50,0xff51,0xff52,0xff53,0xff54,0xff55,
0xff56,0xff57,0xff58,0xff59,0xff5a,0xff5b,0xff5c,0xff5d,0xff5e,0xffe0,
0xffe1,0xffe3,0xffe5
};
/* total number of code points (and glyphs) */
#define GLYPH_COUNT (sizeof(gb2312_in_ucs2_codetable) / sizeof(short))
#endif /* __GB2312_IN_UCS2_H__ */

View File

@ -14,7 +14,7 @@ void eliminate_duplicates(std::vector<DataFile::glyphentry_t> &glyphtable)
{ {
for (int c : glyphtable.at(j).chars) for (int c : glyphtable.at(j).chars)
glyphtable.at(i).chars.push_back(c); glyphtable.at(i).chars.push_back(c);
glyphtable.erase(glyphtable.begin() + j); glyphtable.erase(glyphtable.begin() + j);
j--; j--;
} }
@ -28,7 +28,7 @@ struct bbox_t
int top; int top;
int right; int right;
int bottom; int bottom;
bbox_t() bbox_t()
{ {
left = std::numeric_limits<int>::max(); left = std::numeric_limits<int>::max();
@ -36,7 +36,7 @@ struct bbox_t
right = std::numeric_limits<int>::min(); right = std::numeric_limits<int>::min();
bottom = std::numeric_limits<int>::min(); bottom = std::numeric_limits<int>::min();
} }
void update(int x, int y) void update(int x, int y)
{ {
if (x < left) left = x; if (x < left) left = x;
@ -55,7 +55,7 @@ void crop_glyphs(std::vector<DataFile::glyphentry_t> &glyphtable,
{ {
if (glyph.data.size() == 0) if (glyph.data.size() == 0)
continue; // Dummy glyph continue; // Dummy glyph
for (int y = 0; y < fontinfo.max_height; y++) for (int y = 0; y < fontinfo.max_height; y++)
{ {
for (int x = 0; x < fontinfo.max_width; x++) for (int x = 0; x < fontinfo.max_width; x++)
@ -65,10 +65,10 @@ void crop_glyphs(std::vector<DataFile::glyphentry_t> &glyphtable,
} }
} }
} }
if (bbox.right < bbox.left) if (bbox.right < bbox.left)
return; // There were no glyphs return; // There were no glyphs
// Crop the glyphs to that // Crop the glyphs to that
size_t old_w = fontinfo.max_width; size_t old_w = fontinfo.max_width;
size_t new_w = bbox.right - bbox.left + 1; size_t new_w = bbox.right - bbox.left + 1;
@ -77,22 +77,22 @@ void crop_glyphs(std::vector<DataFile::glyphentry_t> &glyphtable,
{ {
if (glyph.data.size() == 0) if (glyph.data.size() == 0)
continue; // Dummy glyph continue; // Dummy glyph
DataFile::pixels_t old = glyph.data; DataFile::pixels_t old = glyph.data;
glyph.data.clear(); glyph.data.clear();
for (size_t y = 0; y < new_h; y++) for (size_t y = 0; y < new_h; y++)
{ {
for (size_t x = 0; x < new_w; x++) for (size_t x = 0; x < new_w; x++)
{ {
size_t old_x = bbox.left + x; size_t old_x = bbox.left + x;
size_t old_y = bbox.top + y; size_t old_y = bbox.top + y;
size_t old_pos = old_w * old_y + old_x; size_t old_pos = old_w * old_y + old_x;
glyph.data.push_back(old.at(old_pos)); glyph.data.push_back(old.at(old_pos));
} }
} }
} }
fontinfo.max_width = new_w; fontinfo.max_width = new_w;
fontinfo.max_height = new_h; fontinfo.max_height = new_h;
fontinfo.baseline_x -= bbox.left; fontinfo.baseline_x -= bbox.left;
@ -104,7 +104,7 @@ void detect_flags(const std::vector<DataFile::glyphentry_t> &glyphtable,
{ {
if (!glyphtable.size()) if (!glyphtable.size())
return; return;
// Check if all glyphs have equal width // Check if all glyphs have equal width
int width = glyphtable[0].width; int width = glyphtable[0].width;
bool is_monospace = true; bool is_monospace = true;
@ -116,10 +116,10 @@ void detect_flags(const std::vector<DataFile::glyphentry_t> &glyphtable,
break; break;
} }
} }
if (is_monospace) if (is_monospace)
fontinfo.flags |= DataFile::FLAG_MONOSPACE; fontinfo.flags |= DataFile::FLAG_MONOSPACE;
// Check if all glyphs contain only 0 or 15 alpha // Check if all glyphs contain only 0 or 15 alpha
bool is_bw = true; bool is_bw = true;
for (const DataFile::glyphentry_t &g : glyphtable) for (const DataFile::glyphentry_t &g : glyphtable)
@ -134,7 +134,7 @@ void detect_flags(const std::vector<DataFile::glyphentry_t> &glyphtable,
} }
if (!is_bw) break; if (!is_bw) break;
} }
if (is_bw) if (is_bw)
fontinfo.flags |= DataFile::FLAG_BW; fontinfo.flags |= DataFile::FLAG_BW;
} }

View File

@ -16,13 +16,14 @@
#include <ctime> #include <ctime>
#include <map> #include <map>
#include "ccfixes.hh" #include "ccfixes.hh"
#include "gb2312_in_ucs2.h"
using namespace mcufont; using namespace mcufont;
static std::string strip_extension(std::string filename) static std::string strip_extension(std::string filename)
{ {
size_t pos = filename.find_last_of('.'); size_t pos = filename.find_last_of('.');
if (pos == std::string::npos) if (pos == std::string::npos)
{ {
return filename; return filename;
@ -36,41 +37,41 @@ static std::string strip_extension(std::string filename)
static std::unique_ptr<DataFile> load_dat(std::string src) static std::unique_ptr<DataFile> load_dat(std::string src)
{ {
std::ifstream infile(src); std::ifstream infile(src);
if (!infile.good()) if (!infile.good())
{ {
std::cerr << "Could not open " << src << std::endl; std::cerr << "Could not open " << src << std::endl;
return nullptr; return nullptr;
} }
std::unique_ptr<DataFile> f = DataFile::Load(infile); std::unique_ptr<DataFile> f = DataFile::Load(infile);
if (!f) if (!f)
{ {
std::cerr << "Invalid format for .dat file: " << src << std::endl; std::cerr << "Invalid format for .dat file: " << src << std::endl;
return nullptr; return nullptr;
} }
return f; return f;
} }
static bool save_dat(std::string dest, DataFile *f) static bool save_dat(std::string dest, DataFile *f)
{ {
std::ofstream outfile(dest); std::ofstream outfile(dest);
if (!outfile.good()) if (!outfile.good())
{ {
std::cerr << "Could not open " << dest << std::endl; std::cerr << "Could not open " << dest << std::endl;
return false; return false;
} }
f->Save(outfile); f->Save(outfile);
if (!outfile.good()) if (!outfile.good())
{ {
std::cerr << "Could not write to " << dest << std::endl; std::cerr << "Could not write to " << dest << std::endl;
return false; return false;
} }
return true; return true;
} }
@ -85,28 +86,28 @@ static status_t cmd_import_ttf(const std::vector<std::string> &args)
{ {
if (args.size() != 3 && args.size() != 4) if (args.size() != 3 && args.size() != 4)
return STATUS_INVALID; return STATUS_INVALID;
std::string src = args.at(1); std::string src = args.at(1);
int size = std::stoi(args.at(2)); int size = std::stoi(args.at(2));
bool bw = (args.size() == 4 && args.at(3) == "bw"); bool bw = (args.size() == 4 && args.at(3) == "bw");
std::string dest = strip_extension(src) + std::to_string(size) + (bw ? "bw" : "") + ".dat"; std::string dest = strip_extension(src) + std::to_string(size) + (bw ? "bw" : "") + ".dat";
std::ifstream infile(src, std::ios::binary); std::ifstream infile(src);
if (!infile.good()) if (!infile.good())
{ {
std::cerr << "Could not open " << src << std::endl; std::cerr << "Could not open " << src << std::endl;
return STATUS_ERROR; return STATUS_ERROR;
} }
std::cout << "Importing " << src << " to " << dest << std::endl; std::cout << "Importing " << src << " to " << dest << std::endl;
std::unique_ptr<DataFile> f = LoadFreetype(infile, size, bw); std::unique_ptr<DataFile> f = LoadFreetype(infile, size, bw);
mcufont::rlefont::init_dictionary(*f); mcufont::rlefont::init_dictionary(*f);
if (!save_dat(dest, f.get())) if (!save_dat(dest, f.get()))
return STATUS_ERROR; return STATUS_ERROR;
std::cout << "Done: " << f->GetGlyphCount() << " unique glyphs." << std::endl; std::cout << "Done: " << f->GetGlyphCount() << " unique glyphs." << std::endl;
return STATUS_OK; return STATUS_OK;
} }
@ -115,26 +116,26 @@ static status_t cmd_import_bdf(const std::vector<std::string> &args)
{ {
if (args.size() != 2) if (args.size() != 2)
return STATUS_INVALID; return STATUS_INVALID;
std::string src = args.at(1); std::string src = args.at(1);
std::string dest = strip_extension(args.at(1)) + ".dat"; std::string dest = strip_extension(args.at(1)) + ".dat";
std::ifstream infile(src, std::ios::binary); std::ifstream infile(src);
if (!infile.good()) if (!infile.good())
{ {
std::cerr << "Could not open " << src << std::endl; std::cerr << "Could not open " << src << std::endl;
return STATUS_ERROR; return STATUS_ERROR;
} }
std::cout << "Importing " << src << " to " << dest << std::endl; std::cout << "Importing " << src << " to " << dest << std::endl;
std::unique_ptr<DataFile> f = LoadBDF(infile); std::unique_ptr<DataFile> f = LoadBDF(infile);
mcufont::rlefont::init_dictionary(*f); mcufont::rlefont::init_dictionary(*f);
if (!save_dat(dest, f.get())) if (!save_dat(dest, f.get()))
return STATUS_ERROR; return STATUS_ERROR;
std::cout << "Done: " << f->GetGlyphCount() << " unique glyphs." << std::endl; std::cout << "Done: " << f->GetGlyphCount() << " unique glyphs." << std::endl;
return STATUS_OK; return STATUS_OK;
} }
@ -143,9 +144,9 @@ static status_t cmd_filter(const std::vector<std::string> &args)
{ {
if (args.size() < 3) if (args.size() < 3)
return STATUS_INVALID; return STATUS_INVALID;
std::set<int> allowed; std::set<int> allowed;
// Parse arguments // Parse arguments
for (size_t i = 2; i < args.size(); i++) for (size_t i = 2; i < args.size(); i++)
{ {
@ -153,35 +154,41 @@ static status_t cmd_filter(const std::vector<std::string> &args)
size_t pos = s.find('-'); size_t pos = s.find('-');
if (pos == std::string::npos) if (pos == std::string::npos)
{ {
// Single char if(s == "gb2312") {
allowed.insert(std::stoi(s, nullptr, 0)); allowed.insert(
&gb2312_in_ucs2_codetable[0],
&gb2312_in_ucs2_codetable[sizeof(gb2312_in_ucs2_codetable)/sizeof(gb2312_in_ucs2_codetable[0])]);
} else {
// Single char
allowed.insert(std::stoi(s, nullptr, 0));
}
} }
else else
{ {
// Range // Range
int start = std::stoi(s.substr(0, pos), nullptr, 0); int start = std::stoi(s.substr(0, pos), nullptr, 0);
int end = std::stoi(s.substr(pos + 1), nullptr, 0); int end = std::stoi(s.substr(pos + 1), nullptr, 0);
for (int j = start; j <= end; j++) for (int j = start; j <= end; j++)
{ {
allowed.insert(j); allowed.insert(j);
} }
} }
} }
std::string src = args.at(1); std::string src = args.at(1);
std::unique_ptr<DataFile> f = load_dat(src); std::unique_ptr<DataFile> f = load_dat(src);
if (!f) if (!f)
return STATUS_ERROR; return STATUS_ERROR;
std::cout << "Font originally had " << f->GetGlyphCount() << " glyphs." << std::endl; std::cout << "Font originally had " << f->GetGlyphCount() << " glyphs." << std::endl;
// Filter the glyphs // Filter the glyphs
std::vector<DataFile::glyphentry_t> newglyphs; std::vector<DataFile::glyphentry_t> newglyphs;
for (size_t i = 0; i < f->GetGlyphCount(); i++) for (size_t i = 0; i < f->GetGlyphCount(); i++)
{ {
DataFile::glyphentry_t g = f->GetGlyphEntry(i); DataFile::glyphentry_t g = f->GetGlyphEntry(i);
for (size_t j = 0; j < g.chars.size(); j++) for (size_t j = 0; j < g.chars.size(); j++)
{ {
if (!allowed.count(g.chars.at(j))) if (!allowed.count(g.chars.at(j)))
@ -190,23 +197,23 @@ static status_t cmd_filter(const std::vector<std::string> &args)
j--; j--;
} }
} }
if (g.chars.size()) if (g.chars.size())
{ {
newglyphs.push_back(g); newglyphs.push_back(g);
} }
} }
DataFile::fontinfo_t fontinfo = f->GetFontInfo(); DataFile::fontinfo_t fontinfo = f->GetFontInfo();
crop_glyphs(newglyphs, fontinfo); crop_glyphs(newglyphs, fontinfo);
detect_flags(newglyphs, fontinfo); detect_flags(newglyphs, fontinfo);
f.reset(new DataFile(f->GetDictionary(), newglyphs, fontinfo)); f.reset(new DataFile(f->GetDictionary(), newglyphs, fontinfo));
std::cout << "After filtering, " << f->GetGlyphCount() << " glyphs remain." << std::endl; std::cout << "After filtering, " << f->GetGlyphCount() << " glyphs remain." << std::endl;
if (!save_dat(src, f.get())) if (!save_dat(src, f.get()))
return STATUS_ERROR; return STATUS_ERROR;
return STATUS_OK; return STATUS_OK;
} }
@ -214,13 +221,13 @@ static status_t cmd_show_glyph(const std::vector<std::string> &args)
{ {
if (args.size() != 3) if (args.size() != 3)
return STATUS_INVALID; return STATUS_INVALID;
std::string src = args.at(1); std::string src = args.at(1);
std::unique_ptr<DataFile> f = load_dat(src); std::unique_ptr<DataFile> f = load_dat(src);
if (!f) if (!f)
return STATUS_ERROR; return STATUS_ERROR;
size_t index = 0; size_t index = 0;
if (args.at(2) == "largest") if (args.at(2) == "largest")
{ {
@ -237,25 +244,25 @@ static status_t cmd_show_glyph(const std::vector<std::string> &args)
} }
i++; i++;
} }
std::cout << "Index " << index << ", length " << maxlen << std::endl; std::cout << "Index " << index << ", length " << maxlen << std::endl;
} }
else else
{ {
index = strtol(args.at(2).c_str(), nullptr, 0); index = strtol(args.at(2).c_str(), nullptr, 0);
} }
if (index < 0 || index >= f->GetGlyphCount()) if (index >= f->GetGlyphCount())
{ {
std::cerr << "No such glyph " << index << std::endl; std::cerr << "No such glyph " << index << std::endl;
return STATUS_ERROR; return STATUS_ERROR;
} }
std::cout << "Width: " << f->GetGlyphEntry(index).width << std::endl; std::cout << "Width: " << f->GetGlyphEntry(index).width << std::endl;
std::cout << "Chars: "; std::cout << "Chars: ";
for (int c: f->GetGlyphEntry(index).chars) std::cout << c << " "; for (int c: f->GetGlyphEntry(index).chars) std::cout << c << " ";
std::cout << std::endl; std::cout << std::endl;
std::cout << f->GlyphToText(index); std::cout << f->GlyphToText(index);
return STATUS_OK; return STATUS_OK;
} }
@ -264,20 +271,20 @@ static status_t cmd_rlefont_export(const std::vector<std::string> &args)
{ {
if (args.size() != 2 && args.size() != 3) if (args.size() != 2 && args.size() != 3)
return STATUS_INVALID; return STATUS_INVALID;
std::string src = args.at(1); std::string src = args.at(1);
std::string dst = (args.size() == 2) ? strip_extension(src) + ".c" : args.at(2); std::string dst = (args.size() == 2) ? strip_extension(src) + ".c" : args.at(2);
std::unique_ptr<DataFile> f = load_dat(src); std::unique_ptr<DataFile> f = load_dat(src);
if (!f) if (!f)
return STATUS_ERROR; return STATUS_ERROR;
{ {
std::ofstream source(dst); std::ofstream source(dst);
mcufont::rlefont::write_source(source, dst, *f); mcufont::rlefont::write_source(source, dst, *f);
std::cout << "Wrote " << dst << std::endl; std::cout << "Wrote " << dst << std::endl;
} }
return STATUS_OK; return STATUS_OK;
} }
@ -285,15 +292,15 @@ static status_t cmd_rlefont_size(const std::vector<std::string> &args)
{ {
if (args.size() != 2) if (args.size() != 2)
return STATUS_INVALID; return STATUS_INVALID;
std::string src = args.at(1); std::string src = args.at(1);
std::unique_ptr<DataFile> f = load_dat(src); std::unique_ptr<DataFile> f = load_dat(src);
if (!f) if (!f)
return STATUS_ERROR; return STATUS_ERROR;
size_t size = mcufont::rlefont::get_encoded_size(*f); size_t size = mcufont::rlefont::get_encoded_size(*f);
std::cout << "Glyph count: " << f->GetGlyphCount() << std::endl; std::cout << "Glyph count: " << f->GetGlyphCount() << std::endl;
std::cout << "Glyph bbox: " << f->GetFontInfo().max_width << "x" std::cout << "Glyph bbox: " << f->GetFontInfo().max_width << "x"
<< f->GetFontInfo().max_height << " pixels" << std::endl; << f->GetFontInfo().max_height << " pixels" << std::endl;
@ -309,28 +316,28 @@ static status_t cmd_rlefont_optimize(const std::vector<std::string> &args)
{ {
if (args.size() != 2 && args.size() != 3) if (args.size() != 2 && args.size() != 3)
return STATUS_INVALID; return STATUS_INVALID;
std::string src = args.at(1); std::string src = args.at(1);
std::unique_ptr<DataFile> f = load_dat(src); std::unique_ptr<DataFile> f = load_dat(src);
if (!f) if (!f)
return STATUS_ERROR; return STATUS_ERROR;
size_t oldsize = mcufont::rlefont::get_encoded_size(*f); size_t oldsize = mcufont::rlefont::get_encoded_size(*f);
std::cout << "Original size is " << oldsize << " bytes" << std::endl; std::cout << "Original size is " << oldsize << " bytes" << std::endl;
std::cout << "Press ctrl-C at any time to stop." << std::endl; std::cout << "Press ctrl-C at any time to stop." << std::endl;
std::cout << "Results are saved automatically after each iteration." << std::endl; std::cout << "Results are saved automatically after each iteration." << std::endl;
int limit = 100; int limit = 100;
if (args.size() == 3) if (args.size() == 3)
{ {
limit = std::stoi(args.at(2)); limit = std::stoi(args.at(2));
} }
if (limit > 0) if (limit > 0)
std::cout << "Limit is " << limit << " iterations" << std::endl; std::cout << "Limit is " << limit << " iterations" << std::endl;
int i = 0; int i = 0;
time_t oldtime = time(NULL); time_t oldtime = time(NULL);
while (!limit || i < limit) while (!limit || i < limit)
@ -339,20 +346,20 @@ static status_t cmd_rlefont_optimize(const std::vector<std::string> &args)
size_t newsize = mcufont::rlefont::get_encoded_size(*f); size_t newsize = mcufont::rlefont::get_encoded_size(*f);
time_t newtime = time(NULL); time_t newtime = time(NULL);
int bytes_per_min = (oldsize - newsize) * 60 / (newtime - oldtime + 1); int bytes_per_min = (oldsize - newsize) * 60 / (newtime - oldtime + 1);
i++; i++;
std::cout << "iteration " << i << ", size " << newsize std::cout << "iteration " << i << ", size " << newsize
<< " bytes, speed " << bytes_per_min << " B/min" << " bytes, speed " << bytes_per_min << " B/min"
<< std::endl; << std::endl;
{ {
if (!save_dat(src, f.get())) if (!save_dat(src, f.get()))
return STATUS_ERROR; return STATUS_ERROR;
} }
} }
return STATUS_OK; return STATUS_OK;
} }
@ -360,13 +367,13 @@ static status_t cmd_rlefont_show_encoded(const std::vector<std::string> &args)
{ {
if (args.size() != 2) if (args.size() != 2)
return STATUS_INVALID; return STATUS_INVALID;
std::string src = args.at(1); std::string src = args.at(1);
std::unique_ptr<DataFile> f = load_dat(src); std::unique_ptr<DataFile> f = load_dat(src);
if (!f) if (!f)
return STATUS_ERROR; return STATUS_ERROR;
std::unique_ptr<mcufont::rlefont::encoded_font_t> e = std::unique_ptr<mcufont::rlefont::encoded_font_t> e =
mcufont::rlefont::encode_font(*f, false); mcufont::rlefont::encode_font(*f, false);
@ -378,7 +385,7 @@ static status_t cmd_rlefont_show_encoded(const std::vector<std::string> &args)
std::cout << std::setfill('0') << std::setw(2) << std::hex << (int)v << " "; std::cout << std::setfill('0') << std::setw(2) << std::hex << (int)v << " ";
std::cout << std::endl; std::cout << std::endl;
} }
for (mcufont::rlefont::encoded_font_t::refstring_t d : e->ref_dictionary) for (mcufont::rlefont::encoded_font_t::refstring_t d : e->ref_dictionary)
{ {
std::cout << "Dict Ref " << 24 + i++ << ": "; std::cout << "Dict Ref " << 24 + i++ << ": ";
@ -386,7 +393,7 @@ static status_t cmd_rlefont_show_encoded(const std::vector<std::string> &args)
std::cout << std::setfill('0') << std::setw(2) << std::hex << (int)v << " "; std::cout << std::setfill('0') << std::setw(2) << std::hex << (int)v << " ";
std::cout << std::endl; std::cout << std::endl;
} }
i = 0; i = 0;
for (mcufont::rlefont::encoded_font_t::refstring_t g : e->glyphs) for (mcufont::rlefont::encoded_font_t::refstring_t g : e->glyphs)
{ {
@ -395,7 +402,7 @@ static status_t cmd_rlefont_show_encoded(const std::vector<std::string> &args)
std::cout << std::setfill('0') << std::setw(2) << std::hex << (int)v << " "; std::cout << std::setfill('0') << std::setw(2) << std::hex << (int)v << " ";
std::cout << std::endl; std::cout << std::endl;
} }
return STATUS_OK; return STATUS_OK;
} }
@ -403,25 +410,25 @@ static status_t cmd_bwfont_export(const std::vector<std::string> &args)
{ {
if (args.size() != 2 && args.size() != 3) if (args.size() != 2 && args.size() != 3)
return STATUS_INVALID; return STATUS_INVALID;
std::string src = args.at(1); std::string src = args.at(1);
std::string dst = (args.size() == 2) ? strip_extension(src) + ".c" : args.at(2); std::string dst = (args.size() == 2) ? strip_extension(src) + ".c" : args.at(2);
std::unique_ptr<DataFile> f = load_dat(src); std::unique_ptr<DataFile> f = load_dat(src);
if (!f) if (!f)
return STATUS_ERROR; return STATUS_ERROR;
if (!(f->GetFontInfo().flags & DataFile::FLAG_BW)) if (!(f->GetFontInfo().flags & DataFile::FLAG_BW))
{ {
std::cout << "Warning: font is not black and white" << std::endl; std::cout << "Warning: font is not black and white" << std::endl;
} }
{ {
std::ofstream source(dst); std::ofstream source(dst);
mcufont::bwfont::write_source(source, dst, *f); mcufont::bwfont::write_source(source, dst, *f);
std::cout << "Wrote " << dst << std::endl; std::cout << "Wrote " << dst << std::endl;
} }
return STATUS_OK; return STATUS_OK;
} }
@ -464,17 +471,17 @@ int main(int argc, char **argv)
std::vector<std::string> args; std::vector<std::string> args;
for (int i = 1; i < argc; i++) for (int i = 1; i < argc; i++)
args.push_back(argv[i]); args.push_back(argv[i]);
status_t status = STATUS_INVALID; status_t status = STATUS_INVALID;
if (args.size() >= 1 && command_list.count(args.at(0))) if (args.size() >= 1 && command_list.count(args.at(0)))
{ {
status = command_list.find(args.at(0))->second(args); status = command_list.find(args.at(0))->second(args);
} }
if (status == STATUS_INVALID) if (status == STATUS_INVALID)
{ {
std::cout << usage_msg << std::endl; std::cout << usage_msg << std::endl;
} }
return status; return status;
} }

View File

@ -17,15 +17,15 @@ std::unique_ptr<DataFile::pixels_t> random_substring(const DataFile &datafile, r
{ {
std::uniform_int_distribution<size_t> dist1(0, datafile.GetGlyphCount() - 1); std::uniform_int_distribution<size_t> dist1(0, datafile.GetGlyphCount() - 1);
size_t index = dist1(rnd); size_t index = dist1(rnd);
const DataFile::pixels_t &pixels = datafile.GetGlyphEntry(index).data; const DataFile::pixels_t &pixels = datafile.GetGlyphEntry(index).data;
std::uniform_int_distribution<size_t> dist2(2, pixels.size()); std::uniform_int_distribution<size_t> dist2(2, pixels.size());
size_t length = dist2(rnd); size_t length = dist2(rnd);
std::uniform_int_distribution<size_t> dist3(0, pixels.size() - length); std::uniform_int_distribution<size_t> dist3(0, pixels.size() - length);
size_t start = dist3(rnd); size_t start = dist3(rnd);
std::unique_ptr<DataFile::pixels_t> result; std::unique_ptr<DataFile::pixels_t> result;
result.reset(new DataFile::pixels_t(pixels.begin() + start, result.reset(new DataFile::pixels_t(pixels.begin() + start,
pixels.begin() + start + length)); pixels.begin() + start + length));
@ -36,22 +36,22 @@ std::unique_ptr<DataFile::pixels_t> random_substring(const DataFile &datafile, r
void optimize_worst(DataFile &datafile, size_t &size, rnd_t &rnd, bool verbose) void optimize_worst(DataFile &datafile, size_t &size, rnd_t &rnd, bool verbose)
{ {
std::uniform_int_distribution<size_t> dist(0, 1); std::uniform_int_distribution<size_t> dist(0, 1);
DataFile trial = datafile; DataFile trial = datafile;
size_t worst = trial.GetLowScoreIndex(); size_t worst = trial.GetLowScoreIndex();
DataFile::dictentry_t d = trial.GetDictionaryEntry(worst); DataFile::dictentry_t d = trial.GetDictionaryEntry(worst);
d.replacement = *random_substring(datafile, rnd); d.replacement = *random_substring(datafile, rnd);
d.ref_encode = dist(rnd); d.ref_encode = dist(rnd);
trial.SetDictionaryEntry(worst, d); trial.SetDictionaryEntry(worst, d);
size_t newsize = get_encoded_size(trial); size_t newsize = get_encoded_size(trial);
if (newsize < size) if (newsize < size)
{ {
d.score = size - newsize; d.score = size - newsize;
datafile.SetDictionaryEntry(worst, d); datafile.SetDictionaryEntry(worst, d);
size = newsize; size = newsize;
if (verbose) if (verbose)
std::cout << "optimize_worst: replaced " << worst std::cout << "optimize_worst: replaced " << worst
<< " score " << d.score << std::endl; << " score " << d.score << std::endl;
@ -67,15 +67,15 @@ void optimize_any(DataFile &datafile, size_t &size, rnd_t &rnd, bool verbose)
DataFile::dictentry_t d = trial.GetDictionaryEntry(index); DataFile::dictentry_t d = trial.GetDictionaryEntry(index);
d.replacement = *random_substring(datafile, rnd); d.replacement = *random_substring(datafile, rnd);
trial.SetDictionaryEntry(index, d); trial.SetDictionaryEntry(index, d);
size_t newsize = get_encoded_size(trial); size_t newsize = get_encoded_size(trial);
if (newsize < size) if (newsize < size)
{ {
d.score = size - newsize; d.score = size - newsize;
datafile.SetDictionaryEntry(index, d); datafile.SetDictionaryEntry(index, d);
size = newsize; size = newsize;
if (verbose) if (verbose)
std::cout << "optimize_any: replaced " << index std::cout << "optimize_any: replaced " << index
<< " score " << d.score << std::endl; << " score " << d.score << std::endl;
@ -89,16 +89,16 @@ void optimize_expand(DataFile &datafile, size_t &size, rnd_t &rnd, bool verbose,
std::uniform_int_distribution<size_t> dist1(0, DataFile::dictionarysize - 1); std::uniform_int_distribution<size_t> dist1(0, DataFile::dictionarysize - 1);
size_t index = dist1(rnd); size_t index = dist1(rnd);
DataFile::dictentry_t d = trial.GetDictionaryEntry(index); DataFile::dictentry_t d = trial.GetDictionaryEntry(index);
std::uniform_int_distribution<size_t> dist3(1, 3); std::uniform_int_distribution<size_t> dist3(1, 3);
size_t count = dist3(rnd); size_t count = dist3(rnd);
for (size_t i = 0; i < count; i++) for (size_t i = 0; i < count; i++)
{ {
std::uniform_int_distribution<size_t> booldist(0, 1); std::uniform_int_distribution<size_t> booldist(0, 1);
std::uniform_int_distribution<size_t> pixeldist(0, 15); std::uniform_int_distribution<size_t> pixeldist(0, 15);
uint8_t pixel; uint8_t pixel;
if (binary_only) if (binary_only)
{ {
pixel = booldist(rnd) ? 15 : 0; pixel = booldist(rnd) ? 15 : 0;
@ -107,9 +107,9 @@ void optimize_expand(DataFile &datafile, size_t &size, rnd_t &rnd, bool verbose,
{ {
pixel = pixeldist(rnd); pixel = pixeldist(rnd);
} }
bool prepend = booldist(rnd); bool prepend = booldist(rnd);
if (prepend) if (prepend)
{ {
d.replacement.insert(d.replacement.begin(), pixel); d.replacement.insert(d.replacement.begin(), pixel);
@ -119,17 +119,17 @@ void optimize_expand(DataFile &datafile, size_t &size, rnd_t &rnd, bool verbose,
d.replacement.push_back(pixel); d.replacement.push_back(pixel);
} }
} }
trial.SetDictionaryEntry(index, d); trial.SetDictionaryEntry(index, d);
size_t newsize = get_encoded_size(trial); size_t newsize = get_encoded_size(trial);
if (newsize < size) if (newsize < size)
{ {
d.score = size - newsize; d.score = size - newsize;
datafile.SetDictionaryEntry(index, d); datafile.SetDictionaryEntry(index, d);
size = newsize; size = newsize;
if (verbose) if (verbose)
std::cout << "optimize_expand: expanded " << index std::cout << "optimize_expand: expanded " << index
<< " by " << count << " pixels, score " << d.score << std::endl; << " by " << count << " pixels, score " << d.score << std::endl;
@ -143,33 +143,33 @@ void optimize_trim(DataFile &datafile, size_t &size, rnd_t &rnd, bool verbose)
std::uniform_int_distribution<size_t> dist1(0, DataFile::dictionarysize - 1); std::uniform_int_distribution<size_t> dist1(0, DataFile::dictionarysize - 1);
size_t index = dist1(rnd); size_t index = dist1(rnd);
DataFile::dictentry_t d = trial.GetDictionaryEntry(index); DataFile::dictentry_t d = trial.GetDictionaryEntry(index);
if (d.replacement.size() <= 2) return; if (d.replacement.size() <= 2) return;
std::uniform_int_distribution<size_t> dist2(0, std::min((int)d.replacement.size() / 2, 5)); std::uniform_int_distribution<size_t> dist2(0, std::min((int)d.replacement.size() / 2, 5));
size_t start = dist2(rnd); size_t start = dist2(rnd);
size_t end = dist2(rnd); size_t end = dist2(rnd);
if (start) if (start)
{ {
d.replacement.erase(d.replacement.begin(), d.replacement.begin() + start); d.replacement.erase(d.replacement.begin(), d.replacement.begin() + start);
} }
if (end) if (end)
{ {
d.replacement.erase(d.replacement.end() - end, d.replacement.end() - 1); d.replacement.erase(d.replacement.end() - end, d.replacement.end() - 1);
} }
trial.SetDictionaryEntry(index, d); trial.SetDictionaryEntry(index, d);
size_t newsize = get_encoded_size(trial); size_t newsize = get_encoded_size(trial);
if (newsize < size) if (newsize < size)
{ {
d.score = size - newsize; d.score = size - newsize;
datafile.SetDictionaryEntry(index, d); datafile.SetDictionaryEntry(index, d);
size = newsize; size = newsize;
if (verbose) if (verbose)
std::cout << "optimize_trim: trimmed " << index std::cout << "optimize_trim: trimmed " << index
<< " by " << start << " pixels from start and " << " by " << start << " pixels from start and "
@ -184,19 +184,19 @@ void optimize_refdict(DataFile &datafile, size_t &size, rnd_t &rnd, bool verbose
std::uniform_int_distribution<size_t> dist1(0, DataFile::dictionarysize - 1); std::uniform_int_distribution<size_t> dist1(0, DataFile::dictionarysize - 1);
size_t index = dist1(rnd); size_t index = dist1(rnd);
DataFile::dictentry_t d = trial.GetDictionaryEntry(index); DataFile::dictentry_t d = trial.GetDictionaryEntry(index);
d.ref_encode = !d.ref_encode; d.ref_encode = !d.ref_encode;
trial.SetDictionaryEntry(index, d); trial.SetDictionaryEntry(index, d);
size_t newsize = get_encoded_size(trial); size_t newsize = get_encoded_size(trial);
if (newsize < size) if (newsize < size)
{ {
d.score = size - newsize; d.score = size - newsize;
datafile.SetDictionaryEntry(index, d); datafile.SetDictionaryEntry(index, d);
size = newsize; size = newsize;
if (verbose) if (verbose)
std::cout << "optimize_refdict: switched " << index std::cout << "optimize_refdict: switched " << index
<< " to " << (d.ref_encode ? "ref" : "RLE") << " to " << (d.ref_encode ? "ref" : "RLE")
@ -212,24 +212,24 @@ void optimize_combine(DataFile &datafile, size_t &size, rnd_t &rnd, bool verbose
size_t worst = datafile.GetLowScoreIndex(); size_t worst = datafile.GetLowScoreIndex();
size_t index1 = dist1(rnd); size_t index1 = dist1(rnd);
size_t index2 = dist1(rnd); size_t index2 = dist1(rnd);
const DataFile::pixels_t &part1 = datafile.GetDictionaryEntry(index1).replacement; const DataFile::pixels_t &part1 = datafile.GetDictionaryEntry(index1).replacement;
const DataFile::pixels_t &part2 = datafile.GetDictionaryEntry(index2).replacement; const DataFile::pixels_t &part2 = datafile.GetDictionaryEntry(index2).replacement;
DataFile::dictentry_t d; DataFile::dictentry_t d;
d.replacement = part1; d.replacement = part1;
d.replacement.insert(d.replacement.end(), part2.begin(), part2.end()); d.replacement.insert(d.replacement.end(), part2.begin(), part2.end());
d.ref_encode = true; d.ref_encode = true;
trial.SetDictionaryEntry(worst, d); trial.SetDictionaryEntry(worst, d);
size_t newsize = get_encoded_size(trial); size_t newsize = get_encoded_size(trial);
if (newsize < size) if (newsize < size)
{ {
d.score = size - newsize; d.score = size - newsize;
datafile.SetDictionaryEntry(worst, d); datafile.SetDictionaryEntry(worst, d);
size = newsize; size = newsize;
if (verbose) if (verbose)
std::cout << "optimize_combine: combined " << index1 std::cout << "optimize_combine: combined " << index1
<< " and " << index2 << " to replace " << worst << " and " << index2 << " to replace " << worst
@ -241,27 +241,27 @@ void optimize_combine(DataFile &datafile, size_t &size, rnd_t &rnd, bool verbose
void optimize_encpart(DataFile &datafile, size_t &size, rnd_t &rnd, bool verbose) void optimize_encpart(DataFile &datafile, size_t &size, rnd_t &rnd, bool verbose)
{ {
std::unique_ptr<encoded_font_t> e = encode_font(datafile); std::unique_ptr<encoded_font_t> e = encode_font(datafile);
// Pick a random encoded glyph // Pick a random encoded glyph
std::uniform_int_distribution<size_t> dist1(0, datafile.GetGlyphCount() - 1); std::uniform_int_distribution<size_t> dist1(0, datafile.GetGlyphCount() - 1);
size_t index = dist1(rnd); size_t index = dist1(rnd);
const encoded_font_t::refstring_t &refstr = e->glyphs.at(index); const encoded_font_t::refstring_t &refstr = e->glyphs.at(index);
if (refstr.size() < 2) if (refstr.size() < 2)
return; return;
// Pick a random part of it // Pick a random part of it
std::uniform_int_distribution<size_t> dist2(2, refstr.size()); std::uniform_int_distribution<size_t> dist2(2, refstr.size());
size_t length = dist2(rnd); size_t length = dist2(rnd);
std::uniform_int_distribution<size_t> dist3(0, refstr.size() - length); std::uniform_int_distribution<size_t> dist3(0, refstr.size() - length);
size_t start = dist3(rnd); size_t start = dist3(rnd);
// Decode that part // Decode that part
encoded_font_t::refstring_t substr(refstr.begin() + start, encoded_font_t::refstring_t substr(refstr.begin() + start,
refstr.begin() + start + length); refstr.begin() + start + length);
std::unique_ptr<DataFile::pixels_t> decoded = std::unique_ptr<DataFile::pixels_t> decoded =
decode_glyph(*e, substr, datafile.GetFontInfo()); decode_glyph(*e, substr, datafile.GetFontInfo());
// Add that as a new dictionary entry // Add that as a new dictionary entry
DataFile trial = datafile; DataFile trial = datafile;
size_t worst = trial.GetLowScoreIndex(); size_t worst = trial.GetLowScoreIndex();
@ -269,15 +269,15 @@ void optimize_encpart(DataFile &datafile, size_t &size, rnd_t &rnd, bool verbose
d.replacement = *decoded; d.replacement = *decoded;
d.ref_encode = true; d.ref_encode = true;
trial.SetDictionaryEntry(worst, d); trial.SetDictionaryEntry(worst, d);
size_t newsize = get_encoded_size(trial); size_t newsize = get_encoded_size(trial);
if (newsize < size) if (newsize < size)
{ {
d.score = size - newsize; d.score = size - newsize;
datafile.SetDictionaryEntry(worst, d); datafile.SetDictionaryEntry(worst, d);
size = newsize; size = newsize;
if (verbose) if (verbose)
std::cout << "optimize_encpart: replaced " << worst std::cout << "optimize_encpart: replaced " << worst
<< " score " << d.score << std::endl; << " score " << d.score << std::endl;
@ -306,14 +306,14 @@ void optimize_parallel(DataFile &datafile, size_t &size, rnd_t &rnd, bool verbos
std::vector<size_t> sizes; std::vector<size_t> sizes;
std::vector<rnd_t> rnds; std::vector<rnd_t> rnds;
std::vector<std::unique_ptr<std::thread> > threads; std::vector<std::unique_ptr<std::thread> > threads;
for (int i = 0; i < num_threads; i++) for (int i = 0; i < num_threads; i++)
{ {
datafiles.emplace_back(datafile); datafiles.emplace_back(datafile);
sizes.emplace_back(size); sizes.emplace_back(size);
rnds.emplace_back(rnd()); rnds.emplace_back(rnd());
} }
for (int i = 0; i < num_threads; i++) for (int i = 0; i < num_threads; i++)
{ {
threads.emplace_back(new std::thread(optimize_pass, threads.emplace_back(new std::thread(optimize_pass,
@ -322,12 +322,12 @@ void optimize_parallel(DataFile &datafile, size_t &size, rnd_t &rnd, bool verbos
std::ref(rnds.at(i)), std::ref(rnds.at(i)),
verbose)); verbose));
} }
for (int i = 0; i < num_threads; i++) for (int i = 0; i < num_threads; i++)
{ {
threads.at(i)->join(); threads.at(i)->join();
} }
int best = std::min_element(sizes.begin(), sizes.end()) - sizes.begin(); int best = std::min_element(sizes.begin(), sizes.end()) - sizes.begin();
size = sizes.at(best); size = sizes.at(best);
datafile = datafiles.at(best); datafile = datafiles.at(best);
@ -338,17 +338,17 @@ void optimize_parallel(DataFile &datafile, size_t &size, rnd_t &rnd, bool verbos
void update_scores(DataFile &datafile, bool verbose) void update_scores(DataFile &datafile, bool verbose)
{ {
size_t oldsize = get_encoded_size(datafile); size_t oldsize = get_encoded_size(datafile);
for (size_t i = 0; i < DataFile::dictionarysize; i++) for (size_t i = 0; i < DataFile::dictionarysize; i++)
{ {
DataFile trial = datafile; DataFile trial = datafile;
DataFile::dictentry_t dummy = {}; DataFile::dictentry_t dummy = {};
trial.SetDictionaryEntry(i, dummy); trial.SetDictionaryEntry(i, dummy);
size_t newsize = get_encoded_size(trial); size_t newsize = get_encoded_size(trial);
DataFile::dictentry_t d = datafile.GetDictionaryEntry(i); DataFile::dictentry_t d = datafile.GetDictionaryEntry(i);
d.score = newsize - oldsize; d.score = newsize - oldsize;
if (d.score > 0) if (d.score > 0)
{ {
datafile.SetDictionaryEntry(i, d); datafile.SetDictionaryEntry(i, d);
@ -356,7 +356,7 @@ void update_scores(DataFile &datafile, bool verbose)
else else
{ {
datafile.SetDictionaryEntry(i, dummy); datafile.SetDictionaryEntry(i, dummy);
if (verbose && d.replacement.size() != 0) if (verbose && d.replacement.size() != 0)
std::cout << "update_scores: dropped " << i std::cout << "update_scores: dropped " << i
<< " score " << -d.score << std::endl; << " score " << -d.score << std::endl;
@ -367,18 +367,18 @@ void update_scores(DataFile &datafile, bool verbose)
void init_dictionary(DataFile &datafile) void init_dictionary(DataFile &datafile)
{ {
rnd_t rnd(datafile.GetSeed()); rnd_t rnd(datafile.GetSeed());
if (datafile.GetGlyphCount() == 0) if (datafile.GetGlyphCount() == 0)
return; return;
std::set<DataFile::pixels_t> seen_substrings; std::set<DataFile::pixels_t> seen_substrings;
std::set<DataFile::pixels_t> added_substrings; std::set<DataFile::pixels_t> added_substrings;
size_t i = 0; size_t i = 0;
while (i < DataFile::dictionarysize) while (i < DataFile::dictionarysize)
{ {
DataFile::pixels_t substring = *random_substring(datafile, rnd); DataFile::pixels_t substring = *random_substring(datafile, rnd);
if (!seen_substrings.count(substring)) if (!seen_substrings.count(substring))
{ {
seen_substrings.insert(substring); seen_substrings.insert(substring);
@ -400,16 +400,16 @@ void optimize(DataFile &datafile, size_t iterations)
{ {
bool verbose = false; bool verbose = false;
rnd_t rnd(datafile.GetSeed()); rnd_t rnd(datafile.GetSeed());
update_scores(datafile, verbose); update_scores(datafile, verbose);
size_t size = get_encoded_size(datafile); size_t size = get_encoded_size(datafile);
for (size_t i = 0; i < iterations; i++) for (size_t i = 0; i < iterations; i++)
{ {
optimize_parallel(datafile, size, rnd, verbose); optimize_parallel(datafile, size, rnd, verbose);
} }
std::uniform_int_distribution<size_t> dist(0, std::numeric_limits<uint32_t>::max()); std::uniform_int_distribution<size_t> dist(0, std::numeric_limits<uint32_t>::max());
datafile.SetSeed(dist(rnd)); datafile.SetSeed(dist(rnd));
} }