예제 #1
0
        public FontGlyph CreateGlyph(char c, int size, float deviceScale)
        {
            var scaledSize = (uint)(size * deviceScale);

            if (FreeType.FT_Set_Pixel_Sizes(face, scaledSize, scaledSize) != FreeType.OK)
            {
                return(EmptyGlyph);
            }

            if (FreeType.FT_Load_Char(face, c, FreeType.FT_LOAD_RENDER) != FreeType.OK)
            {
                return(EmptyGlyph);
            }

            // Extract the glyph data we care about
            // HACK: This uses raw pointer offsets to avoid defining structs and types that are 95% unnecessary
            var glyph = Marshal.ReadIntPtr(IntPtr.Add(face, FreeType.FaceRecGlyphOffset));               // face->glyph

            var metrics        = IntPtr.Add(glyph, FreeType.GlyphSlotMetricsOffset);                     // face->glyph->metrics
            var metricsWidth   = Marshal.ReadIntPtr(IntPtr.Add(metrics, FreeType.MetricsWidthOffset));   // face->glyph->metrics.width
            var metricsHeight  = Marshal.ReadIntPtr(IntPtr.Add(metrics, FreeType.MetricsHeightOffset));  // face->glyph->metrics.width
            var metricsAdvance = Marshal.ReadIntPtr(IntPtr.Add(metrics, FreeType.MetricsAdvanceOffset)); // face->glyph->metrics.horiAdvance

            var bitmap       = IntPtr.Add(glyph, FreeType.GlyphSlotBitmapOffset);                        // face->glyph->bitmap
            var bitmapPitch  = Marshal.ReadInt32(IntPtr.Add(bitmap, FreeType.BitmapPitchOffset));        // face->glyph->bitmap.pitch
            var bitmapBuffer = Marshal.ReadIntPtr(IntPtr.Add(bitmap, FreeType.BitmapBufferOffset));      // face->glyph->bitmap.buffer

            var bitmapLeft = Marshal.ReadInt32(IntPtr.Add(glyph, FreeType.GlyphSlotBitmapLeftOffset));   // face->glyph.bitmap_left
            var bitmapTop  = Marshal.ReadInt32(IntPtr.Add(glyph, FreeType.GlyphSlotBitmapTopOffset));    // face->glyph.bitmap_top

            // Convert FreeType's 26.6 fixed point format to integers by discarding fractional bits
            var glyphSize    = new Size((int)metricsWidth >> 6, (int)metricsHeight >> 6);
            var glyphAdvance = (int)metricsAdvance >> 6;

            var g = new FontGlyph
            {
                Advance = glyphAdvance,
                Offset  = new int2(bitmapLeft, -bitmapTop),
                Size    = glyphSize,
                Data    = new byte[glyphSize.Width * glyphSize.Height]
            };

            unsafe
            {
                var p = (byte *)bitmapBuffer;
                var k = 0;
                for (var j = 0; j < glyphSize.Height; j++)
                {
                    for (var i = 0; i < glyphSize.Width; i++)
                    {
                        g.Data[k++] = p[i];
                    }

                    p += bitmapPitch;
                }
            }

            return(g);
        }
예제 #2
0
        public void Dispose()
        {
            if (!disposed)
            {
                if (faceHandle.IsAllocated)
                {
                    FreeType.FT_Done_Face(face);

                    faceHandle.Free();
                    disposed = true;
                }
            }
        }
예제 #3
0
        public FreeTypeFont(byte[] data)
        {
            if (library == IntPtr.Zero && FreeType.FT_Init_FreeType(out library) != FreeType.OK)
            {
                throw new InvalidOperationException("Failed to initialize FreeType");
            }

            faceHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
            if (FreeType.FT_New_Memory_Face(library, faceHandle.AddrOfPinnedObject(), data.Length, 0, out face) != FreeType.OK)
            {
                throw new InvalidDataException("Failed to initialize font");
            }
        }
예제 #4
0
        public void SetSize(int size, float deviceScale)
        {
            var scaledSize = (uint)(size * deviceScale);

            if (FreeType.FT_Set_Pixel_Sizes(face, scaledSize, scaledSize) != FreeType.OK)
            {
                throw new InvalidDataException("Failed to set size");
            }

            var faceSize  = Marshal.ReadIntPtr(IntPtr.Add(face, FreeType.FaceRecSizeOffset));             // face->size
            var metrics   = IntPtr.Add(faceSize, FreeType.SizeRecMetricsOffset);                          // face->size->metrics
            var ascender  = Marshal.ReadIntPtr(IntPtr.Add(metrics, FreeType.SizeMetricsAscenderOffset));  // face->size->metrics.ascender
            var descender = Marshal.ReadIntPtr(IntPtr.Add(metrics, FreeType.SizeMetricsDescenderOffset)); // face->size->metrics.descender

            var ascenderValue  = (int)ascender >> 6;
            var descenderValue = (int)descender >> 6;

            Height = (int)((ascenderValue - Math.Abs(descenderValue)) / deviceScale);
        }