WPF中GDI+图形图像的绘制:(一)绘制文本——动态设置字体、大小、颜色
GDI+(Graphics Device Interface Plus图形设备接口加)是.NET框架的重要组成部分,负责在屏幕和打印机上绘制图形图像和显示信息。GDI+不但在功能上比GDI 要强大很多,而且在代码编写方面也更简单,因此很快成为了Windows图形图像程序开发的首选。
从程序设计的角度看,GDI包括两部分:GDI对象和GDI函数。GDI对象定义了GDI函数使用的工具和环境变量;而GDI函数使用GDI对象绘制各种图形。
GDI+主要提供了以下三种功能:
1)二维矢量图形;2)图像处理;3)文字显示版式。
图形类Graphics是GDI+的核心,它提供绘制图形、图像和文本的各种方法(操作/函数),还可以存储显示设备和被画项目的属性(到图元文件)。所有的画图方法都被包括在Graphics类中,在绘制任何对象时,我们首先要创建一个Ggraphics实例,这个实例相当于创建了一块画布,有了画布才可以使用各种画图方法绘图。
下面主要通过创建实例并不断丰富完善的方式来简单介绍GDI+图形图像绘制中的一些概念与技巧,首先是绘制文本,实现效果如图:
1、新建WPF应用程序DrawDemo。
添加System.Drawing的引用,System.Drawing命名空间提供了对 GDI+ 基本图形功能的访问权限。
在主窗体添加一个Canvas控件。Canvas是WPF里基本的面板,它是一个存储控件的容器,主要用途是用来画图。通过设置ClipToBounds=”True”来裁剪超过自身范围的内容。设置HorizontalAlignment="Left",VerticalAlignment="Top"来设置以左上角为中心。
2、分别添加其他控件用来设置字体类型、大小、颜色。由于WPF中没有NumericUpDown控件,这里采用添加Winform控件的方式。
窗体xaml如下:
<Window x:Class="DrawDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DrawDemo"
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
mc:Ignorable="d"
WindowStartupLocation="CenterScreen" ResizeMode="NoResize"
Title="GDI+文本绘制" Height="768" Width="1280" Loaded="Window_Loaded">
<Grid Background="#f0f0f0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition ></ColumnDefinition>
</Grid.ColumnDefinitions>
<Canvas x:Name="mainCanvas" Grid.Column="0" Background="White" Width="960" Height="720" Margin="10,5,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
ClipToBounds="True">
<Image x:Name="imgFont"></Image>
</Canvas>
<Grid Grid.Column="1" Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="文本" VerticalAlignment="Center" HorizontalAlignment="Left"></Label>
<TextBox x:Name="tbFontText" Grid.Row="0" Grid.Column="1" Height="26" Width="180" VerticalAlignment="Center" HorizontalAlignment="Left" TextChanged="tbFontText_TextChanged"></TextBox>
<Label Grid.Row="1" Grid.Column="0" Content="选择字体" VerticalAlignment="Center" HorizontalAlignment="Left"></Label>
<ComboBox x:Name="cbFontName" Grid.Row="1" Grid.Column="1" Height="26" Width="180" VerticalAlignment="Center" HorizontalAlignment="Left" SelectionChanged="cbFontName_SelectionChanged"></ComboBox>
<Label Grid.Row="2" Grid.Column="0" Content="字体大小" VerticalAlignment="Center" HorizontalAlignment="Left"></Label>
<WindowsFormsHost Grid.Row="2" Grid.Column="1" Height="26" Width="180" VerticalAlignment="Center" HorizontalAlignment="Left">
<wf:NumericUpDown x:Name="numFontSize" Value="50" Maximum="1000" Minimum="1" ValueChanged="numFontSize_ValueChanged"/>
</WindowsFormsHost>
<Label Grid.Row="3" Grid.Column="0" Content="字体颜色" VerticalAlignment="Center" HorizontalAlignment="Left"></Label>
<Rectangle x:Name="rFontColor" Grid.Row="3" Grid.Column="1" Fill="Black" Width="30" Height="30" VerticalAlignment="Center" HorizontalAlignment="Left" MouseLeftButtonDown="rFontColor_MouseLeftButtonDown"></Rectangle>
</Grid>
</Grid>
</Window>
3、为了更方便的绘制,抽象出FontItem类,来控制字体的绘制。代码如下:
using System.Windows.Media;
namespace DrawDemo.Root
{
public class FontItem
{
private string text; // 字体内容
private string fontName; // 字体名称
private int fontSize; // 字体大小
private Color fontColor; // 字体颜色
public string Text
{
get
{
return text;
}
set
{
text = value;
}
}
public string FontName
{
get
{
return fontName;
}
set
{
fontName = value;
}
}
public int FontSize
{
get
{
return fontSize;
}
set
{
fontSize = value;
}
}
public Color FontColor
{
get
{
return fontColor;
}
set
{
fontColor = value;
}
}
}
}
4、主窗体交互逻辑:
(1)设置全局字体变量;
private FontItem fontItem;
(2)在窗体Loaded事件里加载本地字体;
/// <summary>
/// 加载本地字体
/// </summary>
private void InitFontName()
{
try
{
InstalledFontCollection insFont = new InstalledFontCollection();
System.Drawing.FontFamily[] families = insFont.Families;
foreach (System.Drawing.FontFamily family in families)
{
this.cbFontName.Items.Add(family.Name);
}
this.cbFontName.SelectedItem = "宋体";
}
catch (Exception)
{
}
}
(3)在TextChanged事件中设置需要绘制的字体,并实现文本绘制,其中TextRenderingHint设置为AntiAliasGridFit,可查看博客WPF字体模糊解决方案;ImageHelper.cs类可查看WPF封装一个常用图片加载、保存、类型转换的类。
/// <summary>
/// 文本改变
/// </summary>
private void tbFontText_TextChanged(object sender, TextChangedEventArgs e)
{
GetFontItem(this.tbFontText.Text.Trim());
DrawText();
}
/// <summary>
/// 设置需要绘制的字体
/// </summary>
private void GetFontItem(string text)
{
if (text.Length <= 0)
{
fontItem = null;
return;
}
fontItem = new FontItem();
fontItem.FontColor = ((SolidColorBrush)this.rStrokeColor.Fill).Color;
fontItem.FontName = this.cbFontName.SelectedValue.ToString();
fontItem.FontSize = (int)this.numFontSize.Value;
fontItem.Text = text;
}
/// <summary>
/// 绘制字体
/// </summary>
private void DrawText()
{
try
{
if (fontItem == null)
{
this.imgFont.Source = null;
return;
}
System.Drawing.Font fontText = new System.Drawing.Font(fontItem.FontName, fontItem.FontSize);
System.Drawing.Size sizeText = System.Windows.Forms.TextRenderer.MeasureText(fontItem.Text, fontText, new System.Drawing.Size(0, 0), System.Windows.Forms.TextFormatFlags.NoPadding);
Rect viewport = new Rect(0, 0, sizeText.Width, sizeText.Height);
if ((int)viewport.Width == 0 || (int)viewport.Height == 0)
return;
System.Drawing.Bitmap tempMap = new System.Drawing.Bitmap((int)viewport.Width, (int)viewport.Height);
System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(tempMap);
g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAliasGridFit;
g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
System.Drawing.RectangleF rect = new System.Drawing.RectangleF(0, 0, sizeText.Width, sizeText.Height);
System.Drawing.Drawing2D.GraphicsPath path = new System.Drawing.Drawing2D.GraphicsPath();
path.AddString(fontItem.Text, fontText.FontFamily, (int)fontText.Style, fontText.Size, rect, System.Drawing.StringFormat.GenericDefault);
g.FillPath(new System.Drawing.SolidBrush(System.Drawing.Color.FromArgb(fontItem.FontColor.A, fontItem.FontColor.R, fontItem.FontColor.G, fontItem.FontColor.B)), path);
path.Dispose();
BitmapImage tempImage = ImageHelper.BitmapToBitmapImage(tempMap,System.Drawing.Imaging.ImageFormat.Png);
g.Dispose();
tempMap.Dispose();
if (tempImage != null)
{
this.imgFont.Source = tempImage;
this.imgFont.Width = tempImage.Width;
this.imgFont.Height = tempImage.Height;
Canvas.SetLeft(this.imgFont, (this.mainCanvas.ActualWidth - tempImage.Width) / 2);
Canvas.SetTop(this.imgFont, (this.mainCanvas.ActualHeight - tempImage.Height) / 2);
}
}
catch (Exception ex)
{
return;
}
}
(4)分别实现字体、大小、颜色设置,其中颜色选择窗体参见WPF实现简单的颜色调色板功能;
/// <summary>
/// 字体选择
/// </summary>
private void cbFontName_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if(fontItem != null)
{
fontItem.FontName = this.cbFontName.SelectedValue.ToString();
DrawText();
}
}
/// <summary>
/// 字体大小
/// </summary>
private void numFontSize_ValueChanged(object sender, EventArgs e)
{
if (fontItem != null)
{
fontItem.FontSize = (int)this.numFontSize.Value;
DrawText();
}
}
/// <summary>
/// 字体颜色
/// </summary>
private void rFontColor_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
ColorSelectorWindow csw = new ColorSelectorWindow();
csw.ShowDialog();
if (fontItem != null)
{
fontItem.FontColor = csw.returnSelectColor;
this.rFontColor.Fill = new SolidColorBrush(csw.returnSelectColor);
DrawText();
}
}