void CreateTextureFontFromGlyphIndices(
            Typeface typeface,
            float sizeInPoint,
            HintTechnique hintTechnique,
            SimpleFontAtlasBuilder atlasBuilder,
            bool applyFilter,
            ushort[] glyphIndices)
        {
            //sample: create sample msdf texture
            //-------------------------------------------------------------
            var builder = new GlyphPathBuilder(typeface);

            builder.SetHintTechnique(hintTechnique);
            //
            if (atlasBuilder.TextureKind == TextureKind.Msdf)
            {
                MsdfGenParams msdfGenParams = new MsdfGenParams();
                int           j             = glyphIndices.Length;
                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)
                    builder.BuildFromGlyphIndex(gindex, -1);
                    var glyphToContour = new GlyphContourBuilder();
                    builder.ReadShapes(glyphToContour);
                    //msdfgen with  scale the glyph to specific shapescale
                    msdfGenParams.shapeScale = 1f / 64; //as original
                    GlyphImage glyphImg = MsdfGlyphGen.CreateMsdfImage(glyphToContour, msdfGenParams);
                    //
                    atlasBuilder.AddGlyph(gindex, glyphImg);
                }
            }
            else
            {
                AggGlyphTextureGen aggTextureGen = new AggGlyphTextureGen();
                aggTextureGen.TextureKind = atlasBuilder.TextureKind;
                int j = glyphIndices.Length;
                for (int i = 0; i < j; ++i)
                {
                    //build glyph
                    ushort gindex = glyphIndices[i];
                    builder.BuildFromGlyphIndex(gindex, sizeInPoint);

                    GlyphImage glyphImg = aggTextureGen.CreateGlyphImage(builder, 1);
                    if (applyFilter)
                    {
                        glyphImg = Sharpen(glyphImg, 1);
                        //TODO:
                        //the filter make the image shift x and y 1 px
                        //temp fix with this,
                        glyphImg.TextureOffsetX += 1;
                        glyphImg.TextureOffsetY += 1;
                    }
                    //
                    atlasBuilder.AddGlyph(gindex, glyphImg);
                }
            }
        }
Exemplo n.º 2
0
        void CreateTextureFontFromGlyphIndices(
            HintTechnique hintTechnique,
            SimpleBitmapAtlasBuilder atlasBuilder,
            char[] chars)
        {
            int j = chars.Length;

            ushort[] glyphIndices = new ushort[j];
            for (int i = 0; i < j; ++i)
            {
                glyphIndices[i] = _typeface.GetGlyphIndex(chars[i]);
            }

            CreateTextureFontFromGlyphIndices(hintTechnique, atlasBuilder, glyphIndices);
        }
Exemplo n.º 3
0
        public void SetCacheInfo(Typeface typeface, float sizeInPts, HintTechnique hintTech)
        {
            //check if we have create the context for this request parameters?
            var key = new GlyphKey()
            {
                hintTech = hintTech, sizeInPts = sizeInPts, typeface = typeface
            };

            if (!_registerGlyphCollection.TryGetValue(key, out _currentGlyphDic))
            {
                //if not found
                //create new
                _currentGlyphDic = new Dictionary <ushort, T>();
                _registerGlyphCollection.Add(key, _currentGlyphDic);
            }
        }
        public void SetCacheInfo(Typeface typeface, float sizeInPts, HintTechnique hintTech)
        {
            //check if we have create the context for this request parameters?
            var key = new HintedVxsConvtextKey()
            {
                hintTech = hintTech, sizeInPts = sizeInPts, typeface = typeface
            };

            if (!_hintedGlyphs.TryGetValue(key, out _currentGlyphDic))
            {
                //if not found
                //create new
                _currentGlyphDic = new Dictionary <ushort, VertexStore>();
                _hintedGlyphs.Add(key, _currentGlyphDic);
            }
        }
        void CreateTextureFontFromGlyphIndices(
            Typeface typeface,
            float sizeInPoint,
            HintTechnique hintTechnique,
            SimpleFontAtlasBuilder atlasBuilder,
            bool applyFilter,
            char[] chars)
        {
            int j = chars.Length;

            ushort[] glyphIndices = new ushort[j];
            for (int i = 0; i < j; ++i)
            {
                glyphIndices[i] = typeface.LookupIndex(chars[i]);
            }

            CreateTextureFontFromGlyphIndices(typeface, sizeInPoint, hintTechnique, atlasBuilder, applyFilter, glyphIndices);
        }
Exemplo n.º 6
0
        public static void SetHintTechnique(this GlyphPathBuilderBase builder, HintTechnique hintTech)
        {
            builder.UseTrueTypeInstructions = false; //reset
            builder.UseVerticalHinting      = false; //reset
            switch (hintTech)
            {
            case HintTechnique.TrueTypeInstruction:
                builder.UseTrueTypeInstructions = true;
                break;

            case HintTechnique.TrueTypeInstruction_VerticalOnly:
                builder.UseTrueTypeInstructions = true;
                builder.UseVerticalHinting      = true;
                break;

            case HintTechnique.CustomAutoFit:
                //custom agg autofit
                builder.UseVerticalHinting = true;
                break;
            }
        }
Exemplo n.º 7
0
        static SimpleFontAtlasBuilder CreateAggSubPixelRenderingTextureFont(
            Typeface typeface, float sizeInPoint, HintTechnique hintTech, IEnumerable <ushort> glyphIndexIter)
        {
            ////read type face from file
            //Typeface typeface;
            //using (var fs = new FileStream(fontfile, FileMode.Open, FileAccess.Read))
            //{
            //    var reader = new OpenFontReader();
            //    //1. read typeface from font file
            //    typeface = reader.Read(fs);
            //}
            //sample: create sample msdf texture
            //-------------------------------------------------------------
            var builder = new GlyphPathBuilder(typeface);

            builder.SetHintTechnique(hintTech);
            //-------------------------------------------------------------
            var atlasBuilder = new SimpleFontAtlasBuilder();

            atlasBuilder.SetAtlasInfo(TextureKind.AggSubPixel, sizeInPoint);
            VertexStorePool vxsPool = new VertexStorePool();

            //create agg cavnas

            foreach (ushort gindex in glyphIndexIter)
            {
                //build glyph

                builder.BuildFromGlyphIndex(gindex, sizeInPoint);


                var txToVxs = new GlyphTranslatorToVxs();
                builder.ReadShapes(txToVxs);
                //
                //create new one
                var glyphVxs = new VertexStore();
                txToVxs.WriteOutput(glyphVxs, vxsPool);
                //find bound

                //--------------------------------------------
                //GlyphImage glyphImg = new GlyphImage()
                RectD bounds = new Agg.RectD();
                BoundingRect.GetBoundingRect(new VertexStoreSnap(glyphVxs), ref bounds);

                //--------------------------------------------
                int w = (int)System.Math.Ceiling(bounds.Width);
                int h = (int)System.Math.Ceiling(bounds.Height);
                if (w < 5)
                {
                    w = 5;
                }
                if (h < 5)
                {
                    h = 5;
                }
                //translate to positive quadrant
                double dx = (bounds.Left < 0) ? -bounds.Left : 0;
                double dy = (bounds.Bottom < 0) ? -bounds.Bottom : 0;
                w = w * 4;

                if (dx != 0 || dy != 0)
                {
                    Agg.Transform.Affine transformMat = Agg.Transform.Affine.NewTranslation(dx, dy);
                    VertexStore          vxs2         = new VertexStore();
                    glyphVxs.TranslateToNewVxs(dx, dy, vxs2);
                    glyphVxs = vxs2;
                }
                //--------------------------------------------
                //create glyph img
                ActualImage      img         = new Agg.ActualImage(w, h, PixelFormat.ARGB32);
                ImageGraphics2D  imgCanvas2d = new Agg.ImageGraphics2D(img);
                AggCanvasPainter painter     = new Agg.AggCanvasPainter(imgCanvas2d);
                //we use white glyph on black bg for this texture
                painter.Clear(Color.Black); //fill with black
                painter.FillColor   = Color.White;
                painter.StrokeColor = Color.White;
                //--------------------------------------------

                painter.UseSubPixelRendering = true;
                //--------------------------------------------


                //--------------------------------------------
                painter.Fill(glyphVxs);
                //--------------------------------------------
                var glyphImage = new GlyphImage(w, h);
                glyphImage.TextureOffsetX = dx;
                glyphImage.TextureOffsetY = dy;
                glyphImage.SetImageBuffer(ActualImage.GetBuffer2(img), false);
                //copy data from agg canvas to glyph image
                atlasBuilder.AddGlyph(gindex, glyphImage);

                //int[] buffer = glyphImage.GetImageBuffer();
                //using (var bmp = new System.Drawing.Bitmap(glyphImage.Width, glyphImage.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb))
                //{
                //    var bmpdata = bmp.LockBits(new System.Drawing.Rectangle(0, 0, glyphImage.Width, glyphImage.Height),
                //        System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat);
                //    System.Runtime.InteropServices.Marshal.Copy(buffer, 0, bmpdata.Scan0, buffer.Length);
                //    bmp.UnlockBits(bmpdata);
                //    bmp.Save("d:\\WImageTest\\a001_subpix_xn2_" + gindex + ".png");
                //}
            }
            //var glyphImg2 = atlasBuilder.BuildSingleImage();
            //using (var bmp = new System.Drawing.Bitmap(glyphImg2.Width, glyphImg2.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb))
            //{
            //    var bmpdata = bmp.LockBits(new System.Drawing.Rectangle(0, 0, glyphImg2.Width, glyphImg2.Height),
            //        System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat);
            //    int[] intBuffer = glyphImg2.GetImageBuffer();

            //    System.Runtime.InteropServices.Marshal.Copy(intBuffer, 0, bmpdata.Scan0, intBuffer.Length);
            //    bmp.UnlockBits(bmpdata);
            //    bmp.Save("d:\\WImageTest\\a_total.png");
            //}
            //atlasBuilder.SaveFontInfo("d:\\WImageTest\\a_info.xml");

            return(atlasBuilder);
        }
Exemplo n.º 8
0
        static SimpleFontAtlasBuilder CreateSampleMsdfTextureFont(
            Typeface typeface,
            float sizeInPoint,
            HintTechnique hintTech,
            IEnumerable <ushort> glyphIndexIter)
        {
            ////read type face from file
            //Typeface typeface;
            //using (var fs = new FileStream(fontfile, FileMode.Open, FileAccess.Read))
            //{
            //    var reader = new OpenFontReader();
            //    //1. read typeface from font file
            //    typeface = reader.Read(fs);
            //}
            //sample: create sample msdf texture
            //-------------------------------------------------------------
            var builder = new GlyphPathBuilder(typeface);

            builder.SetHintTechnique(hintTech);
            MsdfGenParams genParams    = new MsdfGenParams();
            var           atlasBuilder = new SimpleFontAtlasBuilder();

            atlasBuilder.SetAtlasInfo(TextureKind.Msdf, sizeInPoint);
            foreach (ushort gindex in glyphIndexIter)
            {
                //build glyph
                builder.BuildFromGlyphIndex(gindex, -1); //use original glyph size (assign -1)
                var glyphToContour = new GlyphContourBuilder();


                //glyphToContour.Read(builder.GetOutputPoints(), builder.GetOutputContours());
                builder.ReadShapes(glyphToContour);
                genParams.shapeScale = 1f / 64; //we scale later (as original C++ code use 1/64)
                GlyphImage glyphImg = MsdfGlyphGen.CreateMsdfImage(glyphToContour, genParams);

                atlasBuilder.AddGlyph(gindex, glyphImg);


                //int[] buffer = glyphImage.GetImageBuffer();
                //using (var bmp = new System.Drawing.Bitmap(glyphImage.Width, glyphImage.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb))
                //{
                //    var bmpdata = bmp.LockBits(new System.Drawing.Rectangle(0, 0, glyphImage.Width, glyphImage.Height),
                //        System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat);
                //    System.Runtime.InteropServices.Marshal.Copy(buffer, 0, bmpdata.Scan0, buffer.Length);
                //    bmp.UnlockBits(bmpdata);
                //    bmp.Save("d:\\WImageTest\\a001_xn2_" + c + ".png");
                //}
            }



            //var glyphImg2 = atlasBuilder.BuildSingleImage();
            //using (var bmp = new System.Drawing.Bitmap(glyphImg2.Width, glyphImg2.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb))
            //{
            //    var bmpdata = bmp.LockBits(new System.Drawing.Rectangle(0, 0, glyphImg2.Width, glyphImg2.Height),
            //        System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat);
            //    int[] intBuffer = glyphImg2.GetImageBuffer();

            //    System.Runtime.InteropServices.Marshal.Copy(intBuffer, 0, bmpdata.Scan0, intBuffer.Length);
            //    bmp.UnlockBits(bmpdata);
            //    bmp.Save("d:\\WImageTest\\a_total.png");
            //}
            //atlasBuilder.SaveFontInfo("d:\\WImageTest\\a_info.xml");

            return(atlasBuilder);
        }
Exemplo n.º 9
0
        public void RenderChar(char testChar, HintTechnique hint)
        {
            builder.SetHintTechnique(hint);
#if DEBUG
            GlyphBoneJoint.dbugTotalId        = 0;//reset
            builder.dbugAlwaysDoCurveAnalysis = true;
#endif
            _infoView.Clear();
            _latestHint = hint;
            _testChar   = testChar;
            //----------------------------------------------------
            //
            builder.Build(testChar, _sizeInPoint);
            var txToVxs1 = new GlyphTranslatorToVxs();
            builder.GlyphDynamicEdgeOffset = this.GlyphEdgeOffset;

            builder.ReadShapes(txToVxs1);

#if DEBUG
            var ps = txToVxs1.dbugGetPathWriter();
            _infoView.ShowOrgBorderInfo(ps.Vxs);
#endif
            PixelFarm.Drawing.VertexStore vxs = new PixelFarm.Drawing.VertexStore();

            txToVxs1.WriteOutput(vxs);
            //----------------------------------------------------

            //----------------------------------------------------
            painter.UseSubPixelLcdEffect = this.UseLcdTechnique;
            //5. use PixelFarm's Agg to render to bitmap...
            //5.1 clear background
            painter.Clear(PixelFarm.Drawing.Color.White);

            RectD bounds = new RectD();
            BoundingRect.GetBoundingRect(new PixelFarm.Drawing.VertexStoreSnap(vxs), ref bounds);
            //----------------------------------------------------
            float scale = _typeface.CalculateScaleToPixelFromPointSize(_sizeInPoint);
            _pxscale = scale;
            this._infoView.PxScale = scale;


            var   left2   = 0;
            int   floor_1 = (int)left2;
            float diff    = left2 - floor_1;
            //----------------------------------------------------
            if (OffsetMinorX)
            {
                MinorOffsetInfo = left2.ToString() + " =>" + floor_1 + ",diff=" + diff;
            }
            else
            {
                MinorOffsetInfo = left2.ToString();
            }


            //5. use PixelFarm's Agg to render to bitmap...
            //5.1 clear background
            painter.Clear(PixelFarm.Drawing.Color.White);

            if (FillBackGround)
            {
                //5.2
                painter.FillColor = PixelFarm.Drawing.Color.Black;

                float xpos = 5;// - diff;
                if (OffsetMinorX)
                {
                    xpos -= diff;
                }

                painter.SetOrigin(xpos, 10);
                painter.Fill(vxs);
            }
            if (DrawBorder)
            {
                //5.4
                painter.StrokeColor = PixelFarm.Drawing.Color.Green;
                //user can specific border width here...
                //5.5
                painter.Draw(vxs);
                //--------------
                int    markOnVertexNo = _infoView.DebugMarkVertexCommand;
                double x, y;
                vxs.GetVertex(markOnVertexNo, out x, out y);
                painter.FillRect(x, y, 4, 4, PixelFarm.Drawing.Color.Red);
                //--------------
                _infoView.ShowFlatternBorderInfo(vxs);
                //--------------
            }
#if DEBUG
            builder.dbugAlwaysDoCurveAnalysis = false;
#endif

            if (ShowTess)
            {
                RenderTessTesult();
            }

            //if (DrawDynamicOutline)
            //{
            //    GlyphDynamicOutline dynamicOutline = builder.LatestGlyphFitOutline;
            //    WalkDynamicOutline(painter, dynamicOutline, scale, DrawRegenerateOutline);

            //}
        }
 public void SetHintTechnique(HintTechnique hintTech)
 {
     _currentHintTech = hintTech;
 }
Exemplo n.º 11
0
        void CreateTextureFontFromGlyphIndices(
            Typeface typeface,
            float sizeInPoint,
            HintTechnique hintTechnique,
            SimpleFontAtlasBuilder atlasBuilder,
            bool applyFilter,
            ushort[] glyphIndices)
        {
            //sample: create sample msdf texture
            //-------------------------------------------------------------
            var builder = new GlyphPathBuilder(typeface);

            builder.SetHintTechnique(hintTechnique);
            //
            if (atlasBuilder.TextureKind == TextureKind.Msdf)
            {
                MsdfGenParams msdfGenParams = new MsdfGenParams();
                int           j             = glyphIndices.Length;
                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)
                    builder.BuildFromGlyphIndex(gindex, -1);
                    var glyphToContour = new GlyphContourBuilder();
                    builder.ReadShapes(glyphToContour);
                    //msdfgen with  scale the glyph to specific shapescale
                    msdfGenParams.shapeScale = 1f / 64; //as original
                    GlyphImage glyphImg = MsdfGlyphGen.CreateMsdfImage(glyphToContour, msdfGenParams);
                    //
                    atlasBuilder.AddGlyph(gindex, glyphImg);
                }
            }
            else
            {
                AggGlyphTextureGen aggTextureGen = new AggGlyphTextureGen();
                aggTextureGen.TextureKind = atlasBuilder.TextureKind;
                //create reusable agg painter***

                //assume each glyph size= 2 * line height
                //TODO: review here again...
                int tmpMemBmpHeight = (int)(2 * typeface.CalculateRecommendLineSpacing() * typeface.CalculateScaleToPixelFromPointSize(sizeInPoint));
                //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];
                        builder.BuildFromGlyphIndex(gindex, sizeInPoint);

                        GlyphImage glyphImg = aggTextureGen.CreateGlyphImage(builder, 1);
                        if (applyFilter)
                        {
                            glyphImg = Sharpen(glyphImg, 1);
                            //TODO:
                            //the filter make the image shift x and y 1 px
                            //temp fix with this,
                            glyphImg.TextureOffsetX += 1;
                            glyphImg.TextureOffsetY += 1;
                        }
                        //
                        atlasBuilder.AddGlyph(gindex, glyphImg);
                    }
                }
            }
        }
Exemplo n.º 12
0
        void CreateTextureFontFromGlyphIndices(
            Typeface typeface,
            float sizeInPoint,
            HintTechnique hintTechnique,
            SimpleBitmapAtlasBuilder atlasBuilder,
            ushort[] glyphIndices)
        {
            //sample: create sample msdf texture
            //-------------------------------------------------------------
            var outlineBuilder = new GlyphOutlineBuilder(typeface);

            outlineBuilder.SetHintTechnique(hintTechnique);
            //
            if (atlasBuilder.TextureKind == TextureKind.Msdf)
            {
                float pxscale       = typeface.CalculateScaleToPixelFromPointSize(sizeInPoint);
                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)

                        outlineBuilder.BuildFromGlyphIndex(gindex, -1);

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

                            atlasBuilder.AddItemSource(glyphImg);
                        }
                    }
                }
                else
                {
                    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)
                        outlineBuilder.BuildFromGlyphIndex(gindex, -1);

                        var glyphToVxs = new GlyphTranslatorToVxs();
                        outlineBuilder.ReadShapes(glyphToVxs);

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

                            atlasBuilder.AddItemSource(glyphImg);
                        }
                    }
                }
            }
            else
            {
                AggGlyphTextureGen aggTextureGen = new AggGlyphTextureGen();
                aggTextureGen.TextureKind = atlasBuilder.TextureKind;
                //create reusable agg painter***

                //assume each glyph size= 2 * line height
                //TODO: review here again...
                int tmpMemBmpHeight = (int)(2 * typeface.CalculateRecommendLineSpacing() * typeface.CalculateScaleToPixelFromPointSize(sizeInPoint));
                //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, sizeInPoint);

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

                        glyphImg.UniqueInt16Name = gindex;
                        _onEachGlyphDel?.Invoke(glyphImg);
                        atlasBuilder.AddItemSource(glyphImg);
                    }
                }
            }
        }
Exemplo n.º 13
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);
                    }
                }
            }
        }