Stroke and fill paths with PDF patterns

Support for stroking and filling paths with PDF patterns has been introduced in XFINIUM.PDF v3.7. Both tiling and shading patterns are supported.

The base class for all patterns is PdfPattern. Shading patterns are defined by PdfShadingPattern class and tiling patterns are defined by PdfTilingPattern class. Both classes inherit from PdfPattern.

A shading pattern uses a shading object to provide a smooth transition between colors across an area to be painted.

A tiling pattern consists of a small graphical figure called a pattern cell. Painting with the pattern replicates the cell at fixed horizontal and vertical intervals to fill an area. Tiling patterns are divided into 2 categories, colored tiling patterns represented by PdfColoredTilingPattern class and uncolored tiling patterns represented by PdfUncoloredTilingPattern class. Both classes inherit from PdfTilingPattern.
A colored tiling pattern sets explicitly the color of each graphical element it paints. An uncolored tiling pattern has no inherent color and the color is specified separately when the pattern is used.

A PdfPatternPen object is used to stroke a path with a pattern and a PdfPatternBrush is used to fill a path with a pattern. Both objects use a PdfPatternColor to specify the stroke and fill style. The PdfPatternColor is created based on a PdfPatternColorSpace which specifies the actual pattern used for painting.

Tiling patterns

When a tiling pattern is created the size of the pattern cell must be specified. The content of the pattern cell is created through the pattern’s Graphics property.
These properties are common to all tiling patterns:

  • PdfGraphics Graphics – the pattern cell drawing surface
  • double Width – the width of a pattern cell
  • double Height – the height of a pattern cell
  • double XStep – the desired horizontal spacing between pattern cells. If XStep matches Width then the pattern cells will painted one next to another. If XStep is lower than Width the pattern cells will overlap on horizontal and if XStep is higher than Width then there will be a horizontal space between pattern cells.
  • double YStep – the desired vertical spacing between pattern cells. If YStep matches Height then the pattern cells will painted one next to another. If YStep is lower than Height the pattern cells will overlap on vertical and if YStep is higher than Height then there will be a vertical space between pattern cells.
  • – PdfMatrix Matrix – the pattern matrix

The content of a colored tilling pattern is created like any other graphics drawn on the page, no special considerations are required.

// Create the pattern visual appearance.
PdfColoredTilingPattern ctp = new PdfColoredTilingPattern(20, 20);
// Red circle
ctp.Graphics.DrawEllipse(darkRedPen, lightRedBrush, 1, 1, 8, 8);
// Cyan square
ctp.Graphics.DrawRectangle(darkCyanPen, lightCyanBrush, 11, 1, 8, 8);
// Green diamond
PdfPath diamondPath = new PdfPath();
diamondPath.StartSubpath(1, 15);
diamondPath.AddPolyLineTo(new PdfPoint[] { new PdfPoint(5, 11), new PdfPoint(9, 15), new PdfPoint(5, 19) });
diamondPath.CloseSubpath();
ctp.Graphics.DrawPath(darkGreenPen, lightGreenBrush, diamondPath);
// Orange triangle
PdfPath trianglePath = new PdfPath();
trianglePath.StartSubpath(11, 19);
trianglePath.AddPolyLineTo(new PdfPoint[] { new PdfPoint(15, 11), new PdfPoint(19, 19) });
trianglePath.CloseSubpath();
ctp.Graphics.DrawPath(darkOrangePen, lightOrangeBrush, trianglePath);

// Create a pattern colorspace from the pattern object.
PdfPatternColorSpace coloredPatternColorSpace = new PdfPatternColorSpace(ctp);
// Create a color based on the pattern colorspace.
PdfPatternColor coloredPatternColor = new PdfPatternColor(coloredPatternColorSpace);
// The pen and brush use the pattern color like any other color.
PdfPatternBrush patternBrush = new PdfPatternBrush(coloredPatternColor);
PdfPatternPen patternPen = new PdfPatternPen(coloredPatternColor, 40);

page.Graphics.DrawEllipse(patternBrush, 25, 90, 250, 200);
page.Graphics.DrawRoundRectangle(patternPen, 310, 110, 250, 160, 100, 100);
' Create the pattern visual appearance.
Dim ctp As New PdfColoredTilingPattern(20, 20)
' Red circle
ctp.Graphics.DrawEllipse(darkRedPen, lightRedBrush, 1, 1, 8, 8)
' Cyan square
ctp.Graphics.DrawRectangle(darkCyanPen, lightCyanBrush, 11, 1, 8, 8)
' Green diamond
Dim diamondPath As New PdfPath()
diamondPath.StartSubpath(1, 15)
diamondPath.AddPolyLineTo(New PdfPoint() {New PdfPoint(5, 11), New PdfPoint(9, 15), New PdfPoint(5, 19)})
diamondPath.CloseSubpath()
ctp.Graphics.DrawPath(darkGreenPen, lightGreenBrush, diamondPath)
' Orange triangle
Dim trianglePath As New PdfPath()
trianglePath.StartSubpath(11, 19)
trianglePath.AddPolyLineTo(New PdfPoint() {New PdfPoint(15, 11), New PdfPoint(19, 19)})
trianglePath.CloseSubpath()
ctp.Graphics.DrawPath(darkOrangePen, lightOrangeBrush, trianglePath)

' Create a pattern colorspace from the pattern object.
Dim coloredPatternColorSpace As New PdfPatternColorSpace(ctp)
' Create a color based on the pattern colorspace.
Dim coloredPatternColor As New PdfPatternColor(coloredPatternColorSpace)
' The pen and brush use the pattern color like any other color.
Dim patternBrush As New PdfPatternBrush(coloredPatternColor)
Dim patternPen As New PdfPatternPen(coloredPatternColor, 40)

page.Graphics.DrawEllipse(patternBrush, 25, 90, 250, 200)
page.Graphics.DrawRoundRectangle(patternPen, 310, 110, 250, 160, 100, 100)

The content of an uncolored tiling patterns is created by using null for pen and brush colors. In this way the paths are stroked and filled but without specifying a color. Also only image masks can be drawn in an uncolored pattern. When a pattern pen or pattern brush that uses an uncolored pattern is used to stroke or fill a path the UncoloredPatternPaintColor property must be set on the pen or brush. This color will actually be used to paint the pattern.

// Create the pattern visual appearance.
PdfUncoloredTilingPattern uctp = new PdfUncoloredTilingPattern(20, 20);
// A pen without color is used to create the pattern content.
PdfPen noColorPen = new PdfPen(null, 0.8);
// Circle
uctp.Graphics.DrawEllipse(noColorPen, 1, 1, 8, 8);
// Square
uctp.Graphics.DrawRectangle(noColorPen, 11, 1, 8, 8);
// Diamond
diamondPath = new PdfPath();
diamondPath.StartSubpath(1, 15);
diamondPath.AddPolyLineTo(new PdfPoint[] { new PdfPoint(5, 11), new PdfPoint(9, 15), new PdfPoint(5, 19) });
diamondPath.CloseSubpath();
uctp.Graphics.DrawPath(noColorPen, diamondPath);
// Triangle
trianglePath = new PdfPath();
trianglePath.StartSubpath(11, 19);
trianglePath.AddPolyLineTo(new PdfPoint[] { new PdfPoint(15, 11), new PdfPoint(19, 19) });
trianglePath.CloseSubpath();
uctp.Graphics.DrawPath(noColorPen, trianglePath);

// Create a pattern colorspace from the pattern object.
PdfPatternColorSpace uncoloredPatternColorSpace = new PdfPatternColorSpace(uctp);
// Create a color based on the pattern colorspace.
PdfPatternColor uncoloredPatternColor = new PdfPatternColor(uncoloredPatternColorSpace);
// The pen and brush use the pattern color like any other color.
patternBrush = new PdfPatternBrush(uncoloredPatternColor);

// Before using the uncolored pattern set the color that will be used to paint the pattern.
patternBrush.UncoloredPatternPaintColor = new PdfRgbColor(0xFF, 0x40, 0x40);
page.Graphics.DrawEllipse(patternBrush, 25, 320, 125, 200);
patternBrush.UncoloredPatternPaintColor = new PdfRgbColor(0xA6, 0x4B, 0x00);
page.Graphics.DrawEllipse(patternBrush, 175, 320, 125, 200);
patternBrush.UncoloredPatternPaintColor = new PdfRgbColor(0x00, 0x63, 0x63);
page.Graphics.DrawEllipse(patternBrush, 325, 320, 125, 200);
patternBrush.UncoloredPatternPaintColor = new PdfRgbColor(0x00, 0x85, 0x00);
page.Graphics.DrawEllipse(patternBrush, 475, 320, 125, 200);
' Create the pattern visual appearance.
Dim uctp As New PdfUncoloredTilingPattern(20, 20)
' A pen without color is used to create the pattern content.
Dim noColorPen As New PdfPen(Nothing, 0.8)
' Circle
uctp.Graphics.DrawEllipse(noColorPen, 1, 1, 8, 8)
' Square
uctp.Graphics.DrawRectangle(noColorPen, 11, 1, 8, 8)
' Diamond
diamondPath = New PdfPath()
diamondPath.StartSubpath(1, 15)
diamondPath.AddPolyLineTo(New PdfPoint() {New PdfPoint(5, 11), New PdfPoint(9, 15), New PdfPoint(5, 19)})
diamondPath.CloseSubpath()
uctp.Graphics.DrawPath(noColorPen, diamondPath)
' Triangle
trianglePath = New PdfPath()
trianglePath.StartSubpath(11, 19)
trianglePath.AddPolyLineTo(New PdfPoint() {New PdfPoint(15, 11), New PdfPoint(19, 19)})
trianglePath.CloseSubpath()
uctp.Graphics.DrawPath(noColorPen, trianglePath)

' Create a pattern colorspace from the pattern object.
Dim uncoloredPatternColorSpace As New PdfPatternColorSpace(uctp)
' Create a color based on the pattern colorspace.
Dim uncoloredPatternColor As New PdfPatternColor(uncoloredPatternColorSpace)
' The pen and brush use the pattern color like any other color.
patternBrush = New PdfPatternBrush(uncoloredPatternColor)

' Before using the uncolored pattern set the color that will be used to paint the pattern.
patternBrush.UncoloredPatternPaintColor = New PdfRgbColor(&Hff, &H40, &H40)
page.Graphics.DrawEllipse(patternBrush, 25, 320, 125, 200)
patternBrush.UncoloredPatternPaintColor = New PdfRgbColor(&Ha6, &H4b, &H0)
page.Graphics.DrawEllipse(patternBrush, 175, 320, 125, 200)
patternBrush.UncoloredPatternPaintColor = New PdfRgbColor(&H0, &H63, &H63)
page.Graphics.DrawEllipse(patternBrush, 325, 320, 125, 200)
patternBrush.UncoloredPatternPaintColor = New PdfRgbColor(&H0, &H85, &H0)
page.Graphics.DrawEllipse(patternBrush, 475, 320, 125, 200)

Shading patterns

A shading pattern encapsulates a shading object for stroking or filling a path. The shading can be specified when the pattern is created or later. The difference between drawing using a shading pattern and drawing using a simple shading object is that the shading pattern can be used for stroking and filling paths when the shading object can only be used to fill a clipping region.

// Create the pattern visual appearance.
PdfAxialShading horizontalShading = new PdfAxialShading();
horizontalShading.StartColor = new PdfRgbColor(255, 0, 0);
horizontalShading.EndColor = new PdfRgbColor(0, 0, 255);
horizontalShading.StartPoint = new PdfPoint(25, 600);
horizontalShading.EndPoint = new PdfPoint(575, 600);
PdfShadingPattern sp = new PdfShadingPattern(horizontalShading);

// Create a pattern colorspace from the pattern object.
PdfPatternColorSpace shadingPatternColorSpace = new PdfPatternColorSpace(sp);
// Create a color based on the pattern colorspace.
PdfPatternColor shadingPatternColor = new PdfPatternColor(shadingPatternColorSpace);
// The pen uses the pattern color like any other color.
patternPen = new PdfPatternPen(shadingPatternColor, 40);
// Stroke an ellipse using the shading
page.Graphics.DrawEllipse(patternPen, 50, 600, 500, 150);
' Create the pattern visual appearance.
Dim horizontalShading As New PdfAxialShading()
horizontalShading.StartColor = New PdfRgbColor(255, 0, 0)
horizontalShading.EndColor = New PdfRgbColor(0, 0, 255)
horizontalShading.StartPoint = New PdfPoint(25, 600)
horizontalShading.EndPoint = New PdfPoint(575, 600)
Dim sp As New PdfShadingPattern(horizontalShading)

' Create a pattern colorspace from the pattern object.
Dim shadingPatternColorSpace As New PdfPatternColorSpace(sp)
' Create a color based on the pattern colorspace.
Dim shadingPatternColor As New PdfPatternColor(shadingPatternColorSpace)
' The pen and brush use the pattern color like any other color.
patternPen = New PdfPatternPen(shadingPatternColor, 40)
// Stroke an ellipse using the shading
page.Graphics.DrawEllipse(patternPen, 50, 600, 500, 150)

The full sample source code is available in our Samples Explorer application, Vector Graphics sample, DrawPatterns method.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Discover more from XFINIUM.PDF Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading