diff options
Diffstat (limited to 'tools/mcufontencoder/src/datafile.hh')
-rw-r--r-- | tools/mcufontencoder/src/datafile.hh | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/tools/mcufontencoder/src/datafile.hh b/tools/mcufontencoder/src/datafile.hh new file mode 100644 index 00000000..460e6039 --- /dev/null +++ b/tools/mcufontencoder/src/datafile.hh @@ -0,0 +1,174 @@ +// Class to store the data of a font while it is being processed. +// This class can be safely cloned using the default copy constructor. + +#pragma once +#include <cstdint> +#include <vector> +#include <string> +#include <fstream> +#include <memory> +#include <map> + +namespace mcufont +{ + +class DataFile +{ +public: + typedef std::vector<uint8_t> pixels_t; + + struct dictentry_t + { + pixels_t replacement; // The expanded version of this block. + int score; // Number of bytes that having this entry saves. + bool ref_encode; // Encode using references to other dictionary entries. + + dictentry_t(): score(0), ref_encode(false) {} + }; + + struct glyphentry_t + { + pixels_t data; // The full data of the glyph. + std::vector<int> chars; // Characters that this glyph represents. + int width; // Tracking width of the character. + }; + + struct fontinfo_t + { + std::string name; // Name of the typeface + int max_width; // Width of the character bounding box. + int max_height; // Height of the character bounding box. + int baseline_x; // X coordinate (from left) of the baseline. + int baseline_y; // Y coordinate (from top) of the baseline. + int line_height; // Line height (vertical advance). + int flags; + }; + + static const int FLAG_MONOSPACE = 0x01; + static const int FLAG_BW = 0x02; + + // Construct from data in memory. + DataFile(const std::vector<dictentry_t> &dictionary, + const std::vector<glyphentry_t> &glyphs, + const fontinfo_t &fontinfo); + + // Save to a file (custom format) + void Save(std::ostream &file) const; + + // Load from a file (custom format) + // Returns nullptr if load fails. + static std::unique_ptr<DataFile> Load(std::istream &file); + + // Get or set an entry in the dictionary. The size of the dictionary + // is constant. Entries 0 to 23 are reserved for special purposes. + static const size_t dictionarysize = 256 - 24; + const dictentry_t &GetDictionaryEntry(size_t index) const + { return m_dictionary.at(index); } + void SetDictionaryEntry(size_t index, const dictentry_t &value); + const std::vector<dictentry_t> &GetDictionary() const + { return m_dictionary; } + + // Get the index of the dictionary entry with the lowest score. + size_t GetLowScoreIndex() const + { return m_lowscoreindex; } + + // Get an entry in the glyph table. + size_t GetGlyphCount() const + { return m_glyphtable.size(); } + const glyphentry_t &GetGlyphEntry(size_t index) const + { return m_glyphtable.at(index); } + const std::vector<glyphentry_t> &GetGlyphTable() const + { return m_glyphtable; } + + // Create a map of char indices to glyph indices + std::map<size_t, size_t> GetCharToGlyphMap() const; + + // Get the information that applies to all glyphs. + const fontinfo_t &GetFontInfo() const + { return m_fontinfo; } + + // Show a glyph as text. + std::string GlyphToText(size_t index) const; + + // Get the random generator seed + // The seed is stored in the datafile to get deterministic behaviour + // for debugging. + uint32_t GetSeed() const { return m_seed; } + void SetSeed(uint32_t seed) { m_seed = seed; } + +private: + std::vector<dictentry_t> m_dictionary; + std::vector<glyphentry_t> m_glyphtable; + fontinfo_t m_fontinfo; + uint32_t m_seed; + + size_t m_lowscoreindex; + + void UpdateLowScoreIndex(); +}; + +std::ostream& operator<<(std::ostream& os, const DataFile::pixels_t& str); +std::istream& operator>>(std::istream& is, DataFile::pixels_t& str); + +} + +#ifdef CXXTEST_RUNNING +#include <cxxtest/TestSuite.h> + +using namespace mcufont; + +class DataFileTests: public CxxTest::TestSuite +{ +public: + void testFileLoad() + { + std::istringstream s(testfile); + std::unique_ptr<DataFile> f = DataFile::Load(s); + + TS_ASSERT_EQUALS(f->GetFontInfo().name, "Sans Serif"); + TS_ASSERT_EQUALS(f->GetFontInfo().max_width, 4); + TS_ASSERT_EQUALS(f->GetFontInfo().max_height, 6); + TS_ASSERT_EQUALS(f->GetDictionaryEntry(0).score, 5); + TS_ASSERT_EQUALS(f->GetDictionaryEntry(1).score, 13); + TS_ASSERT_EQUALS(f->GetGlyphCount(), 3); + + 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 + }; + TS_ASSERT_EQUALS(f->GetGlyphEntry(0).data.size(), 24); + TS_ASSERT(f->GetGlyphEntry(0).data == expected); + } + + void testFileSave() + { + std::istringstream is1(testfile); + std::unique_ptr<DataFile> f1 = DataFile::Load(is1); + + std::ostringstream os; + f1->Save(os); + + std::string text = os.str(); + std::istringstream is2(text); + std::unique_ptr<DataFile> f2 = DataFile::Load(is2); + + TS_ASSERT_EQUALS(f1->GetFontInfo().name, f2->GetFontInfo().name); + TS_ASSERT(f1->GetGlyphEntry(0).data == f2->GetGlyphEntry(0).data); + } + +private: + static constexpr const char *testfile = + "Version 1\n" + "FontName Sans Serif\n" + "MaxWidth 4\n" + "MaxHeight 6\n" + "BaselineX 1\n" + "BaselineY 1\n" + "DictEntry 5 0 0F0F0\n" + "DictEntry 13 0 F0F0F0\n" + "DictEntry 1 0 F0F0F0\n" + "Glyph 1,2,3 4 0F0F0F0F0F0F0F0F0F0F0F0F\n" + "Glyph 4 4 0F0F0F0F0F0F0F0F0F0F0F0F\n" + "Glyph 5 4 0F0F0F0F0F0F0F0F0F0F0F0F\n"; +}; + +#endif |