Advertisement
dan-masek

Bitmap Font encoding prototype

Mar 28th, 2018
269
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.21 KB | None | 0 0
  1. #include <boost/algorithm/string/classification.hpp>
  2. #include <boost/algorithm/string/split.hpp>
  3.  
  4. #include <array>
  5. #include <cstdint>
  6. #include <fstream>
  7. #include <iostream>
  8. #include <iomanip>
  9. #include <string>
  10. #include <sstream>
  11. #include <vector>
  12.  
  13.  
  14. struct glyph
  15. {
  16.     uint8_t code;
  17.     std::array<uint16_t, 16> rows;
  18. };
  19.  
  20. struct font
  21. {
  22.     std::string header;
  23.     std::vector<glyph> glyphs;
  24. };
  25.  
  26. font load_font_txt(std::string const& file_name)
  27. {
  28.     font f;
  29.  
  30.     std::ifstream input(file_name);
  31.     getline(input, f.header);
  32.     for (std::string line; getline(input, line);) {
  33.         std::vector<std::string> parts;
  34.         boost::split(parts, line, boost::is_any_of("|"));
  35.         std::vector<std::string> rows;
  36.         boost::split(rows, parts[1], boost::is_any_of(" "));
  37.  
  38.         glyph g;
  39.         g.code = static_cast<uint8_t>(std::stoul(parts[0]));
  40.         for (uint32_t i(0); i < 16; ++i) {
  41.             g.rows[i] = static_cast<uint16_t>(std::stoul(rows[i], nullptr, 16));
  42.         }
  43.  
  44.         f.glyphs.push_back(g);
  45.     }
  46.  
  47.     return f;
  48. }
  49.  
  50. void encode_v0(font const& f, std::vector<uint8_t>& buffer)
  51. {
  52.     std::copy(f.header.begin(), f.header.end(), std::back_inserter(buffer));
  53.     buffer.push_back('\r');
  54.     buffer.push_back('\n');
  55.     for (glyph const& g : f.glyphs) {
  56.         std::ostringstream s;
  57.         s << int(g.code) << "|";
  58.         for (uint32_t i(0); i < 16; ++i) {
  59.             s << (i ? " " : "") << std::uppercase
  60.                 << std::setfill('0') << std::setw(3) << std::hex
  61.                 << g.rows[i];
  62.         }
  63.         s << "\r\n";
  64.         std::string temp(s.str());
  65.         std::copy(temp.begin(), temp.end(), std::back_inserter(buffer));
  66.     }
  67. }
  68.  
  69. void encode_header(font const& f, std::vector<uint8_t>& buffer)
  70. {
  71.     // Store header directly
  72.     std::copy(f.header.begin(), f.header.end(), std::back_inserter(buffer));
  73.     // and terminate with null
  74.     buffer.push_back(0);
  75. }
  76.  
  77.  
  78. struct simple_bitstream
  79. {
  80.     simple_bitstream(std::vector<uint8_t>& buffer)
  81.         : buf_(buffer)
  82.         , temp_(0)
  83.         , temp_size_(0)
  84.     {
  85.     }
  86.  
  87.     void write_bits(uint32_t v, uint8_t bits)
  88.     {
  89.         if (bits) {
  90.             write_bits(v >> 1, bits - 1);
  91.             write_bit(v & 1);
  92.         }        
  93.     }
  94.  
  95.     void write_bit(uint8_t v)
  96.     {
  97.         temp_ = (temp_ << 1) | (v & 1);
  98.         ++temp_size_;
  99.         if (temp_size_ == 8) {
  100.             buf_.push_back(temp_);
  101.             temp_size_ = 0;
  102.             temp_ = 0;
  103.         }
  104.     }
  105.  
  106.     void flush()
  107.     {
  108.         for (; temp_size_;) {
  109.             write_bit(0);
  110.         }
  111.     }
  112.  
  113.     std::vector<uint8_t>& buf_;
  114.     uint8_t temp_;
  115.     uint8_t temp_size_;
  116. };
  117.  
  118. void encode_v1(font const& f, std::vector<uint8_t>& buffer)
  119. {
  120.     encode_header(f, buffer);
  121.     simple_bitstream b(buffer);
  122.     for (glyph const& g : f.glyphs) {
  123.         // Code using 1 byte
  124.         b.write_bits(g.code, 8);
  125.         for (uint32_t i(0); i < 16; ++i) {
  126.             // Pixel using 2 bytes, most significant bits first, prefixed by 4 bit padding
  127.             b.write_bits(g.rows[i], 16);
  128.         }
  129.     }
  130. }
  131.  
  132. void encode_v2(font const& f, std::vector<uint8_t>& buffer)
  133. {
  134.     encode_header(f, buffer);
  135.     simple_bitstream b(buffer);
  136.     for (glyph const& g : f.glyphs) {
  137.         // Code using 1 byte
  138.         b.write_bits(g.code, 8);
  139.         for (uint32_t i(0); i < 16; i += 2) {
  140.             // 2 pixels using 3 bytes, most significant bits first
  141.             b.write_bits(g.rows[i], 12);
  142.             b.write_bits(g.rows[i + 1], 12);
  143.         }
  144.     }
  145. }
  146.  
  147. void encode_v3(font const& f, std::vector<uint8_t>& buffer)
  148. {
  149.     encode_header(f, buffer);
  150.     simple_bitstream b(buffer);
  151.     for (glyph const& g : f.glyphs) {
  152.         // Code using 1 byte
  153.         b.write_bits(g.code, 8);
  154.  
  155.         for (uint32_t i(0); i < 16; ++i) {
  156.             uint16_t row(g.rows[i]);
  157.             if (row == 0) {
  158.                 // An empty row
  159.                 b.write_bit(1);
  160.             } else {
  161.                 // Verbatim row
  162.                 b.write_bit(0);
  163.                 b.write_bits(row, 12);
  164.             }
  165.         }
  166.     }
  167. }
  168.  
  169. // Find nearest identical preceding row in this glyph
  170. uint8_t find_nearest_copy(glyph const& g, uint32_t i)
  171. {
  172.     uint8_t offset(0);
  173.     uint16_t row(g.rows[i]);
  174.     for (uint8_t j(1); j < i; ++j) {
  175.         if (row == g.rows[i - j]) {
  176.             offset = j;
  177.             break;
  178.         }
  179.     }
  180.     return offset;
  181. }
  182.  
  183. void encode_v4(font const& f, std::vector<uint8_t>& buffer)
  184. {
  185.     uint32_t OP_VERBATIM(0), OP_COPY(1);
  186.  
  187.     encode_header(f, buffer);
  188.     simple_bitstream b(buffer);
  189.     for (glyph const& g : f.glyphs) {
  190.         // Code using 1 byte
  191.         b.write_bits(g.code, 8);
  192.  
  193.         for (uint32_t i(0); i < 16; ++i) {
  194.             uint16_t row(g.rows[i]);
  195.             if (row == 0) {
  196.                 // Empty row, copy with offset 0
  197.                 b.write_bit(OP_COPY);
  198.                 b.write_bits(0, 4);
  199.                 continue;
  200.             }
  201.  
  202.             // Find nearest identical preceding row in this glyph
  203.             uint8_t offset(find_nearest_copy(g, i));
  204.             if (offset) {
  205.                 // Copy with non-zero offset
  206.                 b.write_bit(OP_COPY);
  207.                 b.write_bits(offset, 4);
  208.             } else {
  209.                 // Verbatim row
  210.                 b.write_bit(OP_VERBATIM);
  211.                 b.write_bits(row, 12);
  212.             }
  213.         }
  214.     }
  215. }
  216.  
  217. void encode_v5(font const& f, std::vector<uint8_t>& buffer)
  218. {
  219.     uint32_t OP_VERBATIM(0), OP_COPY(1), OP_EMPTY(2);
  220.  
  221.     encode_header(f, buffer);
  222.     simple_bitstream b(buffer);
  223.     for (glyph const& g : f.glyphs) {
  224.         // Code using 1 byte
  225.         b.write_bits(g.code, 8);
  226.  
  227.         for (uint32_t i(0); i < 16; ++i) {
  228.             uint16_t row(g.rows[i]);
  229.             if (row == 0) {
  230.                 // Empty row
  231.                 b.write_bits(OP_EMPTY, 2);
  232.                 continue;
  233.             }
  234.  
  235.             // Find nearest identical preceding row in this glyph
  236.             uint8_t offset(find_nearest_copy(g, i));
  237.             if (offset) {
  238.                 // Copy with non-zero offset
  239.                 b.write_bits(OP_COPY, 2);
  240.                 b.write_bits(offset, 4);
  241.             } else {
  242.                 // Verbatim row
  243.                 b.write_bits(OP_VERBATIM, 2);
  244.                 b.write_bits(row, 12);
  245.             }
  246.         }
  247.     }
  248. }
  249.  
  250. uint32_t find_end_row(glyph const& g)
  251. {
  252.     uint32_t end_row(16);
  253.     for (uint32_t i(0); i < 16; ++i) {
  254.         if (g.rows[15 - i] > 0) {
  255.             break;
  256.         }
  257.         --end_row;
  258.     }
  259.     return end_row;
  260. }
  261.  
  262.  
  263. void encode_v6(font const& f, std::vector<uint8_t>& buffer)
  264. {
  265.     uint32_t OP_VERBATIM(0), OP_COPY(1), OP_EMPTY(2), OP_END(3);
  266.  
  267.     encode_header(f, buffer);
  268.     simple_bitstream b(buffer);
  269.     for (glyph const& g : f.glyphs) {
  270.         // Code using 1 byte
  271.         b.write_bits(g.code, 8);
  272.  
  273.         uint32_t end_row(find_end_row(g));
  274.         for (uint32_t i(0); i < end_row; ++i) {
  275.             uint16_t row(g.rows[i]);
  276.             if (row == 0) {
  277.                 // Empty row
  278.                 b.write_bits(OP_EMPTY, 2);
  279.                 continue;
  280.             }
  281.  
  282.             // Find nearest identical preceding row in this glyph
  283.             uint8_t offset(find_nearest_copy(g, i));
  284.             if (offset) {
  285.                 // Copy with non-zero offset
  286.                 b.write_bits(OP_COPY, 2);
  287.                 b.write_bits(offset - 1, 4);
  288.             } else {
  289.                 // Verbatim row
  290.                 b.write_bits(OP_VERBATIM, 2);
  291.                 b.write_bits(row, 12);
  292.             }
  293.         }
  294.         if (end_row < 16) {
  295.             // End the glyph (any remaining rows are empty)
  296.             b.write_bits(OP_END, 2);
  297.         }
  298.     }
  299. }
  300.  
  301.  
  302. int main()
  303. {
  304.     font f(load_font_txt("font_full.txt"));
  305.  
  306.     std::vector<std::vector<uint8_t>> buf(7);
  307.    
  308.     encode_v0(f, buf[0]);
  309.     encode_v1(f, buf[1]);
  310.     encode_v2(f, buf[2]);
  311.     encode_v3(f, buf[3]);
  312.     encode_v4(f, buf[4]);
  313.     encode_v5(f, buf[5]);
  314.     encode_v6(f, buf[6]);
  315.  
  316.     for (uint32_t i(0); i < buf.size(); ++i) {
  317.         std::cout << "Variant " << i << ": " << buf[i].size() << " bytes\n";
  318.     }
  319.  
  320.     return 0;
  321. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement