public SimpleBitmapAtlasBuilder CreateTextureFontFromInputChars( Typeface typeface, float sizeInPoint, TextureKind textureKind, char[] chars, OnEachGlyph onEachGlyphDel = null) { _onEachGlyphDel = onEachGlyphDel; //convert input chars into glyphIndex List <ushort> glyphIndices = new List <ushort>(chars.Length); int i = 0; foreach (char ch in chars) { glyphIndices.Add(typeface.GetGlyphIndex(ch)); i++; } //------------------------------------------------------------- var atlasBuilder = new SimpleBitmapAtlasBuilder(); atlasBuilder.SetAtlasInfo(textureKind, sizeInPoint); //------------------------------------------------------------- //we can specfic subset with special setting for each set CreateTextureFontFromGlyphIndices(typeface, sizeInPoint, HintTechnique.TrueTypeInstruction_VerticalOnly, atlasBuilder, GetUniqueGlyphIndexList(glyphIndices)); _onEachGlyphDel = null;//reset return(atlasBuilder); }
public GlyphNotFoundHelper( SimpleBitmapAtlasBuilder atlasBuilder, GlyphOutlineBuilder outlineBuilder, OnEachGlyph onEachGlyphDel, AggGlyphTextureGen aggTextureGen, float sizeInPoints) { _atlasBuilder = atlasBuilder; _outlineBuilder = outlineBuilder; _onEachGlyphDel = onEachGlyphDel; _aggTextureGen = aggTextureGen; _sizeInPoints = sizeInPoints; }
/// <summary> /// get from cache or create a new one /// </summary> /// <param name="reqFont"></param> /// <returns></returns> public SimpleBitmapAtlas GetBitmapAtlas(string atlasName, out B outputBitmap) { #if DEBUG _dbugStopWatch.Reset(); _dbugStopWatch.Start(); #endif if (!_createdAtlases.TryGetValue(atlasName, out SimpleBitmapAtlas foundAtlas)) { //check from pre-built cache (if availiable) string textureInfoFile = atlasName + ".info"; string textureImgFilename = atlasName + ".png"; //check if the file exist if (StorageService.Provider.DataExists(textureInfoFile) && StorageService.Provider.DataExists(textureImgFilename)) { SimpleBitmapAtlasBuilder atlasBuilder = new SimpleBitmapAtlasBuilder(); using (System.IO.Stream fontAtlasTextureInfo = StorageService.Provider.ReadDataStream(textureInfoFile)) using (System.IO.Stream fontImgStream = StorageService.Provider.ReadDataStream(textureImgFilename)) { try { List <SimpleBitmapAtlas> atlasList = atlasBuilder.LoadAtlasInfo(fontAtlasTextureInfo); foundAtlas = atlasList[0]; foundAtlas.SetMainBitmap(MemBitmap.LoadBitmap(fontImgStream), true); _createdAtlases.Add(atlasName, foundAtlas); } catch (Exception ex) { throw ex; } } } } if (foundAtlas != null) { outputBitmap = _loadAtlases.GetOrCreateNewOne(foundAtlas); return(foundAtlas); } else { #if DEBUG //show warning about this System.Diagnostics.Debug.WriteLine("not found atlas:" + atlasName); #endif outputBitmap = default(B); return(null); } }
public SimpleBitmapAtlasBuilder CreateTextureFontFromBuildDetail( Typeface typeface, float sizeInPoint, TextureKind textureKind, GlyphTextureBuildDetail[] details, OnEachGlyph onEachGlyphDel = null) { _onEachGlyphDel = onEachGlyphDel; //------------------------------------------------------------- var atlasBuilder = new SimpleBitmapAtlasBuilder(); atlasBuilder.SetAtlasInfo(textureKind, sizeInPoint); //------------------------------------------------------------- int j = details.Length; for (int i = 0; i < j; ++i) { GlyphTextureBuildDetail detail = details[i]; if (detail.ScriptLang != null) { //skip those script lang=null //2. find associated glyph index base on input script langs List <ushort> outputGlyphIndexList = new List <ushort>(); typeface.CollectAllAssociateGlyphIndex(outputGlyphIndexList, detail.ScriptLang); CreateTextureFontFromGlyphIndices(typeface, sizeInPoint, detail.HintTechnique, atlasBuilder, GetUniqueGlyphIndexList(outputGlyphIndexList) ); } } for (int i = 0; i < j; ++i) { GlyphTextureBuildDetail detail = details[i]; if (detail.OnlySelectedGlyphIndices != null) { //skip those script lang=null //2. find associated glyph index base on input script langs CreateTextureFontFromGlyphIndices(typeface, sizeInPoint, detail.HintTechnique, atlasBuilder, detail.OnlySelectedGlyphIndices ); } } _onEachGlyphDel = null;//reset return(atlasBuilder); }
void CreateTextureFontFromGlyphIndices( HintTechnique hintTechnique, SimpleBitmapAtlasBuilder atlasBuilder, char[] chars) { int j = chars.Length; ushort[] glyphIndices = new ushort[j]; for (int i = 0; i < j; ++i) { glyphIndices[i] = _typeface.GetGlyphIndex(chars[i]); } CreateTextureFontFromGlyphIndices(hintTechnique, atlasBuilder, glyphIndices); }
public void RegisterBitmapAtlas(string atlasName, byte[] atlasInfoBuffer, byte[] totalImgBuffer) { //direct register atlas //instead of loading it from file if (!_createdAtlases.ContainsKey(atlasName)) { SimpleBitmapAtlasBuilder atlasBuilder = new SimpleBitmapAtlasBuilder(); using (System.IO.Stream fontAtlasTextureInfo = new MemoryStream(atlasInfoBuffer)) using (System.IO.Stream fontImgStream = new MemoryStream(totalImgBuffer)) { try { List <SimpleBitmapAtlas> atlasList = atlasBuilder.LoadAtlasInfo(fontAtlasTextureInfo); SimpleBitmapAtlas foundAtlas = atlasList[0]; foundAtlas.SetMainBitmap(MemBitmap.LoadBitmap(fontImgStream), true); _createdAtlases.Add(atlasName, foundAtlas); } catch (Exception ex) { throw ex; } } } }
void CreateTextureFontFromGlyphIndices( Typeface typeface, float sizeInPoint, HintTechnique hintTechnique, SimpleBitmapAtlasBuilder atlasBuilder, ushort[] glyphIndices) { //sample: create sample msdf texture //------------------------------------------------------------- var outlineBuilder = new GlyphOutlineBuilder(typeface); outlineBuilder.SetHintTechnique(hintTechnique); // if (atlasBuilder.TextureKind == TextureKind.Msdf) { float pxscale = typeface.CalculateScaleToPixelFromPointSize(sizeInPoint); 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) outlineBuilder.BuildFromGlyphIndex(gindex, -1); var glyphToVxs = new GlyphTranslatorToVxs(); outlineBuilder.ReadShapes(glyphToVxs); using (Tools.BorrowVxs(out var vxs)) { glyphToVxs.WriteUnFlattenOutput(vxs, pxscale); BitmapAtlasItemSource glyphImg = gen3.GenerateMsdfTexture(vxs); glyphImg.UniqueInt16Name = gindex; _onEachGlyphDel?.Invoke(glyphImg); // atlasBuilder.AddItemSource(glyphImg); } } } else { 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) outlineBuilder.BuildFromGlyphIndex(gindex, -1); var glyphToVxs = new GlyphTranslatorToVxs(); outlineBuilder.ReadShapes(glyphToVxs); using (Tools.BorrowVxs(out var vxs)) { glyphToVxs.WriteUnFlattenOutput(vxs, pxscale); BitmapAtlasItemSource glyphImg = gen3.GenerateMsdfTexture(vxs); glyphImg.UniqueInt16Name = gindex; _onEachGlyphDel?.Invoke(glyphImg); atlasBuilder.AddItemSource(glyphImg); } } } } else { AggGlyphTextureGen aggTextureGen = new AggGlyphTextureGen(); aggTextureGen.TextureKind = atlasBuilder.TextureKind; //create reusable agg painter*** //assume each glyph size= 2 * line height //TODO: review here again... int tmpMemBmpHeight = (int)(2 * typeface.CalculateRecommendLineSpacing() * typeface.CalculateScaleToPixelFromPointSize(sizeInPoint)); //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, sizeInPoint); BitmapAtlasItemSource glyphImg = aggTextureGen.CreateAtlasItem(outlineBuilder, 1); glyphImg.UniqueInt16Name = gindex; _onEachGlyphDel?.Invoke(glyphImg); atlasBuilder.AddItemSource(glyphImg); } } } }
/// <summary> /// get from cache or create a new one /// </summary> /// <param name="reqFont"></param> /// <returns></returns> public SimpleBitmapAtlas GetFontAtlas(RequestFont reqFont, out B outputBitmap) { #if DEBUG _dbugStopWatch.Reset(); _dbugStopWatch.Start(); #endif int fontKey = reqFont.FontKey; if (_createdAtlases.TryGetValue(fontKey, out SimpleBitmapAtlas fontAtlas)) { outputBitmap = _loadAtlases.GetOrCreateNewOne(fontAtlas); return(fontAtlas); } //check if we have small msdf texture or not if (_msdfTextureFonts.TryGetValue(reqFont.Name, out SimpleBitmapAtlas msdfTexture)) { //use this outputBitmap = _loadAtlases.GetOrCreateNewOne(msdfTexture); return(msdfTexture); } //-------------------------------- //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"; if (StorageService.Provider.DataExists(fontTextureInfoFile) && StorageService.Provider.DataExists(fontTextureImgFilename)) { //check local caching, if found then load-> create it SimpleBitmapAtlasBuilder atlasBuilder = new SimpleBitmapAtlasBuilder(); lock (s_loadDataLock) { using (System.IO.Stream textureInfoFileStream = StorageService.Provider.ReadDataStream(fontTextureInfoFile)) using (System.IO.Stream fontAtlasImgStream = StorageService.Provider.ReadDataStream(fontTextureImgFilename)) { try { //TODO: review here fontAtlas = atlasBuilder.LoadAtlasInfo(textureInfoFileStream)[0]; fontAtlas.SetMainBitmap(ReadGlyphImages(fontAtlasImgStream), true); fontAtlas.OriginalFontSizePts = reqFont.SizeInPoints; _createdAtlases.Add(fontKey, fontAtlas); } catch (Exception ex) { throw ex; } } } } else { //------------- //if not found the request font //we generate it realtime here, (add add the cache '_createdAtlases') //------------- //1. create glyph-texture-bitmap generator var glyphTextureGen = new GlyphTextureBitmapGenerator(); //2. generate the glyphs SimpleBitmapAtlasBuilder atlasBuilder = glyphTextureGen.CreateTextureFontFromBuildDetail( resolvedTypeface, reqFont.SizeInPoints, TextureKindForNewFont, GlyphTextureCustomConfigs.TryGetGlyphTextureBuildDetail(reqFont, false, false) ); //3. set information before write to font-info atlasBuilder.FontFilename = reqFont.Name;//TODO: review here, check if we need 'filename' or 'fontname' atlasBuilder.FontKey = reqFont.FontKey; atlasBuilder.SpaceCompactOption = SimpleBitmapAtlasBuilder.CompactOption.ArrangeByHeight; //4. merge all glyph in the builder into a single image PixelFarm.CpuBlit.MemBitmap totalGlyphsImg = atlasBuilder.BuildSingleImage(true); //------------------------------------------------------------- //5. create a simple font atlas from information inside this atlas builder. fontAtlas = atlasBuilder.CreateSimpleBitmapAtlas(); fontAtlas.SetMainBitmap(totalGlyphsImg, true); #if DEBUG //save glyph image for debug //PixelFarm.Agg.ActualImage.SaveImgBufferToPngFile( // totalGlyphsImg.GetImageBuffer(), // totalGlyphsImg.Width * 4, // totalGlyphsImg.Width, totalGlyphsImg.Height, // "total_" + reqFont.Name + "_" + reqFont.SizeInPoints + ".png"); ////save image to cache totalGlyphsImg.SaveImage(fontTextureImgFilename); #endif //6. cache this in the memory, _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 //TODO: review here again //save font info to local disk cache using (System.IO.MemoryStream ms = new System.IO.MemoryStream()) { atlasBuilder.SaveAtlasInfo(ms); StorageService.Provider.SaveData(fontTextureInfoFile, ms.ToArray()); #if DEBUG //write temp debug info #if !__MOBILE__ System.IO.File.WriteAllBytes(fontTextureInfoFile, ms.ToArray()); System.IO.File.WriteAllText(fontTextureInfoFile + ".txt", reqFont.Name + ",size" + reqFont.SizeInPoints + "pts"); #endif #endif } } outputBitmap = _loadAtlases.GetOrCreateNewOne(fontAtlas); return(fontAtlas); }
public void CreateTextureFontFromBuildDetail( SimpleBitmapAtlasBuilder atlasBuilder, Typeface typeface, float sizeInPoint, TextureKind textureKind, GlyphTextureBuildDetail[] details, OnEachGlyph onEachGlyphDel = null) { _onEachGlyphDel = onEachGlyphDel; SetCurrentFontInfo(typeface, sizeInPoint); //------------------------------------------------------------- atlasBuilder.SetAtlasInfo(textureKind, _currentDPI); atlasBuilder.SetAtlasFontInfo(typeface.Name, sizeInPoint); //------------------------------------------------------------- int j = details.Length; for (int i = 0; i < j; ++i) { GlyphTextureBuildDetail detail = details[i]; if (detail.AllGlyphs) { //all int count = typeface.GlyphCount; ushort[] glyphIndexList = new ushort[count]; for (ushort m = 0; m < count; ++m) { glyphIndexList[m] = m; } CreateTextureFontFromGlyphIndices( detail.HintTechnique, atlasBuilder, glyphIndexList ); } else if (!detail.ScriptLang.IsEmpty()) { //skip those script lang=null //2. find associated glyph index base on input script langs atlasBuilder.ScriptTags.Add(detail.ScriptLang.scriptTag); List <ushort> outputGlyphIndexList = new List <ushort>(); typeface.CollectAllAssociateGlyphIndex(outputGlyphIndexList, detail.ScriptLang); CreateTextureFontFromGlyphIndices( detail.HintTechnique, atlasBuilder, GetUniqueGlyphIndexList(outputGlyphIndexList) ); } else { //?? } } for (int i = 0; i < j; ++i) { GlyphTextureBuildDetail detail = details[i]; if (detail.OnlySelectedChars != null) { //skip those script lang=null //2. find associated glyph index base on input script langs CreateTextureFontFromGlyphIndices( detail.HintTechnique, atlasBuilder, detail.OnlySelectedChars ); } } _onEachGlyphDel = null;//reset }
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); } } } }