initial commit
This commit is contained in:
commit
852fc3ff63
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
/packages/
|
||||||
|
riderModule.iml
|
||||||
|
/_ReSharper.Caches/
|
13
.idea/.idea.MSDF-Test/.idea/.gitignore
generated
vendored
Normal file
13
.idea/.idea.MSDF-Test/.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Rider ignored files
|
||||||
|
/modules.xml
|
||||||
|
/.idea.MSDF-Test.iml
|
||||||
|
/contentModel.xml
|
||||||
|
/projectSettingsUpdater.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
4
.idea/.idea.MSDF-Test/.idea/encodings.xml
generated
Normal file
4
.idea/.idea.MSDF-Test/.idea/encodings.xml
generated
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
|
||||||
|
</project>
|
8
.idea/.idea.MSDF-Test/.idea/indexLayout.xml
generated
Normal file
8
.idea/.idea.MSDF-Test/.idea/indexLayout.xml
generated
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="UserContentModel">
|
||||||
|
<attachedFolders />
|
||||||
|
<explicitIncludes />
|
||||||
|
<explicitExcludes />
|
||||||
|
</component>
|
||||||
|
</project>
|
6
.idea/.idea.MSDF-Test/.idea/vcs.xml
generated
Normal file
6
.idea/.idea.MSDF-Test/.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
16
MSDF-Test.sln
Normal file
16
MSDF-Test.sln
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MSDF-Test", "MSDF-Test\MSDF-Test.csproj", "{73871F30-FF9E-48D3-9DF3-8B7809FBC6B8}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{73871F30-FF9E-48D3-9DF3-8B7809FBC6B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{73871F30-FF9E-48D3-9DF3-8B7809FBC6B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{73871F30-FF9E-48D3-9DF3-8B7809FBC6B8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{73871F30-FF9E-48D3-9DF3-8B7809FBC6B8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
22
MSDF-Test/Extensions.cs
Normal file
22
MSDF-Test/Extensions.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace MSDF_Test;
|
||||||
|
|
||||||
|
public static class Extensions
|
||||||
|
{
|
||||||
|
|
||||||
|
internal static Color MultiplyWith(this Color color, double factor)
|
||||||
|
{
|
||||||
|
return Color.FromArgb((int)(color.R * factor), (int)(color.G * factor), (int)(color.B * factor));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Color Add(this Color c1, Color c2)
|
||||||
|
{
|
||||||
|
return Color.FromArgb(c1.R + c2.R, c1.G + c2.G, c1.B + c2.B);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static PointF Scale(this PointF point, float factor)
|
||||||
|
{
|
||||||
|
return new PointF(point.X * factor, point.Y * factor);
|
||||||
|
}
|
||||||
|
}
|
72
MSDF-Test/Glyph.cs
Normal file
72
MSDF-Test/Glyph.cs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace MSDF_Test;
|
||||||
|
|
||||||
|
public class Glyph
|
||||||
|
{
|
||||||
|
private Bitmap originalBitmap;
|
||||||
|
private const float MaxColor = 255; //255 for Bitmaps
|
||||||
|
private const float DistanceRange = 255; //255 for Bitmaps
|
||||||
|
|
||||||
|
public Glyph(Bitmap texture)
|
||||||
|
{
|
||||||
|
this.originalBitmap = texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Bitmap GetBitmap(int size, Color foreground, Color background)
|
||||||
|
{
|
||||||
|
Bitmap ret = new(size, size, originalBitmap.PixelFormat);
|
||||||
|
for (int x = 0; x < ret.Width; x++)
|
||||||
|
{
|
||||||
|
for (int y = 0; y < ret.Height; y++)
|
||||||
|
{
|
||||||
|
PointF scaledPoint = new (x, y);
|
||||||
|
ret.SetPixel(x, y, GeneratePixel(scaledPoint.Scale((float)originalBitmap.Width / size)) ? foreground : background);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool GeneratePixel(PointF point)
|
||||||
|
{
|
||||||
|
Color s = SampleBilinear(point);
|
||||||
|
float sample = Median(s);
|
||||||
|
float d = ColorDistance(sample);
|
||||||
|
return d >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Color SampleBilinear(PointF point)
|
||||||
|
{
|
||||||
|
int x1 = (int)Math.Floor(point.X - .5);
|
||||||
|
int y1 = (int)Math.Floor(point.Y - .5);
|
||||||
|
int x2 = x1 + 1;
|
||||||
|
int y2 = y1 + 1;
|
||||||
|
double wx = point.X - x1 - .5;
|
||||||
|
double wy = point.Y - y1 - .5;
|
||||||
|
|
||||||
|
if (x1 >= 0 && y1 >= 0 && x2 <= (originalBitmap.Width - 1) && y2 <= (originalBitmap.Height - 1))
|
||||||
|
{
|
||||||
|
Color x1y1 = originalBitmap.GetPixel(x1, y1).MultiplyWith((1 - wx) * (1 - wy));
|
||||||
|
Color x1y2 = originalBitmap.GetPixel(x1, y2).MultiplyWith((1 - wx) * wy);
|
||||||
|
Color x2y1 = originalBitmap.GetPixel(x2, y1).MultiplyWith(wx * (1 - wy));
|
||||||
|
Color x2y2 = originalBitmap.GetPixel(x2, y2).MultiplyWith(wx * wy);
|
||||||
|
|
||||||
|
return x1y1.Add(x1y2).Add(x2y1).Add(x2y2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Color.Black; //Edges can not be interpolated. Just return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static float Median(float r, float g, float b)
|
||||||
|
{
|
||||||
|
return Math.Max(Math.Min(r, g), Math.Min(Math.Max(r, g), b));
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static float Median(Color c) => Median(c.R, c.G, c.B);
|
||||||
|
|
||||||
|
internal static float ColorDistance(float sample)
|
||||||
|
{
|
||||||
|
return ((sample / MaxColor) - .5f) * DistanceRange;
|
||||||
|
}
|
||||||
|
}
|
16
MSDF-Test/MSDF-Test.csproj
Normal file
16
MSDF-Test/MSDF-Test.csproj
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<RootNamespace>MSDF_Test</RootNamespace>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
|
<PackageReference Include="System.Drawing.Common" Version="8.0.4" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
35
MSDF-Test/MSDF.cs
Normal file
35
MSDF-Test/MSDF.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
using System.Drawing;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace MSDF_Test;
|
||||||
|
|
||||||
|
public class MSDF
|
||||||
|
{
|
||||||
|
private readonly Texture _texture;
|
||||||
|
private readonly Dictionary<char, Glyph> _glyphs = new();
|
||||||
|
|
||||||
|
public MSDF(string texturePath, int glyphSize, int padding)
|
||||||
|
{
|
||||||
|
this._texture = new Texture(texturePath, glyphSize, padding);
|
||||||
|
List<Bitmap> glyphBitmaps = this._texture.GetGlyphBitmaps();
|
||||||
|
for(int i = 32; i < 128; i++)
|
||||||
|
_glyphs.Add((char)(i+1), new Glyph(glyphBitmaps[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bitmap Render(string str, int size)
|
||||||
|
{
|
||||||
|
Bitmap ret = new(size * str.Length, size);
|
||||||
|
using (Graphics grD = Graphics.FromImage(ret))
|
||||||
|
{
|
||||||
|
for(int i = 0; i < str.Length; i++)
|
||||||
|
{
|
||||||
|
if (_glyphs.TryGetValue(str[i], out Glyph? glyph))
|
||||||
|
{
|
||||||
|
int destOffsetX = i * size;
|
||||||
|
grD.DrawImage(glyph.GetBitmap(size, Color.White, Color.Transparent), new PointF(destOffsetX, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
24
MSDF-Test/Program.cs
Normal file
24
MSDF-Test/Program.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
using MSDF_Test;
|
||||||
|
|
||||||
|
MSDF msdf = new ("T_RobotoBlack_FONT.png", 66, 3);
|
||||||
|
|
||||||
|
Console.Write("String: ");
|
||||||
|
string? str;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
str = Console.ReadLine();
|
||||||
|
}while(str is null);
|
||||||
|
Console.Write("Size: ");
|
||||||
|
string? sizeStr;
|
||||||
|
int size;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
sizeStr = Console.ReadLine();
|
||||||
|
}while(sizeStr is null || !int.TryParse(sizeStr, out size));
|
||||||
|
|
||||||
|
Console.WriteLine("Rendering...");
|
||||||
|
Bitmap render = msdf.Render(str, size);
|
||||||
|
render.Save("render.png", ImageFormat.Png);
|
||||||
|
Console.WriteLine("Done.");
|
37
MSDF-Test/Texture.cs
Normal file
37
MSDF-Test/Texture.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace MSDF_Test;
|
||||||
|
|
||||||
|
public struct Texture
|
||||||
|
{
|
||||||
|
internal Bitmap Image;
|
||||||
|
internal int GlyphSize;
|
||||||
|
internal int Padding;
|
||||||
|
|
||||||
|
public Texture(Bitmap image, int glyphSize, int padding)
|
||||||
|
{
|
||||||
|
this.Image = image;
|
||||||
|
this.GlyphSize = glyphSize;
|
||||||
|
this.Padding = padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal List<Bitmap> GetGlyphBitmaps()
|
||||||
|
{
|
||||||
|
List<Bitmap> ret = new();
|
||||||
|
for (int y = Padding; y < Image.Width - Padding; y += GlyphSize + Padding)
|
||||||
|
{
|
||||||
|
for (int x = Padding; x < Image.Height - Padding; x += GlyphSize + Padding)
|
||||||
|
{
|
||||||
|
Point topLeft = new (x, y);
|
||||||
|
ret.Add(Image.Clone(new Rectangle(topLeft, new Size(GlyphSize, GlyphSize)), Image.PixelFormat));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Texture(string imagePath, int glyphSize, int padding) : this((Bitmap)Bitmap.FromFile(imagePath), glyphSize, padding)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user