Ejemplo n.º 1
0
        public SimpleBitmapAtlasBuilder CreateTextureFontFromInputChars(
            Typeface typeface, float sizeInPoint,
            TextureKind textureKind,
            char[] chars,
            OnEachGlyph onEachGlyphDel = null)
        {
            _onEachGlyphDel = onEachGlyphDel;
            //convert input chars into glyphIndex
            List <ushort> glyphIndices = new List <ushort>(chars.Length);
            int           i            = 0;

            foreach (char ch in chars)
            {
                glyphIndices.Add(typeface.GetGlyphIndex(ch));
                i++;
            }
            //-------------------------------------------------------------
            var atlasBuilder = new SimpleBitmapAtlasBuilder();

            atlasBuilder.SetAtlasInfo(textureKind, sizeInPoint);
            //-------------------------------------------------------------
            //we can specfic subset with special setting for each set
            CreateTextureFontFromGlyphIndices(typeface, sizeInPoint,
                                              HintTechnique.TrueTypeInstruction_VerticalOnly, atlasBuilder, GetUniqueGlyphIndexList(glyphIndices));

            _onEachGlyphDel = null;//reset
            return(atlasBuilder);
        }
Ejemplo n.º 2
0
 public GlyphNotFoundHelper(
     SimpleBitmapAtlasBuilder atlasBuilder,
     GlyphOutlineBuilder outlineBuilder,
     OnEachGlyph onEachGlyphDel,
     AggGlyphTextureGen aggTextureGen, float sizeInPoints)
 {
     _atlasBuilder   = atlasBuilder;
     _outlineBuilder = outlineBuilder;
     _onEachGlyphDel = onEachGlyphDel;
     _aggTextureGen  = aggTextureGen;
     _sizeInPoints   = sizeInPoints;
 }
Ejemplo n.º 3
0
        /// <summary>
        /// get from cache or create a new one
        /// </summary>
        /// <param name="reqFont"></param>
        /// <returns></returns>
        public SimpleBitmapAtlas GetBitmapAtlas(string atlasName, out B outputBitmap)
        {
#if DEBUG
            _dbugStopWatch.Reset();
            _dbugStopWatch.Start();
#endif


            if (!_createdAtlases.TryGetValue(atlasName, out SimpleBitmapAtlas foundAtlas))
            {
                //check from pre-built cache (if availiable)
                string textureInfoFile    = atlasName + ".info";
                string textureImgFilename = atlasName + ".png";
                //check if the file exist

                if (StorageService.Provider.DataExists(textureInfoFile) &&
                    StorageService.Provider.DataExists(textureImgFilename))
                {
                    SimpleBitmapAtlasBuilder atlasBuilder = new SimpleBitmapAtlasBuilder();
                    using (System.IO.Stream fontAtlasTextureInfo = StorageService.Provider.ReadDataStream(textureInfoFile))
                        using (System.IO.Stream fontImgStream = StorageService.Provider.ReadDataStream(textureImgFilename))
                        {
                            try
                            {
                                List <SimpleBitmapAtlas> atlasList = atlasBuilder.LoadAtlasInfo(fontAtlasTextureInfo);
                                foundAtlas = atlasList[0];
                                foundAtlas.SetMainBitmap(MemBitmap.LoadBitmap(fontImgStream), true);
                                _createdAtlases.Add(atlasName, foundAtlas);
                            }
                            catch (Exception ex)
                            {
                                throw ex;
                            }
                        }
                }
            }
            if (foundAtlas != null)
            {
                outputBitmap = _loadAtlases.GetOrCreateNewOne(foundAtlas);
                return(foundAtlas);
            }
            else
            {
#if DEBUG
                //show warning about this
                System.Diagnostics.Debug.WriteLine("not found atlas:" + atlasName);
#endif

                outputBitmap = default(B);
                return(null);
            }
        }
Ejemplo n.º 4
0
        public SimpleBitmapAtlasBuilder CreateTextureFontFromBuildDetail(
            Typeface typeface, float sizeInPoint,
            TextureKind textureKind,
            GlyphTextureBuildDetail[] details,
            OnEachGlyph onEachGlyphDel = null)
        {
            _onEachGlyphDel = onEachGlyphDel;
            //-------------------------------------------------------------
            var atlasBuilder = new SimpleBitmapAtlasBuilder();

            atlasBuilder.SetAtlasInfo(textureKind, sizeInPoint);
            //-------------------------------------------------------------
            int j = details.Length;

            for (int i = 0; i < j; ++i)
            {
                GlyphTextureBuildDetail detail = details[i];
                if (detail.ScriptLang != null)
                {
                    //skip those script lang=null
                    //2. find associated glyph index base on input script langs
                    List <ushort> outputGlyphIndexList = new List <ushort>();
                    typeface.CollectAllAssociateGlyphIndex(outputGlyphIndexList, detail.ScriptLang);
                    CreateTextureFontFromGlyphIndices(typeface,
                                                      sizeInPoint,
                                                      detail.HintTechnique,
                                                      atlasBuilder,
                                                      GetUniqueGlyphIndexList(outputGlyphIndexList)
                                                      );
                }
            }
            for (int i = 0; i < j; ++i)
            {
                GlyphTextureBuildDetail detail = details[i];
                if (detail.OnlySelectedGlyphIndices != null)
                {
                    //skip those script lang=null
                    //2. find associated glyph index base on input script langs

                    CreateTextureFontFromGlyphIndices(typeface,
                                                      sizeInPoint,
                                                      detail.HintTechnique,
                                                      atlasBuilder,
                                                      detail.OnlySelectedGlyphIndices
                                                      );
                }
            }

            _onEachGlyphDel = null;//reset
            return(atlasBuilder);
        }
Ejemplo n.º 5
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);
        }
Ejemplo n.º 6
0
 public void RegisterBitmapAtlas(string atlasName, byte[] atlasInfoBuffer, byte[] totalImgBuffer)
 {
     //direct register atlas
     //instead of loading it from file
     if (!_createdAtlases.ContainsKey(atlasName))
     {
         SimpleBitmapAtlasBuilder atlasBuilder = new SimpleBitmapAtlasBuilder();
         using (System.IO.Stream fontAtlasTextureInfo = new MemoryStream(atlasInfoBuffer))
             using (System.IO.Stream fontImgStream = new MemoryStream(totalImgBuffer))
             {
                 try
                 {
                     List <SimpleBitmapAtlas> atlasList  = atlasBuilder.LoadAtlasInfo(fontAtlasTextureInfo);
                     SimpleBitmapAtlas        foundAtlas = atlasList[0];
                     foundAtlas.SetMainBitmap(MemBitmap.LoadBitmap(fontImgStream), true);
                     _createdAtlases.Add(atlasName, foundAtlas);
                 }
                 catch (Exception ex)
                 {
                     throw ex;
                 }
             }
     }
 }
Ejemplo n.º 7
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);
                    }
                }
            }
        }
Ejemplo n.º 8
0
        /// <summary>
        /// get from cache or create a new one
        /// </summary>
        /// <param name="reqFont"></param>
        /// <returns></returns>
        public SimpleBitmapAtlas GetFontAtlas(RequestFont reqFont, out B outputBitmap)
        {
#if DEBUG
            _dbugStopWatch.Reset();
            _dbugStopWatch.Start();
#endif

            int fontKey = reqFont.FontKey;

            if (_createdAtlases.TryGetValue(fontKey, out SimpleBitmapAtlas fontAtlas))
            {
                outputBitmap = _loadAtlases.GetOrCreateNewOne(fontAtlas);
                return(fontAtlas);
            }

            //check if we have small msdf texture or not
            if (_msdfTextureFonts.TryGetValue(reqFont.Name, out SimpleBitmapAtlas msdfTexture))
            {
                //use this
                outputBitmap = _loadAtlases.GetOrCreateNewOne(msdfTexture);
                return(msdfTexture);
            }


            //--------------------------------
            //check from pre-built cache (if availiable)
            Typeface resolvedTypeface       = _textServices.ResolveTypeface(reqFont);
            string   fontTextureFile        = reqFont.Name + "_" + fontKey;
            string   resolveFontFile        = fontTextureFile + ".info";
            string   fontTextureInfoFile    = resolveFontFile;
            string   fontTextureImgFilename = fontTextureInfoFile + ".png";


            if (StorageService.Provider.DataExists(fontTextureInfoFile) &&
                StorageService.Provider.DataExists(fontTextureImgFilename))
            {
                //check local caching, if found then load-> create it

                SimpleBitmapAtlasBuilder atlasBuilder = new SimpleBitmapAtlasBuilder();


                lock (s_loadDataLock)
                {
                    using (System.IO.Stream textureInfoFileStream = StorageService.Provider.ReadDataStream(fontTextureInfoFile))
                        using (System.IO.Stream fontAtlasImgStream = StorageService.Provider.ReadDataStream(fontTextureImgFilename))
                        {
                            try
                            {
                                //TODO: review here
                                fontAtlas = atlasBuilder.LoadAtlasInfo(textureInfoFileStream)[0];
                                fontAtlas.SetMainBitmap(ReadGlyphImages(fontAtlasImgStream), true);
                                fontAtlas.OriginalFontSizePts = reqFont.SizeInPoints;
                                _createdAtlases.Add(fontKey, fontAtlas);
                            }
                            catch (Exception ex)
                            {
                                throw ex;
                            }
                        }
                }
            }
            else
            {
                //-------------
                //if not found the request font
                //we generate it realtime here, (add add the cache '_createdAtlases')
                //-------------


                //1. create glyph-texture-bitmap generator
                var glyphTextureGen = new GlyphTextureBitmapGenerator();

                //2. generate the glyphs
                SimpleBitmapAtlasBuilder atlasBuilder = glyphTextureGen.CreateTextureFontFromBuildDetail(
                    resolvedTypeface,
                    reqFont.SizeInPoints,
                    TextureKindForNewFont,
                    GlyphTextureCustomConfigs.TryGetGlyphTextureBuildDetail(reqFont, false, false)
                    );

                //3. set information before write to font-info
                atlasBuilder.FontFilename       = reqFont.Name;//TODO: review here, check if we need 'filename' or 'fontname'
                atlasBuilder.FontKey            = reqFont.FontKey;
                atlasBuilder.SpaceCompactOption = SimpleBitmapAtlasBuilder.CompactOption.ArrangeByHeight;

                //4. merge all glyph in the builder into a single image
                PixelFarm.CpuBlit.MemBitmap totalGlyphsImg = atlasBuilder.BuildSingleImage(true);

                //-------------------------------------------------------------

                //5. create a simple font atlas from information inside this atlas builder.
                fontAtlas = atlasBuilder.CreateSimpleBitmapAtlas();
                fontAtlas.SetMainBitmap(totalGlyphsImg, true);
#if DEBUG
                //save glyph image for debug
                //PixelFarm.Agg.ActualImage.SaveImgBufferToPngFile(
                //    totalGlyphsImg.GetImageBuffer(),
                //    totalGlyphsImg.Width * 4,
                //    totalGlyphsImg.Width, totalGlyphsImg.Height,
                //    "total_" + reqFont.Name + "_" + reqFont.SizeInPoints + ".png");
                ////save image to cache
                totalGlyphsImg.SaveImage(fontTextureImgFilename);
#endif


                //6. cache this in the memory,
                _createdAtlases.Add(fontKey, fontAtlas);

                //
                ////calculate some commonly used values
                //fontAtlas.SetTextureScaleInfo(
                //    resolvedTypeface.CalculateScaleToPixelFromPointSize(fontAtlas.OriginalFontSizePts),
                //    resolvedTypeface.CalculateScaleToPixelFromPointSize(reqFont.SizeInPoints));
                ////TODO: review here, use scaled or unscaled values
                //fontAtlas.SetCommonFontMetricValues(
                //    resolvedTypeface.Ascender,
                //    resolvedTypeface.Descender,
                //    resolvedTypeface.LineGap,
                //    resolvedTypeface.CalculateRecommendLineSpacing());

                ///
#if DEBUG
                _dbugStopWatch.Stop();
                System.Diagnostics.Debug.WriteLine("build font atlas: " + _dbugStopWatch.ElapsedMilliseconds + " ms");
#endif

                //TODO: review here again
                //save font info to local disk cache
                using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
                {
                    atlasBuilder.SaveAtlasInfo(ms);
                    StorageService.Provider.SaveData(fontTextureInfoFile, ms.ToArray());
#if DEBUG
                    //write temp debug info
#if !__MOBILE__
                    System.IO.File.WriteAllBytes(fontTextureInfoFile, ms.ToArray());
                    System.IO.File.WriteAllText(fontTextureInfoFile + ".txt", reqFont.Name + ",size" + reqFont.SizeInPoints + "pts");
#endif
#endif
                }
            }


            outputBitmap = _loadAtlases.GetOrCreateNewOne(fontAtlas);
            return(fontAtlas);
        }
Ejemplo n.º 9
0
        public void CreateTextureFontFromBuildDetail(
            SimpleBitmapAtlasBuilder atlasBuilder,
            Typeface typeface,
            float sizeInPoint,
            TextureKind textureKind,
            GlyphTextureBuildDetail[] details,
            OnEachGlyph onEachGlyphDel = null)
        {
            _onEachGlyphDel = onEachGlyphDel;
            SetCurrentFontInfo(typeface, sizeInPoint);
            //-------------------------------------------------------------

            atlasBuilder.SetAtlasInfo(textureKind, _currentDPI);
            atlasBuilder.SetAtlasFontInfo(typeface.Name, sizeInPoint);
            //-------------------------------------------------------------
            int j = details.Length;

            for (int i = 0; i < j; ++i)
            {
                GlyphTextureBuildDetail detail = details[i];
                if (detail.AllGlyphs)
                {
                    //all
                    int      count          = typeface.GlyphCount;
                    ushort[] glyphIndexList = new ushort[count];
                    for (ushort m = 0; m < count; ++m)
                    {
                        glyphIndexList[m] = m;
                    }
                    CreateTextureFontFromGlyphIndices(
                        detail.HintTechnique,
                        atlasBuilder,
                        glyphIndexList
                        );
                }
                else if (!detail.ScriptLang.IsEmpty())
                {
                    //skip those script lang=null
                    //2. find associated glyph index base on input script langs
                    atlasBuilder.ScriptTags.Add(detail.ScriptLang.scriptTag);


                    List <ushort> outputGlyphIndexList = new List <ushort>();

                    typeface.CollectAllAssociateGlyphIndex(outputGlyphIndexList, detail.ScriptLang);
                    CreateTextureFontFromGlyphIndices(
                        detail.HintTechnique,
                        atlasBuilder,
                        GetUniqueGlyphIndexList(outputGlyphIndexList)
                        );
                }
                else
                {
                    //??
                }
            }

            for (int i = 0; i < j; ++i)
            {
                GlyphTextureBuildDetail detail = details[i];
                if (detail.OnlySelectedChars != null)
                {
                    //skip those script lang=null
                    //2. find associated glyph index base on input script langs

                    CreateTextureFontFromGlyphIndices(
                        detail.HintTechnique,
                        atlasBuilder,
                        detail.OnlySelectedChars
                        );
                }
            }

            _onEachGlyphDel = null;//reset
        }
Ejemplo n.º 10
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);
                    }
                }
            }
        }