GDI+ without training and a really good book or two is like being handed all the
tools necessary to build a rocket and not being shown how. Tons of capability
with absolutely no clue (or useful documentation from Mr. Bill Gates) how to
use it. You can imagine my journey over the last few days after being asked
to incorporate highly flexbile color branding to a rather powerful survey web
site tool I've been working on.
Essentially, our marketing department wants to have user settings for changing button
background color, button color, button gradient fade color, text color, etc...
for every possible hex color combination. Plus, they want rounded rectangles
similar to XP for buttons and special text sections inside color filled rounded
text areas. Knowing just how flexible this would need to be, I opted to put
together a branding class to draw the graphics at runtime. Plus, I also whipped
up an http handler page to draw the objects and use the image url as a unique
key to cache the images if they haven't been drawn yet.
Here's a sample of a rounded rectangle. This has no fancy formatting or effects. I'll
be posting tips in the near future regarding the use of textures and gradients.
The following code sample is a small excerpt from my project. It is also well suited
for implementation in our desktop tools that will soon require similar functionality. The
drawing strategy I used was to draw an arc for all 4 corners, place a rectangle
in the middle, and use the GraphicsPath object to meld them together and fill
the contents. Let's check out the code below:
// How To Call Method
// Not all of the properties shown here are actually used in the sample
// method. I have many methods for drawing other shapes and
effects not
// shown here.
var ImgSetting = new Branding.Images.Settings();
ImgSetting.BackGroundColor = Color.White;
ImgSetting.BackColor = ColorTranslator.FromHtml("#6699ff");
ImgSetting.ForeColor = Color.Black;
ImgSetting.TextColor = Color.White;
ImgSetting.Height = 30;
ImgSetting.Width = 190;
ImgSetting.Text
= "Save And Return Later";
ImgSetting.TextFont = new Font("Arial",10,FontStyle.Bold,GraphicsUnit.Point);
ImgSetting.ApplyGlass = false;
ImgSetting.ApplyBorder = true;
ImgSetting.ApplyInternalFill = true;
ImgSetting.BorderColor = ColorTranslator.FromHtml("#000000");
var oTest = Branding.Images.GetRoundedRectangle(ImgSetting);
this.pictureBox1.Image = oTest;
// Method Source Code
using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.Drawing.Text;
using Branding;
namespace Branding
{
public class Images
{
public Images()
{
}
#region Settings
public struct Settings
{
public Color BackGroundColor;
public Color BackColor;
public Color ForeColor;
public Color TextColor;
public Color BorderColor;
public Font TextFont;
public string Text;
public int Width;
public int Height;
public bool ApplyGlass;
public bool ApplyInternalFill;
public bool ApplyBorder;
}
#endregion
#region Get Rounded Rectangle
public static Bitmap GetRoundedRectangle(Branding.Images.Settings ImageSetting)
{
// Define the size of the rectangle used for each of the 4 arcs.
Size CornerSize = new Size(10,10);
// Define the buffer between the rounded rectangle and the image itself.
int x = 5;
int y = 5;
// Set positions for the arcs and center positions for the rectangle
int w = ImageSetting.Width;
int h = ImageSetting.Height;
int xr = Convert.ToInt32(w - (x + CornerSize.Width));
int yr = Convert.ToInt32(h - (y + CornerSize.Height));
int iw = Convert.ToInt32(w - xr);
int ih = Convert.ToInt32(h - yr);
// Standard angle for each arc.
float sweepAngle = 90.0f;
Bitmap bm = null;
SolidBrush fillBrush;
Color FillColor;
// Create a new bitmap from scratch
bm = new Bitmap(w,h,PixelFormat.Format32bppArgb);
Graphics g = Graphics.FromImage(bm);
// Give us fairly high line quality.
g.SmoothingMode = SmoothingMode.AntiAlias;
// Create a rectangle for the background of the image
Rectangle bgImg = new Rectangle(0,0,w,h);
// Fill the entire image with our image background color
SolidBrush bgBrush = new SolidBrush(ImageSetting.BackGroundColor);
g.FillRectangle(bgBrush,bgImg);
bgBrush.Dispose();
// Create 4 10 x 10 rectangles for our arcs to fit in. tl=topleft, br=bottomright
Rectangle tl = new Rectangle(x,y,CornerSize.Width,CornerSize.Height);
Rectangle tr = new Rectangle(xr,y,CornerSize.Width,CornerSize.Height);
Rectangle bl = new Rectangle(x,yr,CornerSize.Width,CornerSize.Height);
Rectangle br = new Rectangle(xr,yr,CornerSize.Width,CornerSize.Height);
// Create an inner rectangle to fill the middle
Rectangle innerRect = new Rectangle(x,CornerSize.Width,x + xr,yr - y);
// Here's how it is all bound together. We need to add the arcs and the
// inner rectangle to a single GraphicsPath object. This allows us to
call
// the .FillPath method to only fill in the section inside the arcs and our rectangle.
GraphicsPath path = new System.Drawing.Drawing2D.GraphicsPath();
path.AddArc(tl,
180, sweepAngle);
path.AddArc(tr,
270, sweepAngle);
path.AddRectangle(innerRect);
path.AddArc(bl, 90, sweepAngle);
path.AddArc(br,
360, sweepAngle);
if (ImageSetting.ApplyInternalFill)
{
FillColor = ImageSetting.BackColor;
}
else
{
FillColor = ImageSetting.BackGroundColor;
}
fillBrush = new SolidBrush(FillColor);
// Connect all border lines drawn in the entire path
path.CloseAllFigures();
g.FillPath(fillBrush,path);
fillBrush.Dispose();
if (ImageSetting.ApplyBorder)
{
// If we want a border, we'll need draw the path first and then
// draw a horizontal line at the top of our inner rectangle and again
// at the bottom with the same color as our rectangle fill color to hide
// extra lines drawn above in the path.CloseAllFigures() method.
Pen borderPen = new Pen(ImageSetting.BorderColor, 1);
Pen fillPen = new Pen(FillColor, 1);
g.DrawPath(borderPen,path);
g.DrawLine(fillPen,innerRect.Left + 1,innerRect.Top,innerRect.Width + (x-1),innerRect.Top);
g.DrawLine(fillPen,innerRect.Left + 1,innerRect.Bottom,innerRect.Width + (x-1),innerRect.Bottom);
fillPen.Dispose();
borderPen.Dispose();
}
if (ImageSetting.Text.Length > 0)
{
// If our image has text, draw it using the Font passed in and center the
// text vertically and horizontally against our innerRect rectangle.
SolidBrush TextBrush
= new SolidBrush(ImageSetting.TextColor);
StringFormat
sf = new StringFormat();
sf.Alignment
= StringAlignment.Center;
sf.Trimming
= StringTrimming.EllipsisCharacter;
sf.LineAlignment
= StringAlignment.Center;
g.TextRenderingHint
= TextRenderingHint.AntiAliasGridFit;
g.DrawString(ImageSetting.Text,ImageSetting.TextFont,TextBrush,innerRect,sf);
TextBrush.Dispose();
sf.Dispose();
}
g.Dispose();
return bm;
}
#endregion
}
}
}