using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Windows.Forms; using System.Xml.Linq; namespace McBitFont { public partial class Export : Form { private MainForm mainForm; //private List comments = new List(); private Dictionary comments = new Dictionary(); public Export(object sender) { InitializeComponent(); mainForm = (MainForm)sender; } private void Export_Load(object sender, EventArgs e) { var groupBoxes = Controls.OfType(); foreach (var gb in groupBoxes) { var comboBoxes = gb.Controls.OfType(); foreach (var cb in comboBoxes) { cb.SelectedIndex = 0; } } comments.Add("header", "// File generated by McBitFont v" + MainForm.version + "\n" + "// made by Anton Mukhin (mcfly@mcflyer.ru)\n" + "//\n" + "//\n" ); comments.Add("scan_order", "// Scan order: "); comments.Add("scan_hdir", "// Horizontal direction: "); comments.Add("scan_vdir", "// Vertical direction: "); comments.Add("num_bit_order", "// Bit order: "); comments.Add("num_base", "// Numbers base: "); comments.Add("num_size", "// Numbers size: "); comments.Add("text_format", "// Text format: "); comments.Add("text_lines", "// Numbers per line: "); comments.Add("font_header_map", "// Font header map:\n" + "// packed; // Flag for packed font\n" + "// width; // Font width in pixels (0 - variable width)\n" + "// height; // Font height in pixels\n" + "// space; // Font space in pixels\n" + "// first; // First character code\n" + "// last; // Last character code\n" ); } private void cbOrder_SelectedIndexChanged(object sender, EventArgs e) { switch (cbOrder.SelectedIndex) { case 0: // Columns cbBitOrder.Items[0] = "LSB Top"; cbBitOrder.Items[1] = "MSB Top"; cbLines.Items[0] = "1 Column per line"; break; case 1: // Rows cbBitOrder.Items[0] = "LSB Left"; cbBitOrder.Items[1] = "MSB Left"; cbLines.Items[0] = "1 Row per line"; break; } } private void btnGenerate_Click(object sender, EventArgs e) { string output = ""; int bTotal = 0; txtOutput.Clear(); bool com = cbComments.Checked; bool hdr = cbHeader.Checked; bool packed = cbPacked.Checked; int lines = cbLines.SelectedIndex; int format = cbFormat.SelectedIndex; bool mono = mainForm.monospaced; int lineslim = (int)nudXLines.Value; int fcount = mainForm.frames.Count; int imin, jmin, imax, jmax, idir, jdir; if (com) { // Header comments //output += comments["header"]; output += comments["scan_order"] + cbOrder.Text + "\n"; output += comments["scan_hdir"] + cbHDir.Text + "\n"; output += comments["scan_vdir"] + cbVDir.Text + "\n\n"; output += comments["num_bit_order"] + cbBitOrder.Text + "\n"; output += comments["num_base"] + cbNumBase.Text + "\n"; output += comments["num_size"] + cbNumSize.Text + "\n\n"; output += comments["text_format"] + cbFormat.Text + "\n"; output += comments["text_lines"] + cbLines.Text + "\n\n"; if (hdr) { // comment about meta header map output += comments["font_header_map"] + "\n\n"; } } // Figure out mins and maxes if (cbOrder.SelectedIndex == 0) { if (cbHDir.SelectedIndex == 0) { // Columns; Left to right imin = 0; imax = mainForm.dotWidth; idir = 1; } else { // Columns; Right to left imin = mainForm.dotWidth - 1; imax = -1; idir = -1; } if (cbVDir.SelectedIndex == 0) { // Columns; Top to bottom jmin = 0; jmax = mainForm.dotHeight; jdir = 1; } else { // Columns; Bottom to top jmin = mainForm.dotHeight - 1; jmax = -1; jdir = -1; } } else { if (cbVDir.SelectedIndex == 0) { // Rows; Left to right imin = 0; imax = mainForm.dotHeight; idir = 1; } else { // Rows; Right to left imin = mainForm.dotHeight - 1; imax = -1; idir = -1; } if (cbHDir.SelectedIndex == 0) { // Rows; Top to bottom jmin = 0; jmax = mainForm.dotWidth; jdir = 1; } else { // Rows; Bottom to top jmin = mainForm.dotWidth - 1; jmax = -1; jdir = -1; } } // C data type selection ushort bits = 8; string dataType = "uint8_t"; switch (cbNumSize.SelectedIndex) { case 0: bits = 8; dataType = "uint8_t"; break; case 1: bits = 16; dataType = "uint16_t"; break; case 2: bits = 32; dataType = "uint32_t"; break; } int nbase = 16; string prefix = "0x"; string pref = ""; int pad = 2; switch (cbNumBase.SelectedIndex) { case 0: nbase = 16; prefix = "0x"; pad = cbZeroes.Checked ? bits / 4 : 0; break; case 1: nbase = 2; prefix = "0b"; pad = cbZeroes.Checked ? bits : 0; break; case 2: nbase = 10; prefix = ""; pad = 0; break; } // Array definition if (format == 0 || format == 1) output += "const " + dataType + " " + mainForm.prjName + "[]" + (format == 1 ? "[]" : "") + " = {\n"; // Should we add the meta header? if (hdr) { output += " // Meta header\n" + " " + (packed ? "1" : "0") + ", // Is it a packed font?\n" + " " + (mono || mainForm.frames.Count == 1 ? mainForm.frames.First().width.ToString() : "0") + ", // Font width in pixels; 0 - variable width\n" + " " + mainForm.frames.First().height.ToString() + ", // Font height in pixels\n" + " 0, // Font space (between symbols) in pixels\n" + " " + mainForm.frames.First().code.ToString() + ", // First character code\n" + " " + mainForm.frames.Last().code.ToString() + ", // Last character code\n" ; bTotal += 6*bits / 8; // Count bytes total } // Brackets for 2D array definition string obracket = format == 1 ? "{ " : ""; string cbracket = format == 1 ? " }" : ""; // Number output counter int numcount = 0; if (com) output += " // Data:\n"; MainForm.FrameMiniature flast = mainForm.frames.Last(); foreach (MainForm.FrameMiniature f in mainForm.frames) { // For each frame uint b = 0; // current number bits int t, x, y; // t - calculated bit number; x - actual x; y - actual y if (com && lines != 1 && fcount > 1) { // Comments enabled and other than "1 symbol per line" selected // Print a symbol comment before its data output += " // " + f.code.ToString() + " --> " + mainForm.DecodeSymbol(f.code); if (f.note != "" && f.note != null) output += " (" + f.note.ToString() + ")"; output += "\n"; } if (lines == 1) { // "1 symbol per line" - new line offset output += " "; numcount = 0; } if (!mono && fcount > 1) { // Not a single image; Variable width font - lets post the width as a 1st number // Should we post a prefix to the number? pref = (!cbZeroes.Checked && ((f.width < 10 && nbase == 16) || (f.width < 2 && nbase == 2))) ? "" : prefix; output += (lines != 1 ? " " : "") + pref + Convert.ToString(f.width, nbase).PadLeft(pad, '0') + (lines != 0 ? (lines == 1 ? ", " : "") : ",\n"); bTotal += bits / 8; // Count bytes total // Count posted numbers numcount++; if (lines != 2) numcount = 0; if (lines == 2 && numcount >= lineslim) { numcount = 0; output += "\n "; } } if (lines == 2 && numcount == 0) { // "X numbers per line" - first line of a symbol offset output += " "; } //Figure out mins and maxes for variable width fonts if (!mono && fcount > 1) { if (cbOrder.SelectedIndex == 0) { if (cbHDir.SelectedIndex == 0) { // Columns; Left to right imax = f.width; } else { // Columns; Right to left imin = f.width - 1; } if (cbVDir.SelectedIndex == 0) { // Columns; Top to bottom jmax = f.height; } else { // Columns; Bottom to top jmin = f.height - 1; } } else { if (cbVDir.SelectedIndex == 0) { // Rows; Left to right imax = f.height; } else { // Rows; Right to left imin = f.height - 1; } if (cbHDir.SelectedIndex == 0) { // Rows; Top to bottom jmax = f.width; } else { // Rows; Bottom to top jmin = f.width - 1; } } } t = jdir < 0 ? bits+1 : -1; for (int i = imin; i != imax; i += idir) { if (lines == 0) { // "Column/Row per line" - new line offset output += " " + obracket; numcount = 0; } for (int j = jmin; j != jmax; j += jdir) { if (packed) { t += jdir; if (t < 0 || t % bits == 0) t = jdir < 0 ? bits : 0; } else { if (jdir < 0) t = jmin - j; else t = j; } if (t % bits == 0) b = 0; if (cbOrder.SelectedIndex == 0) { // Columns x = i; y = j; } else { // Rows x = j; y = i; } if (f.data[x, y]) { if ((cbBitOrder.SelectedIndex == 0 && jdir > 0) || (cbBitOrder.SelectedIndex == 1 && jdir < 0)) { // LSB on top/Left b |= (uint)(1 << (t % bits)); } else { // MSB on top/Left b |= (uint)(1 << (bits - (t % bits) - 1)); } } if (((t + 1) % bits == 0) || (j + jdir == jmax && !packed)) { // we have filled a number with bits - let's post it // should we post a comma before the number? output += numcount == 0 ? "" : ", "; // should we post a prefix to the number? pref = (!cbZeroes.Checked && ((b < 10 && nbase == 16) || (b < 2 && nbase == 2))) ? "" : prefix; output += pref + Convert.ToString(b, nbase).PadLeft(pad, '0'); bTotal += bits / 8; // Count bytes total // count posted numbers numcount++; if (lines == 2 && numcount >= lineslim && !(j + jdir == jmax && i + idir == imax)) { // "X numbers per line" - line break numcount = 0; output += ",\n "; } } } if (lines == 0) { // "Column/Row per line" - closing line output += cbracket + ((i + idir == imax) && f.Equals(flast) ? "" : ",") + "\n"; } } if (packed && (f.width * f.height) % bits > 0) { // post leftovers in last number // should we post a prefix to the number? pref = (!cbZeroes.Checked && ((b < 10 && nbase == 16) || (b < 2 && nbase == 2))) ? "" : prefix; output += (numcount > 0? ", " : "") + pref + Convert.ToString(b, nbase).PadLeft(pad, '0'); bTotal += bits / 8; // Count bytes total // count posted numbers numcount++; } if (lines == 1) { // "1 symbol per line" - closing line if (!f.Equals(flast) && f.width > 0) output += ","; if (com && fcount > 1) { //...with a comment output += " // " + f.code.ToString() + " --> " + mainForm.DecodeSymbol(f.code); if (f.note != "" && f.note != null) output += " (" + f.note.ToString() + ")"; } output += "\n"; } if (lines == 2) { // "X numbers per line" - closing line if (!f.Equals(flast)) output += ","; output += "\n"; numcount = 0; } } // Close array definition output += "};\n"; // Add header and bytes total counter if (com) { output = "// Bytes total: " + bTotal.ToString() + "\n" + output; output = comments["header"] + output; } txtOutput.Text = output; txtOutput.SelectionStart = 0; txtOutput.ScrollToCaret(); } private void cbFormat_SelectedIndexChanged(object sender, EventArgs e) { if (cbFormat.SelectedIndex == 1 && cbHeader.Checked) { MessageBox.Show("Cannot pack the font meta header into 2D array!\nChoose 1D array or disable the meta header.\n(Setting array format to 1D array)", "No header in 2D array!", MessageBoxButtons.OK, MessageBoxIcon.Information); cbFormat.SelectedIndex = 0; } if (!mainForm.monospaced && cbFormat.SelectedIndex == 1 && mainForm.frames.Count > 1) { MessageBox.Show("Cannot pack the variable width font into 2D array!\n(Setting array format to 1D array)", "2D arrays are for monospaced fonts only!", MessageBoxButtons.OK, MessageBoxIcon.Information); cbFormat.SelectedIndex = 0; } if (cbFormat.SelectedIndex == 1) { cbLines.SelectedIndex = 0; cbLines.Enabled = false; } else { cbLines.Enabled = true; } } private void cbLines_SelectedIndexChanged(object sender, EventArgs e) { if (cbLines.SelectedIndex == 0 && cbPacked.Checked) { MessageBox.Show("Cannot make one line per column/row in packed font as there are bytes used in several columns/rows!\n(Setting text format to 1 Symbol per line)", "No 1 Symbol per line for packed fonts!", MessageBoxButtons.OK, MessageBoxIcon.Information); cbLines.SelectedIndex = 1; } if (cbLines.SelectedIndex == 2) { nudXLines.Enabled = true; lblXLines.Enabled = true; } else { nudXLines.Enabled = false; lblXLines.Enabled = false; } } private void cbPacked_CheckedChanged(object sender, EventArgs e) { if (cbPacked.Checked && cbLines.SelectedIndex == 0) cbLines.SelectedIndex = 1; } } }