WPF and Silverlight 学习笔记(二十七):基本图形的使用(2)Path和位图操作

在上一篇文章中主要讨论的是除Path之外的基本图形,本文主要讨论使用Path创建更加复杂的图形以及位图的处理。

一、使用Path构建复杂图形

Path所构建的图形由Data属性来定义,其属性的类型为Geometry(几何类),几何类类型的继承关系请参考我上一篇文章。例如要创建一个100*30的矩形,可以有两种做法:

   1: <StackPanel>
   2:     <!--使用Rectangle直接创建矩形图形-->
   3:     <Rectangle Fill="Red" Width="100" Height="30" HorizontalAlignment="Left" />
   4:     <!--使用Path创建矩形图形-->
   5:     <Path Fill="Blue">
   6:         <Path.Data>
   7:             <RectangleGeometry Rect="0,0,100,30" />
   8:         </Path.Data>
   9:     </Path>
  10: </StackPanel>

从上面的代码来看,如果创建单一的图形,使用相应的图形类更简单,但是通过Path可以构建更加复杂的图形,例如想创建一个圆环,一种做法是使用两个圆形构建,另一种做法就是例如Path,可以直接绘制出圆环:

   1: <Grid>
   2:     <Grid.RowDefinitions>
   3:         <RowDefinition />
   4:         <RowDefinition />
   5:     </Grid.RowDefinitions>
   6:     <!--使用两个圆形叠加出圆环,但要受到其所有容器的限制-->
   7:     <Canvas Grid.Row="0">
   8:         <Ellipse Fill="Red" Canvas.Left="10" Canvas.Top="10"
   9:                  Width="100" Height="100" />
  10:         <Ellipse Fill="White" Canvas.Left="35" Canvas.Top="35"
  11:                  Width="50" Height="50" />
  12:     </Canvas>
  13:     <!--直接使用Path构建圆环-->
  14:     <Canvas Grid.Row="1">
  15:         <Path Fill="Red">
  16:             <Path.Data>
  17:                 <GeometryGroup>
  18:                     <!--Center为圆心的坐标,RadiusX、RadiusY分别为X、Y两轴的半径-->
  19:                     <EllipseGeometry RadiusX="50" RadiusY="50"
  20:                                      Center="60,60" />
  21:                     <EllipseGeometry RadiusX="25" RadiusY="25"
  22:                                      Center="60,60" />
  23:                 </GeometryGroup>
  24:             </Path.Data>
  25:         </Path>
  26:     </Canvas>
  27: </Grid>

27-1

另外,由于第一种做法是一种“虚假”的圆环,所以,当给两个圆环所在的Canvas添加背景时,第一种做法的圆环不能出现“镂空”的效果,例如为两个Canvas添加如下的背景图片:

   1: <Canvas.Background>
   2:     <ImageBrush ImageSource="Images/Logo.png" Stretch="Uniform" />
   3: </Canvas.Background>

效果为:

27-2

此外Path还可以构建很多更复杂的图形,在这里就不一一列举了,请感兴趣的朋友自行尝试。

二、位图操作

WPF支持以下格式的位图:BMP、JPEG、PNG、TIFF、Windows Media Photo、GIF和ICO。在System.Windows.Media.Imaging命名空间定义了一系列处理图像文件的类型,其中最常使用的是Image类处理位图。

使用Image类型的Source属性加载图片,Source属性的类型是ImageSource类型。ImageSource有两个子类DrawingImage和BitmapSource,分别用来处理不依赖分辨率的图画对象和依赖分辨率的图画对象(位图)。其继承关系如下图所示:

27-3

1、使用BitmapImage加载图片

BitmapImage类型是Image类型Source属性默认的类型,它用来加载已存在的图片,这个图片可以是存放在网络上的,也可以是本地或项目资源中的图片,例如:

   1: <StackPanel Orientation="Horizontal">
   2:     <!--使用绝对URL定位网络上的图片-->
   3:     <Image Source="http://www.cnblogs.com/images/logo.gif" 
   4:        Margin="10"/>
   5:     <!--使用绝对URL定位本地计算机上的图片-->
   6:     <Image Source="D:\Pictures\mct.gif" 
   7:        Margin="10"/>
   8:     <!--使用相对URL定位到项目中的资源图片-->
   9:     <Image Source="Images/Logo.png"
  10:            Margin="10"/>
  11: </StackPanel>

27-4

2、使用RenderTargetBitmap创建图片

使用RenderTargetBitmap可以自定义任意一个Visual类型的子类,将其作为图片的内容,创建一个ImageSource,供界面显示,例如创建一个红色的五角星:

XAML代码如下:

   1: <Window x:Class="WPF_27.Window4"
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:     Title="Window4" Height="250" Width="250">
   5:     <Canvas Background="Yellow" Width="200" Height="200">
   6:         <Image x:Name="img" Stretch="None"/>
   7:     </Canvas>
   8: </Window>

在后台的代码中:

   1: private void DrawImage()
   2: {
   3:     // 创建一个RenderTargetBitmap对象
   4:     RenderTargetBitmap bmp = new RenderTargetBitmap(
   5:         200, 200,       // 设置图片的大小(单位为像素)
   6:         96, 96,         // 设置图片的水平及竖直分辨率
   7:                         //(注间此处应与系统定义的DPI相同,否则会出现图形异常)
   8:         PixelFormats.Pbgra32);  // 图片的格式
   9:  
  10:     // 定义五角星的五个顶点
  11:     Point p1 = new Point(
  12:         100 + 100 * Math.Sin(0),
  13:         100 - 100 * Math.Cos(0));
  14:     Point p2 = new Point(
  15:         100 + 100 * Math.Sin(2 * Math.PI / 5),
  16:         100 - 100 * Math.Cos(2 * Math.PI / 5));
  17:     Point p3 = new Point(
  18:         100 + 100 * Math.Sin(2 * Math.PI * 2 / 5),
  19:         100 - 100 * Math.Cos(2 * Math.PI * 2 / 5));
  20:     Point p4 = new Point(
  21:         100 + 100 * Math.Sin(2 * Math.PI * 3 / 5),
  22:         100 - 100 * Math.Cos(2 * Math.PI * 3 / 5));
  23:     Point p5 = new Point(
  24:         100 + 100 * Math.Sin(2 * Math.PI * 4 / 5),
  25:         100 - 100 * Math.Cos(2 * Math.PI * 4 / 5));
  26:  
  27:     
  28:     // 定义红色的五角星
  29:     Polygon p = new Polygon();
  30:     p.Fill = new SolidColorBrush(Colors.Red);
  31:     p.FillRule = FillRule.Nonzero;
  32:  
  33:     p.Points.Add(p1);
  34:     p.Points.Add(p3);
  35:     p.Points.Add(p5);
  36:     p.Points.Add(p2);
  37:     p.Points.Add(p4);
  38:  
  39:     // 定义圆
  40:     Ellipse e = new Ellipse();
  41:     e.Stroke = new SolidColorBrush(Colors.Red);
  42:     e.Width = 200;
  43:     e.Height = 200;
  44:  
  45:     Canvas.SetLeft(p,0);
  46:     Canvas.SetTop(p,0);
  47:     Canvas.SetLeft(e,0);
  48:     Canvas.SetTop(e,0);
  49:  
  50:     // 定义承载两个图形的Canvas对象
  51:     Canvas c = new Canvas();
  52:     c.Background = new SolidColorBrush(Colors.Yellow);
  53:     c.Children.Add(e);
  54:     c.Children.Add(p);
  55:  
  56:     // 处理其显示的大小及位置
  57:     c.Measure(new Size(200, 200));
  58:     c.Arrange(new Rect(0, 0, 200, 200));
  59:  
  60:     // 生成图片并显示
  61:     bmp.Render(c);
  62:     img.Source = bmp;
  63: }

执行之后的效果如下图所示:

27-5

在此处要注意显示器的像素和分辨率的关系,有关两者间的关系,园子中有一篇文章写的比较清楚,大家可以参考:

http://www.cnblogs.com/helloj2ee/archive/2009/04/21/1440709.html

3、为图片添加水印

例如,对上节第二张图片加水印,可以使用如下代码:

   1: private void ShowPicture()
   2: {
   3:     BitmapImage source = new BitmapImage();
   4:     source.BeginInit();
   5:     // 获取网络上的一张图片
   6:     source.UriSource =
   7:         new Uri(
   8:             "http://images.cnblogs.com/cnblogs_com/DragonInSea/" + 
   9:             "WindowsLiveWriter/WPFandSilverlight1_B8D5/26-2_6.png");
  10:  
  11:     // 当图片下载完成后,对源图片加水印
  12:     source.DownloadCompleted += delegate
  13:     {
  14:         // 源图片
  15:         Image backImage = new Image();
  16:         backImage.Source = source;
  17:  
  18:         // 水印
  19:         TextBlock water = new TextBlock();
  20:         water.Text = "Dragon In Sea";
  21:         water.FontSize = 24;
  22:         water.FontFamily = new FontFamily("Consolas");
  23:         water.Background = new SolidColorBrush(Color.FromArgb(128, 0, 0, 0));
  24:         water.Foreground = Brushes.Gold;
  25:  
  26:         Canvas.SetLeft(backImage,0);
  27:         Canvas.SetTop(backImage,0);
  28:  
  29:         Canvas.SetLeft(water, source.Width - 200);
  30:         Canvas.SetTop(water,source.Height-50);
  31:  
  32:         // 将源图片与水印添加到同一个Canvas容器中
  33:         Canvas canvas = new Canvas();
  34:         canvas.Children.Add(backImage);
  35:         canvas.Children.Add(water);
  36:  
  37:         canvas.Measure(new Size(source.Width, source.Height));
  38:         canvas.Arrange(new Rect(0, 0, source.Width, source.Height));
  39:  
  40:         // 显示全成后的图片
  41:         RenderTargetBitmap newImage = new RenderTargetBitmap(
  42:             (int)source.Width, (int)source.Height,
  43:             source.DpiX, source.DpiY,
  44:             PixelFormats.Pbgra32);
  45:         newImage.Render(canvas);
  46:  
  47:         img.Source = newImage;
  48:     };
  49:  
  50:     source.EndInit();
  51: }

执行的结果如下图所示:

27-6

用此方法,不更改源图片,显示出来的是合成后的图片。

下一篇,我们将继续讨论对于图片的操作。

posted @ 2009-06-16 16:18  龙腾于海  阅读(6923)  评论(3编辑  收藏  举报