Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Applying Matrix Transformations in GDI+

0.00/5 (No votes)
20 Jun 2014 1  
Steps to implement the “Fit picture to fill the shape” option in PowerPoint like applications using GDI+

Introduction

While working on an application which used GDI+ to draw advanced graphics, I came across a requirement to draw shapes like ellipse, square, triangle, arrow, etc. and fill it with image selected by the user.

Background

This feature is similar to that available in Microsoft PowerPoint where the user is provided two options as follows:

  1. Tile picture as Texture: In this option, the image selected by the user is tiled inside the shape.

  2. Fit picture to fill the Shape: In this option, the image selected by the user is drawn inside the shape such that the image is properly spread across the shape. Tiling will not occur even after the size of the shape is increased or decreased.

We would be looking at the Fit picture to fill the shape option in depth in this blog as this mode poses a typical challenge when we fill any shape using Image Texture brush.

Windows GDI + provides us the facility to create a Texture brush (WrapModeClamp option) and then use it to draw inside the shape selected by the user.

Steps to Implement the “Fit Picture to Fill the Shape” option

  1. Load the image that you want to fill inside the shape:
    Image image(L"C:\\Users\\Public\\Pictures\\Sample Pictures\\Tulips.jpg");
    Image* ptrImagePoly = (Image*)&bmpInMemoryPoly;
    Graphics graphicsInMemoryPoly(ptrImagePoly );
  2. While creating the Texture brush, specify the image for the brush:
    TextureBrush tBrushPoly(ptrImagePoly );
  3. Then specify the wrap mode Clamp (fit to shape) in the texture brush:
    tBrushPoly.SetWrapMode( WrapModeClamp );
  4. Create the matrix object and set the proper relative translation (see Code Listing 2 and 3 below):
    Matrix X1;
    X1.Translate( 247, 100 );
  5. Set the matrix translation to the texture brush so that the brush draws the image at the proper location. If this is not done, then by default the brush draws the image at 0, 0 location and the image will not be properly filled in the shape.
    // Set the translation to the image brush rect 
    tBrushPoly.MultiplyTransform(&X1);

Code listing 1: Basic GDI code setup to draw any annotations:

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 );

Code listing 2: Draw a square and fill it with an Image:

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) );

Code listing 3: Draw an arrow and fill it with an image:

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

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here