Beispiel #1
0
 static void SaveImgBufferToFile(GlyphImage glyphImg, string filename)
 {
     using (PixelFarm.CpuBlit.MemBitmap memBmp = PixelFarm.CpuBlit.MemBitmap.CreateFromCopy(
                glyphImg.Width, glyphImg.Height, glyphImg.GetImageBuffer(), false))
     {
         PixelFarm.CpuBlit.MemBitmapExtensions.SaveImage(memBmp, filename, PixelFarm.CpuBlit.MemBitmapIO.OutputImageFormat.Png);
     }
 }
Beispiel #2
0
 static void SaveImgBufferToFile(GlyphImage glyphImg, string filename)
 {
     using (PixelFarm.CpuBlit.MemBitmap memBmp = PixelFarm.CpuBlit.MemBitmap.CreateFromCopy(
                glyphImg.Width, glyphImg.Height, glyphImg.GetImageBuffer(), true))
     {
         StorageService.Provider.SavePngBitmap(memBmp, filename);
     }
 }
Beispiel #3
0
        static GlyphImage ReadGlyphImages(string filename)
        {
            PixelFarm.CpuBlit.ActualBitmap bmp = StorageService.Provider.ReadPngBitmap(filename);
            GlyphImage img = new GlyphImage(bmp.Width, bmp.Height);

            img.SetImageBuffer(PixelFarm.CpuBlit.ActualBitmap.GetBuffer(bmp), true);
            return(img);
        }
Beispiel #4
0
        /// <summary>
        /// add or replace
        /// </summary>
        /// <param name="glyphIndex"></param>
        /// <param name="img"></param>
        public void AddGlyph(ushort glyphIndex, GlyphImage img)
        {
            var glyphCache = new CacheGlyph();

            glyphCache.glyphIndex = glyphIndex;
            glyphCache.img        = img;
            _glyphs[glyphIndex]   = glyphCache;
        }
        public void AddGlyph(int codePoint, GlyphImage img)
        {
            var glyphCache = new CacheGlyph();

            glyphCache.codePoint = codePoint;
            glyphCache.img       = img;

            glyphs[codePoint] = glyphCache;
        }
Beispiel #6
0
        static GlyphImage ReadGlyphImages(string filename)
        {
            PixelFarm.CpuBlit.ActualBitmap bmp = StorageService.Provider.ReadPngBitmap(filename);
            GlyphImage img = new GlyphImage(bmp.Width, bmp.Height);

            int[] buffer = new int[bmp.Width * bmp.Height];
            unsafe
            {
                PixelFarm.CpuBlit.Imaging.TempMemPtr tmp = PixelFarm.CpuBlit.ActualBitmap.GetBufferPtr(bmp);
                System.Runtime.InteropServices.Marshal.Copy(tmp.Ptr, buffer, 0, bmp.Width * bmp.Height);
                img.SetImageBuffer(buffer, true);
            }
            return(img);
        }
Beispiel #7
0
 static GlyphImage ReadGlyphImages(System.IO.Stream stream)
 {
     using (PixelFarm.CpuBlit.MemBitmap bmp = PixelFarm.CpuBlit.MemBitmap.LoadBitmap(stream))
     {
         GlyphImage img    = new GlyphImage(bmp.Width, bmp.Height);
         int[]      buffer = new int[bmp.Width * bmp.Height];
         unsafe
         {
             PixelFarm.CpuBlit.Imaging.TempMemPtr tmp = PixelFarm.CpuBlit.MemBitmap.GetBufferPtr(bmp);
             System.Runtime.InteropServices.Marshal.Copy(tmp.Ptr, buffer, 0, bmp.Width * bmp.Height);
             img.SetImageBuffer(buffer, true);
         }
         return(img);
     }
 }
Beispiel #8
0
        public MySimpleGLBitmapFontManager(TextureKind textureKind, LayoutFarm.OpenFontTextService textServices)
        {
            this.textServices = textServices;
            //glyph cahce for specific atlas
            _loadedGlyphs = new GLBitmapCache <SimpleFontAtlas>(atlas =>
            {
                //create new one
                Typography.Rendering.GlyphImage totalGlyphImg = atlas.TotalGlyph;
                //load to glbmp
                GLBitmap found = new GLBitmap(totalGlyphImg.Width, totalGlyphImg.Height, totalGlyphImg.GetImageBuffer(), false);
                found.IsInvert = false;
                return(found);
            });

            _textureKind = textureKind;
        }
Beispiel #9
0
        /// <summary>
        /// test only, shapen org image with Paint.net sharpen filter
        /// </summary>
        /// <param name="org"></param>
        /// <param name="radius"></param>
        /// <returns></returns>
        static GlyphImage Sharpen(GlyphImage org, int radius)
        {
            GlyphImage newImg = new GlyphImage(org.Width, org.Height);

            PixelFarm.CpuBlit.Imaging.ShapenFilterPdn sharpen1 = new PixelFarm.CpuBlit.Imaging.ShapenFilterPdn();
            int[] orgBuffer = org.GetImageBuffer();
            unsafe
            {
                fixed(int *orgHeader = &orgBuffer[0])
                {
                    int[] output = sharpen1.Sharpen(orgHeader, org.Width, org.Height, org.Width * 4, radius);
                    newImg.SetImageBuffer(output, org.IsBigEndian);
                }
            }

            return(newImg);
        }
Beispiel #10
0
        public static GlyphImage CreateMsdfImage(Msdfgen.Shape shape)
        {
            double left, bottom, right, top;

            shape.findBounds(out left, out bottom, out right, out top);
            int w = (int)Math.Ceiling((right - left));
            int h = (int)Math.Ceiling((top - bottom));

            if (w < 5)
            {
                w = 5;
            }
            if (h < 5)
            {
                h = 5;
            }


            int borderW   = (int)((float)w / 5f);
            var translate = new Msdfgen.Vector2(left < 0 ? -left + borderW : borderW, bottom < 0 ? -bottom + borderW : borderW);

            w += borderW * 2; //borders,left- right
            h += borderW * 2; //borders, top- bottom



            Msdfgen.FloatRGBBmp frgbBmp = new Msdfgen.FloatRGBBmp(w, h);
            Msdfgen.EdgeColoring.edgeColoringSimple(shape, 3);


            Msdfgen.MsdfGenerator.generateMSDF(frgbBmp,
                                               shape,
                                               4,
                                               new Msdfgen.Vector2(1, 1), //scale
                                               translate,                 //translate to positive quadrant
                                               -1);
            //-----------------------------------
            int[] buffer = Msdfgen.MsdfGenerator.ConvertToIntBmp(frgbBmp);

            GlyphImage img = new GlyphImage(w, h);

            img.TextureOffsetX = translate.x;
            img.TextureOffsetY = translate.y;
            img.SetImageBuffer(buffer, false);
            return(img);
        }
Beispiel #11
0
        public void AddSimpleFontAtlas(SimpleFontAtlas[] simpleFontAtlases, System.IO.Stream totalGlyphImgStream)
        {
            //multiple font atlas that share the same glyphImg

            GlyphImage glyphImg = ReadGlyphImages(totalGlyphImgStream);

            for (int i = 0; i < simpleFontAtlases.Length; ++i)
            {
                SimpleFontAtlas simpleFontAtlas = simpleFontAtlases[i];
                simpleFontAtlas.TotalGlyph          = glyphImg;
                simpleFontAtlas.UseSharedGlyphImage = true;
                _createdAtlases.Add(simpleFontAtlas.FontKey, simpleFontAtlas);

                if (simpleFontAtlas.TextureKind == PixelFarm.Drawing.BitmapAtlas.TextureKind.Msdf)
                {
                    //if we have msdf texture
                    //then we can use this to do autoscale
                    _msdfTextureFonts.Add(simpleFontAtlas.FontFilename, simpleFontAtlas);
                }
            }
        }
Beispiel #12
0
 public CacheGlyph(ushort glyphIndex, GlyphImage img)
 {
     this.glyphIndex = glyphIndex;
     this.img        = img;
 }
        public GlyphImage BuildSingleImage()
        {
            //1. add to list
            var glyphList = new List <CacheGlyph>(glyphs.Count);

            foreach (CacheGlyph glyphImg in glyphs.Values)
            {
                //sort data
                glyphList.Add(glyphImg);
            }


            int totalMaxLim  = MaxAtlasWidth;
            int maxRowHeight = 0;
            int currentY     = 0;
            int currentX     = 0;


            if (CompactGlyphSpace)
            {
                //2. sort by glyph width
                glyphList.Sort((a, b) =>
                {
                    return(a.img.Width.CompareTo(b.img.Width));
                });
                //3. layout
                for (int i = glyphList.Count - 1; i >= 0; --i)
                {
                    CacheGlyph g = glyphList[i];
                    if (g.img.Height > maxRowHeight)
                    {
                        maxRowHeight = g.img.Height;
                    }
                    if (currentX + g.img.Width > totalMaxLim)
                    {
                        //start new row
                        currentY += maxRowHeight;
                        currentX  = 0;
                    }
                    //-------------------
                    g.area    = new Rectangle(currentX, currentY, g.img.Width, g.img.Height);
                    currentX += g.img.Width;
                }
            }
            else
            {    //3. layout
                int glyphCount = glyphList.Count;
                for (int i = 0; i < glyphCount; ++i)
                {
                    CacheGlyph g = glyphList[i];
                    if (g.img.Height > maxRowHeight)
                    {
                        maxRowHeight = g.img.Height;
                    }
                    if (currentX + g.img.Width > totalMaxLim)
                    {
                        //start new row
                        currentY += maxRowHeight;
                        currentX  = 0;
                    }
                    //-------------------
                    g.area    = new Rectangle(currentX, currentY, g.img.Width, g.img.Height);
                    currentX += g.img.Width;
                }
            }

            currentY += maxRowHeight;
            int imgH = currentY;
            // -------------------------------
            //compact image location
            // TODO: review performance here again***

            int totalImgWidth = totalMaxLim;

            if (CompactGlyphSpace)
            {
                totalImgWidth = 0;//reset
                BinPacker binPacker = new BinPacker(totalMaxLim, currentY);
                for (int i = glyphList.Count - 1; i >= 0; --i)
                {
                    CacheGlyph  g       = glyphList[i];
                    BinPackRect newRect = binPacker.Insert(g.img.Width, g.img.Height);
                    g.area = new Rectangle(newRect.X, newRect.Y,
                                           g.img.Width, g.img.Height);


                    //recalculate proper max midth again, after arrange and compact space
                    if (newRect.Right > totalImgWidth)
                    {
                        totalImgWidth = newRect.Right;
                    }
                }
            }


            // -------------------------------
            //4. create array that can hold data
            int[] totalBuffer = new int[totalImgWidth * imgH];
            if (CompactGlyphSpace)
            {
                for (int i = glyphList.Count - 1; i >= 0; --i)
                {
                    CacheGlyph g = glyphList[i];
                    //copy data to totalBuffer
                    GlyphImage img = g.img;
                    CopyToDest(img.GetImageBuffer(), img.Width, img.Height, totalBuffer, g.area.Left, g.area.Top, totalImgWidth);
                }
            }
            else
            {
                int glyphCount = glyphList.Count;
                for (int i = 0; i < glyphCount; ++i)
                {
                    CacheGlyph g = glyphList[i];
                    //copy data to totalBuffer
                    GlyphImage img = g.img;
                    CopyToDest(img.GetImageBuffer(), img.Width, img.Height, totalBuffer, g.area.Left, g.area.Top, totalImgWidth);
                }
            }

            GlyphImage glyphImage = new GlyphImage(totalImgWidth, imgH);

            glyphImage.SetImageBuffer(totalBuffer, true);
            latestGenGlyphImage = glyphImage;
            return(glyphImage);
        }
        public GlyphImage CreateGlyphImage(GlyphPathBuilder builder, float pxscale)
        {
            //1. create

            var txToVxs = new GlyphTranslatorToVxs();

            builder.ReadShapes(txToVxs);
            //
            //create new one
            var glyphVxs = new VertexStore();

            txToVxs.WriteOutput(glyphVxs, pxscale);
            //find bound
            //--------------------------------------------
            //GlyphImage glyphImg = new GlyphImage()
            RectD bounds = new 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;

            //we need some borders
            int horizontal_margin = 1; //'margin' 1px
            int vertical_margin   = 1; //margin 1 px

            dx += horizontal_margin;   //+ left margin
            dy += vertical_margin;     //+ top margin
                                       //--------------------------------------------
                                       //create glyph img


            w = (int)Math.Ceiling(dx + w + horizontal_margin); //+right margin
            h = (int)Math.Ceiling(dy + h + vertical_margin);   //+bottom margin

            ActualImage      img     = new ActualImage(w, h, PixelFormat.ARGB32);
            AggRenderSurface aggsx   = new AggRenderSurface(img);
            AggPainter       painter = new AggPainter(aggsx);

            if (TextureKind == TextureKind.StencilLcdEffect)
            {
                VertexStore vxs2 = new VertexStore();
                glyphVxs.TranslateToNewVxs(dx + 0.33f, dy, vxs2); //offset to proper x of subpixel rendering  ***
                glyphVxs = vxs2;
                //
                painter.UseSubPixelLcdEffect = true;

                //we use white glyph on black bg for this texture
                painter.Clear(Color.Black);
                painter.FillColor = Color.White;
                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
            {
                VertexStore vxs2 = new VertexStore();
                glyphVxs.TranslateToNewVxs(dx, dy, vxs2);
                glyphVxs = vxs2;

                painter.UseSubPixelLcdEffect = false;

                if (TextureKind == TextureKind.StencilGreyScale)
                {
                    painter.Clear(Color.Empty);
                    painter.FillColor = Color.Black;
                }
                else
                {
                    painter.Clear(BackGroundColor);
                    painter.FillColor = this.GlyphColor;
                }
                painter.Fill(glyphVxs);
            }
            //
            var glyphImage = new GlyphImage(w, h);

            glyphImage.TextureOffsetX = dx;
            glyphImage.TextureOffsetY = dy;
            glyphImage.SetImageBuffer(ActualImageExtensions.CopyImgBuffer(img, w), false);
            //copy data from agg canvas to glyph image
            return(glyphImage);
        }
Beispiel #15
0
        public static GlyphImage CreateMsdfImage(Msdfgen.Shape shape, MsdfGenParams genParams)
        {
            double left, bottom, right, top;

            shape.findBounds(out left, out bottom, out right, out top);
            int w = (int)Math.Ceiling((right - left));
            int h = (int)Math.Ceiling((top - bottom));

            if (w < genParams.minImgWidth)
            {
                w = genParams.minImgWidth;
            }
            if (h < genParams.minImgHeight)
            {
                h = genParams.minImgHeight;
            }


            //temp, for debug with glyph 'I', tahoma font
            //double edgeThreshold = 1.00000001;//default, if edgeThreshold < 0 then  set  edgeThreshold=1
            //Msdfgen.Vector2 scale = new Msdfgen.Vector2(0.98714652956298199, 0.98714652956298199);
            //double pxRange = 4;
            //translate = new Msdfgen.Vector2(12.552083333333332, 4.0520833333333330);
            //double range = pxRange / Math.Min(scale.x, scale.y);


            int borderW   = (int)((float)w / 5f);
            var translate = new Msdfgen.Vector2(left < 0 ? -left + borderW : borderW, bottom < 0 ? -bottom + borderW : borderW);

            w += borderW * 2; //borders,left- right
            h += borderW * 2; //borders, top- bottom

            double edgeThreshold = genParams.edgeThreshold;

            if (edgeThreshold < 0)
            {
                edgeThreshold = 1.00000001; //use default if  edgeThreshold <0
            }

            var    scale = new Msdfgen.Vector2(genParams.scaleX, genParams.scaleY); //scale
            double range = genParams.pxRange / Math.Min(scale.x, scale.y);

            //---------
            Msdfgen.FloatRGBBmp frgbBmp = new Msdfgen.FloatRGBBmp(w, h);
            Msdfgen.EdgeColoring.edgeColoringSimple(shape, genParams.angleThreshold);
            Msdfgen.MsdfGenerator.generateMSDF(frgbBmp,
                                               shape,
                                               range,
                                               scale,
                                               translate,//translate to positive quadrant
                                               edgeThreshold);
            //-----------------------------------
            int[] buffer = Msdfgen.MsdfGenerator.ConvertToIntBmp(frgbBmp);

            GlyphImage img = new GlyphImage(w, h);

            img.TextureOffsetX = (short)translate.x;
            img.TextureOffsetY = (short)translate.y;
            img.SetImageBuffer(buffer, false);
            return(img);
        }
Beispiel #16
0
        /// <summary>
        /// get from cache or create a new one
        /// </summary>
        /// <param name="reqFont"></param>
        /// <returns></returns>
        public SimpleFontAtlas GetFontAtlas(RequestFont reqFont, out B outputBitmap)
        {
#if DEBUG
            _dbugStopWatch.Reset();
            _dbugStopWatch.Start();
#endif

            int             fontKey = reqFont.FontKey;
            SimpleFontAtlas fontAtlas;
            if (!_createdAtlases.TryGetValue(fontKey, out fontAtlas))
            {
                //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";

                //check if the file exist

                if (StorageService.Provider.DataExists(fontTextureInfoFile) &&
                    StorageService.Provider.DataExists(fontTextureImgFilename))
                {
                    SimpleFontAtlasBuilder atlasBuilder = new SimpleFontAtlasBuilder();
                    using (System.IO.Stream dataStream = StorageService.Provider.ReadDataStream(fontTextureInfoFile))
                    {
                        try
                        {
                            fontAtlas                     = atlasBuilder.LoadFontInfo(dataStream);
                            fontAtlas.TotalGlyph          = ReadGlyphImages(fontTextureImgFilename);
                            fontAtlas.OriginalFontSizePts = reqFont.SizeInPoints;
                            _createdAtlases.Add(fontKey, fontAtlas);
                        }
                        catch (Exception ex)
                        {
                            throw ex;
                        }
                    }
                }
                else
                {
                    GlyphImage             totalGlyphsImg = null;
                    SimpleFontAtlasBuilder atlasBuilder   = null;
                    var glyphTextureGen = new GlyphTextureBitmapGenerator();
                    glyphTextureGen.CreateTextureFontBuildDetail(
                        resolvedTypeface,
                        reqFont.SizeInPoints,
                        _textureKind,
                        GlyphTextureCustomConfigs.TryGetGlyphTextureBuildDetail(reqFont),
                        (glyphIndex, glyphImage, outputAtlasBuilder) =>
                    {
                        if (outputAtlasBuilder != null)
                        {
                            //finish
                            atlasBuilder = outputAtlasBuilder;
                        }
                    }
                        );

                    atlasBuilder.SpaceCompactOption = SimpleFontAtlasBuilder.CompactOption.ArrangeByHeight;
                    totalGlyphsImg = atlasBuilder.BuildSingleImage();
                    //if (reqFont.SizeInPoints == 14 && cacheImg != null)
                    //{
                    //    totalGlyphsImg = cacheImg;
                    //}
                    //totalGlyphsImg = Sharpen(totalGlyphsImg, 1); //test shapen primary image
                    //-
                    //
                    //create atlas
                    fontAtlas            = atlasBuilder.CreateSimpleFontAtlas();
                    fontAtlas.TotalGlyph = totalGlyphsImg;
#if DEBUG
                    //save glyph image for debug
                    //PixelFarm.Agg.ActualImage.SaveImgBufferToPngFile(
                    //    totalGlyphsImg.GetImageBuffer(),
                    //    totalGlyphsImg.Width * 4,
                    //    totalGlyphsImg.Width, totalGlyphsImg.Height,
                    //    "d:\\WImageTest\\total_" + reqFont.Name + "_" + reqFont.SizeInPoints + ".png");
                    ////save image to cache
                    SaveImgBufferToFile(totalGlyphsImg, fontTextureImgFilename);
#endif

                    //cache the atlas
                    _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

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

            outputBitmap = _loadedGlyphs.GetOrCreateNewOne(fontAtlas);
            return(fontAtlas);
        }
        public GlyphImage BuildSingleImage()
        {
            //1. add to list
            var glyphList = new List <CacheGlyph>(glyphs.Count);

            foreach (CacheGlyph glyphImg in glyphs.Values)
            {
                //sort data
                glyphList.Add(glyphImg);
            }
            //2. sort
            glyphList.Sort((a, b) =>
            {
                return(a.img.Width.CompareTo(b.img.Width));
            });
            //3. layout

            int totalMaxLim  = 800;
            int maxRowHeight = 0;
            int currentY     = 0;
            int currentX     = 0;

            for (int i = glyphList.Count - 1; i >= 0; --i)
            {
                CacheGlyph g = glyphList[i];
                if (g.img.Height > maxRowHeight)
                {
                    maxRowHeight = g.img.Height;
                }
                if (currentX + g.img.Width > totalMaxLim)
                {
                    //start new row
                    currentY += maxRowHeight;
                    currentX  = 0;
                }
                //-------------------
                g.area    = new Rectangle(currentX, currentY, g.img.Width, g.img.Height);
                currentX += g.img.Width;
            }
            currentY += maxRowHeight;
            int imgH = currentY;
            //-------------------------------
            //compact image location
            //TODO: review performance here again***
            BinPacker binPacker = new BinPacker(totalMaxLim, currentY);

            for (int i = glyphList.Count - 1; i >= 0; --i)
            {
                CacheGlyph  g       = glyphList[i];
                BinPackRect newRect = binPacker.Insert(g.img.Width, g.img.Height);
                g.area = new Rectangle(newRect.X, newRect.Y,
                                       g.img.Width, g.img.Height);
            }
            //-------------------------------

            //4. create array that can hold data
            int[] totalBuffer = new int[totalMaxLim * imgH];
            for (int i = glyphList.Count - 1; i >= 0; --i)
            {
                CacheGlyph g = glyphList[i];
                //copy data to totalBuffer
                GlyphImage img = g.img;
                CopyToDest(img.GetImageBuffer(), img.Width, img.Height, totalBuffer, g.area.Left, g.area.Top, totalMaxLim);
            }
            //------------------

            GlyphImage glyphImage = new GlyphImage(totalMaxLim, imgH);

            glyphImage.SetImageBuffer(totalBuffer, true);
            latestGenGlyphImage = glyphImage;
            return(glyphImage);
        }
Beispiel #18
0
        public GlyphImage BuildSingleImage()
        {
            //1. add to list
            var glyphList = new List <CacheGlyph>(_glyphs.Count);

            foreach (CacheGlyph glyphImg in _glyphs.Values)
            {
                //sort data
                glyphList.Add(glyphImg);
            }

            int totalMaxLim  = MaxAtlasWidth;
            int maxRowHeight = 0;
            int currentY     = 0;
            int currentX     = 0;

            switch (this.SpaceCompactOption)
            {
            default:
                throw new System.NotSupportedException();

            case CompactOption.BinPack:
            {
                //2. sort by glyph width
                glyphList.Sort((a, b) =>
                    {
                        return(a.img.Width.CompareTo(b.img.Width));
                    });
                //3. layout
                for (int i = glyphList.Count - 1; i >= 0; --i)
                {
                    CacheGlyph g = glyphList[i];
                    if (g.img.Height > maxRowHeight)
                    {
                        maxRowHeight = g.img.Height;
                    }
                    if (currentX + g.img.Width > totalMaxLim)
                    {
                        //start new row
                        currentY += maxRowHeight;
                        currentX  = 0;
                    }
                    //-------------------
                    g.area    = new Rectangle(currentX, currentY, g.img.Width, g.img.Height);
                    currentX += g.img.Width;
                }
            }
            break;

            case CompactOption.ArrangeByHeight:
            {
                //2. sort by height
                glyphList.Sort((a, b) =>
                    {
                        return(a.img.Height.CompareTo(b.img.Height));
                    });
                //3. layout
                int glyphCount = glyphList.Count;
                for (int i = 0; i < glyphCount; ++i)
                {
                    CacheGlyph g = glyphList[i];
                    if (g.img.Height > maxRowHeight)
                    {
                        maxRowHeight = g.img.Height;
                    }
                    if (currentX + g.img.Width > totalMaxLim)
                    {
                        //start new row
                        currentY    += maxRowHeight;
                        currentX     = 0;
                        maxRowHeight = g.img.Height;        //reset, after start new row
                    }
                    //-------------------
                    g.area    = new Rectangle(currentX, currentY, g.img.Width, g.img.Height);
                    currentX += g.img.Width;
                }
            }
            break;

            case CompactOption.None:
            {
                //3. layout
                int glyphCount = glyphList.Count;
                for (int i = 0; i < glyphCount; ++i)
                {
                    CacheGlyph g = glyphList[i];
                    if (g.img.Height > maxRowHeight)
                    {
                        maxRowHeight = g.img.Height;
                    }
                    if (currentX + g.img.Width > totalMaxLim)
                    {
                        //start new row
                        currentY    += maxRowHeight;
                        currentX     = 0;
                        maxRowHeight = g.img.Height;        //reset, after start new row
                    }
                    //-------------------
                    g.area    = new Rectangle(currentX, currentY, g.img.Width, g.img.Height);
                    currentX += g.img.Width;
                }
            }
            break;
            }

            currentY += maxRowHeight;
            int imgH = currentY;
            // -------------------------------
            //compact image location
            // TODO: review performance here again***

            int totalImgWidth = totalMaxLim;

            if (SpaceCompactOption == CompactOption.BinPack) //again here?
            {
                totalImgWidth = 0;                           //reset
                //use bin packer
                BinPacker binPacker = new BinPacker(totalMaxLim, currentY);
                for (int i = glyphList.Count - 1; i >= 0; --i)
                {
                    CacheGlyph  g       = glyphList[i];
                    BinPackRect newRect = binPacker.Insert(g.img.Width, g.img.Height);
                    g.area = new Rectangle(newRect.X, newRect.Y,
                                           g.img.Width, g.img.Height);


                    //recalculate proper max midth again, after arrange and compact space
                    if (newRect.Right > totalImgWidth)
                    {
                        totalImgWidth = newRect.Right;
                    }
                }
            }
            // -------------------------------
            //4. create array that can hold data
            int[] totalBuffer = new int[totalImgWidth * imgH];
            if (SpaceCompactOption == CompactOption.BinPack) //again here?
            {
                for (int i = glyphList.Count - 1; i >= 0; --i)
                {
                    CacheGlyph g = glyphList[i];
                    //copy data to totalBuffer
                    GlyphImage img = g.img;
                    CopyToDest(img.GetImageBuffer(), img.Width, img.Height, totalBuffer, g.area.Left, g.area.Top, totalImgWidth);
                }
            }
            else
            {
                int glyphCount = glyphList.Count;
                for (int i = 0; i < glyphCount; ++i)
                {
                    CacheGlyph g = glyphList[i];
                    //copy data to totalBuffer
                    GlyphImage img = g.img;
                    CopyToDest(img.GetImageBuffer(), img.Width, img.Height, totalBuffer, g.area.Left, g.area.Top, totalImgWidth);
                }
            }

            //new total glyph img
            GlyphImage glyphImage = new GlyphImage(totalImgWidth, imgH);

            //flip vertical Y
            {
                int[] totalBufferFlipY = new int[totalBuffer.Length];
                int   srcRowIndex      = imgH - 1;
                int   strideInBytes    = totalImgWidth * 4;
                for (int i = 0; i < imgH; ++i)
                {
                    //copy each row from src to dst
                    System.Buffer.BlockCopy(totalBuffer, strideInBytes * srcRowIndex, totalBufferFlipY, strideInBytes * i, strideInBytes);
                    srcRowIndex--;
                }
                totalBuffer = totalBufferFlipY;
            }
            glyphImage.SetImageBuffer(totalBuffer, true);
            _latestGenGlyphImage = glyphImage;
            return(glyphImage);
        }
 /// <summary>
 /// add or replace
 /// </summary>
 /// <param name="glyphIndex"></param>
 /// <param name="img"></param>
 public void AddGlyph(ushort glyphIndex, GlyphImage img)
 {
     _glyphs[glyphIndex] = new CacheGlyph(glyphIndex, img);
 }
Beispiel #20
0
        static void SaveImgBufferToFile(GlyphImage glyphImg, string filename)
        {
            var bmp = new PixelFarm.CpuBlit.ActualBitmap(glyphImg.Width, glyphImg.Height, glyphImg.GetImageBuffer());

            StorageService.Provider.SavePngBitmap(bmp, filename);
        }