public static Bitmap Convert(this FTBitmap ftbmp, Color color, uint charCode) { switch (ftbmp.PixelMode) { case PixelMode.Mono: return(FromMono(ftbmp, color)); case PixelMode.Gray4: throw new NotImplementedException(); case PixelMode.Gray: return(FromGray(ftbmp, color)); case PixelMode.Lcd: throw new NotImplementedException(); default: #if NET45 return(ftbmp.ToGdipBitmap()); #else throw new NotImplementedException(); #endif } }
private int renderCharacter(Face face, char character, int posX, int posY, int atlas, FontInfo info, Graphics graphics) { uint index = face.GetCharIndex(character); face.LoadGlyph(index, LoadFlags.Default, LoadTarget.Normal); face.Glyph.RenderGlyph(RenderMode.Normal); GlyphMetrics metrics = face.Glyph.Metrics; int width = metrics.Width.ToInt32() + metrics.HorizontalBearingX.ToInt32(); int xAdvance = metrics.HorizontalAdvance.ToInt32(); int yoffset = metrics.VerticalAdvance.ToInt32() - metrics.HorizontalBearingY.ToInt32(); int charHeight = metrics.Height.ToInt32(); if (face.Glyph.Bitmap.Width > 0) { FTBitmap ftbmp = face.Glyph.Bitmap; Bitmap copy = ftbmp.ToGdipBitmap(Color.White); graphics.DrawImageUnscaled(copy, posX + metrics.HorizontalBearingX.ToInt32(), posY); } info.addCharacter(new CharacterInfo(character, posX, posY, width, charHeight, xAdvance, yoffset, atlas)); return(width); }
public Texture2D RenderString(Face font, string text, Color4 foreColor, Color4 backColor, bool wrapText) { LineMetrics[] metrics = formatText(font, text, wrapText); float maxWidth = 0f, maxHeight = 0f, totalHeight = 0f; for (int lineIndex = 0; lineIndex < metrics.Length; lineIndex++) { LineMetrics lineMetric = metrics[lineIndex]; maxWidth = (lineMetric.Width > maxWidth) ? lineMetric.Width : maxWidth; maxHeight = (lineMetric.Height > maxHeight) ? lineMetric.Height : maxHeight; //Check is to ensure we don't have additional extra space accumulating beneath the texture for large Heights (commas being an example) totalHeight += (lineIndex < metrics.Length - 1) ? lineMetric.BaseHeight + LineSpacing : lineMetric.Height; metrics[lineIndex] = lineMetric; } //If any dimension is 0, we can't create a bitmap if (maxWidth <= 0 || totalHeight <= 0) { return(null); } //Create a new bitmap that fits the string. Bitmap bmp = new Bitmap((int)Math.Ceiling(maxWidth), (int)Math.Ceiling(totalHeight)); using (var g = Graphics.FromImage(bmp)) { #region Rendering Code g.CompositingQuality = CompositingQuality.HighQuality; g.SmoothingMode = SmoothingMode.HighQuality; g.CompositingMode = CompositingMode.SourceOver; g.Clear((Color)backColor); //Draw the string into the bitmap. float lineOffset = 0f; for (int lineIndex = 0; lineIndex < metrics.Length; lineIndex++) { LineMetrics lineMetrics = metrics[lineIndex]; //float xOffset = (maxWidth - lineMetrics.Width) / 2f; //Centered float xOffset = 0f; //float xOffset = maxWidth - lineMetrics.Width - 20f; float penX = 0f, penY = 0f; for (int i = 0; i < lineMetrics.Characters.Count; i++) { var cm = lineMetrics.Characters[i]; char c = cm.Character; uint glyphIndex = font.GetCharIndex(c); font.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal); font.Glyph.RenderGlyph(RenderMode.Normal); FTBitmap ftbmp = font.Glyph.Bitmap; //Underrun if (penX == 0) //First character { penX += -(cm.BearingX); } //We can't draw a 0-size bitmap, but the pen position will still get advanced. if (ftbmp.Width > 0 && ftbmp.Rows > 0) { using (Bitmap cBmp = ftbmp.ToGdipBitmap((Color)foreColor)) { int x = (int)Math.Round(penX + cm.BearingX + xOffset); int y = (int)Math.Round(penY + lineMetrics.Top - cm.BearingY + lineOffset); g.DrawImageUnscaled(cBmp, x, y); } } //Advance pen position for the next character penX += cm.AdvanceX + cm.Kern; } lineOffset += lineMetrics.BaseHeight + LineSpacing; } #endregion } Texture2D texture = Texture2D.CreateFromBitmap(bmp); bmp.Dispose(); return(texture); }
internal static Bitmap RenderString(Library library, Face face, string text, Color foreColor, Color backColor) { var measuredChars = new List <DebugChar>(); var renderedChars = new List <DebugChar>(); float penX = 0, penY = 0; float stringWidth = 0; // the measured width of the string float stringHeight = 0; // the measured height of the string float overrun = 0; float underrun = 0; float kern = 0; int spacingError = 0; bool trackingUnderrun = true; int rightEdge = 0; // tracking rendered right side for debugging // Bottom and top are both positive for simplicity. // Drawing in .Net has 0,0 at the top left corner, with positive X to the right // and positive Y downward. // Glyph metrics have an origin typically on the left side and at baseline // of the visual data, but can draw parts of the glyph in any quadrant, and // even move the origin (via kerning). float top = 0, bottom = 0; // Measure the size of the string before rendering it. We need to do this so // we can create the proper size of bitmap (canvas) to draw the characters on. for (int i = 0; i < text.Length; i++) { #region Load character char c = text[i]; // Look up the glyph index for this character. uint glyphIndex = face.GetCharIndex(c); // Load the glyph into the font's glyph slot. There is usually only one slot in the font. face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal); // Refer to the diagram entitled "Glyph Metrics" at http://www.freetype.org/freetype2/docs/tutorial/step2.html. // There is also a glyph diagram included in this example (glyph-dims.svg). // The metrics below are for the glyph loaded in the slot. float gAdvanceX = (float)face.Glyph.Advance.X; // same as the advance in metrics float gBearingX = (float)face.Glyph.Metrics.HorizontalBearingX; //float gWidth = face.Glyph.Metrics.Width.ToSingle(); float gWidth = face.Glyph.Metrics.Width; var rc = new DebugChar(c, gAdvanceX, gBearingX, gWidth); #endregion #region Underrun // Negative bearing would cause clipping of the first character // at the left boundary, if not accounted for. // A positive bearing would cause empty space. underrun += -(gBearingX); if (stringWidth == 0) { stringWidth += underrun; } if (trackingUnderrun) { rc.Underrun = underrun; } if (trackingUnderrun && underrun <= 0) { underrun = 0; trackingUnderrun = false; } #endregion #region Overrun // Accumulate overrun, which coould cause clipping at the right side of characters near // the end of the string (typically affects fonts with slanted characters) if (gBearingX + gWidth > 0 || gAdvanceX > 0) { overrun -= Math.Max(gBearingX + gWidth, gAdvanceX); if (overrun <= 0) { overrun = 0; } } overrun += (float)(gBearingX == 0 && gWidth == 0 ? 0 : gBearingX + gWidth - gAdvanceX); // On the last character, apply whatever overrun we have to the overall width. // Positive overrun prevents clipping, negative overrun prevents extra space. if (i == text.Length - 1) { stringWidth += overrun; } rc.Overrun = overrun; // accumulating (per above) #endregion #region Top/Bottom // If this character goes higher or lower than any previous character, adjust // the overall height of the bitmap. float glyphTop = (float)face.Glyph.Metrics.HorizontalBearingY; float glyphBottom = (float)(face.Glyph.Metrics.Height - face.Glyph.Metrics.HorizontalBearingY); if (glyphTop > top) { top = glyphTop; } if (glyphBottom > bottom) { bottom = glyphBottom; } #endregion // Accumulate the distance between the origin of each character (simple width). stringWidth += gAdvanceX; rc.RightEdge = stringWidth; measuredChars.Add(rc); #region Kerning (for NEXT character) // Calculate kern for the NEXT character (if any) // The kern value adjusts the origin of the next character (positive or negative). if (face.HasKerning && i < text.Length - 1) { char cNext = text[i + 1]; kern = (float)face.GetKerning(glyphIndex, face.GetCharIndex(cNext), KerningMode.Default).X; // sanity check for some fonts that have kern way out of whack if (kern > gAdvanceX * 5 || kern < -(gAdvanceX * 5)) { kern = 0; } rc.Kern = kern; stringWidth += kern; } #endregion } stringHeight = top + bottom; // If any dimension is 0, we can't create a bitmap if (stringWidth == 0 || stringHeight == 0) { return(null); } // Create a new bitmap that fits the string. Bitmap bmp = new Bitmap((int)Math.Ceiling(stringWidth), (int)Math.Ceiling(stringHeight)); trackingUnderrun = true; underrun = 0; overrun = 0; stringWidth = 0; using (var g = Graphics.FromImage(bmp)) { #region Set up graphics // HighQuality and GammaCorrected both specify gamma correction be applied (2.2 in sRGB) // https://msdn.microsoft.com/en-us/library/windows/desktop/ms534094(v=vs.85).aspx g.CompositingQuality = CompositingQuality.HighQuality; // HighQuality and AntiAlias both specify antialiasing g.SmoothingMode = SmoothingMode.HighQuality; // If a background color is specified, blend over it. g.CompositingMode = CompositingMode.SourceOver; g.Clear(backColor); #endregion // Draw the string into the bitmap. // A lot of this is a repeat of the measuring steps, but this time we have // an actual bitmap to work with (both canvas and bitmaps in the glyph slot). for (int i = 0; i < text.Length; i++) { #region Load character char c = text[i]; // Same as when we were measuring, except RenderGlyph() causes the glyph data // to be converted to a bitmap. uint glyphIndex = face.GetCharIndex(c); face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal); face.Glyph.RenderGlyph(RenderMode.Normal); FTBitmap ftbmp = face.Glyph.Bitmap; float gAdvanceX = (float)face.Glyph.Advance.X; float gBearingX = (float)face.Glyph.Metrics.HorizontalBearingX; float gWidth = (float)face.Glyph.Metrics.Width; var rc = new DebugChar(c, gAdvanceX, gBearingX, gWidth); #endregion #region Underrun // Underrun underrun += -(gBearingX); if (penX == 0) { penX += underrun; } if (trackingUnderrun) { rc.Underrun = underrun; } if (trackingUnderrun && underrun <= 0) { underrun = 0; trackingUnderrun = false; } #endregion #region Draw glyph // Whitespace characters sometimes have a bitmap of zero size, but a non-zero advance. // We can't draw a 0-size bitmap, but the pen position will still get advanced (below). if ((ftbmp.Width > 0 && ftbmp.Rows > 0)) { // Get a bitmap that .Net can draw (GDI+ in this case). Bitmap cBmp = ftbmp.ToGdipBitmap(foreColor); rc.Width = cBmp.Width; rc.BearingX = face.Glyph.BitmapLeft; int x = (int)Math.Round(penX + face.Glyph.BitmapLeft); int y = (int)Math.Round(penY + top - (float)face.Glyph.Metrics.HorizontalBearingY); //Not using g.DrawImage because some characters come out blurry/clipped. (Is this still true?) g.DrawImageUnscaled(cBmp, x, y); rc.Overrun = face.Glyph.BitmapLeft + cBmp.Width - gAdvanceX; // Check if we are aligned properly on the right edge (for debugging) rightEdge = Math.Max(rightEdge, x + cBmp.Width); spacingError = bmp.Width - rightEdge; } else { rightEdge = (int)(penX + gAdvanceX); spacingError = bmp.Width - rightEdge; } #endregion #region Overrun if (gBearingX + gWidth > 0 || gAdvanceX > 0) { overrun -= Math.Max(gBearingX + gWidth, gAdvanceX); if (overrun <= 0) { overrun = 0; } } overrun += (float)(gBearingX == 0 && gWidth == 0 ? 0 : gBearingX + gWidth - gAdvanceX); if (i == text.Length - 1) { penX += overrun; } rc.Overrun = overrun; #endregion // Advance pen positions for drawing the next character. penX += (float)face.Glyph.Advance.X; // same as Metrics.HorizontalAdvance? penY += (float)face.Glyph.Advance.Y; rc.RightEdge = penX; spacingError = bmp.Width - (int)Math.Round(rc.RightEdge); renderedChars.Add(rc); #region Kerning (for NEXT character) // Adjust for kerning between this character and the next. if (face.HasKerning && i < text.Length - 1) { char cNext = text[i + 1]; kern = (float)face.GetKerning(glyphIndex, face.GetCharIndex(cNext), KerningMode.Default).X; if (kern > gAdvanceX * 5 || kern < -(gAdvanceX * 5)) { kern = 0; } rc.Kern = kern; penX += (float)kern; } #endregion } } bool printedHeader = false; if (spacingError != 0) { for (int i = 0; i < renderedChars.Count; i++) { //if (measuredChars[i].RightEdge != renderedChars[i].RightEdge) //{ if (!printedHeader) { DebugChar.PrintHeader(); } printedHeader = true; Debug.Print(measuredChars[i].ToString()); Debug.Print(renderedChars[i].ToString()); //} } string msg = string.Format("Right edge: {0,3} ({1}) {2}", spacingError, spacingError == 0 ? "perfect" : spacingError > 0 ? "space " : "clipped", face.FamilyName); System.Diagnostics.Debug.Print(msg); //throw new ApplicationException(msg); } return(bmp); }
public NISFont DrawT3BFontBitmap(char[] strings) { NISFont fnt_data = new NISFont(); Bitmap bmp = new Bitmap(Config.texture_width, Config.texture_height); Graphics g = Graphics.FromImage(bmp); g.Clear(Color.FromArgb(0x00000000)); int x = 0, y = 0; int tile_w = Config.fontWidth; int tile_h = Config.fontHeight; int relativePositionX = 1; int relativePositionY = -2; int font_height = Config.fontSize; Library library = new Library(); string facename = Config.ttfName; Face face = library.NewFace(facename, 0); float left, right, top, bottom, FHT; int FHD, kx, ky; foreach (char currentChar0 in strings) { uint charid = uchar2code(currentChar0.ToString()); face.SetCharSize(0, font_height, 0, 72); if (charid < 0x7f) { font_height = Config.fontSize - 2; face.SetCharSize(0, font_height, 0, 72); } else { font_height = Config.fontSize; } face.SetPixelSizes((uint)0, (uint)font_height); uint glyphIndex = face.GetCharIndex(charid); //Console.WriteLine(glyphIndex); face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Lcd); face.Glyph.Outline.Embolden(0.5); face.Glyph.RenderGlyph(RenderMode.Normal); FTBitmap ftbmp = face.Glyph.Bitmap; FTBitmap ftbmp2 = face.Glyph.Bitmap; left = (float)face.Glyph.Metrics.HorizontalBearingX; right = (float)face.Glyph.Metrics.HorizontalBearingX + (float)face.Glyph.Metrics.Width; top = (float)face.Glyph.Metrics.HorizontalBearingY; bottom = (float)face.Glyph.Metrics.HorizontalBearingY + (float)face.Glyph.Metrics.Height; FHT = font_height; FHD = (int)Math.Ceiling(FHT); kx = x + (int)Math.Round(left); ky = (int)Math.Round((float)y + (float)Math.Ceiling(FHT) - (float)top); if (ftbmp.Width == 0 || glyphIndex < 0x20) { Face face1 = library.NewFace(Config.baseName, 0); face1.SetCharSize(0, font_height, 0, 72); face1.SetPixelSizes((uint)0, (uint)font_height); glyphIndex = face1.GetCharIndex(charid); face1.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Lcd); face1.Glyph.Outline.Embolden(Fixed26Dot6.FromDouble(0.4)); face1.Glyph.RenderGlyph(RenderMode.Normal); left = (float)face1.Glyph.Metrics.HorizontalBearingX; right = (float)face1.Glyph.Metrics.HorizontalBearingX + (float)face1.Glyph.Metrics.Width; top = (float)face1.Glyph.Metrics.HorizontalBearingY; bottom = (float)face1.Glyph.Metrics.HorizontalBearingY + (float)face1.Glyph.Metrics.Height; FHT = font_height; FHD = (int)Math.Ceiling(FHT); kx = x + (int)Math.Round(left); ky = (int)Math.Round((float)y + (float)Math.Ceiling(FHT) - (float)top); ftbmp = face1.Glyph.Bitmap; ftbmp2 = face1.Glyph.Bitmap; } fnt_data.charvalues.Add(new XYWH((int)uchar2code(currentChar0.ToString()), x, y, tile_w, tile_h, 0)); if (ftbmp2.Width == 0) { x += tile_w; if (x + tile_w > Config.texture_width) { x = 0; y += tile_h; } continue; } Bitmap cBmp = ftbmp2.ToGdipBitmap(Color.White); g.DrawImageUnscaled(cBmp, kx + relativePositionX, ky + relativePositionY); g.DrawImageUnscaled(cBmp, kx + relativePositionX, ky + relativePositionY); cBmp.Dispose(); x += tile_w; if (x + tile_w > Config.texture_width) { x = 0; y += tile_h; } } fnt_data.bitmap = bmp; return(fnt_data); }
public Bitmap test_draw(string teststrings) { //teststrings = teststrings.Replace("\n" , ""); //teststrings = teststrings.Replace("\r", ""); Library library = new Library(); Face face = library.NewFace(fontName, 0); Bitmap bmp = new Bitmap((int)Math.Ceiling((double)image_width), (int)Math.Ceiling((double)image_height)); Graphics g = Graphics.FromImage(bmp); g.Clear(GlobalSettings.cBgColor); //g.Clear(Color.Black); int x = 0, y = 0; for (int i = 0; i < teststrings.ToCharArray().Length; i++) { string currentChar0 = teststrings.ToCharArray()[i].ToString(); uint glyphIndex = face.GetCharIndex(uchar2code(currentChar0)); if (this.fontHeight <= 14) { face.SetPixelSizes((uint)0, (uint)this.fontHeight); face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal); face.Glyph.RenderGlyph(RenderMode.Normal); } else { face.SetCharSize(0, this.fontHeight, 0, 72); face.LoadGlyph(glyphIndex, LoadFlags.ForceAutohint, LoadTarget.Lcd); face.Glyph.RenderGlyph(RenderMode.Lcd); } //获取字符对齐 float left, right, top, bottom, FHT; int FHD, kx, ky; left = (float)face.Glyph.Metrics.HorizontalBearingX; right = (float)face.Glyph.Metrics.HorizontalBearingX + (float)face.Glyph.Metrics.Width; top = (float)face.Glyph.Metrics.HorizontalBearingY; bottom = (float)face.Glyph.Metrics.HorizontalBearingY + (float)face.Glyph.Metrics.Height; FHT = this.fontHeight; FHD = (int)Math.Ceiling(FHT); kx = x + face.Glyph.BitmapLeft; ky = (int)Math.Round((float)y + (FHD - face.Glyph.BitmapTop)); //选择渲染模式(1倍 or 2倍) if (this.grender_mode == "freetype_nearestneighbor") { face.SetCharSize(0, this.fontHeight * 2, 0, 72); face.LoadGlyph(glyphIndex, LoadFlags.ForceAutohint, LoadTarget.Lcd); face.Glyph.RenderGlyph(RenderMode.Lcd); left = (float)face.Glyph.Metrics.HorizontalBearingX; right = (float)face.Glyph.Metrics.HorizontalBearingX + (float)face.Glyph.Metrics.Width; top = (float)face.Glyph.Metrics.HorizontalBearingY; bottom = (float)face.Glyph.Metrics.HorizontalBearingY + (float)face.Glyph.Metrics.Height; FHT = this.fontHeight; FHD = (int)Math.Ceiling(FHT); kx = x + face.Glyph.BitmapLeft; ky = (int)Math.Round((float)y + (FHD - face.Glyph.BitmapTop)); kx = x + face.Glyph.BitmapLeft; ky = (int)Math.Round((float)y + (FHD - (float)face.Glyph.Metrics.HorizontalBearingY)); FTBitmap ftbmp = face.Glyph.Bitmap; if (ftbmp.Width == 0) { x += this.tile_width; if (x + this.tile_width > this.image_width) { x = 0; y += this.tile_height; } continue; } Bitmap tmpBmp = ftbmp.ToGdipBitmap(this.penColor); tmpBmp = kPasteImage(tmpBmp, tile_width * 2, tile_height * 2, (int)face.Glyph.BitmapLeft, (int)Math.Round(((float)this.fontHeight * 2 - face.Glyph.BitmapTop))); Bitmap cBmp = kResizeImage(tmpBmp, tmpBmp.Width / 2, tmpBmp.Height / 2, System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor); Bitmap nBmp = gray2alpha(cBmp); cBmp.Dispose(); g.DrawImageUnscaled(nBmp, x + GlobalSettings.relativePositionX, y + GlobalSettings.relativePositionY); nBmp.Dispose(); } else if (this.grender_mode == "freetype_HighQualityBicubic") { face.SetCharSize(0, this.fontHeight * 2, 0, 72); face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal); face.Glyph.RenderGlyph(RenderMode.Normal); left = (float)face.Glyph.Metrics.HorizontalBearingX; right = (float)face.Glyph.Metrics.HorizontalBearingX + (float)face.Glyph.Metrics.Width; top = (float)face.Glyph.Metrics.HorizontalBearingY; bottom = (float)face.Glyph.Metrics.HorizontalBearingY + (float)face.Glyph.Metrics.Height; FHT = this.fontHeight; FHD = (int)Math.Ceiling(FHT); kx = x + face.Glyph.BitmapLeft; ky = (int)Math.Round((float)y + (FHD - face.Glyph.BitmapTop)); kx = x + face.Glyph.BitmapLeft; ky = (int)Math.Round((float)y + (FHD - (float)face.Glyph.Metrics.HorizontalBearingY)); FTBitmap ftbmp = face.Glyph.Bitmap; if (ftbmp.Width == 0) { x += this.tile_width; if (x + this.tile_width > this.image_width) { x = 0; y += this.tile_height; } continue; } Bitmap tmpBmp = ftbmp.ToGdipBitmap(this.penColor); tmpBmp = kPasteImage(tmpBmp, tile_width * 2, tile_height * 2, (int)face.Glyph.BitmapLeft, (int)Math.Round(((float)this.fontHeight * 2 - face.Glyph.BitmapTop))); Bitmap cBmp = kResizeImage(tmpBmp, tmpBmp.Width / 2, tmpBmp.Height / 2, System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic); Bitmap nBmp = gray2alpha(cBmp); cBmp.Dispose(); g.DrawImageUnscaled(nBmp, x + GlobalSettings.relativePositionX, y + GlobalSettings.relativePositionY); nBmp.Dispose(); } else if (this.grender_mode == "freetype_drawtwice") { face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal); face.Glyph.RenderGlyph(RenderMode.Normal); left = (float)face.Glyph.Metrics.HorizontalBearingX; right = (float)face.Glyph.Metrics.HorizontalBearingX + (float)face.Glyph.Metrics.Width; top = (float)face.Glyph.Metrics.HorizontalBearingY; bottom = (float)face.Glyph.Metrics.HorizontalBearingY + (float)face.Glyph.Metrics.Height; FHT = this.fontHeight; FHD = (int)Math.Ceiling(FHT); kx = x + face.Glyph.BitmapLeft; ky = (int)Math.Round((float)y + (FHD - face.Glyph.BitmapTop)); kx = x + face.Glyph.BitmapLeft; ky = (int)Math.Round((float)y + (FHD - (float)face.Glyph.Metrics.HorizontalBearingY)); FTBitmap ftbmp = face.Glyph.Bitmap; if (ftbmp.Width == 0) { x += this.tile_width; if (x + this.tile_width > this.image_width) { x = 0; y += this.tile_height; } continue; } //这是一个临时描边的功能,还没有添加到UI if (GlobalSettings.bUseOutlineEffect == true) { Bitmap cBmp = ftbmp.ToGdipBitmap(this.penColor); face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal); face.Glyph.Outline.Embolden(2); face.Glyph.RenderGlyph(RenderMode.Normal); left = (float)face.Glyph.Metrics.HorizontalBearingX; right = (float)face.Glyph.Metrics.HorizontalBearingX + (float)face.Glyph.Metrics.Width; top = (float)face.Glyph.Metrics.HorizontalBearingY; bottom = (float)face.Glyph.Metrics.HorizontalBearingY + (float)face.Glyph.Metrics.Height; FHT = this.fontHeight; FHD = (int)Math.Ceiling(FHT); kx = x + face.Glyph.BitmapLeft; ky = (int)Math.Round((float)y + (FHD - face.Glyph.BitmapTop)); kx = x + face.Glyph.BitmapLeft; ky = (int)Math.Round((float)y + (FHD - (float)face.Glyph.Metrics.HorizontalBearingY)); FTBitmap ftbmp1 = face.Glyph.Bitmap; Bitmap sBmp = ftbmp1.ToGdipBitmap(GlobalSettings.cShadowColor); Bitmap nBmp = gray2alpha(cBmp); //Bitmap s2Bmp = gray2alpha(sBmp); g.DrawImageUnscaled(sBmp, kx + GlobalSettings.relativePositionX - 1, ky + GlobalSettings.relativePositionY - 1);//draw twice g.DrawImageUnscaled(nBmp, kx + GlobalSettings.relativePositionX, ky + GlobalSettings.relativePositionY); cBmp.Dispose(); nBmp.Dispose(); sBmp.Dispose(); } else { Bitmap cBmp = ftbmp.ToGdipBitmap(this.penColor); face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal); face.Glyph.RenderGlyph(RenderMode.Normal); left = (float)face.Glyph.Metrics.HorizontalBearingX; right = (float)face.Glyph.Metrics.HorizontalBearingX + (float)face.Glyph.Metrics.Width; top = (float)face.Glyph.Metrics.HorizontalBearingY; bottom = (float)face.Glyph.Metrics.HorizontalBearingY + (float)face.Glyph.Metrics.Height; FHT = this.fontHeight; FHD = (int)Math.Ceiling(FHT); kx = x + face.Glyph.BitmapLeft; ky = (int)Math.Round((float)y + (FHD - face.Glyph.BitmapTop)); kx = x + face.Glyph.BitmapLeft; ky = (int)Math.Round((float)y + (FHD - (float)face.Glyph.Metrics.HorizontalBearingY)); FTBitmap ftbmp1 = face.Glyph.Bitmap; Bitmap sBmp = ftbmp1.ToGdipBitmap(this.penColor); Bitmap nBmp = gray2alpha(cBmp); sBmp = gray2alpha(sBmp); g.DrawImageUnscaled(sBmp, kx + GlobalSettings.relativePositionX - 1, ky + GlobalSettings.relativePositionY - 1);//draw twice g.DrawImageUnscaled(nBmp, kx + GlobalSettings.relativePositionX, ky + GlobalSettings.relativePositionY); cBmp.Dispose(); nBmp.Dispose(); sBmp.Dispose(); } } else if (this.grender_mode == "freetype_nosmoothing") { face.SetPixelSizes((uint)0, (uint)this.fontHeight); face.LoadGlyph(glyphIndex, LoadFlags.Monochrome, LoadTarget.Mono); face.Glyph.RenderGlyph(RenderMode.Mono); left = (float)face.Glyph.Metrics.HorizontalBearingX; right = (float)face.Glyph.Metrics.HorizontalBearingX + (float)face.Glyph.Metrics.Width; top = (float)face.Glyph.Metrics.HorizontalBearingY; bottom = (float)face.Glyph.Metrics.HorizontalBearingY + (float)face.Glyph.Metrics.Height; FHT = this.fontHeight; FHD = (int)Math.Ceiling(FHT); kx = x + face.Glyph.BitmapLeft; ky = (int)Math.Round((float)y + (FHD - face.Glyph.BitmapTop)); kx = x + face.Glyph.BitmapLeft; ky = (int)Math.Round((float)y + (FHD - (float)face.Glyph.Metrics.HorizontalBearingY)); FTBitmap ftbmp = face.Glyph.Bitmap; if (ftbmp.Width == 0) { x += this.tile_width; if (x + this.tile_width > this.image_width) { x = 0; y += this.tile_height; } continue; } Bitmap cBmp = ftbmp.ToGdipBitmap(this.penColor); g.DrawImageUnscaled(cBmp, kx + GlobalSettings.relativePositionX, ky + GlobalSettings.relativePositionY); cBmp.Dispose(); } else { face.SetCharSize(0, this.fontHeight, 0, 72); if (GlobalSettings.iFontBold > (float)0) { //临时加粗face.Glyph.Outline.Embolden(0.4);值要小于1,不然很丑 face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal); face.Glyph.Outline.Embolden(0.4); face.Glyph.RenderGlyph(RenderMode.Normal); left = (float)face.Glyph.Metrics.HorizontalBearingX; right = (float)face.Glyph.Metrics.HorizontalBearingX + (float)face.Glyph.Metrics.Width; top = (float)face.Glyph.Metrics.HorizontalBearingY; bottom = (float)face.Glyph.Metrics.HorizontalBearingY + (float)face.Glyph.Metrics.Height; FHT = this.fontHeight; FHD = (int)Math.Ceiling(FHT); kx = x + face.Glyph.BitmapLeft; ky = (int)Math.Round((float)y + (FHD - face.Glyph.BitmapTop)); kx = x + face.Glyph.BitmapLeft; ky = (int)Math.Round((float)y + (FHD - (float)face.Glyph.Metrics.HorizontalBearingY)); } FTBitmap ftbmp = face.Glyph.Bitmap; if (ftbmp.Width == 0) { x += this.tile_width; if (x + this.tile_width > this.image_width) { x = 0; y += this.tile_height; } continue; } if (GlobalSettings.bUseOutlineEffect == true) { Bitmap cBmp = ftbmp.ToGdipBitmap(this.penColor); face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal); face.Glyph.Outline.Embolden(2); face.Glyph.RenderGlyph(RenderMode.Normal); left = (float)face.Glyph.Metrics.HorizontalBearingX; right = (float)face.Glyph.Metrics.HorizontalBearingX + (float)face.Glyph.Metrics.Width; top = (float)face.Glyph.Metrics.HorizontalBearingY; bottom = (float)face.Glyph.Metrics.HorizontalBearingY + (float)face.Glyph.Metrics.Height; FHT = this.fontHeight; FHD = (int)Math.Ceiling(FHT); kx = x + face.Glyph.BitmapLeft; ky = (int)Math.Round((float)y + (FHD - face.Glyph.BitmapTop)); kx = x + face.Glyph.BitmapLeft; ky = (int)Math.Round((float)y + (FHD - (float)face.Glyph.Metrics.HorizontalBearingY)); FTBitmap ftbmp1 = face.Glyph.Bitmap; Bitmap sBmp = ftbmp1.ToGdipBitmap(GlobalSettings.cShadowColor); Bitmap nBmp = gray2alpha(cBmp); //Bitmap s2Bmp = gray2alpha(sBmp); g.DrawImageUnscaled(sBmp, kx + GlobalSettings.relativePositionX - 1, ky + GlobalSettings.relativePositionY - 1);//draw twice g.DrawImageUnscaled(nBmp, kx + GlobalSettings.relativePositionX, ky + GlobalSettings.relativePositionY); cBmp.Dispose(); nBmp.Dispose(); sBmp.Dispose(); } else { Bitmap cBmp = ftbmp.ToGdipBitmap(this.penColor); Bitmap nBmp = gray2alpha(cBmp); cBmp.Dispose(); g.DrawImageUnscaled(nBmp, kx + GlobalSettings.relativePositionX, ky + GlobalSettings.relativePositionY); nBmp.Dispose(); } } x += this.tile_width; if (x + this.tile_width > this.image_width) { x = 0; y += this.tile_height; } } g.Dispose(); library.Dispose(); return(bmp); }
public static Bitmap RenderString(Library library, Face face, string text) { float penX = 0, penY = 0; float width = 0; float height = 0; //both bottom and top are positive for simplicity float top = 0, bottom = 0; //measure the size of the string before rendering it, requirement of Bitmap. for (int i = 0; i < text.Length; i++) { char c = text[i]; uint glyphIndex = face.GetCharIndex(c); face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal); width += (float)face.Glyph.Advance.X; if (face.HasKerning && i < text.Length - 1) { char cNext = text[i + 1]; width += (float)face.GetKerning(glyphIndex, face.GetCharIndex(cNext), KerningMode.Default).X; } float glyphTop = (float)face.Glyph.Metrics.HorizontalBearingY; float glyphBottom = (float)(face.Glyph.Metrics.Height - face.Glyph.Metrics.HorizontalBearingY); if (glyphTop > top) { top = glyphTop; } if (glyphBottom > bottom) { bottom = glyphBottom; } } height = top + bottom; //create a new bitmap that fits the string. Bitmap bmp = new Bitmap((int)Math.Ceiling(width), (int)Math.Ceiling(height)); Graphics g = Graphics.FromImage(bmp); g.Clear(SystemColors.Control); //draw the string for (int i = 0; i < text.Length; i++) { char c = text[i]; uint glyphIndex = face.GetCharIndex(c); face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal); face.Glyph.RenderGlyph(RenderMode.Normal); if (c == ' ') { penX += (float)face.Glyph.Advance.X; if (face.HasKerning && i < text.Length - 1) { char cNext = text[i + 1]; width += (float)face.GetKerning(glyphIndex, face.GetCharIndex(cNext), KerningMode.Default).X; } penY += (float)face.Glyph.Advance.Y; } else { //FTBitmap ftbmp = face.Glyph.Bitmap.Copy(library); FTBitmap ftbmp = face.Glyph.Bitmap; Bitmap cBmp = ftbmp.ToGdipBitmap(Color.Black); //Not using g.DrawImage because some characters come out blurry/clipped. g.DrawImageUnscaled(cBmp, (int)Math.Round(penX + face.Glyph.BitmapLeft), (int)Math.Round(penY + (top - (float)face.Glyph.Metrics.HorizontalBearingY))); penX += (float)face.Glyph.Metrics.HorizontalAdvance; penY += (float)face.Glyph.Advance.Y; if (face.HasKerning && i < text.Length - 1) { char cNext = text[i + 1]; var kern = face.GetKerning(glyphIndex, face.GetCharIndex(cNext), KerningMode.Default); penX += (float)kern.X; } } } g.Dispose(); return(bmp); }
public void ExportFont(string outputPath) { // should this be user input? int padX = 5; int padY = 5; int atlas = 0; float posX = 0; float posY = 0; List <Bitmap> bitmaps = new List <Bitmap>(); Dictionary <string, List <Info> > infos = new Dictionary <string, List <Info> >(); Bitmap bitmap = new Bitmap(maxWidth, maxHeight, PixelFormat.Format32bppArgb); Graphics graphics = Graphics.FromImage(bitmap); graphics.Clear(Color.Transparent); string output = "module.font = {\n\tinformation = {\n"; output += "\t\tfamily = \"" + family + "\";\n"; output += "\t\tstyles = {" + string.Join(", ", getStyles()) + "};\n"; output += "\t\tsizes = {" + string.Join(", ", sizes) + "};\n"; output += "\t\tuseEnums = " + useEnums() + ";\n\t};\n"; output += "\tstyles = {\n"; foreach (Face face in faces) { infos[face.StyleName] = new List <Info>(); output += "\t\t[\"" + face.StyleName + "\"] = {\n"; foreach (int size in sizes) { Info info = new Info(face.StyleName, size); int lineAdvance = 0; int firstAdjust = 0; float width = 0; float height = 0; float lineHeight = 0; face.SetCharSize(size * 96 / 72, 0, 96, 96); for (int i = 0; i < characters.Length; i++) { char c = characters[i]; uint index = face.GetCharIndex(c); face.LoadGlyph(index, LoadFlags.Default, LoadTarget.Normal); width += (float)face.Glyph.Metrics.HorizontalAdvance; if (face.Glyph.Metrics.Height > lineHeight) { // Get extra space and subtract it from first line draw? firstAdjust = face.Glyph.Metrics.VerticalAdvance.ToInt32() - face.Glyph.Metrics.HorizontalBearingY.ToInt32(); lineHeight = (float)face.Glyph.Metrics.Height; } for (int j = 0; j < characters.Length; j++) { char k = characters[j]; uint index2 = face.GetCharIndex(k); FTVector26Dot6 kern = face.GetKerning(index, index2, KerningMode.Default); int kernx = kern.X.ToInt32(); int kerny = kern.Y.ToInt32(); if (kernx != 0 | kerny != 0) { info.addKerning(c, new Info.kerningInfo(k, kernx, kerny)); } } } if (width > maxWidth) { int overlaps = (int)Math.Truncate(width / maxWidth); width = maxWidth; height = ((overlaps + 1) * (lineHeight + padY)); } else { width = maxWidth; height = lineHeight + padY; } face.SetUnpatentedHinting(true); for (int i = 0; i < characters.Length; i++) { char c = characters[i]; uint index = face.GetCharIndex(c); face.LoadGlyph(index, LoadFlags.Default, LoadTarget.Normal); face.Glyph.RenderGlyph(RenderMode.Normal); if (c == ' ') { posX += (float)face.Glyph.Metrics.HorizontalAdvance + (float)padX; info.addCharacter(c, new Info.characterInfo(c, face.Glyph.Metrics.HorizontalAdvance.ToInt32(), 0, 0, 0, 0, 0, atlas)); continue; } if (posX + face.Glyph.Metrics.Width + face.Glyph.BitmapLeft + padX > width) { posX = 0; posY += lineHeight + padY; } if (posY > (maxHeight - (lineHeight + padY))) { bitmaps.Add(bitmap); bitmap = new Bitmap(maxWidth, maxHeight, PixelFormat.Format32bppArgb); graphics = Graphics.FromImage(bitmap); graphics.Clear(Color.Transparent); posX = 0; posY = 0; atlas += 1; } int xadvance = face.Glyph.Metrics.HorizontalAdvance.ToInt32(); int imgWidth = face.Glyph.Metrics.Width.ToInt32(); int imgHeight = face.Glyph.Metrics.Height.ToInt32(); int imgX = (int)posX; int imgY = (int)posY; int yoffset = face.Glyph.Metrics.VerticalAdvance.ToInt32() - face.Glyph.Metrics.HorizontalBearingY.ToInt32(); // some fonts that might be missing characters will leave open spaces because their bitmap is empty. if (face.Glyph.Bitmap.Width > 0) { FTBitmap ftbmp = face.Glyph.Bitmap; Bitmap copy = ftbmp.ToGdipBitmap(Color.White); graphics.DrawImageUnscaled(copy, imgX, imgY); } info.addCharacter(c, new Info.characterInfo(c, xadvance, imgX, imgY, yoffset, imgWidth, imgHeight, atlas)); posX += (float)imgWidth + (float)padX; lineAdvance = face.Glyph.Metrics.VerticalAdvance.ToInt32(); } posX = 0; posY += lineHeight + padY; info.lineHeight = lineAdvance; info.firstAdjust = firstAdjust; infos[face.StyleName].Add(info); output += info.buildLuaString("\t\t\t") + "\n"; } output += "\t\t};\n"; } output += "\t};\n};\n"; bitmaps.Add(bitmap); graphics.Dispose(); // create images int count = 0; foreach (Bitmap bmp in bitmaps) { count += 1; bmp.Save(outputPath + "\\" + family + "_" + count + ".png"); } string header = "--[[\n\t@Font " + family + "\n"; header += "\t@Sizes {" + string.Join(", ", sizes) + "}\n"; header += "\t@Author N/A\n"; header += "\t@Link N/A\n--]]\n\n"; header += "local module = {};\n\n"; header += "module.atlases = {\n"; for (int i = 1; i <= count; i++) { header += "\t[" + i + "] = \"rbxassetid://\";\n"; } header += "};\n\n" + output; header += "\n\nreturn module;"; File.WriteAllText(outputPath + "\\" + family + ".lua", header); }
public T3BFont DrawT3BFontBitmap(char[] strings) { T3BFont t3bFont = new T3BFont(); #region font texture settings int texture_width = 512; int texture_height = 512; int font_height = 14; int tile_w = 17; int tile_h = 17; int swizzle_w = 32; int swizzle_h = 8; int a2 = texture_width / tile_w; string fontName = "Font/font.ttf"; int relativePositionX = 1; int relativePositionY = -1; byte[] o_data = File.ReadAllBytes("Font/base.font"); Bitmap _bm = new Bitmap("Font/base.png"); Graphics base_grp = System.Drawing.Graphics.FromImage(_bm); #endregion Library library = new Library(); Face face = library.NewFace(fontName, 0); int tmp_length = strings.Length; if (tmp_length <= 0x76d) { Console.WriteLine("字太少了,多放点字到charlist.txt"); throw new Exception("字太少了,多放点字到charlist.txt"); } if (tmp_length >= 2700) { Console.WriteLine("字太多了,无法装入那么多字,>2700"); throw new Exception("字太多了,无法装入那么多字"); } if (tmp_length >= 0x76d) { //当超出0x76D时,加入按钮占用的tile数 tmp_length += 23; } //获得texture能达到的最大tile数,00000024h int max_tiles = ((int)Math.Ceiling(((double)tmp_length / (double)30)) + 1) * 30; t3bFont.max_tiles = max_tiles; //获取符合32x8并能容下所有字符的最接近texture_height int t1 = tmp_length / 900; int t2 = tmp_length % 900; int t3 = t1 * 512 + (int)Math.Ceiling(((double)t2 / (double)a2) + 1) * tile_h; texture_height = (int)Math.Ceiling((double)t3 / (double)swizzle_h) * swizzle_h; Bitmap bmp = new Bitmap((int)Math.Ceiling((double)texture_width), (int)Math.Ceiling((double)texture_height)); Graphics g = Graphics.FromImage(bmp); g.Clear(Color.Transparent); int x = 0, y = 0; bool bGetFromBitmap = false; for (int i = 0; i < tmp_length; i++) { string currentChar0; if (i <= 0xc8) { //字母数字和标点, 从原始图片中截取(bGetFromBitmap = true) t3bFont.tbl.Add(string.Format("{0:x4}={1}", i, strings[i].ToString())); currentChar0 = " "; bGetFromBitmap = true; } else if ((0xc9 <= i) && (i <= 0x76c)) { //在按钮之前的字符, 使用freetype绘制点阵 currentChar0 = strings[i].ToString(); t3bFont.tbl.Add(string.Format("{0:x4}={1}", i, strings[i].ToString())); bGetFromBitmap = false; } else if (i >= 0x784) { //在按钮之后的字符, 使用freetype绘制点阵 currentChar0 = strings[i - 23].ToString(); t3bFont.tbl.Add(string.Format("{0:x4}={1}", i, currentChar0.ToString())); bGetFromBitmap = false; } else { //按钮图片, 从原始图片中截取(bGetFromBitmap = true) currentChar0 = " "; bGetFromBitmap = true; } if (bGetFromBitmap == false) { face.SetCharSize(0, font_height, 0, 72); face.SetPixelSizes((uint)0, (uint)font_height); uint glyphIndex = face.GetCharIndex(uchar2code(currentChar0)); //face.LoadGlyph(glyphIndex, LoadFlags.Monochrome, LoadTarget.Mono); //face.Glyph.RenderGlyph(RenderMode.Mono); face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Lcd); face.Glyph.RenderGlyph(RenderMode.Normal); float left = (float)face.Glyph.Metrics.HorizontalBearingX; float right = (float)face.Glyph.Metrics.HorizontalBearingX + (float)face.Glyph.Metrics.Width; float top = (float)face.Glyph.Metrics.HorizontalBearingY; float bottom = (float)face.Glyph.Metrics.HorizontalBearingY + (float)face.Glyph.Metrics.Height; float FHT = font_height; int FHD = (int)Math.Ceiling(FHT); int kx = x + (int)Math.Round(left); int ky = (int)Math.Round((float)y + (FHD - top)); //int ky = (int)Math.Round((float)y + (FHD - face.Glyph.BitmapTop)); FTBitmap ftbmp = face.Glyph.Bitmap; if (ftbmp.Width == 0) { x += tile_w; if (x + tile_w > tile_w) { x = 0; y += tile_h; } if (i + 1 == 900 || i + 1 == 1800 || i + 1 == 2700) { y += (2); } continue; } Bitmap dBmp = ftbmp.ToGdipBitmap(Color.FromArgb(255, 0x24, 0x24, 0x24)); g.DrawImageUnscaled(dBmp, kx + relativePositionX - 1, ky + relativePositionY); g.DrawImageUnscaled(dBmp, kx + relativePositionX + 1, ky + relativePositionY); g.DrawImageUnscaled(dBmp, kx + relativePositionX, ky + relativePositionY - 1); g.DrawImageUnscaled(dBmp, kx + relativePositionX, ky + relativePositionY + 1); dBmp.Dispose(); FTBitmap ftbmp2 = face.Glyph.Bitmap; Bitmap cBmp = ftbmp2.ToGdipBitmap(Color.White); g.DrawImageUnscaled(cBmp, kx + relativePositionX, ky + relativePositionY); g.DrawImageUnscaled(cBmp, kx + relativePositionX, ky + relativePositionY); cBmp.Dispose(); x += tile_w; if (x + tile_w > texture_width) { x = 0; y += tile_h; } if (i + 1 == 900 || i + 1 == 1800 || i + 1 == 2700) { y += (2); } t3bFont.charvalues.Add(16); } else { //从原版位图中获取并粘贴位置; //do somethings. int kx = x; int ky = y; int kw = (int)o_data[i + 0x47840]; int kh = 17; if (kw > 0) { Bitmap current_bm = new Bitmap(kw, kh); Graphics _tmp_grp = System.Drawing.Graphics.FromImage(current_bm); _tmp_grp.DrawImage(_bm, new Rectangle(0, 0, kw, kh), new Rectangle(kx, ky, kw, kh), GraphicsUnit.Pixel); _tmp_grp.Dispose(); g.DrawImageUnscaled(current_bm, kx, ky); //Console.WriteLine(String.Format("x:{0},y:{1},w:{2},h:{3}" , x, y ,kw ,kh)); } x += tile_w; if (x + tile_w > texture_width) { x = 0; y += tile_h; } if (i + 1 == 900 || i + 1 == 1800 || i + 1 == 2700) { y += (2); } t3bFont.charvalues.Add(kw); } } g.Dispose(); base_grp.Dispose(); _bm.Dispose(); library.Dispose(); t3bFont.bitmap = bmp; return(t3bFont); }
public static bool DrawBitmap(string currentChar0, int width, int height, string ttfName, float scaleRatio, out Bitmap bmp) { if (charConstDictionary.ContainsKey(currentChar0)) { currentChar0 = charConstDictionary[currentChar0]; } bmp = new Bitmap(width, height); Graphics g = Graphics.FromImage(bmp); g.Clear(Color.Transparent); //设定字体信息 int font_height = (int)Math.Round((float)height * 3f / 4f * scaleRatio); int relativePositionX = 0; int relativePositionY = 0; string fontName = ttfName; Library library = new Library(); Face face = library.NewFace(fontName, 0); face.SetCharSize(0, font_height, 0, 96); face.SetPixelSizes((uint)0, (uint)font_height); uint glyphIndex = face.GetCharIndex(uchar2code(currentChar0)); face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Lcd); face.Glyph.RenderGlyph(RenderMode.Normal); float left = (float)face.Glyph.Metrics.HorizontalBearingX; float right = (float)face.Glyph.Metrics.HorizontalBearingX + (float)face.Glyph.Metrics.Width; float top = (float)face.Glyph.Metrics.HorizontalBearingY; float bottom = (float)face.Glyph.Metrics.HorizontalBearingY + (float)face.Glyph.Metrics.Height; int FHD = (int)Math.Ceiling((float)font_height); int kx = (int)Math.Round(left); int ky = (int)Math.Round((float)0 + (FHD - top)); Bitmap dBmp; FTBitmap ftbmp = face.Glyph.Bitmap; bool hasGlyph = false; if (ftbmp.Width == 0) { dBmp = new Bitmap(width, width); } else { dBmp = ftbmp.ToGdipBitmap(Color.FromArgb(255, 0, 0, 255));//描边 hasGlyph = true; } g.DrawImageUnscaled(dBmp, kx + relativePositionX - 1, ky + relativePositionY); g.DrawImageUnscaled(dBmp, kx + relativePositionX + 1, ky + relativePositionY); g.DrawImageUnscaled(dBmp, kx + relativePositionX, ky + relativePositionY - 1); g.DrawImageUnscaled(dBmp, kx + relativePositionX, ky + relativePositionY + 1); dBmp.Dispose(); if (hasGlyph) { FTBitmap ftbmp2 = face.Glyph.Bitmap; Bitmap cBmp = ftbmp2.ToGdipBitmap(Color.FromArgb(255, 0xf0, 0xf0, 0xf0));//实色 g.DrawImageUnscaled(cBmp, kx + relativePositionX, ky + relativePositionY); g.DrawImageUnscaled(cBmp, kx + relativePositionX, ky + relativePositionY); cBmp.Dispose(); } g.Dispose(); return(hasGlyph); }
public Bitmap test_draw(ObservableCollection <System.Windows.UIElement> list, ObservableCollection <FontModel> fontList, MaxRectsBinPack binPack, string alphabet, FontSettings fontSettings) { alphabet = alphabet.Replace("\n", ""); alphabet = alphabet.Replace("\r", ""); Library library = new Library(); Face face = library.NewFace(fontSettings.FontName, 0); // Find the largest glyph bounding rectangle // Rect glyphRect = getGlyphRect(face, alphabet); //int glyphWidth = (int)Math.Ceiling(glyphRect.Width) + 4 * fontSettings.OutlineWidth; //int glyphHeight = (int)Math.Ceiling(glyphRect.Height) + 4 * fontSettings.OutlineWidth; int glyphWidth = 18 + 4 * fontSettings.OutlineWidth; int glyphHeight = 18 + 4 * fontSettings.OutlineWidth; //add new font FontModel newFont = new FontModel() { Id = (ushort)fontSettings.FontSize, size = fontSettings.FontSize, lineheight = glyphHeight, // 22, spacelength = (int)(glyphWidth * 0.6f), //todo ? baseline = 0, kerning = -0.5f, monowidth = fontSettings.FontSize + 1, letterspacing = 0, rangeFrom = alphabet[0], rangeTo = alphabet[alphabet.Length - 1] }; fontList.Add(newFont); Bitmap bmp = new Bitmap((int)Math.Ceiling((double)fontSettings.ImageWidth), (int)Math.Ceiling((double)fontSettings.ImageHeight)); Graphics g = Graphics.FromImage(bmp); g.Clear(fontSettings.BgColor); //g.Clear(Color.Black);q int x = 0, y = 0; for (int i = 0; i < alphabet.ToCharArray().Length; i++) { string currentChar0 = alphabet.ToCharArray()[i].ToString(); uint glyphIndex = face.GetCharIndex(uchar2code(currentChar0)); if (fontSettings.FontSize <= 14) { face.SetPixelSizes((uint)0, (uint)fontSettings.FontSize); face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal); face.Glyph.RenderGlyph(RenderMode.Normal); } else { face.SetCharSize(0, fontSettings.FontSize, 0, 72); face.LoadGlyph(glyphIndex, LoadFlags.ForceAutohint, LoadTarget.Lcd); face.Glyph.RenderGlyph(RenderMode.Lcd); } //Get character alignment float left = (float)face.Glyph.Metrics.HorizontalBearingX; float right = (float)face.Glyph.Metrics.HorizontalBearingX + (float)face.Glyph.Metrics.Width; float top = (float)face.Glyph.Metrics.HorizontalBearingY; float bottom = (float)face.Glyph.Metrics.HorizontalBearingY + (float)face.Glyph.Metrics.Height; float FHT = fontSettings.FontSize; int FHD = (int)Math.Ceiling(FHT); int kx = x + face.Glyph.BitmapLeft; int ky = (int)Math.Round((float)y + (FHD - face.Glyph.BitmapTop)); ////Select render mode (1 times or 2 times) //if (this.grender_mode == "freetype_nearestneighbor") //{ // face.SetCharSize(0, this.fontHeight * 2, 0, 72); // face.LoadGlyph(glyphIndex, LoadFlags.ForceAutohint, LoadTarget.Lcd); // face.Glyph.RenderGlyph(RenderMode.Lcd); // FTBitmap ftbmp = face.Glyph.Bitmap; // if (ftbmp.Width == 0) // { // x += this.tile_width; // if (x + this.tile_width > this.image_width) // { // x = 0; // y += this.tile_height; // } // continue; // } // Bitmap tmpBmp = ftbmp.ToGdipBitmap(this.penColor); // tmpBmp = kPasteImage(tmpBmp, tile_width * 2, tile_height * 2, (int)face.Glyph.BitmapLeft, // (int)Math.Round(((float)this.fontHeight * 2 - face.Glyph.BitmapTop))); // Bitmap cBmp = kResizeImage(tmpBmp, tmpBmp.Width / 2, tmpBmp.Height / 2, System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor); // Bitmap nBmp = gray2alpha(cBmp); // cBmp.Dispose(); // g.DrawImageUnscaled(nBmp, x + FontSettings.relativePositionX, y + FontSettings.relativePositionY); // nBmp.Dispose(); //} //else if (this.grender_mode == "freetype_HighQualityBicubic") //{ // face.SetCharSize(0, this.fontHeight * 2, 0, 72); // face.LoadGlyph(glyphIndex, LoadFlags.ForceAutohint, LoadTarget.Lcd); // face.Glyph.RenderGlyph(RenderMode.Lcd); // FTBitmap ftbmp = face.Glyph.Bitmap; // if (ftbmp.Width == 0) // { // x += this.tile_width; // if (x + this.tile_width > this.image_width) // { // x = 0; // y += this.tile_height; // } // continue; // } // Bitmap tmpBmp = ftbmp.ToGdipBitmap(this.penColor); // tmpBmp = kPasteImage(tmpBmp, tile_width * 2, tile_height * 2, (int)face.Glyph.BitmapLeft, // (int)Math.Round(((float)this.fontHeight * 2 - face.Glyph.BitmapTop))); // Bitmap cBmp = kResizeImage(tmpBmp, tmpBmp.Width / 2, tmpBmp.Height / 2, System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic); // Bitmap nBmp = gray2alpha(cBmp); // cBmp.Dispose(); // g.DrawImageUnscaled(nBmp, x + FontSettings.relativePositionX, y + FontSettings.relativePositionY); // nBmp.Dispose(); //} //else if (this.grender_mode == "freetype_drawtwice") //{ // face.LoadGlyph(glyphIndex, LoadFlags.Default, LoadTarget.Normal); // face.Glyph.RenderGlyph(RenderMode.Normal); // FTBitmap ftbmp = face.Glyph.Bitmap; // if (ftbmp.Width == 0) // { // x += this.tile_width; // if (x + this.tile_width > this.image_width) // { // x = 0; // y += this.tile_height; // } // continue; // } // Bitmap cBmp = ftbmp.ToGdipBitmap(this.penColor); // Bitmap sBmp = ftbmp.ToGdipBitmap(this.shadowColor); // Bitmap nBmp = gray2alpha(cBmp); // cBmp.Dispose(); // g.DrawImageUnscaled(sBmp, kx + FontSettings.relativePositionX + 1, ky + FontSettings.relativePositionY + 1);//draw twice // g.DrawImageUnscaled(nBmp, kx + FontSettings.relativePositionX, ky + FontSettings.relativePositionY); // cBmp.Dispose(); // nBmp.Dispose(); //} //else if (this.grender_mode == "freeyype_nosmoothing") //{ // face.SetPixelSizes((uint)0, (uint)this.fontHeight); // face.LoadGlyph(glyphIndex, LoadFlags.Monochrome, LoadTarget.Mono); // face.Glyph.RenderGlyph(RenderMode.Mono); // FTBitmap ftbmp = face.Glyph.Bitmap; // if (ftbmp.Width == 0) // { // x += this.tile_width; // if (x + this.tile_width > this.image_width) // { // x = 0; // y += this.tile_height; // } // continue; // } // Bitmap cBmp = ftbmp.ToGdipBitmap(this.penColor); // g.DrawImageUnscaled(cBmp, kx + FontSettings.relativePositionX, ky + FontSettings.relativePositionY); // cBmp.Dispose(); //} // int tile_width = 24; //int tile_height = FontSettings.iFontHeight;//24; ////else ////{ FTBitmap ftbmp = face.Glyph.Bitmap; // if (ftbmp.Width == 0) // { // x += tile_width; // if (x + tile_width > this.image_width) // { // x = 0; // y += tile_height; // } // continue; // } Bitmap cBmp = ftbmp.ToGdipBitmap(fontSettings.PenColor); Bitmap nBmp = gray2alpha(cBmp); Rect newPos = binPack.Insert(cBmp.Width, cBmp.Height, MaxRectsBinPack.FreeRectChoiceHeuristic.RectBottomLeftRule); //DebugRectangle System.Windows.Shapes.Rectangle testRect = new System.Windows.Shapes.Rectangle { Stroke = System.Windows.Media.Brushes.LightGreen, StrokeThickness = 0 }; ImageBrush ib = new ImageBrush(); // cBmp.MakeTransparent(); cBmp.Dispose(); var source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(nBmp.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions()); nBmp.Dispose(); ib.ImageSource = source; testRect.Fill = ib; testRect.Width = newPos.Width; testRect.Height = newPos.Height; Canvas.SetLeft(testRect, newPos.Left); Canvas.SetTop(testRect, newPos.Top); list.Add(testRect); Glyph newGlyph = new Glyph() { X = (int)Math.Ceiling(newPos.Left), Y = (int)Math.Ceiling(newPos.Top), width = (int)Math.Ceiling(newPos.Width), height = (int)Math.Ceiling(newPos.Height) }; newFont.SetGlyph(currentChar0, newGlyph); //if(glyphIndex == 33) //{ //} // Construct KerningData for (int j = 0; j < alphabet.ToCharArray().Length; j++) { string left_Char0 = alphabet.ToCharArray()[j].ToString(); uint left_glyphIndex = face.GetCharIndex(uchar2code(left_Char0)); //if (left_glyphIndex == 45) //{ //} //char c1 = mAlphabet[i]; //FT_UInt c1Index = FT_Get_Char_Index(face, c1); var delta = face.GetKerning(left_glyphIndex, glyphIndex, KerningMode.Default); // KerningData kd = new KerningData(kern_currentChar0, currentChar0, delta.X.ToInt32() >> 6, 0, delta.Y.ToInt32() >> 6, 0); if (left_glyphIndex == 0 || delta.X == 0) //no kerning { continue; } Kerning newKerning = new Kerning(); newKerning.RightGlyphID = left_glyphIndex; newKerning.KerningValue = delta.X.ToInt32() >> 6; newFont.SetKerning(left_Char0, newKerning); } newFont.SetVerticalOffset(currentChar0, ky); //cBmp.Dispose(); //g.DrawImageUnscaled(nBmp, (int)Math.Ceiling(newPos.X) + fontSettings.relativePositionX, (int)Math.Ceiling(newPos.Y) + fontSettings.relativePositionY); //// g.DrawImageUnscaled(nBmp, kx + FontSettings.relativePositionX, ky + FontSettings.relativePositionY); //nBmp.Dispose(); } g.Dispose(); library.Dispose(); return(bmp); }