在 GDI+ 中应用矩阵变换





5.00/5 (2投票s)
使用 GDI+ 实现 PowerPoint 等应用中的“将图片填充到形状”选项的步骤。
引言
在开发一个使用 GDI+ 绘制高级图形的应用程序时,我遇到了一个需求,即绘制椭圆、正方形、三角形、箭头等形状,并用用户选择的图像填充它们。
背景
此功能类似于 Microsoft PowerPoint 中提供的两种选项:
- 将图片平铺为纹理: 在此选项中,用户选择的图像在形状内部平铺。
- 将图片填充到形状: 在此选项中,用户选择的图像在形状内部绘制,使图像在形状上正确展开。即使增加或减小形状的大小,也不会发生平铺。
在这篇博文中,我们将深入探讨 “将图片填充到形状”选项,因为当使用图像纹理画笔填充任何形状时,这种模式会带来典型的挑战。
Windows GDI+ 提供了创建纹理画笔(WrapModeClamp
选项)并将其用于在用户选择的形状内部绘制的设施。
实现“将图片填充到形状”选项的步骤
- 加载要填充到形状内部的图像
Image image(L"C:\\Users\\Public\\Pictures\\Sample Pictures\\Tulips.jpg"); Image* ptrImagePoly = (Image*)&bmpInMemoryPoly; Graphics graphicsInMemoryPoly(ptrImagePoly );
- 在创建纹理画笔时,指定画笔的图像
TextureBrush tBrushPoly(ptrImagePoly );
- 然后在纹理画笔中指定 WrapMode Clamp(适应形状)
tBrushPoly.SetWrapMode( WrapModeClamp );
- 创建矩阵对象并设置适当的相对平移(请参阅下面的代码列表 2 和 3)
Matrix X1; X1.Translate( 247, 100 );
- 将矩阵平移设置为纹理画笔,以便画笔在正确的位置绘制图像。如果未执行此操作,则画笔默认在 0, 0 位置绘制图像,并且图像将无法正确填充到形状中。
// Set the translation to the image brush rect tBrushPoly.MultiplyTransform(&X1);
代码列表 1:用于绘制任何注释的基本 GDI 代码设置
CPaintDC dc(this);
Graphics graphics(dc.m_hDC);
Image image(L"C:\\Users\\Public\\Pictures\\Sample Pictures\\Tulips.jpg");
Pen blackPen(Color(255, 255, 0, 0));
graphics.SetInterpolationMode( InterpolationModeHighQuality );
代码列表 2:绘制一个正方形并用图像填充它
Bitmap bmpInMemoryRect( 200, 200 );
Image* ptrRect = (Image*)&bmpInMemoryRect;
Graphics graphicsInMemoryRect( ptrRect );
// Set translation according to the top-left tip of the Square shape.
// This moves the origin to 20, 20.
Matrix X2;
X2.Translate( 20, 20 );
graphicsInMemoryRect.DrawImage( &image, 0, 0, 200, 200 );
TextureBrush tBrushRect( ptrRect );
// Set the translation to the image brush rect
tBrushRect.MultiplyTransform(&X2,MatrixOrderAppend);
tBrushRect.SetWrapMode( WrapModeClamp );
graphics.DrawRectangle( &blackPen, Rect(20, 20, 200, 200) );
graphics.FillRectangle( &tBrushRect, Rect(20, 20, 200, 200) );
代码列表 3:绘制一个箭头并用图像填充它
Point * points;
int iPointCount = 7;
points = new Point[iPointCount];
// point[6]
// /\
// point[5] / \ point[0]
// - -
// point[4] || point[3]
// point[4] ||
// point[2] -- point[1]
points[0].X = (int)406.78;
points[0].Y = (int)220.11;
points[1].X = (int)367.04;
points[1].Y = (int)220.11;
points[2].X = (int)367.04;
points[2].Y = (int)321.66;
points[3].X = (int)287.57;
points[3].Y = (int)321.66;
points[4].X = (int)287.57;
points[4].Y = (int)220.11;
points[5].X = (int)247.83;
points[5].Y = (int)220.11;
points[6].X = (int)327.31;
points[6].Y = (int)100.65;
Bitmap bmpInMemoryPoly( 160, 222);
Image* ptrImagePoly = (Image*)&bmpInMemoryPoly;
Graphics graphicsInMemoryPoly(ptrImagePoly );
// Set translation according to the Left Most 'X' point and the Top Most 'Y' point of the arrow
Matrix X1;
X1.Translate( 247, 100 );
graphicsInMemoryPoly.DrawImage( &image, 0, 0, 160, 222 );
TextureBrush tBrushPoly(ptrImagePoly );
tBrushPoly.SetWrapMode( WrapModeClamp );
// Set the translation to the image brush rect
tBrushPoly.MultiplyTransform(&X1);
graphics.DrawPolygon( &blackPen, points, iPointCount );
graphics.FillPolygon( &tBrushPoly, points, iPointCount );
delete [] points