2023-09-22 18:30:17 +02:00
|
|
|
using System;
|
2024-05-15 22:17:01 +02:00
|
|
|
using System.Buffers;
|
2023-09-22 18:30:17 +02:00
|
|
|
using System.IO;
|
2024-06-24 21:28:41 +02:00
|
|
|
using ReFuel.FreeType;
|
2023-09-22 18:30:17 +02:00
|
|
|
using Quik.Media.Color;
|
2024-05-15 22:17:01 +02:00
|
|
|
using Quik.Media.Font;
|
2023-09-22 18:30:17 +02:00
|
|
|
|
|
|
|
namespace Quik.Media.Defaults
|
|
|
|
{
|
|
|
|
public class QFontFreeType : QFont
|
|
|
|
{
|
|
|
|
private MemoryStream ms;
|
|
|
|
private FTFace face;
|
|
|
|
|
2024-05-15 22:17:01 +02:00
|
|
|
public override FontFace Face => throw new NotImplementedException();
|
2023-09-22 18:30:17 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2024-05-15 22:17:01 +02:00
|
|
|
protected override QImage Render(out QGlyphMetrics metrics, int codepoint, float size, in FontRasterizerOptions options)
|
2023-09-22 18:30:17 +02:00
|
|
|
{
|
|
|
|
FT.SetCharSize(face, 0, (long)Math.Round(64*size), 0, (uint)Math.Round(options.Resolution));
|
|
|
|
|
2024-05-15 22:17:01 +02:00
|
|
|
uint index = FT.GetCharIndex(face, (ulong)codepoint);
|
|
|
|
FT.LoadGlyph(face, index, FTLoadFlags.Default);
|
|
|
|
|
|
|
|
ref readonly FTGlyphMetrics ftmetrics = ref face.Glyph.Metrics;
|
|
|
|
metrics = new QGlyphMetrics(codepoint,
|
|
|
|
new QVec2(ftmetrics.Width/64f, ftmetrics.Height/64f),
|
|
|
|
new QVec2(ftmetrics.HorizontalBearingX/64f, ftmetrics.HorizontalBearingY/64f),
|
|
|
|
new QVec2(ftmetrics.VerticalBearingX/64f, ftmetrics.VerticalBearingY/64f),
|
|
|
|
new QVec2(ftmetrics.HorizontalAdvance/64f, ftmetrics.VerticalAdvance/64f)
|
|
|
|
);
|
2023-09-22 18:30:17 +02:00
|
|
|
|
2024-05-15 22:17:01 +02:00
|
|
|
FT.RenderGlyph(face.Glyph, options.Sdf ? FTRenderMode.Sdf : FTRenderMode.Normal);
|
|
|
|
ref readonly FTBitmap bitmap = ref face.Glyph.Bitmap;
|
|
|
|
|
|
|
|
if (bitmap.Width == 0 || bitmap.Pitch == 0 || bitmap.Buffer == IntPtr.Zero)
|
2023-09-22 18:30:17 +02:00
|
|
|
{
|
2024-05-15 22:17:01 +02:00
|
|
|
return null;
|
2023-09-22 18:30:17 +02:00
|
|
|
}
|
|
|
|
|
2024-05-16 21:58:22 +02:00
|
|
|
QImageBuffer image = new QImageBuffer(QImageFormat.AlphaU8, (int)bitmap.Width, (int)bitmap.Rows);
|
2024-05-15 22:17:01 +02:00
|
|
|
image.LockBits2d(out QImageLock lk, QImageLockOptions.Default);
|
2023-09-22 18:30:17 +02:00
|
|
|
|
2024-05-15 22:17:01 +02:00
|
|
|
unsafe
|
2023-09-22 18:30:17 +02:00
|
|
|
{
|
2024-05-15 22:17:01 +02:00
|
|
|
Buffer.MemoryCopy((void*)bitmap.Buffer, (void*)lk.ImagePtr, lk.Width * lk.Height, bitmap.Width * bitmap.Rows);
|
2023-09-22 18:30:17 +02:00
|
|
|
}
|
|
|
|
|
2024-05-15 22:17:01 +02:00
|
|
|
image.UnlockBits();
|
|
|
|
return image;
|
2023-09-22 18:30:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
protected override void Dispose(bool disposing)
|
|
|
|
{
|
|
|
|
base.Dispose(disposing);
|
|
|
|
|
|
|
|
if (disposing)
|
|
|
|
{
|
|
|
|
ms.Dispose();
|
|
|
|
}
|
|
|
|
|
|
|
|
FT.DoneFace(face);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static FTLibrary Ft => FTProvider.Ft;
|
|
|
|
}
|
|
|
|
}
|