Create a super basic test for fonts.
@ -7,11 +7,6 @@
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="StbImageSharp" Version="2.27.13" />
|
||||
<PackageReference Include="StbTrueTypeSharp" Version="1.26.11" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Quik\Quik.csproj" />
|
||||
<ProjectReference Include="..\Quik.StbImage\Quik.StbImage.csproj" />
|
||||
|
@ -11,4 +11,11 @@
|
||||
<PackageReference Include="Quik.StbTrueType.redist" Version="1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="runtimes/**">
|
||||
<PackagePath>runtimes</PackagePath>
|
||||
<Pack>true</Pack>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
355
Quik.StbTrueType/StbFont.cs
Normal file
@ -0,0 +1,355 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Quik.Stb
|
||||
{
|
||||
public unsafe class StbFont : IDisposable
|
||||
{
|
||||
IntPtr _buffer;
|
||||
stbtt_fontinfo* _info;
|
||||
List<stbtt_kerningentry> _kerningTable;
|
||||
|
||||
public IntPtr FontBuffer => _buffer;
|
||||
public ref stbtt_fontinfo FontInfo => ref *_info;
|
||||
|
||||
public IReadOnlyList<stbtt_kerningentry> KerningTable
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_kerningTable != null)
|
||||
return _kerningTable;
|
||||
|
||||
int count = Stbtt.GetKerningTableLength(_info);
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
return _kerningTable = new List<stbtt_kerningentry>();
|
||||
}
|
||||
else
|
||||
{
|
||||
stbtt_kerningentry[] array = new stbtt_kerningentry[count];
|
||||
|
||||
fixed (stbtt_kerningentry *ptr = array)
|
||||
Stbtt.GetKerningTable(_info, ptr, count);
|
||||
|
||||
return _kerningTable = new List<stbtt_kerningentry>(array);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Ascend { get; }
|
||||
public int Descend { get; }
|
||||
public int VerticalLineGap { get; }
|
||||
public int AscendOS2 { get; }
|
||||
public int DescendOS2 { get; }
|
||||
public int VerticalLineGapOS2 { get; }
|
||||
public Box BoundingBox { get; }
|
||||
|
||||
private StbFont(IntPtr buffer, stbtt_fontinfo* info)
|
||||
{
|
||||
_buffer = buffer;
|
||||
_info = info;
|
||||
|
||||
int a, b, c, d;
|
||||
|
||||
Stbtt.GetFontVMetrics(_info, &a, &b, &c);
|
||||
Ascend = a;
|
||||
Descend = b;
|
||||
VerticalLineGap = c;
|
||||
|
||||
Stbtt.GetFontVMetricsOS2(_info, &a, &b, &c);
|
||||
AscendOS2 = a;
|
||||
DescendOS2 = b;
|
||||
VerticalLineGapOS2 = c;
|
||||
|
||||
Stbtt.GetFontBoundingBox(_info, &a, &b, &c, &d);
|
||||
BoundingBox = new Box(a, b, c, d);
|
||||
}
|
||||
~StbFont()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
|
||||
public int FindGlyphIndex(int codepoint)
|
||||
{
|
||||
return Stbtt.FindGlyphIndex(_info, codepoint);
|
||||
}
|
||||
public int FindGlyphIndex(Rune codepoint) => FindGlyphIndex(codepoint.Value);
|
||||
|
||||
public float ScaleForPixelHeight(float pixels)
|
||||
{
|
||||
return Stbtt.ScaleForPixelHeight(_info, pixels);
|
||||
}
|
||||
|
||||
public float ScaleForMappingEmToPixels(float pixels)
|
||||
{
|
||||
return Stbtt.ScaleForMappingEmToPixels(_info, pixels);
|
||||
}
|
||||
|
||||
public void GetCodepointHMetrics(int codepoint, out int advance, out int bearing)
|
||||
{
|
||||
int a, b;
|
||||
|
||||
Stbtt.GetCodepointHMetrics(_info, codepoint, &a, &b);
|
||||
|
||||
advance = a;
|
||||
bearing = b;
|
||||
}
|
||||
|
||||
public void GetCodepointHMetrics(Rune codepoint, out int advance, out int bearing)
|
||||
=> GetCodepointHMetrics(codepoint.Value, out advance, out bearing);
|
||||
|
||||
public int GetCodepointKernAdvance(int cp1, int cp2)
|
||||
{
|
||||
return Stbtt.GetCodepointKernAdvance(_info, cp1, cp2);
|
||||
}
|
||||
public int GetCodepointKernAdvance(Rune cp1, Rune cp2) => GetCodepointKernAdvance(cp1.Value, cp2.Value);
|
||||
|
||||
public int GetCodepointBox(int codepoint, out Box box)
|
||||
{
|
||||
int x0, y0;
|
||||
int x1, y1;
|
||||
int rval;
|
||||
|
||||
rval = Stbtt.GetCodepointBox(_info, codepoint, &x0, &y0, &x1, &y1);
|
||||
|
||||
box = new Box(x0, y0, x1, y1);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
public void GetGlyphHMetrics(int glyph, out int advance, out int bearing)
|
||||
{
|
||||
int a, b;
|
||||
|
||||
Stbtt.GetGlyphHMetrics(_info, glyph, &a, &b);
|
||||
|
||||
advance = a;
|
||||
bearing = b;
|
||||
}
|
||||
|
||||
public int GetGlyphKernAdvance(int gl1, int gl2)
|
||||
{
|
||||
return Stbtt.GetGlyphKernAdvance(_info, gl1, gl2);
|
||||
}
|
||||
|
||||
public int GetGlyphBox(int glyph, out Box box)
|
||||
{
|
||||
int x0, y0;
|
||||
int x1, y1;
|
||||
int rval;
|
||||
|
||||
rval = Stbtt.GetGlyphBox(_info, glyph, &x0, &y0, &x1, &y1);
|
||||
|
||||
box = new Box(x0, y0, x1, y1);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
public bool IsGlyphEmpty(int glyph)
|
||||
{
|
||||
return Stbtt.IsGlyphEmpty(_info, glyph) != 0;
|
||||
}
|
||||
|
||||
public Bitmap GetCodepointBitmap(float scaleX, float scaleY, int codepoint, out int offsetX, out int offsetY)
|
||||
{
|
||||
int w, h, x, y;
|
||||
void* ptr = Stbtt.GetCodepointBitmap(_info, scaleX, scaleY, codepoint, &w, &h, &x, &y);
|
||||
|
||||
offsetX = x;
|
||||
offsetY = y;
|
||||
|
||||
return new Bitmap((IntPtr)ptr, w, h, FreeBitmap);
|
||||
}
|
||||
|
||||
public Bitmap GetCodepointBitmap(float scaleX, float scaleY, Rune codepoint, out int offsetX, out int offsetY)
|
||||
=> GetCodepointBitmap(scaleX, scaleY, codepoint.Value, out offsetX, out offsetY);
|
||||
|
||||
public Bitmap GetCodepointBitmapSubpixel(float scaleX, float scaleY, float shiftX, float shiftY, int codepoint, out int offsetX, out int offsetY)
|
||||
{
|
||||
int w, h, x, y;
|
||||
void* ptr = Stbtt.GetCodepointBitmapSubpixel(_info, scaleX, scaleY, shiftX, shiftY, codepoint, &w, &h, &x, &y);
|
||||
|
||||
offsetX = x;
|
||||
offsetY = y;
|
||||
|
||||
return new Bitmap((IntPtr)ptr, w, h, FreeBitmap);
|
||||
}
|
||||
|
||||
public Bitmap GetCodepointBitmapSubpixel(float scaleX, float scaleY, float shiftX, float shiftY, Rune codepoint, out int offsetX, out int offsetY)
|
||||
=> GetCodepointBitmapSubpixel(scaleX, scaleY, shiftX, shiftY, codepoint.Value, out offsetX, out offsetY);
|
||||
|
||||
public Bitmap GetGlyphBitmap(float scaleX, float scaleY, int glyph, out int offsetX, out int offsetY)
|
||||
{
|
||||
int w, h, x, y;
|
||||
void* ptr = Stbtt.GetGlyphBitmap(_info, scaleX, scaleY, glyph, &w, &h, &x, &y);
|
||||
|
||||
offsetX = x;
|
||||
offsetY = y;
|
||||
|
||||
return new Bitmap((IntPtr)ptr, w, h, FreeBitmap);
|
||||
}
|
||||
|
||||
public Bitmap GetGlyphBitmapSubpixel(float scaleX, float scaleY, float shiftX, float shiftY, int glyph, out int offsetX, out int offsetY)
|
||||
{
|
||||
int w, h, x, y;
|
||||
void* ptr = Stbtt.GetGlyphBitmapSubpixel(_info, scaleX, scaleY, shiftX, shiftY, glyph, &w, &h, &x, &y);
|
||||
|
||||
offsetX = x;
|
||||
offsetY = y;
|
||||
|
||||
return new Bitmap((IntPtr)ptr, w, h, FreeBitmap);
|
||||
}
|
||||
|
||||
public Bitmap GetGlyphSdf(float scale, int glyph, int padding, byte edgeValue, float pixelDistScale, out int offsetX, out int offsetY)
|
||||
{
|
||||
int w, h, x, y;
|
||||
void *ptr = Stbtt.GetGlyphSDF(_info, scale, glyph, padding, edgeValue, pixelDistScale, &w, &h, &x, &y);
|
||||
|
||||
offsetX = x;
|
||||
offsetY = y;
|
||||
|
||||
return new Bitmap((IntPtr)ptr, w, h, FreeSdf);
|
||||
}
|
||||
|
||||
public Bitmap GetCodepointSdf(float scale, int codepoint, int padding, byte edgeValue, float pixelDistScale, out int offsetX, out int offsetY)
|
||||
{
|
||||
int w, h, x, y;
|
||||
void *ptr = Stbtt.GetCodepointSDF(_info, scale, codepoint, padding, edgeValue, pixelDistScale, &w, &h, &x, &y);
|
||||
|
||||
offsetX = x;
|
||||
offsetY = y;
|
||||
|
||||
return new Bitmap((IntPtr)ptr, w, h, FreeSdf);
|
||||
}
|
||||
|
||||
public Bitmap GetCodepointSdf(float scale, Rune codepoint, int padding, byte edgeValue, float pixelDistScale, out int offsetX, out int offsetY)
|
||||
=> GetCodepointSdf(scale, codepoint.Value, padding, edgeValue, pixelDistScale, out offsetX, out offsetY);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
bool isDisposed = false;
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (isDisposed) return;
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
|
||||
Marshal.FreeHGlobal(_buffer);
|
||||
Marshal.FreeHGlobal((IntPtr)_info);
|
||||
isDisposed = true;
|
||||
}
|
||||
|
||||
public static bool TryLoad(Stream stream, out StbFont font)
|
||||
{
|
||||
byte* buffer = (byte*)Marshal.AllocHGlobal((int)stream.Length);
|
||||
stbtt_fontinfo* fontInfo = (stbtt_fontinfo*)Marshal.AllocHGlobal(sizeof(stbtt_fontinfo));
|
||||
|
||||
stream.Read(new Span<byte>(buffer, (int)stream.Length));
|
||||
|
||||
int nfont = Stbtt.GetNumberOfFonts(buffer);
|
||||
|
||||
if (nfont == 0)
|
||||
{
|
||||
font = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
int offset = Stbtt.GetFontOffsetForIndex(buffer, 0);
|
||||
|
||||
if (Stbtt.InitFont(fontInfo, (byte*)buffer, offset) == 0)
|
||||
{
|
||||
Marshal.FreeHGlobal((IntPtr)buffer);
|
||||
Marshal.FreeHGlobal((IntPtr)fontInfo);
|
||||
|
||||
font = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
font = new StbFont((IntPtr)buffer, fontInfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static StbFont Load(Stream stream)
|
||||
{
|
||||
if (TryLoad(stream, out StbFont font))
|
||||
{
|
||||
return font;
|
||||
}
|
||||
|
||||
throw new Exception("Could not load the font.");
|
||||
}
|
||||
|
||||
private static void FreeBitmap(IntPtr buffer)
|
||||
{
|
||||
Stbtt.FreeBitmap((byte*)buffer, null);
|
||||
}
|
||||
|
||||
private static void FreeSdf(IntPtr buffer)
|
||||
{
|
||||
Stbtt.FreeSDF((byte*)buffer, null);
|
||||
}
|
||||
|
||||
public struct Box
|
||||
{
|
||||
public int X0;
|
||||
public int Y0;
|
||||
public int X1;
|
||||
public int Y1;
|
||||
|
||||
public Box(int x0, int y0, int x1, int y1)
|
||||
{
|
||||
X0 = x0; Y0 = y0;
|
||||
X1 = x1; Y1 = y1;
|
||||
}
|
||||
}
|
||||
|
||||
public class Bitmap : IDisposable
|
||||
{
|
||||
public IntPtr Buffer { get; }
|
||||
public int Width { get; }
|
||||
public int Height { get; }
|
||||
|
||||
private readonly Action<IntPtr> Destroy;
|
||||
|
||||
public Bitmap(IntPtr buffer, int width, int height, Action<IntPtr> destroy)
|
||||
{
|
||||
Buffer = buffer;
|
||||
Width = width;
|
||||
Height = height;
|
||||
Destroy = destroy;
|
||||
}
|
||||
~Bitmap()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public void Dispose() => Dispose(true);
|
||||
|
||||
private bool isDiposed = false;
|
||||
public void Dispose(bool disposing)
|
||||
{
|
||||
if (isDiposed) return;
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
Destroy(Buffer);
|
||||
isDiposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
63
Quik.StbTrueType/Stbtt.Manual.cs
Normal file
@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Quik.Stb
|
||||
{
|
||||
public unsafe static partial class Stbtt
|
||||
{
|
||||
private delegate void FailedAssertProc(byte *expression, byte *file, int line, byte *function);
|
||||
|
||||
private static readonly string[] LibraryNames = new string[]
|
||||
{
|
||||
//FIXME: This is wrong on so many levels, but, i need to do this
|
||||
// in order to get a change of this running.
|
||||
"runtimes/win-x64/native/libstbtt.dll",
|
||||
"runtimes/win-x86/native/libstbtt.dll",
|
||||
"runtimes/linux-arm/native/libstbtt.so",
|
||||
"runtimes/linux-arm64/native/libstbtt.so",
|
||||
"runtimes/linux-x64/native/libstbtt.so",
|
||||
"runtimes/native/libstbtt.dylib",
|
||||
"libstbtt.dll",
|
||||
"libstbtt.so",
|
||||
"libstbtt.dylib",
|
||||
};
|
||||
|
||||
static Stbtt()
|
||||
{
|
||||
NativeLibrary.SetDllImportResolver(Assembly.GetExecutingAssembly(), Resolver);
|
||||
|
||||
quik_stbtt_failed_assert_store(Marshal.GetFunctionPointerForDelegate<FailedAssertProc>(FailedAssert));
|
||||
}
|
||||
|
||||
private static IntPtr Resolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
|
||||
{
|
||||
if (libraryName != "stbtt")
|
||||
return IntPtr.Zero;
|
||||
|
||||
foreach (string name in LibraryNames)
|
||||
{
|
||||
if (NativeLibrary.TryLoad(name, assembly, searchPath, out IntPtr handle))
|
||||
{
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
|
||||
return NativeLibrary.Load(libraryName);
|
||||
}
|
||||
|
||||
private static void FailedAssert(byte *expression, byte *file, int line, byte *function)
|
||||
{
|
||||
string expr = expression == null ? string.Empty : Marshal.PtrToStringUTF8((IntPtr)expression);
|
||||
string f = file == null ? string.Empty : Marshal.PtrToStringUTF8((IntPtr)file);
|
||||
string func = function == null ? string.Empty : Marshal.PtrToStringUTF8((IntPtr)function);
|
||||
|
||||
Exception ex = new Exception("Assert failed in native stbtt code.");
|
||||
ex.Data.Add("Expression", expr);
|
||||
ex.Data.Add("File", f);
|
||||
ex.Data.Add("Line", line);
|
||||
ex.Data.Add("Function", func);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
}
|
34
Quik.sln
@ -9,12 +9,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Quik.StbImage", "Quik.StbIm
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Quik.StbTrueType", "Quik.StbTrueType\Quik.StbTrueType.csproj", "{AD5B02B0-F957-4816-8CE9-5F278B856C70}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{5E87AF9C-AC12-4E48-99B1-CBEC0C97B624}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Quik.StbImage.Tests", "tests\Quik.StbImage.Tests\Quik.StbImage.Tests.csproj", "{AFF181CF-D51E-4E16-B3C6-38ED1E1FF615}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Quik.Media.Stb", "Quik.Media.Stb\Quik.Media.Stb.csproj", "{3D354BE0-42A7-45C4-AAEA-B0F8963A5745}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{AE05ADE5-A809-479F-97D5-BEAFE7604285}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Quik.Stb.Tests", "tests\Quik.Stb.Tests\Quik.Stb.Tests.csproj", "{BC7D3002-B79B-4141-B6CC-74FB2175B474}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -73,18 +73,6 @@ Global
|
||||
{AD5B02B0-F957-4816-8CE9-5F278B856C70}.Release|x64.Build.0 = Release|Any CPU
|
||||
{AD5B02B0-F957-4816-8CE9-5F278B856C70}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{AD5B02B0-F957-4816-8CE9-5F278B856C70}.Release|x86.Build.0 = Release|Any CPU
|
||||
{AFF181CF-D51E-4E16-B3C6-38ED1E1FF615}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AFF181CF-D51E-4E16-B3C6-38ED1E1FF615}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AFF181CF-D51E-4E16-B3C6-38ED1E1FF615}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{AFF181CF-D51E-4E16-B3C6-38ED1E1FF615}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{AFF181CF-D51E-4E16-B3C6-38ED1E1FF615}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{AFF181CF-D51E-4E16-B3C6-38ED1E1FF615}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{AFF181CF-D51E-4E16-B3C6-38ED1E1FF615}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AFF181CF-D51E-4E16-B3C6-38ED1E1FF615}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AFF181CF-D51E-4E16-B3C6-38ED1E1FF615}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{AFF181CF-D51E-4E16-B3C6-38ED1E1FF615}.Release|x64.Build.0 = Release|Any CPU
|
||||
{AFF181CF-D51E-4E16-B3C6-38ED1E1FF615}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{AFF181CF-D51E-4E16-B3C6-38ED1E1FF615}.Release|x86.Build.0 = Release|Any CPU
|
||||
{3D354BE0-42A7-45C4-AAEA-B0F8963A5745}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3D354BE0-42A7-45C4-AAEA-B0F8963A5745}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3D354BE0-42A7-45C4-AAEA-B0F8963A5745}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
@ -97,8 +85,20 @@ Global
|
||||
{3D354BE0-42A7-45C4-AAEA-B0F8963A5745}.Release|x64.Build.0 = Release|Any CPU
|
||||
{3D354BE0-42A7-45C4-AAEA-B0F8963A5745}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{3D354BE0-42A7-45C4-AAEA-B0F8963A5745}.Release|x86.Build.0 = Release|Any CPU
|
||||
{BC7D3002-B79B-4141-B6CC-74FB2175B474}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{BC7D3002-B79B-4141-B6CC-74FB2175B474}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BC7D3002-B79B-4141-B6CC-74FB2175B474}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{BC7D3002-B79B-4141-B6CC-74FB2175B474}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{BC7D3002-B79B-4141-B6CC-74FB2175B474}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{BC7D3002-B79B-4141-B6CC-74FB2175B474}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{BC7D3002-B79B-4141-B6CC-74FB2175B474}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BC7D3002-B79B-4141-B6CC-74FB2175B474}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{BC7D3002-B79B-4141-B6CC-74FB2175B474}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{BC7D3002-B79B-4141-B6CC-74FB2175B474}.Release|x64.Build.0 = Release|Any CPU
|
||||
{BC7D3002-B79B-4141-B6CC-74FB2175B474}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{BC7D3002-B79B-4141-B6CC-74FB2175B474}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{AFF181CF-D51E-4E16-B3C6-38ED1E1FF615} = {5E87AF9C-AC12-4E48-99B1-CBEC0C97B624}
|
||||
{BC7D3002-B79B-4141-B6CC-74FB2175B474} = {AE05ADE5-A809-479F-97D5-BEAFE7604285}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
72
tests/Quik.Stb.Tests/LoadFont.cs
Normal file
@ -0,0 +1,72 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using Quik.Stb;
|
||||
|
||||
namespace Quik.Stb
|
||||
{
|
||||
[TestClass]
|
||||
[TestCategory("Load Font")]
|
||||
public class LoadFont
|
||||
{
|
||||
StbFont? font;
|
||||
|
||||
[TestInitialize]
|
||||
public void Initialize()
|
||||
{
|
||||
using (Stream? str = GetType().Assembly.GetManifestResourceStream("Quik.Stb.Tests.res.Varicka.ttf"))
|
||||
{
|
||||
Assert.IsNotNull(str, "Test font file not packed.");
|
||||
font = StbFont.Load(str);
|
||||
}
|
||||
}
|
||||
|
||||
[TestCleanup]
|
||||
public void Deinitialize()
|
||||
{
|
||||
font?.Dispose();
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void AscendIsValid()
|
||||
{
|
||||
Assert.AreNotEqual(-1, font!.Ascend);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void DescendIsValid()
|
||||
{
|
||||
Assert.AreNotEqual(-1, font!.Descend);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void VLineGapIsValid()
|
||||
{
|
||||
Assert.AreNotEqual(-1, font!.VerticalLineGap);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void BBoxIsValid()
|
||||
{
|
||||
Assert.AreNotEqual(default, font!.BoundingBox);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void KerningTableIsValid()
|
||||
{
|
||||
Assert.IsNotNull(font!.KerningTable);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void GetGlyphsForAscii()
|
||||
{
|
||||
for (int i = 0; i < 128; i++)
|
||||
{
|
||||
int glyph = font!.FindGlyphIndex(i);
|
||||
|
||||
Assert.AreNotEqual(-1, glyph);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +1,7 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using Quik.Stb;
|
||||
using Image = Quik.Stb.StbImage;
|
||||
|
||||
namespace Quik.StbImage.Tests
|
||||
namespace Quik.Stb.Tests
|
||||
{
|
||||
[TestClass]
|
||||
[TestCategory("Load Image")]
|
||||
@ -27,7 +23,7 @@ namespace Quik.StbImage.Tests
|
||||
|
||||
private unsafe void TestImage(string path, int width, int height)
|
||||
{
|
||||
Image image = Image.Load(GetImage(path));
|
||||
StbImage image = StbImage.Load(GetImage(path));
|
||||
|
||||
Assert.IsNotNull(image);
|
||||
|
||||
@ -41,9 +37,9 @@ namespace Quik.StbImage.Tests
|
||||
const int HEIGHT = 512;
|
||||
|
||||
[TestMethod("Load a single frame GIF")]
|
||||
public unsafe void LoadGif() => TestImage("Quik.StbImage.Tests.res.kodim.kodim23.gif", WIDTH, HEIGHT);
|
||||
public unsafe void LoadGif() => TestImage("Quik.Stb.Tests.res.kodim.kodim23.gif", WIDTH, HEIGHT);
|
||||
[TestMethod("Load a JPEG")]
|
||||
public unsafe void LoadJpg() => TestImage("Quik.StbImage.Tests.res.kodim.kodim23.jpg", WIDTH, HEIGHT);
|
||||
[TestMethod("Load a PNG")] public unsafe void LoadPng() => TestImage("Quik.StbImage.Tests.res.kodim.kodim23.png", WIDTH, HEIGHT);
|
||||
public unsafe void LoadJpg() => TestImage("Quik.Stb.Tests.res.kodim.kodim23.jpg", WIDTH, HEIGHT);
|
||||
[TestMethod("Load a PNG")] public unsafe void LoadPng() => TestImage("Quik.Stb.Tests.res.kodim.kodim23.png", WIDTH, HEIGHT);
|
||||
}
|
||||
}
|
@ -23,6 +23,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Quik.StbImage\Quik.StbImage.csproj" />
|
||||
<ProjectReference Include="..\..\Quik.StbTrueType\Quik.StbTrueType.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
BIN
tests/Quik.Stb.Tests/res/Varicka.ttf
Normal file
12
tests/Quik.Stb.Tests/res/Varicka.txt
Normal file
@ -0,0 +1,12 @@
|
||||
Varicka (Truetype and Opentype with no OT features)
|
||||
|
||||
Based on 'Varick', from "Decorative Condensed Alphabets", by Dan Solo, Page 94.
|
||||
|
||||
Letter spacing is set to balance the letterforms themselves; the space between most adjacent letters is identical to the horizontal space inside such letters as 'O' and 'H'. Kerning is supplied as needed for certain letter combinations, particularly those that have a letter with a projection on the left, such as A, E, F, H, K, P, and R.
|
||||
|
||||
Varicka is superficially similar to Red Rooster's Triple Gothic Condensed, but the Solo book's font has different features and some very different letterforms.
|
||||
|
||||
This font is free and available for all use, personal and commercial, with no restrictions.
|
||||
|
||||
Character
|
||||
February 13, 2010
|
Before Width: | Height: | Size: 156 KiB After Width: | Height: | Size: 156 KiB |
Before Width: | Height: | Size: 97 KiB After Width: | Height: | Size: 97 KiB |
Before Width: | Height: | Size: 544 KiB After Width: | Height: | Size: 544 KiB |
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 55 KiB |