Click here to Skip to main content
Click here to Skip to main content

Applying Matrix Transformations in GDI+

, 20 Jun 2014
Rate this:
Please Sign up or sign in to vote.
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Virendra Kulkarni
Technical Lead Persistent Systems Ltd.
India India
I am currently working as a Tech Lead for VC++ projects. My role is to Design applications and to make them extensible and very easy to maintain. I use lot of design patterns into my work to design applications. I would like to share the knowledge gained while using these patterns with everybody.

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Mobile
Web03 | 2.8.140721.1 | Last Updated 20 Jun 2014
Article Copyright 2014 by Virendra Kulkarni
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid