void CreateTextureFontFromGlyphIndices( Typeface typeface, float sizeInPoint, HintTechnique hintTechnique, SimpleFontAtlasBuilder atlasBuilder, bool applyFilter, ushort[] glyphIndices) { //sample: create sample msdf texture //------------------------------------------------------------- var builder = new GlyphPathBuilder(typeface); builder.SetHintTechnique(hintTechnique); // if (atlasBuilder.TextureKind == TextureKind.Msdf) { MsdfGenParams msdfGenParams = new MsdfGenParams(); int j = glyphIndices.Length; 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) builder.BuildFromGlyphIndex(gindex, -1); var glyphToContour = new GlyphContourBuilder(); builder.ReadShapes(glyphToContour); //msdfgen with scale the glyph to specific shapescale msdfGenParams.shapeScale = 1f / 64; //as original GlyphImage glyphImg = MsdfGlyphGen.CreateMsdfImage(glyphToContour, msdfGenParams); // atlasBuilder.AddGlyph(gindex, glyphImg); } } else { AggGlyphTextureGen aggTextureGen = new AggGlyphTextureGen(); aggTextureGen.TextureKind = atlasBuilder.TextureKind; int j = glyphIndices.Length; for (int i = 0; i < j; ++i) { //build glyph ushort gindex = glyphIndices[i]; builder.BuildFromGlyphIndex(gindex, sizeInPoint); GlyphImage glyphImg = aggTextureGen.CreateGlyphImage(builder, 1); if (applyFilter) { glyphImg = Sharpen(glyphImg, 1); //TODO: //the filter make the image shift x and y 1 px //temp fix with this, glyphImg.TextureOffsetX += 1; glyphImg.TextureOffsetY += 1; } // atlasBuilder.AddGlyph(gindex, glyphImg); } } }
public void DrawString(char[] text, int startAt, int len, double x, double y) { float ox = canvasPainter.OriginX; float oy = canvasPainter.OriginY; //1. update some props.. //2. update current type face UpdateTypefaceAndGlyphBuilder(); Typeface typeface = _glyphPathBuilder.Typeface; //3. layout glyphs with selected layout technique //TODO: review this again, we should use pixel? float fontSizePoint = this.FontSizeInPoints; float scale = typeface.CalculateToPixelScaleFromPointSize(fontSizePoint); _outputGlyphPlans.Clear(); _glyphLayout.Layout(typeface, text, startAt, len, _outputGlyphPlans); //4. render each glyph int j = _outputGlyphPlans.Count; //--------------------------------------------------- //consider use cached glyph, to increase performance hintGlyphCollection.SetCacheInfo(typeface, fontSizePoint, this.HintTechnique); //--------------------------------------------------- for (int i = 0; i < j; ++i) { GlyphPlan glyphPlan = _outputGlyphPlans[i]; //----------------------------------- //TODO: review here *** //PERFORMANCE revisit here //if we have create a vxs we can cache it for later use? //----------------------------------- VertexStore glyphVxs; if (!hintGlyphCollection.TryGetCacheGlyph(glyphPlan.glyphIndex, out glyphVxs)) { //if not found then create new glyph vxs and cache it _glyphPathBuilder.SetHintTechnique(this.HintTechnique); _glyphPathBuilder.BuildFromGlyphIndex(glyphPlan.glyphIndex, fontSizePoint); //----------------------------------- _tovxs.Reset(); _glyphPathBuilder.ReadShapes(_tovxs); //TODO: review here, //float pxScale = _glyphPathBuilder.GetPixelScale(); glyphVxs = new VertexStore(); _tovxs.WriteOutput(glyphVxs, _vxsPool); // hintGlyphCollection.RegisterCachedGlyph(glyphPlan.glyphIndex, glyphVxs); } canvasPainter.SetOrigin((float)(glyphPlan.x * scale + x), (float)(glyphPlan.y * scale + y)); canvasPainter.Fill(glyphVxs); } //restore prev origin canvasPainter.SetOrigin(ox, oy); }
static void CreateSampleMsdfTextureFont( string fontfile, float sizeInPoint, char[] chars, string outputFile) { //sample var reader = new OpenFontReader(); using (var fs = new FileStream(fontfile, FileMode.Open)) { //1. read typeface from font file Typeface typeface = reader.Read(fs); //sample: create sample msdf texture //------------------------------------------------------------- var builder = new GlyphPathBuilder(typeface); //builder.UseTrueTypeInterpreter = this.chkTrueTypeHint.Checked; //builder.UseVerticalHinting = this.chkVerticalHinting.Checked; //------------------------------------------------------------- var atlasBuilder = new SimpleFontAtlasBuilder(); MsdfGenParams msdfGenParams = new MsdfGenParams(); int j = chars.Length; for (int i = 0; i < j; ++i) { //build glyph ushort gindex = typeface.LookupIndex(chars[i]); builder.BuildFromGlyphIndex(gindex, -1); var glyphToContour = new GlyphContourBuilder(); //glyphToContour.Read(builder.GetOutputPoints(), builder.GetOutputContours()); builder.ReadShapes(glyphToContour); msdfGenParams.shapeScale = 1f / 64; GlyphImage glyphImg = MsdfGlyphGen.CreateMsdfImage(glyphToContour, msdfGenParams); atlasBuilder.AddGlyph(gindex, glyphImg); int w = glyphImg.Width; int h = glyphImg.Height; using (Bitmap bmp = new Bitmap(glyphImg.Width, glyphImg.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) { var bmpdata = bmp.LockBits(new System.Drawing.Rectangle(0, 0, w, h), System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat); int[] imgBuffer = glyphImg.GetImageBuffer(); System.Runtime.InteropServices.Marshal.Copy(imgBuffer, 0, bmpdata.Scan0, imgBuffer.Length); bmp.UnlockBits(bmpdata); bmp.Save("d:\\WImageTest\\a001_xn2_" + (chars[i]) + ".png"); } } var glyphImg2 = atlasBuilder.BuildSingleImage(); using (Bitmap bmp = new Bitmap(glyphImg2.Width, glyphImg2.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) { var bmpdata = bmp.LockBits(new System.Drawing.Rectangle(0, 0, glyphImg2.Width, glyphImg2.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat); int[] intBuffer = glyphImg2.GetImageBuffer(); System.Runtime.InteropServices.Marshal.Copy(intBuffer, 0, bmpdata.Scan0, intBuffer.Length); bmp.UnlockBits(bmpdata); bmp.Save("d:\\WImageTest\\a_total.png"); } atlasBuilder.SaveFontInfo("d:\\WImageTest\\a_info.xml"); } }
private void InitGlyphPointsAndContourEnds(char c) { try { using (FileStream fs = File.OpenRead(ttfPath)) { OpenFontReader reader = new OpenFontReader(); Typeface typeface = reader.Read(fs); var builder = new GlyphPathBuilder(typeface); builder.BuildFromGlyphIndex(typeface.LookupIndex(c), 300); var txToPath = new GlyphTranslatorToPath(); var writablePath = new WritablePath(); txToPath.SetOutput(writablePath); builder.ReadShapes(txToPath); var curveFlattener = new SimpleCurveFlattener(); float[] flattenPoints = curveFlattener.Flatten( writablePath._points, out _contourEnds); _glyphPoints2 = flattenPoints; } } catch (Exception) { ClearGlyphData(); pnlGlyph.Invalidate(); } }
public override void DrawFromGlyphPlans(GlyphPlanSequence seq, int startAt, int len, float x, float y) { UpdateVisualOutputSettings(); //draw data in glyph plan //3. render each glyph float sizeInPoints = this.FontSizeInPoints; float pxscale = _currentTypeface.CalculateScaleToPixelFromPointSize(sizeInPoints); // _glyphMeshCollections.SetCacheInfo(this.Typeface, sizeInPoints, this.HintTechnique); //this draw a single line text span*** Graphics g = this.TargetGraphics; float cx = 0; float cy = 0; var snapToPxScale = new GlyphPlanSequenceSnapPixelScaleLayout(seq, startAt, len, pxscale); while (snapToPxScale.Read()) { GraphicsPath foundPath; if (!_glyphMeshCollections.TryGetCacheGlyph(snapToPxScale.CurrentGlyphIndex, out foundPath)) { //if not found then create a new one _currentGlyphPathBuilder.BuildFromGlyphIndex(snapToPxScale.CurrentGlyphIndex, sizeInPoints); _txToGdiPath.Reset(); _currentGlyphPathBuilder.ReadShapes(_txToGdiPath); foundPath = _txToGdiPath.ResultGraphicsPath; //register _glyphMeshCollections.RegisterCachedGlyph(snapToPxScale.CurrentGlyphIndex, foundPath); } //------ //then move pen point to the position we want to draw a glyph cx = (float)Math.Round(snapToPxScale.ExactX + x); cy = (float)Math.Floor(snapToPxScale.ExactY + y); g.TranslateTransform(cx, cy); if (FillBackground) { g.FillPath(_fillBrush, foundPath); } if (DrawOutline) { g.DrawPath(_outlinePen, foundPath); } //and then we reset back *** g.TranslateTransform(-cx, -cy); } }
public override void DrawFromGlyphPlans(List <GlyphPlan> glyphPlanList, int startAt, int len, float x, float y) { UpdateVisualOutputSettings(); //draw data in glyph plan //3. render each glyph float sizeInPoints = this.FontSizeInPoints; float scale = _currentTypeface.CalculateToPixelScaleFromPointSize(sizeInPoints); // _glyphMeshCollections.SetCacheInfo(this.Typeface, sizeInPoints, this.HintTechnique); //this draw a single line text span*** int endBefore = startAt + len; Graphics g = this.TargetGraphics; for (int i = startAt; i < endBefore; ++i) { GlyphPlan glyphPlan = glyphPlanList[i]; //check if we have a cache of this glyph //if not -> create it GraphicsPath foundPath; if (!_glyphMeshCollections.TryGetCacheGlyph(glyphPlan.glyphIndex, out foundPath)) { //if not found then create a new one _currentGlyphPathBuilder.BuildFromGlyphIndex(glyphPlan.glyphIndex, sizeInPoints); _txToGdiPath.Reset(); _currentGlyphPathBuilder.ReadShapes(_txToGdiPath); foundPath = _txToGdiPath.ResultGraphicsPath; //register _glyphMeshCollections.RegisterCachedGlyph(glyphPlan.glyphIndex, foundPath); } //------ //then move pen point to the position we want to draw a glyph float tx = x + glyphPlan.ExactX; float ty = y + glyphPlan.ExactY; g.TranslateTransform(tx, ty); if (FillBackground) { g.FillPath(_fillBrush, foundPath); } if (DrawOutline) { g.DrawPath(_outlinePen, foundPath); } //and then we reset back *** g.TranslateTransform(-tx, -ty); } }
/// <summary> /// generate glyph run into a given textRun /// </summary> /// <param name="outputTextRun"></param> /// <param name="charBuffer"></param> /// <param name="start"></param> /// <param name="len"></param> public void GenerateGlyphRuns(TextRun outputTextRun, char[] charBuffer, int start, int len) { // layout glyphs with selected layout technique float sizeInPoints = this.FontSizeInPoints; outputTextRun.typeface = this.CurrentTypeFace; outputTextRun.sizeInPoints = sizeInPoints; //in this version we store original glyph into the mesh collection //and then we scale it later, so I just specific font size=0 (you can use any value) _glyphMeshCollection.SetCacheInfo(this.CurrentTypeFace, 0, this.HintTechnique); outputGlyphPlans.Clear(); glyphLayout.Typeface = this.CurrentTypeFace; glyphLayout.GenerateGlyphPlans(charBuffer, start, len, outputGlyphPlans, null); // render each glyph int planCount = outputGlyphPlans.Count; for (var i = 0; i < planCount; ++i) { pathTranslator.Reset(); //---- //glyph path //---- GlyphPlan glyphPlan = outputGlyphPlans[i]; // //1. check if we have this glyph in cache? //if yes, not need to build it again ProcessedGlyph processGlyph; float[] tessData = null; if (!_glyphMeshCollection.TryGetCacheGlyph(glyphPlan.glyphIndex, out processGlyph)) { //if not found the create a new one and register it var writablePath = new WritablePath(); pathTranslator.SetOutput(writablePath); currentGlyphPathBuilder.BuildFromGlyphIndex(glyphPlan.glyphIndex, sizeInPoints); currentGlyphPathBuilder.ReadShapes(pathTranslator); //------- //do tess int[] endContours; float[] flattenPoints = _curveFlattener.Flatten(writablePath._points, out endContours); int nTessElems; tessData = _tessTool.TessPolygon(flattenPoints, endContours, out nTessElems); //------- processGlyph = new ProcessedGlyph(tessData, (ushort)nTessElems); _glyphMeshCollection.RegisterCachedGlyph(glyphPlan.glyphIndex, processGlyph); } outputTextRun.AddGlyph( new GlyphRun(glyphPlan, processGlyph.tessData, processGlyph.tessNElements)); } }
static void CreateSampleMsdfTextureFont(string fontfile, float sizeInPoint, ushort startGlyphIndex, ushort endGlyphIndex, string outputFile) { //sample var reader = new OpenFontReader(); using (var fs = new FileStream(fontfile, FileMode.Open)) { //1. read typeface from font file Typeface typeface = reader.Read(fs); //sample: create sample msdf texture //------------------------------------------------------------- var builder = new GlyphPathBuilder(typeface); //builder.UseTrueTypeInterpreter = this.chkTrueTypeHint.Checked; //builder.UseVerticalHinting = this.chkVerticalHinting.Checked; //------------------------------------------------------------- var atlasBuilder = new SimpleFontAtlasBuilder(); for (ushort gindex = startGlyphIndex; gindex <= endGlyphIndex; ++gindex) { //build glyph builder.BuildFromGlyphIndex(gindex, sizeInPoint); var glyphToContour = new GlyphContourBuilder(); //glyphToContour.Read(builder.GetOutputPoints(), builder.GetOutputContours()); var genParams = new MsdfGenParams(); builder.ReadShapes(glyphToContour); genParams.shapeScale = 1f / 64; //we scale later (as original C++ code use 1/64) GlyphImage glyphImg = MsdfGlyphGen.CreateMsdfImage(glyphToContour, genParams); atlasBuilder.AddGlyph(gindex, glyphImg); //using (Bitmap bmp = new Bitmap(w, h, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) //{ // var bmpdata = bmp.LockBits(new Rectangle(0, 0, w, h), System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat); // System.Runtime.InteropServices.Marshal.Copy(buffer, 0, bmpdata.Scan0, buffer.Length); // bmp.UnlockBits(bmpdata); // bmp.Save("d:\\WImageTest\\a001_xn2_" + n + ".png"); //} } var glyphImg2 = atlasBuilder.BuildSingleImage(); using (Bitmap bmp = new Bitmap(glyphImg2.Width, glyphImg2.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) { var bmpdata = bmp.LockBits(new System.Drawing.Rectangle(0, 0, glyphImg2.Width, glyphImg2.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat); int[] intBuffer = glyphImg2.GetImageBuffer(); System.Runtime.InteropServices.Marshal.Copy(intBuffer, 0, bmpdata.Scan0, intBuffer.Length); bmp.UnlockBits(bmpdata); bmp.Save("d:\\WImageTest\\a_total.png"); } atlasBuilder.SaveFontInfo("d:\\WImageTest\\a_info.xml"); } }
public override void DrawGlyphPlanList(List <GlyphPlan> glyphPlanList, int startAt, int len, float xpos, float ypos) { CanvasPainter canvasPainter = this.TargetCanvasPainter; Typeface typeface = _glyphPathBuilder.Typeface; //3. layout glyphs with selected layout technique //TODO: review this again, we should use pixel? float fontSizePoint = this.FontSizeInPoints; float scale = typeface.CalculateFromPointToPixelScale(fontSizePoint); //4. render each glyph float ox = canvasPainter.OriginX; float oy = canvasPainter.OriginY; int endBefore = startAt + len; //--------------------------------------------------- //consider use cached glyph, to increase performance hintGlyphCollection.SetCacheInfo(typeface, fontSizePoint, this.HintTechnique); //--------------------------------------------------- for (int i = startAt; i < endBefore; ++i) { GlyphPlan glyphPlan = glyphPlanList[i]; //----------------------------------- //TODO: review here *** //PERFORMANCE revisit here //if we have create a vxs we can cache it for later use? //----------------------------------- VertexStore glyphVxs; if (!hintGlyphCollection.TryGetCacheGlyph(glyphPlan.glyphIndex, out glyphVxs)) { //if not found then create new glyph vxs and cache it _glyphPathBuilder.BuildFromGlyphIndex(glyphPlan.glyphIndex, fontSizePoint); //----------------------------------- _tovxs.Reset(); _glyphPathBuilder.ReadShapes(_tovxs); //TODO: review here, //float pxScale = _glyphPathBuilder.GetPixelScale(); glyphVxs = new VertexStore(); _tovxs.WriteOutput(glyphVxs, _vxsPool); // hintGlyphCollection.RegisterCachedGlyph(glyphPlan.glyphIndex, glyphVxs); } canvasPainter.SetOrigin((float)(glyphPlan.x * scale + xpos), (float)(glyphPlan.y * scale + ypos)); canvasPainter.Fill(glyphVxs); } //restore prev origin canvasPainter.SetOrigin(ox, oy); }
public override void DrawGlyphPlanList(List <GlyphPlan> glyphPlanList, int startAt, int len, float x, float y) { UpdateVisualOutputSettings(); //draw data in glyph plan //3. render each glyph System.Drawing.Drawing2D.Matrix scaleMat = null; float sizeInPoints = this.FontSizeInPoints; float scale = _currentTypeface.CalculateFromPointToPixelScale(sizeInPoints); //this draw a single line text span*** int endBefore = startAt + len; Graphics g = this.TargetGraphics; for (int i = startAt; i < endBefore; ++i) { GlyphPlan glyphPlan = glyphPlanList[i]; _currentGlyphPathBuilder.BuildFromGlyphIndex(glyphPlan.glyphIndex, sizeInPoints); // scaleMat = new System.Drawing.Drawing2D.Matrix( 1, 0, //scale x 0, 1, //scale y x + glyphPlan.x * scale, y + glyphPlan.y * scale //xpos,ypos ); // _txToGdiPath.Reset(); _currentGlyphPathBuilder.ReadShapes(_txToGdiPath); System.Drawing.Drawing2D.GraphicsPath path = _txToGdiPath.ResultGraphicsPath; path.Transform(scaleMat); if (FillBackground) { g.FillPath(_fillBrush, path); } if (DrawOutline) { g.DrawPath(_outlinePen, path); } } }
static SimpleFontAtlasBuilder CreateAggSubPixelRenderingTextureFont( Typeface typeface, float sizeInPoint, HintTechnique hintTech, IEnumerable <ushort> glyphIndexIter) { ////read type face from file //Typeface typeface; //using (var fs = new FileStream(fontfile, FileMode.Open, FileAccess.Read)) //{ // var reader = new OpenFontReader(); // //1. read typeface from font file // typeface = reader.Read(fs); //} //sample: create sample msdf texture //------------------------------------------------------------- var builder = new GlyphPathBuilder(typeface); builder.SetHintTechnique(hintTech); //------------------------------------------------------------- var atlasBuilder = new SimpleFontAtlasBuilder(); atlasBuilder.SetAtlasInfo(TextureKind.AggSubPixel, sizeInPoint); VertexStorePool vxsPool = new VertexStorePool(); //create agg cavnas foreach (ushort gindex in glyphIndexIter) { //build glyph builder.BuildFromGlyphIndex(gindex, sizeInPoint); var txToVxs = new GlyphTranslatorToVxs(); builder.ReadShapes(txToVxs); // //create new one var glyphVxs = new VertexStore(); txToVxs.WriteOutput(glyphVxs, vxsPool); //find bound //-------------------------------------------- //GlyphImage glyphImg = new GlyphImage() RectD bounds = new Agg.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; w = w * 4; if (dx != 0 || dy != 0) { Agg.Transform.Affine transformMat = Agg.Transform.Affine.NewTranslation(dx, dy); VertexStore vxs2 = new VertexStore(); glyphVxs.TranslateToNewVxs(dx, dy, vxs2); glyphVxs = vxs2; } //-------------------------------------------- //create glyph img ActualImage img = new Agg.ActualImage(w, h, PixelFormat.ARGB32); ImageGraphics2D imgCanvas2d = new Agg.ImageGraphics2D(img); AggCanvasPainter painter = new Agg.AggCanvasPainter(imgCanvas2d); //we use white glyph on black bg for this texture painter.Clear(Color.Black); //fill with black painter.FillColor = Color.White; painter.StrokeColor = Color.White; //-------------------------------------------- painter.UseSubPixelRendering = true; //-------------------------------------------- //-------------------------------------------- painter.Fill(glyphVxs); //-------------------------------------------- var glyphImage = new GlyphImage(w, h); glyphImage.TextureOffsetX = dx; glyphImage.TextureOffsetY = dy; glyphImage.SetImageBuffer(ActualImage.GetBuffer2(img), false); //copy data from agg canvas to glyph image atlasBuilder.AddGlyph(gindex, glyphImage); //int[] buffer = glyphImage.GetImageBuffer(); //using (var bmp = new System.Drawing.Bitmap(glyphImage.Width, glyphImage.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) //{ // var bmpdata = bmp.LockBits(new System.Drawing.Rectangle(0, 0, glyphImage.Width, glyphImage.Height), // System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat); // System.Runtime.InteropServices.Marshal.Copy(buffer, 0, bmpdata.Scan0, buffer.Length); // bmp.UnlockBits(bmpdata); // bmp.Save("d:\\WImageTest\\a001_subpix_xn2_" + gindex + ".png"); //} } //var glyphImg2 = atlasBuilder.BuildSingleImage(); //using (var bmp = new System.Drawing.Bitmap(glyphImg2.Width, glyphImg2.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) //{ // var bmpdata = bmp.LockBits(new System.Drawing.Rectangle(0, 0, glyphImg2.Width, glyphImg2.Height), // System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat); // int[] intBuffer = glyphImg2.GetImageBuffer(); // System.Runtime.InteropServices.Marshal.Copy(intBuffer, 0, bmpdata.Scan0, intBuffer.Length); // bmp.UnlockBits(bmpdata); // bmp.Save("d:\\WImageTest\\a_total.png"); //} //atlasBuilder.SaveFontInfo("d:\\WImageTest\\a_info.xml"); return(atlasBuilder); }
static SimpleFontAtlasBuilder CreateSampleMsdfTextureFont( Typeface typeface, float sizeInPoint, HintTechnique hintTech, IEnumerable <ushort> glyphIndexIter) { ////read type face from file //Typeface typeface; //using (var fs = new FileStream(fontfile, FileMode.Open, FileAccess.Read)) //{ // var reader = new OpenFontReader(); // //1. read typeface from font file // typeface = reader.Read(fs); //} //sample: create sample msdf texture //------------------------------------------------------------- var builder = new GlyphPathBuilder(typeface); builder.SetHintTechnique(hintTech); MsdfGenParams genParams = new MsdfGenParams(); var atlasBuilder = new SimpleFontAtlasBuilder(); atlasBuilder.SetAtlasInfo(TextureKind.Msdf, sizeInPoint); foreach (ushort gindex in glyphIndexIter) { //build glyph builder.BuildFromGlyphIndex(gindex, -1); //use original glyph size (assign -1) var glyphToContour = new GlyphContourBuilder(); //glyphToContour.Read(builder.GetOutputPoints(), builder.GetOutputContours()); builder.ReadShapes(glyphToContour); genParams.shapeScale = 1f / 64; //we scale later (as original C++ code use 1/64) GlyphImage glyphImg = MsdfGlyphGen.CreateMsdfImage(glyphToContour, genParams); atlasBuilder.AddGlyph(gindex, glyphImg); //int[] buffer = glyphImage.GetImageBuffer(); //using (var bmp = new System.Drawing.Bitmap(glyphImage.Width, glyphImage.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) //{ // var bmpdata = bmp.LockBits(new System.Drawing.Rectangle(0, 0, glyphImage.Width, glyphImage.Height), // System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat); // System.Runtime.InteropServices.Marshal.Copy(buffer, 0, bmpdata.Scan0, buffer.Length); // bmp.UnlockBits(bmpdata); // bmp.Save("d:\\WImageTest\\a001_xn2_" + c + ".png"); //} } //var glyphImg2 = atlasBuilder.BuildSingleImage(); //using (var bmp = new System.Drawing.Bitmap(glyphImg2.Width, glyphImg2.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) //{ // var bmpdata = bmp.LockBits(new System.Drawing.Rectangle(0, 0, glyphImg2.Width, glyphImg2.Height), // System.Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat); // int[] intBuffer = glyphImg2.GetImageBuffer(); // System.Runtime.InteropServices.Marshal.Copy(intBuffer, 0, bmpdata.Scan0, intBuffer.Length); // bmp.UnlockBits(bmpdata); // bmp.Save("d:\\WImageTest\\a_total.png"); //} //atlasBuilder.SaveFontInfo("d:\\WImageTest\\a_info.xml"); return(atlasBuilder); }
void CreateTextureFontFromGlyphIndices( Typeface typeface, float sizeInPoint, HintTechnique hintTechnique, SimpleFontAtlasBuilder atlasBuilder, bool applyFilter, ushort[] glyphIndices) { //sample: create sample msdf texture //------------------------------------------------------------- var builder = new GlyphPathBuilder(typeface); builder.SetHintTechnique(hintTechnique); // if (atlasBuilder.TextureKind == TextureKind.Msdf) { MsdfGenParams msdfGenParams = new MsdfGenParams(); int j = glyphIndices.Length; 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) builder.BuildFromGlyphIndex(gindex, -1); var glyphToContour = new GlyphContourBuilder(); builder.ReadShapes(glyphToContour); //msdfgen with scale the glyph to specific shapescale msdfGenParams.shapeScale = 1f / 64; //as original GlyphImage glyphImg = MsdfGlyphGen.CreateMsdfImage(glyphToContour, msdfGenParams); // atlasBuilder.AddGlyph(gindex, 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]; builder.BuildFromGlyphIndex(gindex, sizeInPoint); GlyphImage glyphImg = aggTextureGen.CreateGlyphImage(builder, 1); if (applyFilter) { glyphImg = Sharpen(glyphImg, 1); //TODO: //the filter make the image shift x and y 1 px //temp fix with this, glyphImg.TextureOffsetX += 1; glyphImg.TextureOffsetY += 1; } // atlasBuilder.AddGlyph(gindex, glyphImg); } } } }
public override void DrawFromGlyphPlans(PxScaledGlyphPlanList glyphPlanList, int startAt, int len, float x, float y) { UpdateVisualOutputSettings(); //draw data in glyph plan //3. render each glyph float sizeInPoints = this.FontSizeInPoints; float scale = _currentTypeface.CalculateScaleToPixelFromPointSize(sizeInPoints); // _glyphMeshCollections.SetCacheInfo(this.Typeface, sizeInPoints, this.HintTechnique); //this draw a single line text span*** int endBefore = startAt + len; Graphics g = this.TargetGraphics; float acc_x = 0; float acc_y = 0; float g_x = 0; float g_y = 0; for (int i = startAt; i < endBefore; ++i) { PxScaledGlyphPlan glyphPlan = glyphPlanList[i]; //check if we have a cache of this glyph //if not -> create it GraphicsPath foundPath; if (!_glyphMeshCollections.TryGetCacheGlyph(glyphPlan.glyphIndex, out foundPath)) { //if not found then create a new one _currentGlyphPathBuilder.BuildFromGlyphIndex(glyphPlan.glyphIndex, sizeInPoints); _txToGdiPath.Reset(); _currentGlyphPathBuilder.ReadShapes(_txToGdiPath); foundPath = _txToGdiPath.ResultGraphicsPath; //register _glyphMeshCollections.RegisterCachedGlyph(glyphPlan.glyphIndex, foundPath); } //------ //then move pen point to the position we want to draw a glyph float ngx = acc_x + (float)Math.Round(glyphPlan.OffsetX * scale); float ngy = acc_y + (float)Math.Round(glyphPlan.OffsetY * scale); g_x = (x + (ngx)); g_y = (y + (ngy)); acc_x += (float)Math.Round(glyphPlan.AdvanceX * scale); //g_x = (float)Math.Round(g_x); g_y = (float)Math.Floor(g_y); g.TranslateTransform(g_x, g_y); if (FillBackground) { g.FillPath(_fillBrush, foundPath); } if (DrawOutline) { g.DrawPath(_outlinePen, foundPath); } //and then we reset back *** g.TranslateTransform(-g_x, -g_y); } }
void CreateTextureFontFromGlyphIndices( Typeface typeface, float sizeInPoint, TextureKind textureKind, ushort[] glyphIndices, OnEachFinishTotal onFinishTotal) { if (onFinishTotal == null) { return; } //sample: create sample msdf texture //------------------------------------------------------------- var builder = new GlyphPathBuilder(typeface); builder.UseTrueTypeInstructions = this.UseTrueTypeInstruction; //------------------------------------------------------------- var atlasBuilder = new SimpleFontAtlasBuilder(); atlasBuilder.SetAtlasInfo(textureKind, sizeInPoint); //------------------------------------------------------------- // MsdfGenParams msdfGenParams = null; AggGlyphTextureGen aggTextureGen = null; if (textureKind == TextureKind.Msdf) { msdfGenParams = new MsdfGenParams(); } else { aggTextureGen = new AggGlyphTextureGen(); } float pxscale = typeface.CalculateScaleToPixelFromPointSize(sizeInPoint); int j = glyphIndices.Length; for (int i = 0; i < j; ++i) { //build glyph ushort gindex = glyphIndices[i]; builder.BuildFromGlyphIndex(gindex, -1); GlyphImage glyphImg = null; if (textureKind == TextureKind.Msdf) { var glyphToContour = new GlyphContourBuilder(); //glyphToContour.Read(builder.GetOutputPoints(), builder.GetOutputContours()); builder.ReadShapes(glyphToContour); msdfGenParams.shapeScale = 1f / 64; //as original glyphImg = MsdfGlyphGen.CreateMsdfImage(glyphToContour, msdfGenParams); } else { //create alpha channel texture aggTextureGen.TextureKind = textureKind; glyphImg = aggTextureGen.CreateGlyphImage(builder, pxscale); } // atlasBuilder.AddGlyph(gindex, glyphImg); onFinishTotal(gindex, glyphImg, null); } onFinishTotal(0, null, atlasBuilder); }
/// <summary> /// generate glyph run into a given textRun /// </summary> /// <param name="outputTextRun"></param> /// <param name="charBuffer"></param> /// <param name="start"></param> /// <param name="len"></param> public void GenerateGlyphRuns(TextRun outputTextRun, char[] charBuffer, int start, int len) { // layout glyphs with selected layout technique float sizeInPoints = this.FontSizeInPoints; outputTextRun.typeface = this.Typeface; outputTextRun.sizeInPoints = sizeInPoints; //in this version we store original glyph into the mesh collection //and then we scale it later, so I just specific font size=0 (you can use any value) _glyphMeshCollection.SetCacheInfo(this.Typeface, 0, this.HintTechnique); GlyphLayoutMan.Typeface = this.Typeface; GlyphLayoutMan.Layout(charBuffer, start, len); float pxscale = this.Typeface.CalculateScaleToPixelFromPointSize(sizeInPoints); _resuableGlyphPlanList.Clear(); GenerateGlyphPlan(charBuffer, 0, charBuffer.Length, _resuableGlyphPlanList); // render each glyph int planCount = _resuableGlyphPlanList.Count; for (var i = 0; i < planCount; ++i) { _pathTranslator.Reset(); //---- //glyph path //---- UnscaledGlyphPlan glyphPlan = _resuableGlyphPlanList[i]; // //1. check if we have this glyph in cache? //if yes, not need to build it again ProcessedGlyph processGlyph; float[] tessData = null; if (!_glyphMeshCollection.TryGetCacheGlyph(glyphPlan.glyphIndex, out processGlyph)) { //if not found the create a new one and register it var writablePath = new WritablePath(); _pathTranslator.SetOutput(writablePath); _currentGlyphPathBuilder.BuildFromGlyphIndex(glyphPlan.glyphIndex, sizeInPoints); _currentGlyphPathBuilder.ReadShapes(_pathTranslator); //------- //do tess int[] endContours; float[] flattenPoints = _curveFlattener.Flatten(writablePath._points, out endContours); tessData = _tessTool.TessAsTriVertexArray(flattenPoints, endContours, out int vertexCount); processGlyph = new ProcessedGlyph(tessData, (ushort)vertexCount); _glyphMeshCollection.RegisterCachedGlyph(glyphPlan.glyphIndex, processGlyph); } outputTextRun.AddGlyph( new GlyphRun(glyphPlan, processGlyph.tessData, processGlyph.vertextCount)); } }