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)); } }