TextRenderer GDI方法基于清晰类型的呈现(旨在屏幕上文本的视觉呈现),使用字形的亚像素表示形式.字母间距的计算完全不同. Microsoft ClearType概述. 缺点是这种计算字母间距的方法使其不适合从WinForms打印. MSDN文档反复指出这一点.关于该主题的其他有趣资源: 艺术开发-文本呈现方法比较或GDI与GDI + 为什么我的文本在GDI +和GDI中看起来不同? GDI与.GDI +文本渲染性能 SO答案: 为什么Graphics.MeasureString()返回一个比预期的数字高? 在System.Drawing.Graphics.DrawString()中修改字距用于生成ASCII文字的应用程序: SourceForge上的ASCII生成器2(免费软件) I'm working with drawing a long string to a bitmap (talking more than a million characters), including multiline characters \r\n, written by a StringBuilder.My Text to Bitmap code is as follows:public static Bitmap GetBitmap(string input, Font inputFont, Color bmpForeground, Color bmpBackground) { Image bmpText = new Bitmap(1, 1); try { // Create a graphics object from the image. Graphics g = Graphics.FromImage(bmpText); // Measure the size of the text when applied to image. SizeF inputSize = g.MeasureString(input, inputFont); // Create a new bitmap with the size of the text. bmpText = new Bitmap((int)inputSize.Width, (int)inputSize.Height); // Instantiate graphics object, again, since our bitmap // was modified. g = Graphics.FromImage(bmpText); // Draw a background to the image. g.FillRectangle(new Pen(bmpBackground).Brush, new Rectangle(0, 0, Convert.ToInt32(inputSize.Width), Convert.ToInt32(inputSize.Height))); // Draw the text to the image. g.DrawString(input, inputFont, new Pen(bmpForeground).Brush, new PointF(0, 0)); } catch { // Draw a blank image with background. Graphics.FromImage(bmpText).FillRectangle( new Pen(bmpBackground).Brush, new Rectangle(0, 0, 1, 1)); } return (Bitmap)bmpText;}Normally, it works as expected -- but only when used for single characters. However, the issue lies when a multitude of characters are used. Simply put, extra lines appear both vertically and horizontally when drawn on to the image.This effect is demonstrated here, zoomed in 1:1 (see the full Image):However, I can render this same text in Notepad++ with just the output of the string and it's essentially as expected:I can view it in any other text viewer; the result will be the same.So how, and why, is the program rendering the Bitmap with those 'extra' lines? 解决方案 When drawing a string of characters (ASCII or a form of Unicode encoded symbols) using Graphics.DrawString() with a fixed sized Font, the resulting graphics appear to generate a sort of grid, degrading the visual quality of the rendering.A solution is to substitute the GDI+ Graphics methods with the GDI methods, using TextRenderer.MeasureText() and TextRenderer.DrawText().Sample code to correct the problem and to reproduce it.Load a text file using the default local CodePage encoding. The source text has been saved without any Unicode encoding. If a different encoding is used, the Encoding.Default must be substituted with the actual Encoding (e.g. Encoding.Unicode, Encoding.UTF8...).The fixed size Font used for all tests is Lucida Console, 4em Regular.Other candidates, usually available, are Consolas and Courier New.using System.Drawing;using System.Drawing.Drawing2D;using System.Drawing.Imaging;using System.Drawing.Text;using System.IO;using System.Text;using System.Windows.Forms;using (FileStream stream = new FileStream(openfile.FileName, FileMode.Open, FileAccess.Read, FileShare.None))using (StreamReader reader = new StreamReader(stream, Encoding.Default)) TextInput = reader.ReadToEnd();Font font = new Font("Lucida Console", 4, FontStyle.Regular, GraphicsUnit.Point);using (Bitmap bitmap = ASCIIArtBitmap(TextInput, font)) bitmap.Save(@"[FilePath1]", ImageFormat.Png);using (Bitmap bitmap = ASCIIArtBitmapGdiPlus(TextInput, font)) bitmap.Save(@"[FilePath2]", ImageFormat.Png);using (Bitmap bitmap = ASCIIArtBitmapGdiPlusPath(TextInput, font)) bitmap.Save(@"[FilePath3]", ImageFormat.Png);font.Dispose();TextRenderer is first used to eliminate the visual defect reported.As a note, both TextRederer.MeasureText and Graphics.DrawString, per the MSDN documentation, should be used to measure a single line of text.Anyway, it's also known that the text is correctly measured when the text is composed of multiple lines, if a line feed separates those lines.It can be easily tested, splitting the source text with Enviroment.Newline as separator and multiplying the number of lines by the height of a single line. The result is always the same.private Bitmap ASCIIArtBitmap(string text, Font font){ TextFormatFlags flags = TextFormatFlags.Top | TextFormatFlags.Left | TextFormatFlags.NoPadding | TextFormatFlags.NoClipping; Size bitmapSize = TextRenderer.MeasureText(text, font, Size.Empty, flags); using (Bitmap bitmap = new Bitmap(bitmapSize.Width, bitmapSize.Height, PixelFormat.Format24bppRgb)) using (Graphics graphics = Graphics.FromImage(bitmap)) { bitmapSize = TextRenderer.MeasureText(graphics, text, font, new Size(bitmap.Width, bitmap.Height), flags); TextRenderer.DrawText(graphics, text, font, Point.Empty, Color.Black, Color.White, flags); return (Bitmap)bitmap.Clone(); }}Low resolution rendering, (150 x 55 chars). No grid effect visible.Using Graphics.DrawString(), to reproduce the reported behaviour.TextRenderingHint.AntiAlias is specified, as an effort to reduce the visual defect. CompositingQuality.HighSpeed seems out of place, but it actually, in this case, renders better than HighQuality.TextContrast = 1 makes the resulting image a little darker. With the default setting is too bright and loses details (my opinion, though).private Bitmap ASCIIArtBitmapGdiPlus(string text, Font font){ using (Bitmap modelbitmap = new Bitmap(10, 10, PixelFormat.Format24bppRgb)) using (Graphics modelgraphics = Graphics.FromImage(modelbitmap)) { modelgraphics.TextRenderingHint = TextRenderingHint.AntiAlias; SizeF bitmapSize = modelgraphics.MeasureString(text, font, Point.Empty, StringFormat.GenericTypographic); using (Bitmap bitmap = new Bitmap((int)bitmapSize.Width, (int)bitmapSize.Height, PixelFormat.Format24bppRgb)) using (Graphics graphics = Graphics.FromImage(bitmap)) { graphics.Clear(Color.White); graphics.TextRenderingHint = TextRenderingHint.AntiAlias; graphics.CompositingQuality = CompositingQuality.HighSpeed; graphics.PixelOffsetMode = PixelOffsetMode.HighSpeed; graphics.TextContrast = 1; graphics.DrawString(text, font, Brushes.Black, PointF.Empty, StringFormat.GenericTypographic); return (Bitmap)bitmap.Clone(); } }}Medium-low resolution (300 x 110 chars), the grid-effect is visible. Graphics.DrawString() TextRenderer.DrawText()Another approach, using GraphicsPath.AddString()The resulting bitmap is a somewhat better, but the grid effect is there anyway.What can be really noticed, is the difference in speed. GraphicsPath is way slower that all other methods tested.private Bitmap ASCIIArtBitmapGdiPlusPath(string text, Font font){ GraphicsPath GPath = new GraphicsPath(FillMode.Alternate); GPath.AddString(text, font.FontFamily, (int)font.Style, 4, Point.Empty, StringFormat.GenericTypographic); Rectangle GPathArea = Rectangle.Round(GPath.GetBounds()); using (Bitmap bitmap = new Bitmap(GPathArea.Width, GPathArea.Height)) using (Graphics graphics = Graphics.FromImage(bitmap)) { graphics.Clear(Color.White); graphics.TextRenderingHint = TextRenderingHint.AntiAliasGridFit; graphics.SmoothingMode = SmoothingMode.HighQuality; graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; graphics.FillPath(Brushes.Black, GPath); return (Bitmap)bitmap.Clone(); }}Why the rendering quality is, in this case, so different?All depends on the nature of the GDI+ resolution-independent grid-fitted rendering.From an obscure document, of Microsoft's origin, found on the WayBack Machine:GDI+ Text, Resolution Independence, and Rendering Methods.In an effort to compensates for Grid Fitting, trying to achieve the best appearance possible for a text, the typographic tracking (usually called letter-spacing), is modified.This "effort" seems to be pushed to the point of modifying the kerning pairs of the glyphs.In a proportional Font, the visual rendering has a benefit, but with a fixed size Font, the previously mentioned calculation produces a sort of grid-alignment, clearly visible when the same symbol is repeated multiple times.TextRenderer GDI methods, based on clear-type rendering - aimed to the visual rendering of text on screen - uses a sub-pixel representation of glyphs. The calculation of letter-spacing is completely different.Microsoft ClearType overview.The drawback is that this method of calculating the letter-spacing, makes it unsuited for printing from WinForms. MSDN documentation repeatedly states this.Other interesting resources on the subject:The Art of dev - Text rendering methods comparison or GDI vs. GDI+Why does my text look different in GDI+ and in GDI?GDI vs. GDI+ Text Rendering PerformanceSO answers:Why is Graphics.MeasureString() returning a higher than expected number?Modifying the kerning in System.Drawing.Graphics.DrawString()Application used to generate the ASCII-art text:ASCII Generator 2 on SourceForge (free software) 这篇关于在位图上绘制长字符串会导致绘制问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
09-05 14:13
查看更多