BLOG.CSHARPHELPER.COM: Draw text filled with rainbow colors in C#
Draw text filled with rainbow colors in C#
In this form's Paint event handler, the program uses the Graphics object's DrawString method to draw some text. The brush it uses to draw the text is a LinearGradientBrush filled with a rainbow of colors. The trickiest part of the code is figuring out exactly where the text will actually appear so the colors cover it nicely. If you define the brush so the colors fill an area that's too big, then the text doesn't use some of the outlying colors such as red and indigo.
To figure out where the text will appear, the code calculates the font's metrics. (See my book Visual Basic 2010 Programmer's Reference for a detailed discussion but briefly these values are:
internal_leading
Space above the characters that is still considered part of the character's height
em_height
The height of the characters from below the internal_leading to the bottom of the descenders (for example, where g and j descend below the baseline)
ascent
The height of the characters from the baseline to the top of the drawing area including the internal leading
descent
The distance the characters may extend below the baseline
cell_height
The total height of the text from bottom to top including the internal leading and descent
line_spacing
The distance between the top of one line of text and the top of the next line of text
external_leading
The distance between the bottom of one line of text (including descent) and the top of the next line of text (including internal leading)
After calculating the font metrics, the code determines where the actual text will be drawn. The text in this example doesn't use descenders (letters such as j and y that descend below the baseline) so the text goes from below the internal leading to the baseline. However real fonts often leave extra space below the internal leading, drop below the baseline, and otherwise violate their metrics slightly. The ways this happens depends on the particular font and its characteristics (bold, italic, and so forth). This example fudges the drawing area down a bit to get a better fit to the actual text.
The code makes a linear gradient brush to fill the text area. It shades the colors red, orange, yellow, green, blue, and indigo (violet looked too pale) over this area. The code maps red and indigo to two positions at the ends of the region so the top of the characters is a bit extra red and the bottom is a tad extra indigo.
Finally, the code draws the text using the rainbow brush. Extra debugging code draws the text's drawing area, internal leading line, baseline, and descent line.
// Make the result smoother. e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
// Make a font. using (Font the_font = new Font("Times New Roman", 150, FontStyle.Bold, GraphicsUnit.Pixel)) { // Get font metrics. // (For a detailed explanation of font metrics, see // my book "Visual Basic 2010 Programmer's Reference." // See www.vb-helper.com/vb_prog_ref.htm // for more about the book.) int em_height = the_font.FontFamily.GetEmHeight(FontStyle.Bold); float em_height_pix = the_font.Size; float design_to_pixels = the_font.Size / em_height; int ascent = the_font.FontFamily.GetCellAscent(FontStyle.Bold); float ascent_pix = ascent * design_to_pixels; int descent = the_font.FontFamily.GetCellDescent(FontStyle.Bold); float descent_pix = descent * design_to_pixels; float cell_height_pix = ascent_pix + descent_pix; float internal_leading_pix = cell_height_pix - em_height_pix; int line_spacing = the_font.FontFamily.GetLineSpacing(FontStyle.Bold); float line_spacing_pix = line_spacing * design_to_pixels; float external_leading_pix = line_spacing_pix - cell_height_pix;
// See how big the text is. SizeF text_size = e.Graphics.MeasureString(TXT, the_font); int x0 = (int)((this.ClientSize.Width - text_size.Width) / 2); int y0 = (int)((this.ClientSize.Height - text_size.Height) / 2);
// Get the Y coordinates that the brush should span. int brush_y0 = (int)(y0 + internal_leading_pix); int brush_y1 = (int)(y0 + ascent_pix);
// Fudge the brush down a smidgen. brush_y0 += (int)(internal_leading_pix); brush_y1 += 5;
// Make a brush to color the area. using (LinearGradientBrush the_brush = new LinearGradientBrush( new Point(x0, brush_y0), new Point(x0, brush_y1), Color.Red, Color.Violet)) { ColorBlend color_blend = new ColorBlend(); color_blend.Colors = new Color[] { Color.Red, Color.Red, Color.Orange, Color.Yellow, Color.Green, Color.Blue, Color.Indigo, Color.Indigo }; color_blend.Positions = new Single[] { 0f, 1 / 7f, 2 / 7f, 3 / 7f, 4 / 7f, 5 / 7f, 6 / 7f, 1f }; the_brush.InterpolationColors = color_blend;
Comments