示例#1
0
 static void SaveImgBufferToFile(BitmapAtlasItemSource 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);
     }
 }
        public MemBitmap BuildSingleImage(bool flipY)
        {
            //1. add to list
            var itemList = new List <BitmapAtlasItemSource>(_items.Values);

            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
                itemList.Sort((a, b) => a.Width.CompareTo(b.Width));
                //3. layout
                for (int i = itemList.Count - 1; i >= 0; --i)
                {
                    BitmapAtlasItemSource g = itemList[i];
                    if (g.Height > maxRowHeight)
                    {
                        maxRowHeight = g.Height;
                    }
                    if (currentX + g.Width > totalMaxLim)
                    {
                        //start new row
                        currentY += maxRowHeight;
                        currentX  = 0;
                    }
                    //-------------------
                    g.Area    = new Rectangle(currentX, currentY, g.Width, g.Height);
                    currentX += g.Width;
                }
            }
            break;

            case CompactOption.ArrangeByHeight:
            {
                //2. sort by height
                itemList.Sort((a, b) => a.Height.CompareTo(b.Height));

                //3. layout
                int glyphCount = itemList.Count;
                for (int i = 0; i < glyphCount; ++i)
                {
                    BitmapAtlasItemSource g = itemList[i];
                    if (g.Height > maxRowHeight)
                    {
                        maxRowHeight = g.Height;
                    }
                    if (currentX + g.Width > totalMaxLim)
                    {
                        //start new row
                        currentY    += maxRowHeight;
                        currentX     = 0;
                        maxRowHeight = g.Height;        //reset, after start new row
                    }
                    //-------------------
                    g.Area    = new Rectangle(currentX, currentY, g.Width, g.Height);
                    currentX += g.Width;
                }
            }
            break;

            case CompactOption.None:
            {
                //3. layout
                int glyphCount = itemList.Count;
                for (int i = 0; i < glyphCount; ++i)
                {
                    BitmapAtlasItemSource g = itemList[i];
                    if (g.Height > maxRowHeight)
                    {
                        maxRowHeight = g.Height;
                    }
                    if (currentX + g.Width > totalMaxLim)
                    {
                        //start new row
                        currentY    += maxRowHeight;
                        currentX     = 0;
                        maxRowHeight = g.Height;        //reset, after start new row
                    }
                    //-------------------
                    g.Area    = new Rectangle(currentX, currentY, g.Width, g.Height);
                    currentX += g.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 = itemList.Count - 1; i >= 0; --i)
                {
                    BitmapAtlasItemSource g       = itemList[i];
                    BinPackRect           newRect = binPacker.Insert(g.Width, g.Height);
                    g.Area = new Rectangle(newRect.X, newRect.Y, g.Width, g.Height);


                    //recalculate proper max midth again, after arrange and compact space
                    if (newRect.Right > totalImgWidth)
                    {
                        totalImgWidth = newRect.Right;
                    }
                }
            }
            // -------------------------------
            //4. create a mergeBmpBuffer
            //please note that original glyph image is head-down (Y axis)
            //so we will flip-Y axis again in step 5.
            int[] mergeBmpBuffer = new int[totalImgWidth * imgH];
            if (SpaceCompactOption == CompactOption.BinPack) //again here?
            {
                for (int i = itemList.Count - 1; i >= 0; --i)
                {
                    BitmapAtlasItemSource g = itemList[i];
                    //copy glyph image buffer to specific area of final result buffer
                    CopyToDest(g.GetImageBuffer(), g.Width, g.Height, mergeBmpBuffer, g.Area.Left, g.Area.Top, totalImgWidth);
                }
            }
            else
            {
                int itemCount = itemList.Count;
                for (int i = 0; i < itemCount; ++i)
                {
                    BitmapAtlasItemSource g = itemList[i];
                    //copy glyph image buffer to specific area of final result buffer

                    CopyToDest(g.GetImageBuffer(), g.Width, g.Height, mergeBmpBuffer, g.Area.Left, g.Area.Top, totalImgWidth);
                }
            }

            //5. since the mergeBmpBuffer is head-down
            //we will flipY axis again to head-up, the head-up img is easy to read and debug

            if (flipY)
            {
                int[] totalBufferFlipY = new int[mergeBmpBuffer.Length];
                int   srcRowIndex      = imgH - 1;
                int   strideInBytes    = totalImgWidth * 4;//32 argb

                for (int i = 0; i < imgH; ++i)
                {
                    //copy each row from src to dst
                    System.Buffer.BlockCopy(mergeBmpBuffer, strideInBytes * srcRowIndex, totalBufferFlipY, strideInBytes * i, strideInBytes);
                    srcRowIndex--;
                }

                //flipY on atlas info too
                for (int i = 0; i < itemList.Count; ++i)
                {
                    BitmapAtlasItemSource g    = itemList[i];
                    Rectangle             rect = g.Area;
                    g.Area = new Rectangle(rect.X, imgH - (rect.Y + rect.Height), rect.Width, rect.Height);
                }


                //***
                //6. generate final output
                //TODO: rename GlyphImage to another name to distinquist
                //between small glyph and a large one
                return(_latestResultBmp = PixelFarm.CpuBlit.MemBitmap.CreateFromCopy(totalImgWidth, imgH, totalBufferFlipY));
            }
            else
            {
                return(_latestResultBmp = PixelFarm.CpuBlit.MemBitmap.CreateFromCopy(totalImgWidth, imgH, mergeBmpBuffer));
            }
        }