Dashboard/Quik.Media.Defaults/QFontFreeType.cs

108 lines
3.6 KiB
C#
Raw Normal View History

2023-09-22 18:30:17 +02:00
using System;
using System.IO;
using Quik.FreeType;
using Quik.Media;
using Quik.Media.Color;
namespace Quik.Media.Defaults
{
public class QFontFreeType : QFont
{
private MemoryStream ms;
private FTFace face;
public override FontInfo Info => throw new NotImplementedException();
public QFontFreeType(Stream stream)
{
ms = new MemoryStream();
stream.CopyTo(ms);
FTError e = FT.NewMemoryFace(Ft, ms.GetBuffer(), ms.Length, 0, out face);
if (e != FTError.None)
{
throw new Exception("Could not load font face from stream.");
}
}
public override bool HasRune(int rune)
{
return FT.GetCharIndex(face, (ulong)rune) != 0;
}
public override QFontPage RasterizePage(int codepage, float size, in FontRasterizerOptions options)
{
FT.SetCharSize(face, 0, (long)Math.Round(64*size), 0, (uint)Math.Round(options.Resolution));
QGlyphMetrics[] allMetrics = new QGlyphMetrics[256];
// Figure out the map size needed.
int pixels = 0;
for (int i = 0; i < 256; i++)
{
uint index = FT.GetCharIndex(face, (ulong)(codepage + i));
FT.LoadGlyph(face, index, FTLoadFlags.Default);
ref readonly FTGlyphMetrics metrics = ref face.Glyph.Metrics;
allMetrics[i] = new QGlyphMetrics(
codepage + i,
new QVec2(metrics.Width, metrics.Height),
new QVec2(metrics.HorizontalBearingX/64f, metrics.HorizontalBearingY/64f),
new QVec2(metrics.VerticalBearingX/64f, metrics.VerticalBearingY/64f),
new QVec2(metrics.HorizontalAdvance/64f, metrics.VerticalAdvance/64f)
);
pixels = (int)Math.Max(pixels, Math.Max(face.Glyph.Metrics.Width/64f, face.Glyph.Metrics.Height/64f));
}
int bits = Math.ILogB(pixels);
if (1 << bits != pixels)
{
pixels = 1 << bits + 1;
}
// Now we can create a bitmap and render our glyphs.
QImageBuffer buffer = new QImageBuffer(QImageFormat.RedU8, (int)pixels, (int)pixels, 256);
for (int i = 0; i < 256; i++)
{
uint index = FT.GetCharIndex(face, (ulong)(codepage + i));
FT.LoadGlyph(face, index, FTLoadFlags.Default);
FT.RenderGlyph(face.Glyph, options.Sdf ? FTRenderMode.Sdf : FTRenderMode.Mono);
ref readonly FTBitmap bitmap = ref face.Glyph.Bitmap;
buffer.LockBits3d(out QImageLock dst, QImageLockOptions.Default, i);
if (bitmap.Buffer != IntPtr.Zero) unsafe
{
for (int j = 0; j < bitmap.Rows; j++)
{
Buffer.MemoryCopy(
(byte*)bitmap.Buffer + (j * bitmap.Pitch),
(byte*)dst.ImagePtr + (j * dst.Width),
dst.Width,
bitmap.Width);
}
}
buffer.UnlockBits();
}
return new QFontPage(this, codepage, size, options, buffer, allMetrics);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
ms.Dispose();
}
FT.DoneFace(face);
}
private static FTLibrary Ft => FTProvider.Ft;
}
}