Ejemplo n.º 1
0
        public void MeasureString(char[] buffer, int startAt, int len, out int w, out int h)
        {
            UpdateGlyphLayoutSettings();
            _glyphMeshStore.SetFont(_currentTypeface, this.FontSizeInPoints);
            _glyphMeshStore.SimulateOblique = this.SimulateSlant;
            TextBufferSpan textBuffSpan = new TextBufferSpan(buffer, startAt, len);
            Size           s            = _textServices.MeasureString(ref textBuffSpan, _painter.CurrentFont);

            w = s.Width;
            h = s.Height;
        }
Ejemplo n.º 2
0
        public void DrawString(RenderVxFormattedString renderVx, double x, double y)
        {
            //TODO: review here
            float ox = _painter.OriginX;
            float oy = _painter.OriginY;

            //1. update some props..
            //2. update current type face
            UpdateGlyphLayoutSettings();
            _glyphMeshStore.SetFont(_currentTypeface, this.FontSizeInPoints);
            _glyphMeshStore.SimulateOblique = this.SimulateSlant;

            //3. layout glyphs with selected layout technique
            //TODO: review this again, we should use pixel?
            float fontSizePoint = this.FontSizeInPoints;
            float scale         = _currentTypeface.CalculateScaleToPixelFromPointSize(fontSizePoint);

            RenderVxGlyphPlan[] glyphPlans = renderVx.glyphList;
            int j = glyphPlans.Length;
            //---------------------------------------------------
            //consider use cached glyph, to increase performance

            //GlyphPosPixelSnapKind x_snap = this.GlyphPosPixelSnapX;
            //GlyphPosPixelSnapKind y_snap = this.GlyphPosPixelSnapY;
            float g_x   = 0;
            float g_y   = 0;
            float baseY = (int)y;

            for (int i = 0; i < j; ++i)
            {
                RenderVxGlyphPlan glyphPlan = glyphPlans[i];
                //-----------------------------------
                //TODO: review here ***
                //PERFORMANCE revisit here
                //if we have create a vxs we can cache it for later use?
                //-----------------------------------
                VertexStore vxs = _glyphMeshStore.GetGlyphMesh(glyphPlan.glyphIndex);
                g_x = (float)(glyphPlan.x * scale + x);
                g_y = (float)glyphPlan.y * scale;

                _painter.SetOrigin(g_x, g_y);
                _painter.Fill(vxs);
            }
            //restore prev origin
            _painter.SetOrigin(ox, oy);
        }
Ejemplo n.º 3
0
 protected override void SetGlyphVxs(GlyphBox glyphBox, Typeface typeface, float sizeInPoint)
 {
     if (glyphBox is VxsGlyphBox vxsGlyphBox)
     {
         _glyphMeshStore.SetFont(typeface, sizeInPoint);//20= font size
         _glyphMeshStore.FlipGlyphUpward = true;
         if (glyphBox.IsItalic)
         {
             _glyphMeshStore.SimulateOblique = glyphBox.IsItalic;
         }
         vxsGlyphBox.GlyphVxs = _glyphMeshStore.GetGlyphMesh(glyphBox.GlyphIndex);
         if (_glyphMeshStore.SimulateOblique)
         {
             _glyphMeshStore.SimulateOblique = false;
         }
     }
 }
Ejemplo n.º 4
0
        private void TxtTestGlyph_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode != Keys.Enter)
            {
                return;
            }
            //---

            string text = txtTestGlyph.Text.Trim();

            if (text.Length == 0)
            {
                return;
            }
            char singleChar = text[0];

            //1. read a single glyph from font file.
            //2. generate vxs from the glyph.

            var glyphMeshStore = new GlyphMeshStore();

            glyphMeshStore.FlipGlyphUpward = false;


            //just example, not need to open-read everytime.
            Typeface typeface = null;
            //string fontpath = "Samples/SourceSansPro-Regular.ttf";
            string fontpath = "Samples/Roboto-Regular.ttf";

            using (FileStream fs = new FileStream(fontpath, FileMode.Open, FileAccess.Read))
            {
                OpenFontReader fontReader = new OpenFontReader();
                typeface = fontReader.Read(fs);

                glyphMeshStore.SetFont(typeface, 56);

                ushort glyphIndex = typeface.GetGlyphIndex(singleChar);


                VertexStore glyphVxs = glyphMeshStore.GetNewUnFlattenVxs(glyphIndex); //**
                //VertexStore glyphVxs = glyphMeshStore.GetGlyphMesh(glyphIndex);//org
                GenerateMsdf(glyphVxs);
            }
        }
Ejemplo n.º 5
0
        private void button3_Click(object sender, EventArgs e)
        {
            //it should be faster if we use 'mesh' cache
            //instead of read-transform it every time like code above(button2_click)

            LoadFont();

            float font_size_in_Point = 20;

            _glyphMeshStore.SetFont(_latinModernMathFont, font_size_in_Point);//20= font size
            _glyphMeshStore.FlipGlyphUpward = true;

            float px_scale = _latinModernMathFont.CalculateScaleToPixelFromPointSize(font_size_in_Point);

            using (Tools.BorrowAggPainter(_memBmp, out var p))
            {
                p.Clear(PixelFarm.Drawing.Color.White);

                float prevX = p.OriginX;
                float prevY = p.OriginY;


                int line_left = 10;
                int line_top  = 50;

                p.SetOrigin(line_left, line_top);//*** test

                //draw reference point
                p.FillRect(0, 0, 5, 5, PixelFarm.Drawing.Color.Red);

                char[] test_str    = "‽_x‾".ToCharArray();
                int    inline_left = 0;
                int    inline_top  = 0;

                //----------
                GlyphLayout glyphLayout = new GlyphLayout();
                glyphLayout.ScriptLang = new ScriptLang("math");
                glyphLayout.Typeface   = _latinModernMathFont;


                //temp fix for some typeface

                glyphLayout.SetGlyphIndexNotFoundHandler((glyph_layout, codepoint, next_codepoint) =>
                {
                    switch (codepoint)
                    {
                    //overline unicode
                    case 8254: return(2246);    //overline-combine, this will break into 3 parts in math layout process
                    }
                    return(0);
                });


                //
                glyphLayout.Layout(test_str, 0, test_str.Length);

                List <UnscaledGlyphPlan> glyphPlans = new List <UnscaledGlyphPlan>();

                foreach (UnscaledGlyphPlan glypyPlan in glyphLayout.GetUnscaledGlyphPlanIter())
                {
                    glyphPlans.Add(glypyPlan);
                }
                //--------
                for (int i = 0; i < glyphPlans.Count; ++i)
                {
                    //ushort glyphIndex = _latinModernMathFont.GetGlyphIndex((int)test_str[i]);
                    ////do some glyph-substitution
                    //ushort advW = _latinModernMathFont.GetAdvanceWidth((int)test_str[i]);//unscale glyph width
                    //now scale it to specific font size

                    UnscaledGlyphPlan glyphPlan = glyphPlans[i];
                    int         advW_s          = (int)System.Math.Round(px_scale * glyphPlan.AdvanceX);
                    VertexStore v1 = _glyphMeshStore.GetGlyphMesh(glyphPlan.glyphIndex);
                    p.SetOrigin(line_left + inline_left, line_top + inline_top);
                    p.Fill(v1, PixelFarm.Drawing.Color.Black);
                    inline_left += advW_s;//move
                }
                //restore
                p.SetOrigin(prevX, prevY);
            }

            //-----------
            CopyBitmapToScreen();
        }
Ejemplo n.º 6
0
        void CreateTextureFontFromGlyphIndices(
            HintTechnique hintTechnique,
            SimpleBitmapAtlasBuilder atlasBuilder,
            ushort[] glyphIndices)
        {
            //sample: create sample msdf texture
            //-------------------------------------------------------------
            var outlineBuilder = new GlyphOutlineBuilder(_typeface);

            outlineBuilder.SetHintTechnique(hintTechnique);
            //
            AggGlyphTextureGen aggTextureGen = new AggGlyphTextureGen();

            GlyphNotFoundHelper glyphNotFoundHelper = new GlyphNotFoundHelper(atlasBuilder,
                                                                              outlineBuilder,
                                                                              _onEachGlyphDel,
                                                                              aggTextureGen,
                                                                              _sizeInPoints);


            //create reusable agg painter***
            //assume each glyph size= 2 * line height
            //TODO: review here again...

            //please note that DPI effect glyph size //***

            int tmpMemBmpHeight = (int)(2 * _typeface.CalculateRecommendLineSpacing() * _px_scale);

            //
            if (atlasBuilder.TextureKind == TextureKind.Msdf)
            {
                var msdfGenParams = new Msdfgen.MsdfGenParams();
                int j             = glyphIndices.Length;

                if (MsdfGenVersion == 3)
                {
                    Msdfgen.MsdfGen3 gen3 = new Msdfgen.MsdfGen3();

                    for (int i = 0; i < j; ++i)
                    {
                        ushort gindex = glyphIndices[i];
                        //create picture with unscaled version set scale=-1
                        //(we will create glyph contours and analyze them)

                        var glyphToVxs = new GlyphTranslatorToVxs();
                        outlineBuilder.BuildFromGlyphIndex(gindex, -1, glyphToVxs);

                        using (Tools.BorrowVxs(out var vxs))
                        {
                            glyphToVxs.WriteUnFlattenOutput(vxs, _px_scale);
                            BitmapAtlasItemSource glyphImg = gen3.GenerateMsdfTexture(vxs);
                            glyphImg.UniqueInt16Name = gindex;
                            _onEachGlyphDel?.Invoke(glyphImg);
                            //

                            atlasBuilder.AddItemSource(glyphImg);
                        }
                    }
                }
                else
                {
                    //use gen3
                    Msdfgen.MsdfGen3 gen3 = new Msdfgen.MsdfGen3();
                    for (int i = 0; i < j; ++i)
                    {
                        ushort gindex = glyphIndices[i];
                        //create picture with unscaled version set scale=-1
                        //(we will create glyph contours and analyze them)

                        var glyphToVxs = new GlyphTranslatorToVxs();
                        outlineBuilder.BuildFromGlyphIndex(gindex, -1, glyphToVxs);

                        using (Tools.BorrowVxs(out var vxs))
                        {
                            glyphToVxs.WriteUnFlattenOutput(vxs, _px_scale);
                            BitmapAtlasItemSource glyphImg = gen3.GenerateMsdfTexture(vxs);
                            glyphImg.UniqueInt16Name = gindex;
                            _onEachGlyphDel?.Invoke(glyphImg);

                            atlasBuilder.AddItemSource(glyphImg);
                        }
                    }
                }
                return;
            }
            else if (atlasBuilder.TextureKind == TextureKind.Bitmap)
            {
                //generate color bitmap atlas
                int j = glyphIndices.Length;

                GlyphMeshStore glyphMeshStore = new GlyphMeshStore();
                glyphMeshStore.SetFont(_typeface, _sizeInPoints);
                aggTextureGen.TextureKind = TextureKind.Bitmap;

                using (PixelFarm.CpuBlit.MemBitmap tmpMemBmp = new PixelFarm.CpuBlit.MemBitmap(tmpMemBmpHeight, tmpMemBmpHeight)) //square
                {
                    aggTextureGen.Painter = PixelFarm.CpuBlit.AggPainter.Create(tmpMemBmp);
#if DEBUG
                    tmpMemBmp._dbugNote = "CreateGlyphImage()";
#endif


                    if (_typeface.HasColorTable())
                    {
                        //outline glyph

                        for (int i = 0; i < j; ++i)
                        {
                            ushort gindex = glyphIndices[i];
                            if (!_typeface.COLRTable.LayerIndices.TryGetValue(gindex, out ushort colorLayerStart))
                            {
                                //not found, then render as normal
                                //TODO: impl

                                //create glyph img
                                glyphNotFoundHelper.HandleNotFoundGlyph(gindex);
                            }
                            else
                            {
                                //TODO: review this again
                                GlyphBitmap glyphBmp = GetGlyphBitmapFromColorOutlineGlyph(gindex, glyphMeshStore, colorLayerStart);
                                if (glyphBmp == null)
                                {
                                    glyphNotFoundHelper.HandleNotFoundGlyph(gindex);
                                }
                                else
                                {
                                    int w = glyphBmp.Width;
                                    int h = glyphBmp.Height;

                                    BitmapAtlasItemSource glyphImage = new BitmapAtlasItemSource(glyphBmp.Width, glyphBmp.Height);

                                    glyphImage.TextureXOffset = (short)glyphBmp.ImageStartX;
                                    glyphImage.TextureYOffset = (short)glyphBmp.ImageStartY;

                                    //
                                    glyphImage.SetImageBuffer(MemBitmapExt.CopyImgBuffer(glyphBmp.Bitmap, w, h, true), false);

                                    glyphImage.UniqueInt16Name = gindex;
                                    _onEachGlyphDel?.Invoke(glyphImage);
                                    atlasBuilder.AddItemSource(glyphImage);

                                    //clear
                                    glyphBmp.Bitmap.Dispose();
                                    glyphBmp.Bitmap = null;
                                }
                            }
                        }
                    }
                    else if (_typeface.IsBitmapFont)
                    {
                        aggTextureGen.TextureKind = TextureKind.Bitmap;
                        //test this with Noto Color Emoji
                        for (int i = 0; i < j; ++i)
                        {
                            ushort gindex = glyphIndices[i];

                            GlyphBitmap glyphBmp = GetGlyphBitmapFromBitmapFont(gindex);
                            if (glyphBmp == null)
                            {
                                glyphNotFoundHelper.HandleNotFoundGlyph(gindex);
                            }
                            else
                            {
                                int w = glyphBmp.Width;
                                int h = glyphBmp.Height;

                                BitmapAtlasItemSource glyphImage = new BitmapAtlasItemSource(glyphBmp.Width, glyphBmp.Height);

                                glyphImage.TextureXOffset = (short)glyphBmp.ImageStartX;
                                glyphImage.TextureYOffset = (short)glyphBmp.ImageStartY;

                                //
                                glyphImage.SetImageBuffer(MemBitmapExt.CopyImgBuffer(glyphBmp.Bitmap, w, h, true), false);

                                glyphImage.UniqueInt16Name = gindex;
                                _onEachGlyphDel?.Invoke(glyphImage);
                                atlasBuilder.AddItemSource(glyphImage);

                                //clear
                                glyphBmp.Bitmap.Dispose();
                                glyphBmp.Bitmap = null;
                            }
                        }
                    }
                    else if (_typeface.HasSvgTable())
                    {
                        aggTextureGen.TextureKind = TextureKind.Bitmap;
                        //test this with TwitterEmoji
                        //generate membitmap from svg
#if DEBUG
                        System.Diagnostics.Stopwatch sw1 = new System.Diagnostics.Stopwatch();
                        sw1.Start();
#endif

                        for (int i = 0; i < j; ++i)
                        {
                            //TODO: add mutli-threads / async version

                            ushort      gindex   = glyphIndices[i];
                            GlyphBitmap glyphBmp = GetGlyphBitmapFromSvg(gindex);
                            if (glyphBmp == null)
                            {
                                glyphNotFoundHelper.HandleNotFoundGlyph(gindex);
                            }
                            else
                            {
                                int w = glyphBmp.Width;
                                int h = glyphBmp.Height;

                                BitmapAtlasItemSource glyphImage = new BitmapAtlasItemSource(glyphBmp.Width, glyphBmp.Height);

                                glyphImage.TextureXOffset = (short)glyphBmp.ImageStartX;
                                glyphImage.TextureYOffset = (short)glyphBmp.ImageStartY;

                                //
                                glyphImage.SetImageBuffer(MemBitmapExt.CopyImgBuffer(glyphBmp.Bitmap, w, h, true), false);

                                glyphImage.UniqueInt16Name = gindex;
                                _onEachGlyphDel?.Invoke(glyphImage);
                                atlasBuilder.AddItemSource(glyphImage);

                                //clear
                                glyphBmp.Bitmap.Dispose();
                                glyphBmp.Bitmap = null;
                            }
                        }

#if DEBUG
                        sw1.Stop();
                        long ms = sw1.ElapsedMilliseconds;
#endif
                    }
                    return; //NO go below //***
                } //END using
            }


            //---------------------------
            //OTHERS....
            {
                aggTextureGen.TextureKind = atlasBuilder.TextureKind;
                //create glyph img
                using (PixelFarm.CpuBlit.MemBitmap tmpMemBmp = new PixelFarm.CpuBlit.MemBitmap(tmpMemBmpHeight, tmpMemBmpHeight)) //square
                {
                    //draw a glyph into tmpMemBmp and then copy to a GlyphImage
                    aggTextureGen.Painter = PixelFarm.CpuBlit.AggPainter.Create(tmpMemBmp);
#if DEBUG
                    tmpMemBmp._dbugNote = "CreateGlyphImage()";
#endif

                    int j = glyphIndices.Length;
                    for (int i = 0; i < j; ++i)
                    {
                        //build glyph
                        ushort gindex = glyphIndices[i];
                        outlineBuilder.BuildFromGlyphIndex(gindex, _sizeInPoints);

                        BitmapAtlasItemSource glyphImg = aggTextureGen.CreateAtlasItem(outlineBuilder, 1);

                        glyphImg.UniqueInt16Name = gindex;
                        _onEachGlyphDel?.Invoke(glyphImg);
                        atlasBuilder.AddItemSource(glyphImg);
                    }
                }
            }
        }