Esempio n. 1
0
        GlyphBitmap GetGlyphBitmapFromBitmapFont(ushort glyphIndex)
        {
            //not found=> create a new one
            if (_typeface.IsBitmapFont)
            {
                //try load
                using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
                {
                    //load actual bitmap font
                    Glyph glyph = _typeface.GetGlyph(glyphIndex);
                    _typeface.ReadBitmapContent(glyph, ms);

                    using (MemBitmap memBitmap = MemBitmapExt.LoadBitmap(ms))
                    {
                        //bitmap that are load may be larger than we need
                        //so we need to scale it to specfic size

                        float target_advW = _typeface.GetAdvanceWidthFromGlyphIndex(glyphIndex) * _px_scale;
                        float scaleForBmp = target_advW / memBitmap.Width;

                        MemBitmap scaledMemBmp = memBitmap.ScaleImage(scaleForBmp, scaleForBmp);

                        var glyphBitmap = new GlyphBitmap
                        {
                            Width  = scaledMemBmp.Width,
                            Height = scaledMemBmp.Height,
                            Bitmap = scaledMemBmp //**
                        };
                        return(glyphBitmap);
                    }
                }
            }
            return(null);
        }
Esempio n. 2
0
 public override void Init()
 {
     string imgFileName = "Samples\\lion1.png";
     if (System.IO.File.Exists(imgFileName))
     {
         _lionImg = MemBitmapExt.LoadBitmap(imgFileName);
     }
 }
Esempio n. 3
0
        double _rotationDeg;//rotation angle in degree
        public ImgFilter1Demo()
        {
            _orgImg = MemBitmapExt.LoadBitmap("../Data/spheres.png");
            _imgW   = _orgImg.Width;
            _imgH   = _orgImg.Height;

            _lut              = new ImageFilterLookUpTable();
            Normalization     = true;//default
            _imgSpanGenCustom = new FragmentProcessing.ImgSpanGenRGBA_CustomFilter();
        }
Esempio n. 4
0
        public FontTextureDemo3()
        {
            string glyphBmp = @"Data\tahoma -488129008.info.png";

            if (System.IO.File.Exists(glyphBmp))
            {
                _glyphAtlasBmp = MemBitmapExt.LoadBitmap(glyphBmp);
            }
            this.Width  = 800;
            this.Height = 600;
        }
Esempio n. 5
0
        public FloodFillDemo()
        {
            //
            _magicWandConfigs = new MagicWandConfigGroup();

            BackgroundColor = Color.White;

            _defaultImg = new MemBitmap(400, 300);

            AggPainter p = AggPainter.Create(_defaultImg);

            p.Clear(Color.White);
            p.FillColor = Color.Black;
            p.FillEllipse(20, 20, 30, 30);


            for (int i = 0; i < 20; i++)
            {
                p.StrokeColor = Color.Black;
                p.DrawEllipse(i * 10, i * 10, 20, 20);
            }

            //
            this.PixelSize = 32;
            this.Gamma     = 1;
            _tolerance     = 30;

            _floodFill = new ColorBucket(Color.Red, _tolerance);
            _magicWand = new MagicWand(_tolerance);

            //
            //_lionPng = MemBitmapExtensions.LoadBitmap("../Data/lion1_v2_2.png");
            //_lionPng =  MemBitmapExtensions.LoadBitmap("../Data/lion1_v2_4_1.png");
            _lionPng = MemBitmapExt.LoadBitmap("../Data/lion1.png");
            //_lionPng =  MemBitmapExtensions.LoadBitmap("../Data/lion_1_v3_2.png");
            //_lionPng = MemBitmapExtensions.LoadBitmap("../Data/glyph_a.png");
            _starsPng    = MemBitmapExt.LoadBitmap("../Data/stars.png");
            _test_glyphs = MemBitmapExt.LoadBitmap("../Data/test_glyphs.png");
            _rect01      = MemBitmapExt.LoadBitmap("../Data/rect01.png");
            //_v_shape =  MemBitmapExtensions.LoadBitmap("../Data/shape_v.png");
            //_v_shape = MemBitmapExtensions.LoadBitmap("../Data/shape_v3.png");
            _bmpToFillOn = _defaultImg;

            OutlineReconstruction = true;
            WithOutlineSimplifier = true;
        }
Esempio n. 6
0
        public LionAlphaMask3()
        {
            string imgFileName = "Data/lion1.png";

            if (System.IO.File.Exists(imgFileName))
            {
                lionImg = MemBitmapExt.LoadBitmap(imgFileName);
            }


            this.Width  = 800;
            this.Height = 600;

#if USE_CLIPPING_ALPHA_MASK
            //alphaMask = new AlphaMaskByteClipped(alphaMaskImageBuffer, 1, 0);
#else
            //alphaMask = new AlphaMaskByteUnclipped(alphaMaskImageBuffer, 1, 0);
#endif
        }
Esempio n. 7
0
 public void RegisterBitmapAtlas(string atlasName, byte[] atlasInfoBuffer, byte[] totalImgBuffer)
 {
     //direct register atlas
     //instead of loading it from file
     if (!_loadedAtlasByNames.ContainsKey(atlasName))
     {
         using (System.IO.Stream fontAtlasTextureInfo = new MemoryStream(atlasInfoBuffer))
             using (System.IO.Stream fontImgStream = new MemoryStream(totalImgBuffer))
             {
                 try
                 {
                     SimpleBitmapAtlasBuilder atlasBuilder = new SimpleBitmapAtlasBuilder();
                     List <SimpleBitmapAtlas> atlasList    = atlasBuilder.LoadAtlasInfo(fontAtlasTextureInfo);
                     SimpleBitmapAtlas        foundAtlas   = atlasList[0];
                     foundAtlas.SetMainBitmap(MemBitmapExt.LoadBitmap(fontImgStream), true);
                     _loadedAtlasByNames.Add(atlasName, foundAtlas);
                 }
                 catch (Exception ex)
                 {
                     throw ex;
                 }
             }
     }
 }
Esempio n. 8
0
        public void BuildMultiFontSize(string multiFontSizeAtlasFilename, string imgOutputFilename)
        {
            //merge to the new one
            //1. ensure same atlas width
            int atlasW      = 0;
            int j           = _atlasList.Count;
            int totalHeight = 0;

            const int interAtlasSpace = 2;

            for (int i = 0; i < j; ++i)
            {
                TempMergingAtlasInfo atlasInfo = _atlasList[i];
                SimpleBitmapAtlas    fontAtlas = atlasInfo.fontAtlasFile.AtlasList[0];
                totalHeight += fontAtlas.Height + interAtlasSpace;
                if (i == 0)
                {
                    atlasW = fontAtlas.Width;
                }
                else
                {
                    if (atlasW != fontAtlas.Width)
                    {
                        throw new NotSupportedException();
                    }
                }
            }
            //--------------------------------------------
            //in this version, the glyph offsetY is measure from bottom***
            int[] offsetFromBottoms = new int[j];
            int   offsetFromBottom  = interAtlasSpace;//start offset

            for (int i = j - 1; i >= 0; --i)
            {
                TempMergingAtlasInfo atlasInfo = _atlasList[i];
                SimpleBitmapAtlas    fontAtlas = atlasInfo.fontAtlasFile.AtlasList[0];
                offsetFromBottoms[i] = offsetFromBottom;
                offsetFromBottom    += fontAtlas.Height + interAtlasSpace;
            }
            //--------------------------------------------
            //merge all img to one
            int top = 0;

            using (MemBitmap memBitmap = new MemBitmap(atlasW, totalHeight))
            {
                AggPainter painter = AggPainter.Create(memBitmap);
                for (int i = 0; i < j; ++i)
                {
                    TempMergingAtlasInfo atlasInfo = _atlasList[i];
                    BitmapAtlasFile      atlasFile = atlasInfo.fontAtlasFile;
                    SimpleBitmapAtlas    fontAtlas = atlasInfo.fontAtlasFile.AtlasList[0];

                    atlasInfo.NewCloneLocations = SimpleBitmapAtlas.CloneLocationWithOffset(fontAtlas, 0, offsetFromBottoms[i]);
                    atlasInfo.ImgUrlDict        = fontAtlas.ImgUrlDict;

                    using (Stream fontImgStream = PixelFarm.Platforms.StorageService.Provider.ReadDataStream(atlasInfo.imgFile))
                        using (MemBitmap atlasBmp = MemBitmapExt.LoadBitmap(fontImgStream))
                        {
                            painter.DrawImage(atlasBmp, 0, top);
                            top += atlasBmp.Height + interAtlasSpace;
                        }
                }
                memBitmap.SaveImage(imgOutputFilename);
            }
            //--------------------------------------------
            //save merged font atlas
            //TODO: use 'File' provider to access system file
            using (FileStream fs = new FileStream(multiFontSizeAtlasFilename, FileMode.Create))
                using (BinaryWriter w = new BinaryWriter(fs))
                {
                    //-----------
                    //overview
                    //total img info
                    BitmapAtlasFile fontAtlasFile = new BitmapAtlasFile();
                    fontAtlasFile.StartWrite(fs);

                    //1. simple atlas count
                    fontAtlasFile.WriteOverviewMultiSizeFontInfo((ushort)j);
                    //2.
                    for (int i = 0; i < j; ++i)
                    {
                        TempMergingAtlasInfo atlasInfo = _atlasList[i];

                        RequestFont reqFont = atlasInfo.reqFont;
                        fontAtlasFile.WriteOverviewFontInfo(reqFont.Name, reqFont.GetReqKey(), reqFont.SizeInPoints);//size in points

                        fontAtlasFile.WriteTotalImageInfo(
                            (ushort)atlasW,
                            (ushort)top,
                            4,
                            atlasInfo.textureKind);
                        //

                        fontAtlasFile.WriteAtlasItems(atlasInfo.NewCloneLocations);

                        if (atlasInfo.ImgUrlDict != null)
                        {
                            fontAtlasFile.WriteImgUrlDict(atlasInfo.ImgUrlDict);
                        }
                    }
                    fontAtlasFile.EndWrite();
                }
        }
Esempio n. 9
0
        public BitmapAtlasItemSource CreateAtlasItem(GlyphOutlineBuilder builder, float pxscale)
        {
            _txToVxs.Reset();
            //1. builder read shape and translate it with _txToVxs
            builder.ReadShapes(_txToVxs);

            using (Tools.BorrowVxs(out var glyphVxs, out var vxs2))
            {
                //2. write translated data (in the _txToVxs) to glyphVxs

                _txToVxs.WriteOutput(glyphVxs, pxscale);

                Q1RectD bounds = glyphVxs.GetBoundingRect();

                //--------------------------------------------
                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;
                }
                //we need some margin
                int horizontal_margin = 1;
                int vertical_margin   = 1;

                //translate to positive quadrant and use minimum space

                int dx = (int)Math.Ceiling((bounds.Left < 0) ? -bounds.Left : 0);
                int dy = 0;

                //vertical adjust =>since we need to move it, then move it with integer value
                if (bounds.Bottom < 0)
                {
                    dy = (int)Math.Ceiling(-bounds.Bottom);
                }
                else if (bounds.Bottom > 0)
                {
                    dy = (int)Math.Floor(-bounds.Bottom);
                }
                dx += horizontal_margin; //margin left
                dy += vertical_margin;
                //--------------------------------------------
                w = dx + w + horizontal_margin;            //+right margin

                h = vertical_margin + h + vertical_margin; //+bottom margin
                AggPainter painter = Painter;
                if (TextureKind == TextureKind.StencilLcdEffect)
                {
                    glyphVxs.TranslateToNewVxs(dx + 0.33f, dy, vxs2); //offset to proper x of subpixel rendering  ***
                    glyphVxs = vxs2;

                    Q1RectD bounds2 = vxs2.GetBoundingRect();
                    if (w < bounds2.Right)
                    {
                        w = (int)Math.Ceiling(bounds2.Right);
                    }
                    //
                    painter.UseLcdEffectSubPixelRendering = true;
                    //we use white glyph on black bg for this texture


                    painter.Clear(Color.Black);
                    painter.FillColor = Color.White;


                    //painter.Clear(Color.FromArgb(0, 255, 255, 255)); //white -transparent
                    //painter.FillColor = Color.Black;


                    //painter.Clear(Color.White);
                    //painter.FillColor = Color.Black;

                    //painter.Clear(Color.Empty);
                    //painter.FillColor = Color.Black;

                    painter.Fill(glyphVxs);

                    //apply sharpen filter
                    //painter.DoFilter(new RectInt(0, h, w, 0), 2);
                    //painter.DoFilter(new RectInt(0, h, w, 0), 2); //?
                }
                else
                {
                    glyphVxs.TranslateToNewVxs(dx, dy, vxs2);
                    glyphVxs = vxs2;

                    painter.UseLcdEffectSubPixelRendering = false;

                    if (TextureKind == TextureKind.StencilGreyScale)
                    {
                        painter.Clear(Color.Empty);
                        painter.FillColor = Color.Black;
                    }
                    else
                    {
                        painter.Clear(BackGroundColor);
                        painter.FillColor = this.GlyphColor;
                    }
                    painter.Fill(glyphVxs);
                }
                //


                if (w > painter.RenderSurface.DestBitmap.Width)
                {
                    w = painter.RenderSurface.DestBitmap.Width;
                }
                if (h > painter.RenderSurface.DestBitmap.Height)
                {
                    h = painter.RenderSurface.DestBitmap.Height;
                }

                var glyphImage = new BitmapAtlasItemSource(w, h);

#if DEBUG
                if (dx < short.MinValue || dx > short.MaxValue)
                {
                    throw new NotSupportedException();
                }
                if (dy < short.MinValue || dy > short.MaxValue)
                {
                    throw new NotSupportedException();
                }
#endif

                glyphImage.TextureXOffset = (short)dx;
                glyphImage.TextureYOffset = (short)dy;

                glyphImage.SetImageBuffer(MemBitmapExt.CopyImgBuffer(painter.RenderSurface.DestBitmap, w, h), false);
                //copy data from agg canvas to glyph image
                return(glyphImage);
            }
        }
Esempio 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);
                    }
                }
            }
        }
Esempio n. 11
0
 public CutCopyPasteDemo()
 {
     _lionPng = MemBitmapExt.LoadBitmap("../Data/lion1.png");
 }
Esempio n. 12
0
        public PixelFarm.CpuBlit.BitmapAtlas.BitmapAtlasItemSource GenerateMsdfTexture(VertexStore vxs)
        {
            Shape shape = CreateShape(vxs, out EdgeBmpLut edgeBmpLut);

            if (MsdfGenParams == null)
            {
                MsdfGenParams = new MsdfGenParams();//use default
            }

            //---preview v1 bounds-----------
            PreviewSizeAndLocation(
                shape,
                MsdfGenParams,
                out int imgW, out int imgH,
                out Vector2 translateVec);

            _dx = translateVec.x;
            _dy = translateVec.y;
            //------------------------------------
            List <ContourCorner> corners = edgeBmpLut.Corners;

            TranslateCorners(corners, _dx, _dy);

            //[1] create lookup table (lut) bitmap that contains area/corner/shape information
            //each pixel inside it contains data that map to area/corner/shape

            //
            using (MemBitmap bmpLut = new MemBitmap(imgW, imgH))
                using (Tools.BorrowAggPainter(bmpLut, out var painter))
                    using (Tools.BorrowShapeBuilder(out var sh))
                    {
                        _msdfEdgePxBlender.ClearOverlapList();//reset
                        painter.RenderSurface.SetCustomPixelBlender(_msdfEdgePxBlender);

                        //1. clear all bg to black
                        painter.Clear(PixelFarm.Drawing.Color.Black);

                        sh.InitVxs(vxs) //...
                        .TranslateToNewVxs(_dx, _dy)
                        .Flatten();


                        //---------
                        //2. force fill the shape (this include hole(s) inside shape to)
                        //( we set threshold to 50 and do force fill)
                        painter.RenderSurface.SetGamma(_prebuiltThresholdGamma_50);
                        _msdfEdgePxBlender.FillMode = MsdfEdgePixelBlender.BlenderFillMode.Force;
                        painter.Fill(sh.CurrentSharedVxs, EdgeBmpLut.EncodeToColor(0, AreaKind.AreaInsideCoverage50));

                        painter.RenderSurface.SetGamma(_prebuiltThresholdGamma_50);//restore
#if DEBUG
                        //debug for output
                        //painter.Fill(v7, Color.Red);
                        //bmpLut.SaveImage("dbug_step0.png");
                        //int curr_step = 1;
#endif
                        //---------

                        int        cornerCount          = corners.Count;
                        List <int> cornerOfNextContours = edgeBmpLut.CornerOfNextContours;
                        int        startAt      = 0;
                        int        n            = 1;
                        int        corner_index = 1;

                        for (int cnt_index = 0; cnt_index < cornerOfNextContours.Count; ++cnt_index)
                        {
                            //contour scope
                            int next_corner_startAt = cornerOfNextContours[cnt_index];

                            //-----------
                            //AA-borders of the contour
                            painter.RenderSurface.SetGamma(_prebuiltThresholdGamma_OverlappedBorder); //this creates overlapped area

                            for (; n < next_corner_startAt; ++n)
                            {
                                //0-> 1
                                //1->2 ... n
                                FillBorders(painter, corners[n - 1], corners[n]);

#if DEBUG
                                //bmpLut.SaveImage("dbug_step" + curr_step + ".png");
                                //curr_step++;
#endif
                            }
                            {
                                //the last one
                                //close contour, n-> 0
                                FillBorders(painter, corners[next_corner_startAt - 1], corners[startAt]);
#if DEBUG
                                //bmpLut.SaveImage("dbug_step" + curr_step + ".png");
                                //curr_step++;
#endif
                            }

                            startAt = next_corner_startAt;
                            n++;
                            corner_index++;
                        }
#if DEBUG
                        //bmpLut.SaveImage("dbug_step2.png");
#endif


                        //painter.RenderSurface.SetGamma(_prebuiltThresholdGamma_100);
                        //_msdfEdgePxBlender.FillMode = MsdfEdgePixelBlender.BlenderFillMode.InnerAreaX;
                        //painter.Fill(sh.CurrentSharedVxs, EdgeBmpLut.EncodeToColor(0, AreaKind.AreaInsideCoverage100));



                        painter.RenderSurface.SetCustomPixelBlender(null);
                        painter.RenderSurface.SetGamma(null);

                        //
                        List <CornerList> overlappedList = MakeUniqueList(_msdfEdgePxBlender._overlapList);
                        edgeBmpLut.SetOverlappedList(overlappedList);

#if DEBUG
                        if (dbugWriteMsdfTexture)
                        {
                            //save for debug
                            //we save to msdf_shape_lut2.png
                            //and check it from external program
                            //but we generate msdf bitmap from msdf_shape_lut.png
                            bmpLut.SaveImage(dbug_msdf_shape_lutName);
                            var   bmp5       = MemBitmapExt.LoadBitmap(dbug_msdf_shape_lutName);
                            int[] lutBuffer5 = bmp5.CopyImgBuffer(bmpLut.Width, bmpLut.Height);
                            if (bmpLut.Width == 338 && bmpLut.Height == 477)
                            {
                                dbugBreak = true;
                            }
                            edgeBmpLut.SetBmpBuffer(bmpLut.Width, bmpLut.Height, lutBuffer5);
                            //generate actual sprite
                            PixelFarm.CpuBlit.BitmapAtlas.BitmapAtlasItemSource item = CreateMsdfImage(shape, MsdfGenParams, imgW, imgH, translateVec, edgeBmpLut);
                            //save msdf bitmap to file
                            using (MemBitmap memBmp = MemBitmap.CreateFromCopy(item.Width, item.Height, item.Source))
                            {
                                memBmp.SaveImage(dbug_msdf_output);
                            }

                            return(item);
                        }
#endif

                        //[B] after we have a lookup table
                        int[] lutBuffer = bmpLut.CopyImgBuffer(bmpLut.Width, bmpLut.Height);
                        edgeBmpLut.SetBmpBuffer(bmpLut.Width, bmpLut.Height, lutBuffer);

                        return(CreateMsdfImage(shape, MsdfGenParams, imgW, imgH, translateVec, edgeBmpLut));
                    }
        }