GDI+ for VCL基础 -- 画刷之TextureBrush

时间:2021-09-15 19:18:53
         本文为GDI+ for VCL基础系列文章之一,主要供GDI+初学者入门参考,例子使用GDI+版本下载地址和说明见《 GDI+ for VCL基础 -- GDI+ 与 VCL 》。如有错误或者建议请来信:maozefa@hotmail.com

        GDI+由二维矢量图形、图像和版面等三部分组成,其中的二维矢量图形的图元,包括点、线条、曲线和图形等的绘制工具就是画笔和画刷,而画笔的特征又是由画刷决定的(在以后的关于画笔的文章中介绍),因此,熟练地掌握GDI+的各种画刷特性和使用方法是绘制GDI+图形的前提条件。

        GDI+提供了SolidBrush(实色刷)、HatchBrush(阴影刷)、TextureBrush(纹理刷)、LinearGradientBrush(渐变刷)和PathGradientBrush(路径刷)等五种画刷,在GDI+ for VCL中,各种画刷在原C++类类名基础上加了TGp前缀,均派生于TGpBrush,其中的TGpSolidBrush和TGpHatchBrush相当于VCL中传统的GDI的画刷TBrush。

        GDI+ for VCL的TGpTextureBrush为纹理刷,也叫位图填充刷,顾名思义,是使用位图中的纹理来填充图形的画刷,假设图形GDI+ for VCL基础 -- 画刷之TextureBrush存储在磁盘文件MyTexture.bmp中,下面的代码将创建一个由MyTexture.bmp中存储的图片反复填充得到的椭圆:

var
  brush: TGpTextureBrush;
  Image: TGpImage;
begin
  Image :
= TGpImage.Create('MyTexture.bmp');
  brush :
= TGpTextureBrush.Create(Image);
  
// 假定TGpGraphics对象g已经建立
  g.FillEllipse(brush, 0010050);
  ......
end;

 GDI+ for VCL基础 -- 画刷之TextureBrush

        TGpTextureBrush的纹理填充效果不仅因不同的位图图案而异,也受各种设置的影响,同样的位图图案会产生各种不同的效果,下面谈谈影响填充效果的几个因素:

        1、绕行模式。GDI+ 定义的绕行模式 如下:

TWrapMode = (
  wmTile,          
// 平铺渐变或纹理。
  wmTileFlipX,  // 水平反转纹理或渐变,然后平铺该纹理或渐变。
  wmTileFlipY,  // 垂直反转纹理或渐变,然后平铺该纹理或渐变。
  wmTileFlipXY, // 水平和垂直反转纹理或渐变,然后平铺该纹理或渐变。
  wmClamp       // 将纹理和渐变向对象边界拉拢。
);

不同的绕行模式决定位图纹理的重复方式,如设置为wmTileFlipX,填充图案依次水平反转进行填充,缺省为wmTile。稍后给出例子。

        2、位图图案裁剪尺寸。这个很容易明白,同一个位图,使用的图案位置和大小对填充肯定有影响。

        3、几何变换。TGpTextureBrush可以设置全局和局部的几何变换,包括平移、缩放、旋转、切变以及各种组合变换,这将造成位图图案的变形,从而影响填充效果,如brush.RotateTransform(45);使得原填充图案旋转45度。填充图案也受TGpGraphics几何变换的影响,比如使用TGpGraphics.TranslateTransform方法后,图案填充将按相对坐标进行,否则会按绝对坐标填充,对于实际的图形位置,相对坐标和绝对坐标会影响填充的效果,因为TGpTextureBrush的图案填充是以坐标原点开始的,g.FillRectangle(brush, 10, 10, 100, 100);使用的是绝对坐标,填充将从图案的10,10点位置开始;而g.TranslateTransform(10, 10);g.FillRectangle(brush, 0, 0, 100, 100);图形输出到前面相同的位置,但是填充却是从图案的0,0点位置开始的。具体例子代码稍后给出。

        4、图像显示属性。建立TGpTextureBrush对象时,可以给定义个TGpImageAttributes(该类将会在以后的文章中具体讨论)对象,而这个对象的各种设置会对位图图案产生影响,如下面的代码会产生一个和前面例子中相同的半透明填充图案的椭圆图形:

const
  ColorMatrix: TColorMatrix 
=
   ((
1.00.00.00.00.0),
    (
0.01.00.00.00.0),
    (
0.00.01.00.00.0),
    (
0.00.00.00.50.0),
    (
0.00.00.00.01.0));
var
  brush: TGpTextureBrush;
  Image: TGpImage;
  attr: TGpImageAttributes;
begin
  Image :
= TGpImage.Create('MyTexture.bmp');
  attr :
= TGpImageAttributes.Create;
  attr.SetColorMatrix(ColorMatrix);  
  brush :
= TGpTextureBrush.Create(Image, GpRect(00, Image.Width, Image.Height), attr);
  
// 假定TGpGraphics对象g已经建立
  g.FillEllipse(brush, 0010050);
  ......
end;

        例子构造方法中的矩形就是参数就是设置位图图案的位置及大小,本例取全部图案。有关纹理刷TGpTextureBrush的介绍就到这里,下面给出例子片断和效果图:

        Delphi 例子:

procedure TForm1.FormCreate(Sender: TObject);
var
  backgroundImage: TGpImage;
begin
  backgroundImage :
= TGpBitmap.Create('....Mediamarble.jpg');
  
try
    FBackgroundBrush :
= TGpTextureBrush.Create(backgroundImage);
  
finally
    backgroundImage.Free;
  end;
  FShadowBrush :
= TGpSolidBrush.Create(ARGB(80, kcBlack));
  DoubleBuffered :
= True;
  PaintProc :
= TexturePaint;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FBackgroundBrush.Free;
  FShadowBrush.Free;
end;

procedure TForm1.PaintBox1Paint(Sender: TObject);
var
  g: TGpGraphics;
begin
  g :
= TGpGraphics.Create(PaintBox1.Canvas.Handle);
  
try
    g.FillRectangle(FBackgroundBrush, GpRect(PaintBox1.ClientRect));
    PaintProc(g);
  
finally
    g.Free;
  end;
end;

procedure TForm1.SetPaintProc(
const Value: TPaintProc);
begin
  FProc :
= Value;
  PaintBox1.Invalidate;
end;

procedure TForm1.TexturePaint(g: TGpGraphics);
var
  brush: TGpTextureBrush;
  Image: TGpImage;
  I: Integer;
begin
  Image :
= TGpImage.Create('....Mediacolorbars1.jpg');
  brush :
= TGpTextureBrush.Create(Image);
  Image.Free;
  
try
    
for I := 0 to 4 do
    begin
      
if I mod 2 = 0 then
      begin
        g.ResetTransform;
        g.TranslateTransform(
-165, I div 2 * 94 + 10);
      end;
      g.TranslateTransform(
1750);
      brush.WrapMode :
= TWrapMode(I);
      g.FillRectangle(FShadowBrush, 
3316585);
      g.FillRectangle(brush, 
0016585);
    end;
    
// 旋转45度
    brush.RotateTransform(45);
    brush.WrapMode :
= wmTile;
    g.TranslateTransform(
1750);
    g.FillRectangle(FShadowBrush, 
3316585);
    g.FillRectangle(brush, 
0016585);
  
finally
    brush.Free;
  end;
end;

 代码中的PaintProc是个过程属性。注意例子中的图案填充是按相对坐标进行的。

        C++ Builder 例子:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
    TGpImage 
*backgroundImage = new TGpBitmap("../../Media/marble.jpg");
    
try
    {
        FBackgroundBrush 
= new TGpTextureBrush(backgroundImage);
    }
    __finally
    {
        delete backgroundImage;
    }
    FShadowBrush 
= new TGpSolidBrush(TGpColor(80, kcBlack));
    DoubleBuffered 
= true;
    PaintProc 
= &TexturePaint;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
    delete FBackgroundBrush;
    delete FShadowBrush;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::SetPaintProc(const TPaintProc Value)
{
    FProc 
= Value;
    PaintBox1
->Invalidate();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::PaintBox1Paint(TObject *Sender)
{
    TGpGraphics 
*= new TGpGraphics(PaintBox1->Canvas->Handle);
    
try
    {
        g
->FillRectangle(FBackgroundBrush, TGpRect(PaintBox1->ClientRect));
        PaintProc(g);
    }
    __finally
    {
        delete g;
    }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::TexturePaint(TGpGraphics *g)
{
    TGpImage 
*Image = new TGpImage("../../Media/colorbars1.jpg");
    TGpTextureBrush 
*brush = new TGpTextureBrush(Image);
    delete Image;
    
try
    {
        
for (int I = wmTile; I <= wmClamp; I ++)
        {
            
if (I % 2 == 0)
            {
                g
->ResetTransform();
                g
->TranslateTransform(-165, I / 2 * 94 + 10);
            }
            g
->TranslateTransform(1750);
            brush
->WrapMode = (TWrapMode)I;
            g
->FillRectangle(FShadowBrush, 3316585);
            g
->FillRectangle(brush, 0016585);
        }
        brush
->RotateTransform(45);
        brush
->WrapMode = wmTile;
        g
->TranslateTransform(1750);
        g
->FillRectangle(FShadowBrush, 3316585);
        g
->FillRectangle(brush, 0016585);
    }
    __finally
    {
        delete brush;
    }
}
//---------------------------------------------------------------------------

效果图:

              GDI+ for VCL基础 -- 画刷之TextureBrush

效果图中,左上为wmTile模式,图案循环填充;右上为wmTileFlipX模式,图案依次水平反转填充;左中为wmTileFlipY模式,图案依次垂直反转填充;右中是wmTileFlipXY,图案水平和垂直方向同时反转填充;左下是wmClamp模式,非平铺填充方式,所以只填充了一个图案,如果使用绝对坐标,由于该位置远离原点,图案将不可见;右下则是wmTile模式,画刷旋转45度后的输出效果。