private void button4_Click(object sender, EventArgs e) { string fontfilename = "d:\\WImageTest\\a_total.xml"; var atlasBuilder = new Typography.Rendering.SimpleFontAtlasBuilder(); SimpleFontAtlas fontAtlas = atlasBuilder.LoadFontInfo(fontfilename); using (Bitmap totalImg = new Bitmap("d:\\WImageTest\\a_total.png")) { var bmpdata = totalImg.LockBits(new System.Drawing.Rectangle(0, 0, totalImg.Width, totalImg.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, totalImg.PixelFormat); var buffer = new int[totalImg.Width * totalImg.Height]; System.Runtime.InteropServices.Marshal.Copy(bmpdata.Scan0, buffer, 0, buffer.Length); totalImg.UnlockBits(bmpdata); var glyImage = new GlyphImage(totalImg.Width, totalImg.Height); glyImage.SetImageBuffer(buffer, false); fontAtlas.TotalGlyph = glyImage; } }
/// <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); Agg.Imaging.ShapenFilterPdn sharpen1 = new Agg.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); }
static GlyphImage ReadGlyphImages(string filename) { using (System.IO.FileStream fs = new System.IO.FileStream(filename, System.IO.FileMode.Open)) { Hjg.Pngcs.PngReader reader = new Hjg.Pngcs.PngReader(fs, filename); Hjg.Pngcs.ImageInfo imgInfo = reader.ImgInfo; Hjg.Pngcs.ImageLine iline2 = new Hjg.Pngcs.ImageLine(imgInfo, Hjg.Pngcs.ImageLine.ESampleType.BYTE); int imgH = imgInfo.Rows; int imgW = imgInfo.Cols; int stride = imgInfo.BytesPerRow; int widthPx = imgInfo.Cols; int[] buffer = new int[(stride / 4) * imgH]; //read each row //and fill the glyph image int startWriteAt = (imgW * (imgH - 1)); int destIndex = startWriteAt; for (int row = 0; row < imgH; row++) { Hjg.Pngcs.ImageLine iline = reader.ReadRowByte(row); byte[] scline = iline.ScanlineB; int b_src = 0; destIndex = startWriteAt; for (int mm = 0; mm < imgW; ++mm) { byte b = scline[b_src]; byte g = scline[b_src + 1]; byte r = scline[b_src + 2]; byte a = scline[b_src + 3]; b_src += 4; buffer[destIndex] = (b << 16) | (g << 8) | (r) | (a << 24); destIndex++; } startWriteAt -= imgW; } GlyphImage img = new GlyphImage(imgW, imgH); img.SetImageBuffer(buffer, true); return(img); } }
private void button5_Click(object sender, EventArgs e) { //1. load font string fontName = "tahoma"; string fontfile = "c:\\Windows\\Fonts\\tahoma.ttf"; //string fontfile = @"D:\WImageTest\THSarabunNew\THSarabunNew.ttf"; ActualFont font = GetActualFont(fontfile, 18);// nativeFontStore.LoadFont(fontName, fontfile, 28); //2. get glyph var atlasBuilder = new Typography.Rendering.SimpleFontAtlasBuilder(); //for (int i = 0; i < 256; ++i) //BuildFontGlyphsByIndex(font, atlasBuilder, 0, 255); //BuildFontGlyphs(font, atlasBuilder, 0x0e00, 0x0e5b); //BuildFontGlyphsByIndex(font, atlasBuilder, 0, 3417); //BuildFontGlyphsByIndex(font, atlasBuilder, 0, 509); //BuildFontGlyphsByIndex(font, atlasBuilder, 97, 97); BuildFontGlyph(font, atlasBuilder, 'B'); //---------------------------------------------------- //GlyphImage totalImg = atlasBuilder.BuildSingleImage(); GlyphImage totalImg = atlasBuilder.BuildSingleImage(); using (Bitmap bmp = new Bitmap(totalImg.Width, totalImg.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) { int[] buffer = totalImg.GetImageBuffer(); if (totalImg.IsBigEndian) { NativeMsdfGen.SwapColorComponentFromBigEndianToWinGdi(buffer); totalImg.SetImageBuffer(buffer, false); } var bmpdata = bmp.LockBits( new System.Drawing.Rectangle(0, 0, totalImg.Width, totalImg.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\\a_total.png"); } string fontfilename = "d:\\WImageTest\\a_total.xml"; atlasBuilder.SaveFontInfo(fontfilename); //---------------------------------- }
static void BuildFontGlyph(ActualFont nativefont, Typography.Rendering.SimpleFontAtlasBuilder atlasBuilder, char c) { //font glyph for specific font face FontGlyph fontGlyph = nativefont.GetGlyph(c); GlyphImage glyphImg = NativeMsdfGen.BuildMsdfFontImage(fontGlyph); int w = glyphImg.Width; int h = glyphImg.Height; int[] buffer = glyphImg.GetImageBuffer(); NativeMsdfGen.SwapColorComponentFromBigEndianToWinGdi(buffer); glyphImg.SetImageBuffer(buffer, false); atlasBuilder.AddGlyph(0, 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_x1_" + (int)c + ".png"); //} }
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); }
public GlyphImage CreateGlyphImage(GlyphPathBuilder builder, float pxscale) { _txToVxs.Reset(); //1. builder read shape and translate it with _txToVxs builder.ReadShapes(_txToVxs); using (VxsTemp.Borrow(out var glyphVxs, out var vxs2)) { //2. write translated data (in the _txToVxs) to glyphVxs _txToVxs.WriteOutput(glyphVxs, pxscale); RectD bounds = glyphVxs.GetBoundingRect(); //-------------------------------------------- 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; } //we need some margin int horizontal_margin = 1; int vertical_margin = 1; //translate to positive quadrant and use minimum space int dx = (int)Math.Ceiling((bounds.Left < 0) ? -bounds.Left : 0); int dy = 0; //vertical adjust =>since we need to move it, then move it with integer value if (bounds.Bottom < 0) { dy = (int)Math.Ceiling(-bounds.Bottom); } else if (bounds.Bottom > 0) { dy = (int)Math.Floor(-bounds.Bottom); } dx += horizontal_margin; //margin left dy += vertical_margin; //-------------------------------------------- w = dx + w + horizontal_margin; //+right margin h = vertical_margin + h + vertical_margin; //+bottom margin AggPainter painter = Painter; if (TextureKind == TextureKind.StencilLcdEffect) { glyphVxs.TranslateToNewVxs(dx + 0.33f, dy, vxs2); //offset to proper x of subpixel rendering *** glyphVxs = vxs2; RectD bounds2 = vxs2.GetBoundingRect(); if (w < bounds2.Right) { w = (int)Math.Ceiling(bounds2.Right); } // 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 { 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); } // if (w > painter.RenderSurface.DestBitmap.Width) { w = painter.RenderSurface.DestBitmap.Width; } if (h > painter.RenderSurface.DestBitmap.Height) { h = painter.RenderSurface.DestBitmap.Height; } var glyphImage = new GlyphImage(w, h); #if DEBUG if (dx < short.MinValue || dx > short.MaxValue) { throw new NotSupportedException(); } if (dy < short.MinValue || dy > short.MaxValue) { throw new NotSupportedException(); } #endif glyphImage.TextureOffsetX = (short)dx; glyphImage.TextureOffsetY = (short)dy; glyphImage.SetImageBuffer(MemBitmapExtensions.CopyImgBuffer(painter.RenderSurface.DestBitmap, w, h), false); //copy data from agg canvas to glyph image return(glyphImage); } }
const double FT_RESIZE = 64; //essential to be floating point internal unsafe static GlyphImage BuildMsdfFontImage(NativeFontGlyph fontGlyph) { IntPtr shape = MyFtLib.CreateShape(); FT_Outline outline = (*(FT_Outline *)fontGlyph.nativeOutlinePtr); //outline version //------------------------------ int npoints = outline.n_points; List <PixelFarm.VectorMath.Vector2> points = new List <PixelFarm.VectorMath.Vector2>(npoints); int startContour = 0; int cpoint_index = 0; int todoContourCount = outline.n_contours; int controlPointCount = 0; while (todoContourCount > 0) { int nextContour = outline.contours[startContour] + 1; bool isFirstPoint = true; //--------------- //create contour IntPtr cnt = MyFtLib.ShapeAddBlankContour(shape); FtVec2 secondControlPoint = new FtVec2(); FtVec2 thirdControlPoint = new FtVec2(); bool justFromCurveMode = false; FtVec2 lastMoveTo = new FtVec2(); FtVec2 lastPoint = new FtVec2(); FtVec2 current_point = new Fonts.FtVec2(); for (; cpoint_index < nextContour; ++cpoint_index) { FT_Vector xvpoint = outline.points[cpoint_index]; current_point = new FtVec2(xvpoint.x / FT_RESIZE, xvpoint.y / FT_RESIZE); //Console.WriteLine(xvpoint.x.ToString() + "," + xvpoint.y); byte vtag = outline.tags[cpoint_index]; bool has_dropout = (((vtag >> 2) & 0x1) != 0); int dropoutMode = vtag >> 3; if ((vtag & 0x1) != 0) { if (justFromCurveMode) { switch (controlPointCount) { case 1: { MyFtLib.ContourAddQuadraticSegment(cnt, lastPoint.x, lastPoint.y, secondControlPoint.x, secondControlPoint.y, current_point.x, current_point.y); lastPoint = current_point; } break; case 2: { MyFtLib.ContourAddCubicSegment(cnt, lastPoint.x, lastPoint.y, secondControlPoint.x, secondControlPoint.y, thirdControlPoint.x, thirdControlPoint.y, current_point.x, current_point.y); lastPoint = current_point; } break; default: { throw new NotSupportedException(); } } controlPointCount = 0; justFromCurveMode = false; } else { //line mode if (isFirstPoint) { isFirstPoint = false; lastMoveTo = lastPoint = current_point; } else { MyFtLib.ContourAddLinearSegment(cnt, lastPoint.x, lastPoint.y, current_point.x, current_point.y); lastPoint = current_point; } } } else { if (isFirstPoint) { isFirstPoint = false; lastMoveTo = lastPoint = current_point; } switch (controlPointCount) { case 0: { //bit 1 set=> off curve, this is a control point //if this is a 2nd order or 3rd order control point if (((vtag >> 1) & 0x1) != 0) { ////printf("[%d] bzc3rd, x: %d,y:%d \n", mm, vpoint.x, vpoint.y); thirdControlPoint = new FtVec2(current_point.x, current_point.y); } else { ////printf("[%d] bzc2nd, x: %d,y:%d \n", mm, vpoint.x, vpoint.y); secondControlPoint = new FtVec2(current_point.x, current_point.y); } } break; case 1: { if (((vtag >> 1) & 0x1) != 0) { ////printf("[%d] bzc3rd, x: %d,y:%d \n", mm, vpoint.x, vpoint.y); thirdControlPoint = new FtVec2(current_point.x, current_point.y); } else { //we already have prev second control point //so auto calculate line to //between 2 point FtVec2 mid = GetMidPoint(secondControlPoint, current_point); MyFtLib.ContourAddQuadraticSegment(cnt, lastPoint.x, lastPoint.y, secondControlPoint.x, secondControlPoint.y, mid.x, mid.y); lastPoint = mid; //------------------------ controlPointCount--; //------------------------ //printf("[%d] bzc2nd, x: %d,y:%d \n", mm, vpoint.x, vpoint.y); secondControlPoint = current_point; } } break; default: { throw new NotSupportedException(); } } controlPointCount++; justFromCurveMode = true; } } //-------- //close figure //if in curve mode if (justFromCurveMode) { switch (controlPointCount) { case 0: break; case 1: { MyFtLib.ContourAddQuadraticSegment(cnt, lastPoint.x, lastPoint.y, secondControlPoint.x, secondControlPoint.y, lastMoveTo.x, lastMoveTo.y); lastPoint = current_point; } break; case 2: { MyFtLib.ContourAddCubicSegment(cnt, lastPoint.x, lastPoint.y, secondControlPoint.x, secondControlPoint.y, thirdControlPoint.x, thirdControlPoint.y, lastMoveTo.x, lastMoveTo.y); lastPoint = current_point; } break; default: { throw new NotSupportedException(); } } justFromCurveMode = false; controlPointCount = 0; } else { MyFtLib.ContourAddLinearSegment(cnt, current_point.x, current_point.y, lastMoveTo.x, lastMoveTo.y); lastPoint = current_point; } //ps.CloseFigure(); //-------- startContour++; todoContourCount--; } //------------ double s_left, s_bottom, s_right, s_top; MyFtLib.ShapeFindBounds(shape, out s_left, out s_bottom, out s_right, out s_top); RectangleF glyphBounds = new RectangleF((float)s_left, (float)s_top, (float)(s_right - s_left), (float)(s_top - s_bottom)); //then create msdf texture if (!MyFtLib.ShapeValidate(shape)) { throw new NotSupportedException(); } MyFtLib.ShapeNormalize(shape); int borderXY = 0; int w = (int)Math.Ceiling(glyphBounds.Width) + (borderXY + borderXY); int h = (int)(Math.Ceiling(glyphBounds.Height)) + (borderXY + borderXY); if (w == 0) { w = 5; h = 5; } int[] outputBuffer = new int[w * h]; GlyphImage glyphImage = new GlyphImage(w, h); glyphImage.BorderXY = borderXY; glyphImage.OriginalGlyphBounds = Typography.Rendering.RectangleF.FromLTRB( glyphBounds.Left, glyphBounds.Top, glyphBounds.Right, glyphBounds.Bottom); unsafe { fixed(int *output_header = &outputBuffer[0]) { float dx = 0; float dy = 0; if (s_left < 0) { //make it positive dx = (float)-s_left; } else if (s_left > 0) { } if (s_bottom < 0) { //make it positive dy = (float)-s_bottom; } else if (s_bottom > 0) { } //this glyph image has border (for msdf to render correctly) MyFtLib.MyFtGenerateMsdf(shape, w, h, 4, 1, dx + borderXY, dy + borderXY, -1, 3, output_header); MyFtLib.DeleteUnmanagedObj(shape); } glyphImage.SetImageBuffer(outputBuffer, true); } 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 = RectD.ZeroIntersection; PixelFarm.CpuBlit.VertexProcessing.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; // dx = Math.Ceiling(dx); //since we need to move it, then move it with integer value dy = Math.Ceiling(dy); //since we need to move it, then move it with integer value //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 ActualBitmap img = new ActualBitmap(w, h); AggPainter painter = AggPainter.Create(img); 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(ActualBitmapExtensions.CopyImgBuffer(img, w), false); //copy data from agg canvas to glyph image return(glyphImage); }
internal unsafe static GlyphImage BuildMsdfFontImage() { IntPtr shape = MyFtLib.CreateShape(); IntPtr cnt = MyFtLib.ShapeAddBlankContour(shape); //MyFtLib.ContourAddLinearSegment(cnt, 10, 10, 25, 25); //MyFtLib.ContourAddLinearSegment(cnt, 25, 25, 15, 10); //MyFtLib.ContourAddLinearSegment(cnt, 15, 10, 10, 10); // MyFtLib.ContourAddLinearSegment(cnt, 10, 10, 25, 25); MyFtLib.ContourAddQuadraticSegment(cnt, 25, 25, 15, 30, 10, 15); MyFtLib.ContourAddLinearSegment(cnt, 10, 15, 10, 10); double s_left, s_bottom, s_right, s_top; MyFtLib.ShapeFindBounds(shape, out s_left, out s_bottom, out s_right, out s_top); var glyphBounds = new PixelFarm.Drawing.RectangleF((float)s_left, (float)s_top, (float)(s_right - s_left), (float)(s_top - s_bottom)); //then create msdf texture if (!MyFtLib.ShapeValidate(shape)) { throw new NotSupportedException(); } MyFtLib.ShapeNormalize(shape); int borderXY = 0; int w = (int)Math.Ceiling(glyphBounds.Width) + (borderXY + borderXY); int h = (int)(Math.Ceiling(glyphBounds.Height)) + (borderXY + borderXY); if (w == 0) { w = 5; h = 5; } int[] outputBuffer = new int[w * h]; GlyphImage glyphImage = new GlyphImage(w, h); glyphImage.BorderXY = borderXY; glyphImage.OriginalGlyphBounds = Typography.Contours.RectangleF.FromLTRB( glyphBounds.Left, glyphBounds.Top, glyphBounds.Right, glyphBounds.Bottom); unsafe { fixed(int *output_header = &outputBuffer[0]) { float dx = 0; float dy = 0; if (s_left < 0) { //make it positive dx = (float)-s_left; } else if (s_left > 0) { } if (s_bottom < 0) { //make it positive dy = (float)-s_bottom; } else if (s_bottom > 0) { } //this glyph image has border (for msdf to render correctly) MyFtLib.MyFtGenerateMsdf(shape, w, h, 4, 1, dx + borderXY, dy + borderXY, -1, 3, output_header); MyFtLib.DeleteUnmanagedObj(shape); } glyphImage.SetImageBuffer(outputBuffer, true); } return(glyphImage); }
private void button6_Click(object sender, EventArgs e) { //1. load font ActualFont font = GetActualFont("tahoma", 28);// nativeFontStore.LoadFont("tahoma", 28); //2. get glyph var g1 = font.GetGlyph('C'); var plans = new List <Typography.TextLayout.GlyphPlan>(); PixelFarm.Drawing.Text.TextShapingService.GetGlyphPos(font, "ABC".ToCharArray(), 0, 3, plans); int[] glyphIndice = new int[] { 1076, 1127, 1164 }; int j = glyphIndice.Length; var atlasBuilder = new Typography.Rendering.SimpleFontAtlasBuilder(); for (int i = 0; i < j; ++i) { int codepoint = glyphIndice[i]; FontGlyph fontGlyph = font.GetGlyphByIndex((uint)codepoint); GlyphImage glyphImg = NativeMsdfGen.BuildMsdfFontImage(fontGlyph); int w = glyphImg.Width; int h = glyphImg.Height; int[] buffer = glyphImg.GetImageBuffer(); NativeMsdfGen.SwapColorComponentFromBigEndianToWinGdi(buffer); glyphImg.SetImageBuffer(buffer, false); atlasBuilder.AddGlyph(codepoint, glyphImg); using (Bitmap bmp = new Bitmap(w, h, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) { var bmpdata = bmp.LockBits(new System.Drawing.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_y1_" + codepoint + ".png"); } } //---------------------------------------------------- GlyphImage totalImg = atlasBuilder.BuildSingleImage(); using (Bitmap bmp = new Bitmap(totalImg.Width, totalImg.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) { int[] buffer = totalImg.GetImageBuffer(); if (totalImg.IsBigEndian) { NativeMsdfGen.SwapColorComponentFromBigEndianToWinGdi(buffer); totalImg.SetImageBuffer(buffer, false); } var bmpdata = bmp.LockBits(new System.Drawing.Rectangle(0, 0, totalImg.Width, totalImg.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\\a_total.png"); } string fontfilename = "d:\\WImageTest\\a_total.xml"; atlasBuilder.SaveFontInfo(fontfilename); //---------------------------------- }
private void button3_Click(object sender, EventArgs e) { //1. load font string fontName = "tahoma"; int fontSizeInPts = 28; ActualFont font = GetActualFont(fontName, fontSizeInPts); //2. get glyph char[] fontChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".ToCharArray(); int j = fontChars.Length; var atlasBuilder = new Typography.Rendering.SimpleFontAtlasBuilder(); atlasBuilder.SetAtlasInfo(TextureKind.Msdf, fontSizeInPts); for (int i = 0; i < j; ++i) { char c = fontChars[i]; FontGlyph fontGlyph = font.GetGlyph(c); GlyphImage glyphImg = NativeMsdfGen.BuildMsdfFontImage(fontGlyph); int w = glyphImg.Width; int h = glyphImg.Height; int[] buffer = glyphImg.GetImageBuffer(); NativeMsdfGen.SwapColorComponentFromBigEndianToWinGdi(buffer); glyphImg.SetImageBuffer(buffer, false); atlasBuilder.AddGlyph(0, glyphImg); using (Bitmap bmp = new Bitmap(w, h, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) { var bmpdata = bmp.LockBits( new System.Drawing.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_x1_" + (int)c + ".png"); } } //---------------------------------------------------- GlyphImage totalImg = atlasBuilder.BuildSingleImage(); using (Bitmap bmp = new Bitmap(totalImg.Width, totalImg.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)) { int[] buffer = totalImg.GetImageBuffer(); if (totalImg.IsBigEndian) { NativeMsdfGen.SwapColorComponentFromBigEndianToWinGdi(buffer); totalImg.SetImageBuffer(buffer, false); } var bmpdata = bmp.LockBits(new System.Drawing.Rectangle(0, 0, totalImg.Width, totalImg.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\\a_total.png"); } string fontfilename = "d:\\WImageTest\\a_total.xml"; atlasBuilder.SaveFontInfo(fontfilename); //---------------------------------- }