Title: Draw text with colors reversed along a sine wave in C#
The post Draw text with colors reversed along a diagonal line in C# demonstrated a general technique for splitting text (or any other image) into pieces that are drawn differently. That example showed how to draw text with some areas drawn with inverted colors.
The general approach is to draw text in different color schemes on different bitmaps. Then use those bitmaps to make TextureBrushes and use the brushes to fill different parts of the final image.
This example uses the following method to draw text above and below a sine curve differently.
// Draw sine split text centered in the indicated rectangle.
private void DrawSineSplitText(Graphics gr,
string text, Font font, Rectangle rect,
Brush top_bg_brush, Brush top_fg_brush,
Brush bottom_bg_brush, Brush bottom_fg_brush,
float num_waves, float y_scale)
{
// Make bitmaps holding the text in different colors.
Bitmap bm_top = new Bitmap(rect.Width, rect.Height);
Bitmap bm_bottom = new Bitmap(rect.Width, rect.Height);
// Make a StringFormat to center text.
using (StringFormat sf = new StringFormat())
{
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
using (Graphics gr_top = Graphics.FromImage(bm_top))
{
gr_top.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
gr_top.FillRectangle(top_bg_brush, rect);
gr_top.DrawString(text, font, top_fg_brush, rect, sf);
}
using (Graphics gr_bottom = Graphics.FromImage(bm_bottom))
{
gr_bottom.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
gr_bottom.FillRectangle(bottom_bg_brush, rect);
gr_bottom.DrawString(text, font, bottom_fg_brush, rect, sf);
}
}
// Fill the rectangle with the top bitmap.
using (TextureBrush brush = new TextureBrush(bm_top))
{
gr.FillRectangle(brush, rect);
}
// Make a polygon to fill the bottom half.
List<PointF> points = new List<PointF>();
float mag = (font.Size * 96f / 72f) / 2 * y_scale;
float y_offset = rect.Height / 2f;
points.Add(new PointF(0, rect.Height));
float x_scale = (float)(num_waves * 2 * Math.PI / rect.Width);
for (int x = 0; x < rect.Width; x++)
{
float y = (float)(y_offset + mag * Math.Sin(x * x_scale));
points.Add(new PointF(x, y));
}
points.Add(new PointF(rect.Width - 1, rect.Height));
// Fill the polygon.
using (TextureBrush brush = new TextureBrush(bm_bottom))
{
gr.SmoothingMode = SmoothingMode.AntiAlias;
gr.FillPolygon(brush, points.ToArray());
}
bm_top.Dispose();
bm_bottom.Dispose();
}
The method starts by making the two bitmaps. It creates a StringFormat object to center text and then draws text using the desired foreground and background colors onto the bitmaps.
Next, the method makes a TextBrush out of the first bitmap and uses it to fill the drawing area.
The method then creates a List<PointF> and adds a point at the lower left corner of the image. It loops through X values for the result image's pixels. For each X coordinate, the code uses the sine function to calculates a Y value. It scales the X values passed into the sine function to give the waves a nice width. It also scales the Y result so the curve passes through the middle part of the text. After it calculates the Y coordinate, the code adds the point to the points list.
After it has finished generating the points, the code adds a point at the lower right corner of the image. Together the points define a polygon that encloses the space below the sine curve on the image. The method uses the second bitmap to create a TextureBrush and then uses it to fill the polygon.
You can use similar techniques to color different parts of other images in various ways. The only trick is creating the polygons, rectangles, ellipses, or other shapes that define the pieces of the image that should be colored differently.
Download the example to experiment with it and to see additional details.
|