GlyphBitmap GetGlyphBitmapFromBitmapFont(ushort glyphIndex) { //not found=> create a new one if (_typeface.IsBitmapFont) { //try load using (System.IO.MemoryStream ms = new System.IO.MemoryStream()) { //load actual bitmap font Glyph glyph = _typeface.GetGlyph(glyphIndex); _typeface.ReadBitmapContent(glyph, ms); using (MemBitmap memBitmap = MemBitmapExt.LoadBitmap(ms)) { //bitmap that are load may be larger than we need //so we need to scale it to specfic size float target_advW = _typeface.GetAdvanceWidthFromGlyphIndex(glyphIndex) * _px_scale; float scaleForBmp = target_advW / memBitmap.Width; MemBitmap scaledMemBmp = memBitmap.ScaleImage(scaleForBmp, scaleForBmp); var glyphBitmap = new GlyphBitmap { Width = scaledMemBmp.Width, Height = scaledMemBmp.Height, Bitmap = scaledMemBmp //** }; return(glyphBitmap); } } } return(null); }
public void SetCurrentTypeface(Typeface typeface) { _currentTypeface = typeface; if (_cacheGlyphBmpLists.TryGetValue(typeface, out _bitmapList)) { return; } //TODO: you can scale down to proper img size //or create a single texture atlas. //if not create a new one _bitmapList = new GlyphBitmapList(); _cacheGlyphBmpLists.Add(typeface, _bitmapList); int glyphCount = typeface.GlyphCount; System.Text.StringBuilder stbuilder = new System.Text.StringBuilder(); for (ushort i = 0; i < glyphCount; ++i) { stbuilder.Length = 0;//reset Glyph glyph = typeface.GetGlyph(i); typeface.ReadSvgContent(glyph, stbuilder); //create bitmap from svg GlyphBitmap glyphBitmap = new GlyphBitmap(); glyphBitmap.Width = glyph.MaxX - glyph.MinX; glyphBitmap.Height = glyph.MaxY - glyph.MinY; if (glyphBitmap.Width == 0 || glyphBitmap.Height == 0) { continue; } glyphBitmap.Bitmap = _svgBmpBuilderFunc(stbuilder);// ParseAndRenderSvg(stbuilder, vgDocHost); if (glyphBitmap.Bitmap == null) { continue; } // //MemBitmapExtensions.SaveImage(glyphBitmap.Bitmap, "testGlyphBmp_" + i + ".png"); _bitmapList.RegisterBitmap(glyph.GlyphIndex, glyphBitmap); } }
public void SetCurrentTypeface(Typeface typeface) { _currentTypeface = typeface; if (_cachedBmpList.TryGetValue(typeface, out _bitmapList)) { return; } //TODO: you can scale down to proper img size //or create a single texture atlas. //if not create a new one _bitmapList = new GlyphBitmapList(); _cachedBmpList.Add(typeface, _bitmapList); int glyphCount = typeface.GlyphCount; using (System.IO.MemoryStream ms = new System.IO.MemoryStream()) { for (ushort i = 0; i < glyphCount; ++i) { ms.SetLength(0); Glyph glyph = typeface.GetGlyph(i); typeface.ReadBitmapContent(glyph, ms); GlyphBitmap glyphBitmap = new GlyphBitmap(); glyphBitmap.Width = glyph.MaxX - glyph.MinX; glyphBitmap.Height = glyph.MaxY - glyph.MinY; //glyphBitmap.Bitmap = ... glyphBitmap.Bitmap = MemBitmap.LoadBitmap(ms); //MemBitmapExtensions.SaveImage(glyphBitmap.Bitmap, "testGlyphBmp_" + i + ".png"); _bitmapList.RegisterBitmap(glyph.GlyphIndex, glyphBitmap); } } }
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); } } } }
public bool TryGetBitmap(ushort glyphIndex, out GlyphBitmap bmp) { return(_dic.TryGetValue(glyphIndex, out bmp)); }
public void RegisterBitmap(ushort glyphIndex, GlyphBitmap bmp) { _dic.Add(glyphIndex, bmp); }
public void RegisterBitmap(ushort glyphIndex, GlyphBitmap bmp) => _bitmapList.RegisterBitmap(glyphIndex, bmp);
public bool TryGetBitmap(ushort glyphIndex, out GlyphBitmap glyphBmp) => _bitmapList.TryGetBitmap(glyphIndex, out glyphBmp);