Scaling the TextureBrush

Resolution independence is a double edged sword. You can easily specify a page-unit setting of inches, millimeters or points but this setting applies to everything which means that textures filled with these settings can look a bit weird. To illustrate this I used the following simple texture shown in figure 1, to fill an area of a form which has a page unit setting of inches.

Figure 1. The texture.

In the Paint event of my form I set the PageUnit of the graphics object to inches and filled an area of 5 inches square to obtain the following result shown in figure 2.

Figure 2. The result of using inches in TextureBrush filling.

To fill an area specified in some real-world measuring system with a texture-brush of the desired appearance is simply a matter of scaling the texture brush to the reciprocal of the page settings.

For inches this is simple enough and can be accomplished with the simple formula 1/DotsPerInch for both the X and Y directions. For example to scale a texture brush to the reciprocal of the page settings we can use the following code:

C#

      e.Graphics.PageUnit=GraphicsUnit.Inch;

      TextureBrush tb=new TextureBrush(Image.FromStream(GetType().Assembly.GetManifestResourceStream("tbinch.Bitmap1.bmp")));

      Matrix mx=new Matrix(1f/e.Graphics.DpiX,0,0,1f/e.Graphics.DpiY,0,0);

      tb.Transform=mx;

      e.Graphics.FillRectangle(tb,0,0,5,5);

VB

  e.Graphics.PageUnit=GraphicsUnit.Inch

  Dim tb as new TextureBrush(Image.FromStream(GetType().Assembly.GetManifestResourceStream("tbinch.Bitmap1.bmp")))

  Dim mx as new Matrix(1f/e.Graphics.DpiX,0,0,1f/e.Graphics.DpiY,0,0)

  tb.Transform=mx

  e.Graphics.FillRectangle(tb,0,0,5,5)

Notice how the matrix is constructed.

For other measuring systems such as millimeters and Points, we have to know the relationship between the unit of measure and inches because the only value we have to determine the scale of the page is the DPI settings of the Graphics object. Millimeters are 25.40 to the inch. Points are 72 to the inch. Other more abstract units such as Display and Document can be catered for easily too. The following method can be used to calculate the reciprocal ratios for all the standard PageUnit settings given a specific Graphics object.

C#

    public SizeF CalcReciprocals(Graphics g)

    {

      switch(g.PageUnit)

      {

        case GraphicsUnit.World:

        case GraphicsUnit.Pixel:

          return new SizeF(1f,1f);

        case GraphicsUnit.Inch:

          return new SizeF(1f/g.DpiX,1f/g.DpiY);

        case GraphicsUnit.Millimeter:

          return new SizeF(25.4f/g.DpiX,25.4f/g.DpiY);

        case GraphicsUnit.Point:

          return new SizeF(72f/g.DpiX,72f/g.DpiY);

        case GraphicsUnit.Display:

          return new SizeF(75f/g.DpiX,75f/g.DpiY);

        case GraphicsUnit.Document:

          return new SizeF(300f/g.DpiX,300f/g.DpiY);

      }

      return new SizeF(10,10);//never gets here...

    }

VB

    Public Function CalcReciprocals(g As Graphics) As SizeF

     Select Case g.PageUnit

      Case GraphicsUnit.World, GraphicsUnit.Pixel

          Return New SizeF(1F, 1F)

      Case GraphicsUnit.Inch

          Return New SizeF(1F / g.DpiX, 1F / g.DpiY)

      Case GraphicsUnit.Millimeter

          Return New SizeF(25.4F / g.DpiX, 25.4F / g.DpiY)

      Case GraphicsUnit.Point

          Return New SizeF(72F / g.DpiX, 72F / g.DpiY)

      Case GraphicsUnit.Display

          Return New SizeF(75F / g.DpiX, 75F / g.DpiY)

      Case GraphicsUnit.Document

          Return New SizeF(300F / g.DpiX, 300F / g.DpiY)

     End Select

     Return New SizeF(10, 10) 'never gets here...

    End Function 'CalcReciprocals

Return to the GDI+ FAQ

Copyright Robert W. Powell 2004. All rights reserved.