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); } }
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); } }
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); }
/// <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; }
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); }
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); } }
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; }
/// <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); }
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); }
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); } } }
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); }
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); }
/// <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); }
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); }
static void SaveImgBufferToFile(GlyphImage glyphImg, string filename) { var bmp = new PixelFarm.CpuBlit.ActualBitmap(glyphImg.Width, glyphImg.Height, glyphImg.GetImageBuffer()); StorageService.Provider.SavePngBitmap(bmp, filename); }