Initial upload of project
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/bin
|
||||
/obj
|
||||
/.vs
|
||||
8
FontGlyphExporter.csproj
Normal file
8
FontGlyphExporter.csproj
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
25
FontGlyphExporter.sln
Normal file
25
FontGlyphExporter.sln
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.13.35828.75 d17.13
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FontGlyphExporter", "FontGlyphExporter.csproj", "{2E8081B2-DFAC-3227-72D0-366CF7F45501}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{2E8081B2-DFAC-3227-72D0-366CF7F45501}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2E8081B2-DFAC-3227-72D0-366CF7F45501}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2E8081B2-DFAC-3227-72D0-366CF7F45501}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2E8081B2-DFAC-3227-72D0-366CF7F45501}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {17BAE8BB-58F1-4268-9740-4AA4ACE38243}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
191
MainForm.Designer.cs
generated
Normal file
191
MainForm.Designer.cs
generated
Normal file
@@ -0,0 +1,191 @@
|
||||
namespace FontGlyphExporter
|
||||
{
|
||||
partial class MainForm
|
||||
{
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
private System.Windows.Forms.TextBox txtTTF;
|
||||
private System.Windows.Forms.TextBox txtCSS;
|
||||
private System.Windows.Forms.Button btnBrowseTTF;
|
||||
private System.Windows.Forms.Button btnBrowseCSS;
|
||||
private System.Windows.Forms.Button btnLoad;
|
||||
private System.Windows.Forms.Button btnExport;
|
||||
private System.Windows.Forms.FlowLayoutPanel iconFlowPanel;
|
||||
private System.Windows.Forms.Label lblCounter;
|
||||
private System.Windows.Forms.ComboBox cboRegexPattern;
|
||||
private System.Windows.Forms.Label lblRegexPattern;
|
||||
private System.Windows.Forms.TextBox txtCustomRegex;
|
||||
private System.Windows.Forms.Label lblCustomRegex;
|
||||
private System.Windows.Forms.Panel pnlSizes;
|
||||
private System.Windows.Forms.Label lblSizes;
|
||||
private System.Windows.Forms.CheckBox chkSize4;
|
||||
private System.Windows.Forms.CheckBox chkSize8;
|
||||
private System.Windows.Forms.CheckBox chkSize12;
|
||||
private System.Windows.Forms.CheckBox chkSize24;
|
||||
private System.Windows.Forms.Label lblSelectedSizes;
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.txtTTF = new System.Windows.Forms.TextBox();
|
||||
this.txtCSS = new System.Windows.Forms.TextBox();
|
||||
this.btnBrowseTTF = new System.Windows.Forms.Button();
|
||||
this.btnBrowseCSS = new System.Windows.Forms.Button();
|
||||
this.btnLoad = new System.Windows.Forms.Button();
|
||||
this.btnExport = new System.Windows.Forms.Button();
|
||||
this.lblCounter = new System.Windows.Forms.Label();
|
||||
this.iconFlowPanel = new System.Windows.Forms.FlowLayoutPanel();
|
||||
this.cboRegexPattern = new System.Windows.Forms.ComboBox();
|
||||
this.lblRegexPattern = new System.Windows.Forms.Label();
|
||||
this.txtCustomRegex = new System.Windows.Forms.TextBox();
|
||||
this.lblCustomRegex = new System.Windows.Forms.Label();
|
||||
this.pnlSizes = new System.Windows.Forms.Panel();
|
||||
this.lblSizes = new System.Windows.Forms.Label();
|
||||
this.chkSize4 = new System.Windows.Forms.CheckBox();
|
||||
this.chkSize8 = new System.Windows.Forms.CheckBox();
|
||||
this.chkSize12 = new System.Windows.Forms.CheckBox();
|
||||
this.chkSize24 = new System.Windows.Forms.CheckBox();
|
||||
this.lblSelectedSizes = new System.Windows.Forms.Label();
|
||||
this.pnlSizes.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// txtTTF
|
||||
this.txtTTF.Location = new System.Drawing.Point(12, 12);
|
||||
this.txtTTF.Size = new System.Drawing.Size(400, 23);
|
||||
//
|
||||
// btnBrowseTTF
|
||||
this.btnBrowseTTF.Location = new System.Drawing.Point(418, 12);
|
||||
this.btnBrowseTTF.Size = new System.Drawing.Size(100, 23);
|
||||
this.btnBrowseTTF.Text = "Browse TTF";
|
||||
this.btnBrowseTTF.Click += new System.EventHandler(this.btnBrowseTTF_Click);
|
||||
//
|
||||
// txtCSS
|
||||
this.txtCSS.Location = new System.Drawing.Point(12, 41);
|
||||
this.txtCSS.Size = new System.Drawing.Size(400, 23);
|
||||
//
|
||||
// btnBrowseCSS
|
||||
this.btnBrowseCSS.Location = new System.Drawing.Point(418, 41);
|
||||
this.btnBrowseCSS.Size = new System.Drawing.Size(100, 23);
|
||||
this.btnBrowseCSS.Text = "Browse CSS";
|
||||
this.btnBrowseCSS.Click += new System.EventHandler(this.btnBrowseCSS_Click);
|
||||
//
|
||||
// lblRegexPattern
|
||||
this.lblRegexPattern.Location = new System.Drawing.Point(540, 12);
|
||||
this.lblRegexPattern.Size = new System.Drawing.Size(80, 23);
|
||||
this.lblRegexPattern.Text = "Regex Pattern:";
|
||||
this.lblRegexPattern.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// cboRegexPattern
|
||||
this.cboRegexPattern.Location = new System.Drawing.Point(625, 12);
|
||||
this.cboRegexPattern.Size = new System.Drawing.Size(150, 23);
|
||||
this.cboRegexPattern.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.cboRegexPattern.Items.AddRange(new object[] {
|
||||
"Font Awesome 5/6",
|
||||
"Font Awesome 4",
|
||||
"Material Icons",
|
||||
"Custom"
|
||||
});
|
||||
this.cboRegexPattern.SelectedIndexChanged += new System.EventHandler(this.cboRegexPattern_SelectedIndexChanged);
|
||||
//
|
||||
// lblCustomRegex
|
||||
this.lblCustomRegex.Location = new System.Drawing.Point(540, 41);
|
||||
this.lblCustomRegex.Size = new System.Drawing.Size(80, 23);
|
||||
this.lblCustomRegex.Text = "Custom Regex:";
|
||||
this.lblCustomRegex.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
this.lblCustomRegex.Visible = false;
|
||||
//
|
||||
// txtCustomRegex
|
||||
this.txtCustomRegex.Location = new System.Drawing.Point(625, 41);
|
||||
this.txtCustomRegex.Size = new System.Drawing.Size(150, 23);
|
||||
this.txtCustomRegex.Visible = false;
|
||||
//
|
||||
// lblSizes
|
||||
this.lblSizes.Location = new System.Drawing.Point(418, 70);
|
||||
this.lblSizes.Size = new System.Drawing.Size(100, 23);
|
||||
this.lblSizes.Text = "Export Sizes:";
|
||||
this.lblSizes.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// pnlSizes
|
||||
this.pnlSizes.Location = new System.Drawing.Point(520, 70);
|
||||
this.pnlSizes.Size = new System.Drawing.Size(255, 25);
|
||||
//
|
||||
// chkSize4
|
||||
this.chkSize4.Location = new System.Drawing.Point(5, 3);
|
||||
this.chkSize4.Size = new System.Drawing.Size(50, 20);
|
||||
this.chkSize4.Text = "4x4";
|
||||
this.chkSize4.CheckedChanged += new System.EventHandler(this.sizeCheckbox_CheckedChanged);
|
||||
this.pnlSizes.Controls.Add(this.chkSize4);
|
||||
//
|
||||
// chkSize8
|
||||
this.chkSize8.Location = new System.Drawing.Point(65, 3);
|
||||
this.chkSize8.Size = new System.Drawing.Size(50, 20);
|
||||
this.chkSize8.Text = "8x8";
|
||||
this.chkSize8.CheckedChanged += new System.EventHandler(this.sizeCheckbox_CheckedChanged);
|
||||
this.pnlSizes.Controls.Add(this.chkSize8);
|
||||
//
|
||||
// chkSize12
|
||||
this.chkSize12.Location = new System.Drawing.Point(125, 3);
|
||||
this.chkSize12.Size = new System.Drawing.Size(60, 20);
|
||||
this.chkSize12.Text = "12x12";
|
||||
this.chkSize12.CheckedChanged += new System.EventHandler(this.sizeCheckbox_CheckedChanged);
|
||||
this.pnlSizes.Controls.Add(this.chkSize12);
|
||||
//
|
||||
// chkSize24
|
||||
this.chkSize24.Location = new System.Drawing.Point(195, 3);
|
||||
this.chkSize24.Size = new System.Drawing.Size(60, 20);
|
||||
this.chkSize24.Text = "24x24";
|
||||
this.chkSize24.CheckedChanged += new System.EventHandler(this.sizeCheckbox_CheckedChanged);
|
||||
this.pnlSizes.Controls.Add(this.chkSize24);
|
||||
//
|
||||
// lblSelectedSizes
|
||||
this.lblSelectedSizes.Location = new System.Drawing.Point(520, 95);
|
||||
this.lblSelectedSizes.Size = new System.Drawing.Size(255, 15);
|
||||
this.lblSelectedSizes.Text = "Selected sizes: 12, 24px";
|
||||
//
|
||||
// btnLoad
|
||||
this.btnLoad.Location = new System.Drawing.Point(12, 70);
|
||||
this.btnLoad.Size = new System.Drawing.Size(100, 23);
|
||||
this.btnLoad.Text = "Load Icons";
|
||||
this.btnLoad.Click += new System.EventHandler(this.btnLoad_Click);
|
||||
//
|
||||
// btnExport
|
||||
this.btnExport.Location = new System.Drawing.Point(118, 70);
|
||||
this.btnExport.Size = new System.Drawing.Size(120, 23);
|
||||
this.btnExport.Text = "Export Selected";
|
||||
this.btnExport.Click += new System.EventHandler(this.btnExport_Click);
|
||||
//
|
||||
// lblCounter
|
||||
this.lblCounter.Location = new System.Drawing.Point(250, 70);
|
||||
this.lblCounter.Size = new System.Drawing.Size(150, 23);
|
||||
this.lblCounter.Text = "Selected: 0 / 0";
|
||||
//
|
||||
// iconFlowPanel
|
||||
this.iconFlowPanel.Location = new System.Drawing.Point(12, 120);
|
||||
this.iconFlowPanel.Size = new System.Drawing.Size(760, 430);
|
||||
this.iconFlowPanel.AutoScroll = true;
|
||||
this.iconFlowPanel.WrapContents = true;
|
||||
this.iconFlowPanel.FlowDirection = System.Windows.Forms.FlowDirection.LeftToRight;
|
||||
//
|
||||
// MainForm
|
||||
this.ClientSize = new System.Drawing.Size(784, 561);
|
||||
this.Controls.Add(this.txtTTF);
|
||||
this.Controls.Add(this.btnBrowseTTF);
|
||||
this.Controls.Add(this.txtCSS);
|
||||
this.Controls.Add(this.btnBrowseCSS);
|
||||
this.Controls.Add(this.lblRegexPattern);
|
||||
this.Controls.Add(this.cboRegexPattern);
|
||||
this.Controls.Add(this.lblCustomRegex);
|
||||
this.Controls.Add(this.txtCustomRegex);
|
||||
this.Controls.Add(this.lblSizes);
|
||||
this.Controls.Add(this.pnlSizes);
|
||||
this.Controls.Add(this.lblSelectedSizes);
|
||||
this.Controls.Add(this.btnLoad);
|
||||
this.Controls.Add(this.btnExport);
|
||||
this.Controls.Add(this.lblCounter);
|
||||
this.Controls.Add(this.iconFlowPanel);
|
||||
this.Name = "MainForm";
|
||||
this.Text = "Font Awesome Icon Exporter";
|
||||
this.pnlSizes.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
}
|
||||
}
|
||||
}
|
||||
291
MainForm.cs
Normal file
291
MainForm.cs
Normal file
@@ -0,0 +1,291 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Text;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace FontGlyphExporter
|
||||
{
|
||||
public partial class MainForm : Form
|
||||
{
|
||||
private string fontPath = "";
|
||||
private string cssPath = "";
|
||||
private List<IconInfo> allIcons = new();
|
||||
private List<IconInfo> selectedIcons = new();
|
||||
private PrivateFontCollection fontCollection = new();
|
||||
private Font font;
|
||||
private Dictionary<string, string> regexPatterns = new();
|
||||
private List<int> selectedSizes = new();
|
||||
|
||||
public MainForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
InitializeRegexPatterns();
|
||||
InitializeSizeCheckboxes();
|
||||
cboRegexPattern.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
private void InitializeRegexPatterns()
|
||||
{
|
||||
regexPatterns.Add("Font Awesome 5/6", @"\.fa-([a-z0-9-]+)\s*{[^}]*--fa:\s*""\\(f[a-f0-9]{3,4})""");
|
||||
regexPatterns.Add("Font Awesome 4", @"\.fa-([a-z0-9-]+):before\s*{[^}]*content:\s*""\\(f[a-f0-9]{3,4})""");
|
||||
regexPatterns.Add("Material Icons", @"\.material-icons-([a-z0-9-]+):before\s*{[^}]*content:\s*""\\(e[a-f0-9]{3,4})""");
|
||||
regexPatterns.Add("Custom", "");
|
||||
}
|
||||
|
||||
private void InitializeSizeCheckboxes()
|
||||
{
|
||||
chkSize4.Tag = 4;
|
||||
chkSize8.Tag = 8;
|
||||
chkSize12.Tag = 12;
|
||||
chkSize24.Tag = 24;
|
||||
|
||||
// Default selection
|
||||
chkSize12.Checked = true;
|
||||
chkSize24.Checked = true;
|
||||
UpdateSelectedSizes();
|
||||
}
|
||||
|
||||
private void UpdateSelectedSizes()
|
||||
{
|
||||
selectedSizes.Clear();
|
||||
|
||||
foreach (Control c in pnlSizes.Controls)
|
||||
{
|
||||
if (c is CheckBox chk && chk.Checked && chk.Tag is int size)
|
||||
{
|
||||
selectedSizes.Add(size);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the selected sizes label
|
||||
lblSelectedSizes.Text = selectedSizes.Count > 0
|
||||
? $"Selected sizes: {string.Join(", ", selectedSizes)}px"
|
||||
: "No sizes selected";
|
||||
}
|
||||
|
||||
private void btnBrowseTTF_Click(object sender, EventArgs e)
|
||||
{
|
||||
using OpenFileDialog ofd = new() { Filter = "Font Files (*.ttf)|*.ttf" };
|
||||
if (ofd.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
fontPath = ofd.FileName;
|
||||
txtTTF.Text = fontPath;
|
||||
}
|
||||
}
|
||||
|
||||
private void btnBrowseCSS_Click(object sender, EventArgs e)
|
||||
{
|
||||
using OpenFileDialog ofd = new() { Filter = "CSS Files (*.css)|*.css" };
|
||||
if (ofd.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
cssPath = ofd.FileName;
|
||||
txtCSS.Text = cssPath;
|
||||
}
|
||||
}
|
||||
|
||||
private void btnLoad_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!File.Exists(fontPath) || !File.Exists(cssPath))
|
||||
{
|
||||
MessageBox.Show("Please select valid CSS and TTF files.");
|
||||
return;
|
||||
}
|
||||
|
||||
fontCollection = new PrivateFontCollection();
|
||||
fontCollection.AddFontFile(fontPath);
|
||||
font = new Font(fontCollection.Families[0], 16);
|
||||
|
||||
string css = File.ReadAllText(cssPath);
|
||||
string patternToUse;
|
||||
|
||||
if (cboRegexPattern.SelectedItem.ToString() == "Custom")
|
||||
{
|
||||
patternToUse = txtCustomRegex.Text;
|
||||
if (string.IsNullOrWhiteSpace(patternToUse))
|
||||
{
|
||||
MessageBox.Show("Please enter a valid regex pattern.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
patternToUse = regexPatterns[cboRegexPattern.SelectedItem.ToString()];
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var matches = Regex.Matches(css, patternToUse, RegexOptions.IgnoreCase);
|
||||
|
||||
allIcons.Clear();
|
||||
foreach (Match match in matches)
|
||||
{
|
||||
if (match.Groups.Count < 3) continue;
|
||||
string name = match.Groups[1].Value;
|
||||
string unicode = match.Groups[2].Value;
|
||||
allIcons.Add(new IconInfo { name = name, unicode = unicode });
|
||||
}
|
||||
|
||||
if (allIcons.Count == 0)
|
||||
{
|
||||
MessageBox.Show("No icons found with the selected pattern. Try a different pattern or check your CSS file.");
|
||||
return;
|
||||
}
|
||||
|
||||
PopulateGrid();
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
MessageBox.Show($"Invalid regex pattern: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void PopulateGrid()
|
||||
{
|
||||
iconFlowPanel.Controls.Clear();
|
||||
selectedIcons.Clear();
|
||||
UpdateCounter();
|
||||
|
||||
foreach (var icon in allIcons)
|
||||
{
|
||||
var panel = new Panel
|
||||
{
|
||||
Width = 80,
|
||||
Height = 100,
|
||||
Margin = new Padding(5),
|
||||
BorderStyle = BorderStyle.FixedSingle,
|
||||
Tag = icon
|
||||
};
|
||||
|
||||
var bmp = new Bitmap(48, 48);
|
||||
using (Graphics g = Graphics.FromImage(bmp))
|
||||
{
|
||||
g.Clear(Color.White);
|
||||
g.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
|
||||
string glyph = char.ConvertFromUtf32(Convert.ToInt32(icon.unicode, 16));
|
||||
g.DrawString(glyph, font, Brushes.Black, 0, 0);
|
||||
}
|
||||
|
||||
var pic = new PictureBox
|
||||
{
|
||||
Image = bmp,
|
||||
SizeMode = PictureBoxSizeMode.CenterImage,
|
||||
Width = 48,
|
||||
Height = 48,
|
||||
Top = 5,
|
||||
Left = 15
|
||||
};
|
||||
|
||||
var lbl = new Label
|
||||
{
|
||||
Text = icon.name,
|
||||
Width = 70,
|
||||
Top = 60,
|
||||
Left = 5,
|
||||
TextAlign = ContentAlignment.MiddleCenter
|
||||
};
|
||||
|
||||
panel.Controls.Add(pic);
|
||||
panel.Controls.Add(lbl);
|
||||
|
||||
panel.Click += (s, e) =>
|
||||
{
|
||||
if (selectedIcons.Contains(icon))
|
||||
{
|
||||
selectedIcons.Remove(icon);
|
||||
panel.BackColor = SystemColors.Control;
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedIcons.Add(icon);
|
||||
panel.BackColor = Color.LightBlue;
|
||||
}
|
||||
UpdateCounter();
|
||||
};
|
||||
|
||||
iconFlowPanel.Controls.Add(panel);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateCounter()
|
||||
{
|
||||
lblCounter.Text = $"Selected: {selectedIcons.Count} / {allIcons.Count}";
|
||||
}
|
||||
|
||||
private void btnExport_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (selectedIcons.Count == 0)
|
||||
{
|
||||
MessageBox.Show("Please select at least one icon to export.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedSizes.Count == 0)
|
||||
{
|
||||
MessageBox.Show("Please select at least one size for export.");
|
||||
return;
|
||||
}
|
||||
|
||||
var icons = new List<object>();
|
||||
var outputDir = Path.Combine("output", "icons");
|
||||
Directory.CreateDirectory(outputDir);
|
||||
|
||||
foreach (var icon in selectedIcons)
|
||||
{
|
||||
foreach (var size in selectedSizes)
|
||||
{
|
||||
string glyph = char.ConvertFromUtf32(Convert.ToInt32(icon.unicode, 16));
|
||||
string file = $"icon_{icon.name}_{size}x{size}.bin";
|
||||
string path = Path.Combine(outputDir, file);
|
||||
|
||||
using Bitmap bmp = new(size, size);
|
||||
using Graphics g = Graphics.FromImage(bmp);
|
||||
g.Clear(Color.White);
|
||||
g.TextRenderingHint = TextRenderingHint.SingleBitPerPixelGridFit;
|
||||
g.DrawString(glyph, new Font(font.FontFamily, size), Brushes.Black, 0, 0);
|
||||
|
||||
using FileStream fs = new(path, FileMode.Create);
|
||||
for (int y = 0; y < bmp.Height; y++)
|
||||
{
|
||||
for (int x = 0; x < bmp.Width; x += 8)
|
||||
{
|
||||
byte b = 0;
|
||||
for (int bit = 0; bit < 8 && (x + bit) < bmp.Width; bit++)
|
||||
{
|
||||
var pixel = bmp.GetPixel(x + bit, y);
|
||||
if (pixel.R < 128) b |= (byte)(1 << bit);
|
||||
}
|
||||
fs.WriteByte(b);
|
||||
}
|
||||
}
|
||||
|
||||
icons.Add(new { name = icon.name, file = file, width = size, height = size });
|
||||
}
|
||||
}
|
||||
|
||||
File.WriteAllText("output/icons_index.json", JsonSerializer.Serialize(icons, new JsonSerializerOptions { WriteIndented = true }));
|
||||
MessageBox.Show("Export complete!");
|
||||
}
|
||||
|
||||
private void cboRegexPattern_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
bool isCustom = cboRegexPattern.SelectedItem.ToString() == "Custom";
|
||||
txtCustomRegex.Visible = isCustom;
|
||||
lblCustomRegex.Visible = isCustom;
|
||||
}
|
||||
|
||||
private void sizeCheckbox_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
UpdateSelectedSizes();
|
||||
}
|
||||
|
||||
public class IconInfo
|
||||
{
|
||||
public string name { get; set; }
|
||||
public string unicode { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
16
Program.cs
Normal file
16
Program.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace FontGlyphExporter
|
||||
{
|
||||
internal static class Program
|
||||
{
|
||||
[STAThread]
|
||||
static void Main()
|
||||
{
|
||||
ApplicationConfiguration.Initialize();
|
||||
Application.Run(new MainForm());
|
||||
}
|
||||
}
|
||||
}
|
||||
120
readme.md
Normal file
120
readme.md
Normal file
@@ -0,0 +1,120 @@
|
||||
# Font Glyph Exporter
|
||||
|
||||
A Windows Forms application for browsing, selecting, and exporting Font Awesome icons (or other icon fonts) as binary files for use in embedded systems, microcontrollers, or other display applications.
|
||||
|
||||

|
||||
|
||||
## Features
|
||||
|
||||
- Browse and preview icons from Font TTF files
|
||||
- Support for multiple font formats through configurable regex patterns
|
||||
- Easy icon selection with visual preview
|
||||
- Export icons in various sizes (4x4, 8x8, 12x12, 24x24)
|
||||
- Exports as 1-bit monochrome binary format for efficiency
|
||||
- Output indexed JSON for easy integration with your applications
|
||||
|
||||
## Requirements
|
||||
|
||||
- .NET 6.0 or later
|
||||
- Windows OS
|
||||
- Font TTF file
|
||||
- Corresponding CSS file with icon mappings
|
||||
|
||||
## Getting Started
|
||||
|
||||
1. Download the latest release or build from source
|
||||
2. Run the application
|
||||
3. Browse to select your TTF font file
|
||||
4. Browse to select your CSS file with icon mappings
|
||||
5. Select the appropriate regex pattern for your font or create a custom one
|
||||
6. Click "Load Icons" to view all available icons
|
||||
7. Select the icons you want to export
|
||||
8. Choose desired output sizes using the checkboxes
|
||||
9. Click "Export Selected" to generate the binary files
|
||||
|
||||
## Building from Source
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone https://github.com/programmingPug/FontGlyphExporter.git
|
||||
|
||||
# Navigate to the project directory
|
||||
cd FontGlyphExporter
|
||||
|
||||
# Build the project
|
||||
dotnet build
|
||||
|
||||
# Run the application
|
||||
dotnet run
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
The application:
|
||||
|
||||
1. Loads the TTF font file into a private font collection
|
||||
2. Parses the CSS file using regex to extract icon names and Unicode values
|
||||
3. Renders each icon in the UI for preview
|
||||
4. When exporting, creates a 1-bit monochrome bitmap for each selected icon at each selected size
|
||||
5. Saves these bitmaps as binary files, where each bit represents a pixel (1 = black, 0 = white)
|
||||
6. Generates a JSON index file mapping icon names to their file information
|
||||
|
||||
## Regex Patterns
|
||||
|
||||
The application includes several predefined regex patterns:
|
||||
|
||||
- **Font Awesome 5/6**: `.fa-([a-z0-9-]+)\s*{[^}]*--fa:\s*"\\(f[a-f0-9]{3,4})"`
|
||||
- **Font Awesome 4**: `.fa-([a-z0-9-]+):before\s*{[^}]*content:\s*"\\(f[a-f0-9]{3,4})"`
|
||||
- **Material Icons**: `.material-icons-([a-z0-9-]+):before\s*{[^}]*content:\s*"\\(e[a-f0-9]{3,4})"`
|
||||
- **Custom**: Enter your own regex pattern
|
||||
|
||||
The regex should capture two groups:
|
||||
1. The icon name
|
||||
2. The Unicode hex value
|
||||
|
||||
## Output Format
|
||||
|
||||
### Binary Files
|
||||
|
||||
The binary files are stored in the `output/icons` directory. Each bit represents a pixel:
|
||||
- 1 = Black pixel (icon)
|
||||
- 0 = White pixel (background)
|
||||
|
||||
Each row is padded to a byte boundary, with bits ordered from least significant to most significant.
|
||||
|
||||
### JSON Index
|
||||
|
||||
The program generates a JSON index file (`output/icons_index.json`) with metadata for all exported icons:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"name": "calendar",
|
||||
"file": "icon_calendar_12x12.bin",
|
||||
"width": 12,
|
||||
"height": 12
|
||||
},
|
||||
{
|
||||
"name": "calendar",
|
||||
"file": "icon_calendar_24x24.bin",
|
||||
"width": 24,
|
||||
"height": 24
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## Use Cases
|
||||
|
||||
- Embedded systems with monochrome displays
|
||||
- Microcontroller applications
|
||||
- LCD/OLED screens
|
||||
- E-paper displays
|
||||
- Any application requiring lightweight icon representation
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT License - see the LICENSE file for details.
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
- .NET Windows Forms for the UI framework
|
||||
Reference in New Issue
Block a user