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