Click or drag to resize

Working With Patterns

This topic contains the following sections:

Overview

When properties such as StrokeColor and FillColor are used to paint an area of the page object, then a single color that covers the area uniformly is applied. However, it is also possible to apply “paint” that consists of a repeating graphical figure or a smoothly varying color gradient instead of a simple color. Such a repeating figure or smooth gradient is called a pattern. Patterns are quite general, and have many uses; for example, they can be used to create various graphical textures, such as weaves, brick walls, sunbursts, and similar geometrical and chromatic effects.

Patterns come in two varieties:

  • Tiling patterns consist of a small graphical figure (called a pattern cell) that is replicated at fixed horizontal and vertical intervals to fill the area to be painted.

  • Shading patterns define a gradient fill that produces a smooth transition between colors across the area. The color to use is specified as a function of position using any of a variety of methods.

Patterns are specified in a special family of color space - CsPattern. This space use pattern objects as the equivalent of color values instead of the numeric component values used with other spaces. These objects are derived from the abstract class PdfPattern and are grouped into the following class hierarchy:

Open in full size

Patterns
General Properties of Patterns

The PdfPattern class contain a property named PatternType, whose value identifies the kind of pattern: PatternTypesTiling for a tiling pattern or PatternTypesShading for a shading pattern.

A pattern’s appearance is described with respect to its own internal coordinate system. Every pattern has a Matrix property, a transformation matrix that maps the pattern’s internal coordinate system to the default coordinate system of the pattern’s parent. The concatenation of the pattern matrix with ParentMatrix establishes the pattern coordinate space, within which all graphics objects in the pattern are interpreted.

Tiling Patterns

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. The effect is as if the figure were painted on the surface of a clear glass tile, identical copies of which were then laid down in an array covering the area and trimmed to its boundaries. This process is called tiling the area.

The pattern cell can include graphical elements such as filled areas, text, and sampled images. Its shape need not be rectangular, and the spacing of tiles can differ from the dimensions of the cell itself. When performing painting operations such as stroke or fill, the application paints the cell on the current page as many times as necessary to fill an area. The order in which individual tiles (instances of the cell) are painted is unspecified and unpredictable; it is inadvisable for the figures on adjacent tiles to overlap.

This type of pattern is identified by a PdfTilingPattern class. The appearance of the pattern cell is defined by a PdfTilingPatternContent collection containing the page objects needed to paint one instance of the cell. Section, Page Objects discusses page objects in detail.

PdfTilingPatternColored

A flag that determines how the color of the pattern cell is to be specified:

  • Colored tiling pattern. The pattern’s Content specifies the colors used to paint the pattern cell.

  • Uncolored tiling pattern. The pattern’s Content does not specify any color information. Instead, the entire pattern cell is painted with a separately specified color each time the pattern is used. Essentially, the content stream describes a stencil through which the current color is to be poured.

PdfTilingPatternTilingType

A code that controls adjustments to the spacing of tiles relative to the device pixel grid:

  • ConstantSpacing. Pattern cells are spaced consistently—that is, by a multiple of a device pixel. To achieve this, the application may need to distort the pattern cell slightly by making small adjustments to Step, and the transformation matrix. The amount of distortion does not exceed 1 device pixel.

  • NoDistortion. The pattern cell is not distorted, but the spacing between pattern cells may vary by as much as 1 device pixel, both horizontally and vertically, when the pattern is painted. This achieves the spacing requested by Step on average but not necessarily for each individual pattern cell.

  • FasterTiling. Pattern cells are spaced consistently as in tiling type 1 but with additional distortion permitted to enable a more efficient implementation.

PdfTilingPatternBoundingBox

This boundary is used to clip the pattern cell.

PdfTilingPatternStep

The desired horizontal and vertical spacing between pattern cells, measured in the pattern coordinate system.

The pattern’s BoundingBox, and Step values are interpreted in the pattern coordinate system, and the page objects in the pattern’s Content are defined with respect to that coordinate system. The placement of pattern cells in the tiling is based on the location of one key pattern cell, which is then displaced by multiples of Step to replicate the pattern. The origin of the key pattern cell coincides with the origin of the pattern coordinate system. The phase of the tiling can be controlled by the translation components of the Matrix property.

Colored Tiling Patterns

A colored tiling pattern is a pattern whose color is self-contained. In the course of painting the pattern cell, the pattern’s Content explicitly sets the color of each page object it paints. A single pattern cell can contain elements that are painted different colors; it can also contain sampled grayscale or color images. This type of pattern is identified by a PdfTilingPatternColored of true.

The below example defines a page that paints three circles and a triangle using a colored tiling pattern over a yellow background. The pattern consists of the symbols for the four suits of playing cards (spades, hearts, diamonds, and clubs), which are character glyphs taken from the ZapfDingbats font; the pattern’s Content specifies the color of each glyph.

C#
using (var doc = PdfDocument.Load("sample.pdf"))
{
    var page = doc.Pages[0];

    //Pattern definition. Tiling pattern, colored
    bool isColored = true;
    var pattern = new PdfTilingPattern(doc, isColored);

    //Create text objects with glyph, position, font and size
    var spades = PdfTextObject.Create("♠", 0, 0, PdfFont.CreateStock(doc, FontStockNames.ZapfDingbats), 22);
    spades.FillColor = FS_COLOR.Black;  // Set nonstroking color to black
    var hearts = PdfTextObject.Create("♥", 12.8f, 0, PdfFont.CreateStock(doc, FontStockNames.ZapfDingbats), 22f);
    hearts.FillColor = FS_COLOR.Red;    // Set nonstroking color to red
    var diamonds = PdfTextObject.Create("♦", 0, 20f, PdfFont.CreateStock(doc, FontStockNames.ZapfDingbats), 22f);
    diamonds.FillColor = FS_COLOR.Green;//Set nonstroking color to green
    var clubs = PdfTextObject.Create("♣", 12.8f, 20, PdfFont.CreateStock(doc, FontStockNames.ZapfDingbats), 22f);
    clubs.FillColor = FS_COLOR.Blue;    //Set nonstroking color to blue

    //Add text objects into pattern's content.
    pattern.Content.Add(spades);
    pattern.Content.Add(hearts);
    pattern.Content.Add(diamonds);
    pattern.Content.Add(clubs);
    //Generate content
    pattern.GenerateContent();

    // Calculate and set bounding box and step
    pattern.CalcBoundingBox();
    pattern.Step = new FS_SIZEF(pattern.BoundingBox.Width, pattern.BoundingBox.Height);

    //Create page objects
    //Rectangle
    var rectObj = PdfPathObject.Create(FillModes.Winding, false);
    rectObj.Path.AppendRect(new FS_RECTF(0, 150, 150, 0));
    rectObj.FillColor = FS_COLOR.Yellow;

    //triangle
    var triangleObj = PdfPathObject.Create(FillModes.Winding, true);
    triangleObj.Path.AppendPolygon(new FS_POINTF[]
    {
        new FS_POINTF(25, 25),
        new FS_POINTF(75, 125),
        new FS_POINTF(125, 25)
    });
    triangleObj.SetFillColor(pattern);  //Set pattern as nonstroking color

    //circle 1
    var circleObj1 = PdfPathObject.Create(FillModes.Winding, true);
    circleObj1.Path.AppendCircle(25, 25, 37.5f);
    circleObj1.SetFillColor(pattern);   //Set pattern as nonstroking color

    //circle 2
    var circleObj2 = PdfPathObject.Create(FillModes.Winding, true);
    circleObj2.Path.AppendCircle(125, 25, 37.5f);
    circleObj2.SetFillColor(pattern);   //Set pattern as nonstroking color

    //circle 3
    var circleObj3 = PdfPathObject.Create(FillModes.Winding, true);
    circleObj3.Path.AppendCircle(75, 125, 37.5f);
    circleObj3.SetFillColor(pattern);   //Set pattern as nonstroking color

    //Add page object into the page content
    page.PageObjects.Add(rectObj);
    page.PageObjects.Add(triangleObj);
    page.PageObjects.Add(circleObj1);
    page.PageObjects.Add(circleObj2);
    page.PageObjects.Add(circleObj3);
    //Generate page content.
    page.GenerateContent();
}
Colored tiling pattern
tiling-colored

Several features of Example are noteworthy:

  • The three circles and the triangle are painted with the same pattern. The pattern cells align, even though the circles and triangle are not aligned with respect to the pattern cell. For example, the position of the green diamonds varies relative to the three circles.

  • The pattern cell does not completely cover the tile: it leaves the spaces between the glyphs unpainted. When the tiling pattern is used as a color, the existing background (the yellow rectangle) shows through these unpainted areas.

  • When specifying the fill color with PdfPageObjectSetFillColor(PdfPattern, PdfColorSpace, Single), the CsPattern color space, and the color array were not specified (the second and third parameters were omitted), because colored tiling patterns do not require additional parameters.

Uncolored Tiling Patterns

An uncolored tiling pattern is a pattern that has no inherent color: the color must be specified separately whenever the pattern is used. It provides a way to tile different regions of the page with pattern cells having the same shape but different colors. The pattern’s Content does not explicitly specify any colors; it can contain an image mask, but no other kind of image. This type of pattern is identified by a PdfTilingPatternColored of false.

A CsPattern color space representing an uncolored tiling pattern requires a parameter: a color space in which the actual color of the pattern is to be specified. The underlying color space is given as the second parameter of the CsPattern(PdfDocument, PdfColorSpace) constructor. For example, the following defines a pattern color space with CsDeviceRGB as its underlying color space.

C#
var cs = new CsPattern(doc, PdfColorSpace.DeviceRGB());
Note  Note

The underlying color space cannot be another Pattern color space.

Calls to SetFillColor/ SetStrokeColor must include such a color space, a color value in this color space, specified by one or more numeric color components, as well as the pattern object representing an uncolored tiling pattern.

The following example is similar to Example for colored tiling patterns, except that it uses an uncolored tiling pattern to paint the three circles and the triangle, each in a different color.

C#
using (var doc = PdfDocument.Load("sample.pdf"))
{
    var page = doc.Pages[0];

    //Pattern definition. Tiling pattern, colored
    bool isColored = false;
    var pattern = new PdfTilingPattern(doc, isColored);

    //Create text objects with glyph, position, font and size
    var spades = PdfTextObject.Create("♠", 0, 0, PdfFont.CreateStock(doc, FontStockNames.ZapfDingbats), 22);
    var hearts = PdfTextObject.Create("♥", 12.8f, 0, PdfFont.CreateStock(doc, FontStockNames.ZapfDingbats), 22f);
    var diamonds = PdfTextObject.Create("♦", 0, 20f, PdfFont.CreateStock(doc, FontStockNames.ZapfDingbats), 22f);
    var clubs = PdfTextObject.Create("♣", 12.8f, 20, PdfFont.CreateStock(doc, FontStockNames.ZapfDingbats), 22f);

    //Add text objects into pattern's content.
    pattern.Content.Add(spades);
    pattern.Content.Add(hearts);
    pattern.Content.Add(diamonds);
    pattern.Content.Add(clubs);
    //Generate content
    pattern.GenerateContent();

    // Calculate and set bounding box and step
    pattern.CalcBoundingBox();
    pattern.Step = new FS_SIZEF(pattern.BoundingBox.Width, pattern.BoundingBox.Height);

    //Create page objects
    //Rectangle
    var rectObj = PdfPathObject.Create(FillModes.Winding, false);
    rectObj.Path.AppendRect(new FS_RECTF(0, 150, 150, 0));
    rectObj.FillColor = FS_COLOR.Yellow;

    //triangle
    var triangleObj = PdfPathObject.Create(FillModes.Winding, true);
    triangleObj.Path.AppendPolygon(new FS_POINTF[]
    {
        new FS_POINTF(25, 25),
        new FS_POINTF(75, 125),
        new FS_POINTF(125, 25)
    });
    triangleObj.SetFillColor(pattern, new CsPattern(doc, new CsDeviceRGB()), FS_COLOR.Violet.ToDeviceRgb());  //Set pattern as nonstroking color

    //circle 1
    var circleObj1 = PdfPathObject.Create(FillModes.Winding, true);
    circleObj1.Path.AppendCircle(25, 25, 37.5f);
    circleObj1.SetFillColor(pattern, new CsPattern(doc, new CsDeviceRGB()), FS_COLOR.Red.ToDeviceRgb());     //Set pattern as nonstroking color

    //circle 2
    var circleObj2 = PdfPathObject.Create(FillModes.Winding, true);
    circleObj2.Path.AppendCircle(125, 25, 37.5f);
    circleObj2.SetFillColor(pattern, new CsPattern(doc, new CsDeviceRGB()), FS_COLOR.Green.ToDeviceRgb());   //Set pattern as nonstroking color

    //circle 3
    var circleObj3 = PdfPathObject.Create(FillModes.Winding, true);
    circleObj3.Path.AppendCircle(75, 125, 37.5f);
    circleObj3.SetFillColor(pattern, new CsPattern(doc, new CsDeviceRGB()), FS_COLOR.Blue.ToDeviceRgb());   //Set pattern as nonstroking color

    //Add page object into the page content
    page.PageObjects.Add(rectObj);
    page.PageObjects.Add(triangleObj);
    page.PageObjects.Add(circleObj1);
    page.PageObjects.Add(circleObj2);
    page.PageObjects.Add(circleObj3);
    //Generate page content.
    page.GenerateContent();
}
Colored tiling pattern
tiling-uncolored
Shading Patterns

Shading patterns provide a smooth transition between colors across an area to be painted, independent of the resolution of any particular output device and without specifying the number of steps in the color transition. Patterns of this type are described by the PdfShadingPattern base class and derived classes listed in the table below.

FunctionBasedPattern

Function-based shadings (type 1) define the color of every point in the domain using a mathematical function (not necessarily smooth or continuous).

AxialPattern

Axial shadings (type 2) define a color blend along a line between two points, optionally extended beyond the boundary points by continuing the boundary colors.

RadialPattern

Radial shadings (type 3) define a blend between two circles, optionally extended beyond the boundary circles by continuing the boundary colors. This type of shading is commonly used to represent three-dimensional spheres and cones.

FreeFormPattern

Free-form Gouraud-shaded triangle meshes (type 4) define a common construct used by many three-dimensional applications to represent complex colored and shaded shapes. Vertices are specified in free-form geometry.

LatticeFormPattern

Lattice-form Gouraud-shaded triangle meshes (type 5) are based on the same geometrical construct as type 4 but with vertices specified as a pseudorectangular lattice.

CubicBezierPattern

Coons patch meshes (type 6) construct a shading from one or more color patches, each bounded by four cubic Bézier curves.

TensorPattern

Tensor-product patch meshes (type 7) are similar to type 6 but with additional control points in each patch, affording greater control over color mapping.

The base class PdfShadingPattern of these patterns has the common properties listed below.

Note  Note

The term target coordinate space, used in many of the following descriptions, refers to the coordinate space into which a shading is painted. For shadings used with a CsPattern color space, this is the pattern coordinate space, discussed in section “General Properties of Patterns”. For shadings used directly with the PdfShadingObject, it is the current user space, discused in section “Page coordinate system”.

PdfShadingPatternShadingType

The shading type.

PdfShadingPatternColorSpace

The color space in which color values are expressed. This may be any device, CIE-based, or special color space except a CsPatternspace.

PdfShadingPatternBackground

An array of color components appropriate to the color space, specifying a single background color value. If present, this color is used, before any painting operation involving the shading, to fill those portions of the area to be painted that lie outside the bounds of the shading object. In the opaque imaging model, the effect is as if the painting operation were performed twice: first with the background color and then with the shading.

The background color is applied only when the shading is used as part of a shading pattern, not when it is painted directly with the PdfShadingObject

PdfShadingPatternBoundingBox

The shading’s bounding box. The coordinates are interpreted in the shading’s target coordinate space. If present, this bounding box is applied as a temporary clipping boundary when the shading is painted, in addition to the current clipping path and any other clipping boundaries in effect at that time.

PdfShadingPatternAntiAlias

A flag indicating whether to filter the shading function to prevent aliasing artifacts.

In addition, some shading patterns also have a Function / TintFunction property whose value is the PdfFunction object defining how colors vary across the area to be shaded. The function is required for some types of shading and optional for others. Functions are described in detail in section, Functions.

Tip  Tip

As mentioned above the PdfShadingPattern can also be used with the PdfShadingObject instead of set it as a color to the page objects such a path, text, etc. if shading pattern is set to the PdfShadingObjectShading property its paint the shape and color shading described by a shading pattern, subject to the current clipping path. The current color in such a page object is neither used nor altered. The effect is different from that of painting a path using a shading pattern as the current color. All coordinates in the shading pattern are interpreted relative to the current user space (by contrast, when a shading pattern is used as a color, the coordinates are expressed in pattern space). All colors are interpreted in the color space identified by the shading’s ColorSpace property. The Background property, if present, is ignored.

Only bounded or geometrically defined shading should be used with PdfShadingObject. If unbounded shading is used, it paints the shading’s gradient fill across the entire clipping region, which may be time-consuming.

Type 1 (Function-Based) Shadings

In type 1 (function-based) shadings, the color at every point in the domain is defined by a specified mathematical function. The function need not be smooth or continuous. This type is the most general of the available shading types and is useful for shadings that cannot be adequately described with any of the other types. The below table shows the properties specific to this type of shading.

Important note  Important

This type of shading cannot be used with an CsIndexed color space.

FunctionBasedPatternDomain

The FS_RECTF structure specifying the rectangular domain of coordinates over which the color function(s) are defined.

FunctionBasedPatternDomainMatrix

The FS_MATRIX structure specifying a transformation matrix mapping the coordinate space specified by the Domain property into the shading’s target coordinate space. For example, to map the domain rectangle [0.0 1.0 0.0 1.0] to a 1-inch square with lower-left corner at coordinates (100, 100) in default user space, the DomainMatrix value would be [72 0 0 72 100 100].

FunctionBasedPatternFunctions

A 2-in, n-out function or an array of n 2-in, 1-out functions (where n is the number of color components in the shading color space). If the value returned by the function for a given color component is out of range, it is adjusted to the nearest valid value.

The domain rectangle (Domain) establishes an internal coordinate space for the shading that is independent of the target coordinate space in which it is to be painted. The color function(s) (Functions) specify the color of the shading at each point within this domain rectangle. The transformation matrix (DomainMatrix) then maps the domain rectangle into a corresponding rectangle or parallelogram in the target coordinate space. Points within the shading’s bounding box (PdfShadingPatternBoundingBox) that fall outside this transformed domain rectangle are painted with the shading’s background color (PdfShadingPatternBackground); if the shading's Background property is not set, such points are left unpainted. If the function is undefined at any point within the declared domain rectangle, an error may occur, even if the corresponding transformed point falls outside the shading’s bounding box.

Type 2 (Axial) Shadings

Type 2 (axial) shadings define a color blend that varies along a linear axis between two endpoints and extends indefinitely perpendicular to that axis. The shading may optionally be extended beyond either or both endpoints by continuing the boundary colors indefinitely. The following table shows the properties specific to this type of shading.

Important note  Important

This type of shading cannot be used with an CsIndexed color space.

AxialPatternFrom
AxialPatternTo

Two points specifying the starting and ending coordinates of the axis, expressed in the shading’s target coordinate space.

AxialPatternExtendStart
AxialPatternExtendEnd

Two boolean values specifying whether to extend the shading beyond the starting and ending points of the axis, respectively.

AxialPatternLowest
AxialPatternHighest

Two numbers [t0 t1] specifying the limiting values of a parametric variable t. The variable is considered to vary linearly between these two values as the color gradient varies between the starting and ending points of the axis. The variable t becomes the input argument to the color function(s).

AxialPatternFunctions

A 1-in, n-out function or an array of n 1-in, 1-out functions (where n is the number of color components in the shading’s color space). The function(s) are called with values of the parametric variable t in the domain defined by the Lowest and Highest properties. Each PdfFunctionDomain must be a superset of that domain. If the value returned by the function for a given color component is out of range, it is adjusted to the nearest valid value.

The color blend is accomplished by linearly mapping each point (x, y) along the axis between the endpoints (x0, y0) and (x1, y1) to a corresponding point in the domain specified by the Lowest and Highest properties.

The below examples show how to use of an axial shading to fill a rectangle and display text. The area to be filled extends beyond the the starting and ending points of the axis. The shading is the same in all three cases, except for the values of the Background and ExtendStart / ExtentEnd properties. In the first example, the shading is not extended at either end and no background color is specified; therefore, the shading is clipped at both ends. The second example still has no background color specified, but the shading is extended at both ends; the result is to fill the remaining portions of the filled area with the colors defined at the ends of the shading. In the third example, the shading is not extended and a background color is specified; therefore, the background color is used for the portions of the filled area beyond the ends of the shading.

C#
private void AxialPatternExample(PdfPage page, bool isExtend, float[] backgroundColor)
{
    //Create function
    int numOfInputs = 1;
    int numOfOutputs = 3;                   //As a 3 components for a DeviceRGB  color space
    float exponent = 1;                     //linear interpolation
    float[] domain = { 0, 1 };              //domain of an input argument
    float[] range = { 0, 1, 0, 1, 0, 1 };   //domain of each output value
    float[] valuesAtStart = FS_COLOR.Yellow.ToDeviceRgb();
    float[] valuesAtEnd = FS_COLOR.Blue.ToDeviceRgb();
    var function = new PdfFuncExponential(numOfInputs, numOfOutputs, exponent, domain, range, valuesAtStart, valuesAtEnd);

    //Create text objects with glyph, position, font and size
    var textObj = PdfTextObject.Create("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 0, 0, PdfFont.CreateStock(page.Document, FontStockNames.ArialBold), 28);
    //Create the rectangle above text object
    var rectObj = PdfPathObject.Create(FillModes.Winding, false);
    var bbox = textObj.BoundingBox;
    bbox.bottom = bbox.top + 10;
    bbox.top = bbox.bottom + 50;
    rectObj.Path.AppendRect(bbox);

    // Add these page objects to the page content
    page.PageObjects.Add(textObj);
    page.PageObjects.Add(rectObj);

    //Calculate the bounding box around the previously added page objects and add it to the page content.
    var commonBBox = PdfPathObject.Create(FillModes.None, true);
    commonBBox.Path.AppendRect(page.PageObjects.CalcuateBoundingBox());
    page.PageObjects.Add(commonBBox);

    //Pattern definition. Axial Shading.
    var startPoint = new FS_POINTF(90, 0);
    var endPoint = new FS_POINTF(410, 0);
    var pattern = new AxialPattern(page.Document, startPoint, endPoint, function, PdfColorSpace.DeviceRGB());
    pattern.ExtendStart = isExtend;
    pattern.ExtendEnd = isExtend;
    pattern.Background = backgroundColor;

    //Set the pattern as a fill color into the text and rectangle objects.
    textObj.SetFillColor(pattern);
    rectObj.SetFillColor(pattern);

    //Generate page content.
    page.GenerateContent();
}
Example 1
using (var doc = PdfDocument.Load("sample.pdf"))
{
    var page = doc.Pages[0];
    AxialPatternExample(page, false, null);
}
Example 2
using (var doc = PdfDocument.Load("sample.pdf"))
{
    var page = doc.Pages[0];
    AxialPatternExample(page, true, null);
}
Example 3
using (var doc = PdfDocument.Load("sample.pdf"))
{
    var page = doc.Pages[0];
    AxialPatternExample(page, false, FS_COLOR.Coral.ToDeviceRgb());
}
Results of the first example.
Axial 01
Results of the second example
Axial 02
Results of the third example
Axial 03

Type 3 (Radial) Shadings

Type 3 (radial) shadings define a color blend that varies between two circles. Shadings of this type are commonly used to depict three-dimensional spheres and cones. The following table shows the properties specific to this type of shading.

Important note  Important

This type of shading cannot be used with an CsIndexed color space.

RadialPatternFrom
RadialPatternTo

Two FS_CIRCLEF structures specifying the centers and radii of the starting and ending circles, expressed in the shading’s target coordinate space. The radii must both be greater than or equal to 0. If one radius is 0, the corresponding circle is treated as a point; if both are 0, nothing is painted.

RadialPatternExtendStart
RadialPatternExtendEnd

Two boolean values specifying whether to extend the shading beyond the starting and ending circles, respectively.

RadialPatternLowest
RadialPatternHighest

Two numbers [t0 t1] specifying the limiting values of a parametric variable t. The variable is considered to vary linearly between these two values as the color gradient varies between the starting and ending circles. The variable t becomes the input argument to the color function(s).

RadialPatternFunctions

A 1-in, n-out function or an array of n 1-in, 1-out functions (where n is the number of color components in the shading’s color space). The function(s) are called with values of the parametric variable t in the domain defined by the Lowest and Highest properties. Each PdfFunctionDomain must be a superset of that domain. If the value returned by the function for a given color component is out of range, it is adjusted to the nearest valid value.

The color blend is based on a family of blend circles interpolated between the starting and ending circles that are defined by the From and To, respectively. The blend circles are defined in terms of a subsidiary parametric variable (S) which varies linearly between 0.0 and 1.0 as t varies across the domain from Lowest to Highest. Each value of S between 0.0 and 1.0 determines a corresponding value of t, which is passed as the input argument to the function(s) defined by the Function property. This yields the component values of the color with which to fill the corresponding blend circle. For values of S not lying between 0.0 and 1.0, the ExtendStart and ExtendEnd determine whether and how the shading is extended. If the first of the two properties is true, the shading is extended beyond the defined starting circle to values of S less than 0.0; if the second property is true, the shading is extended beyond the defined ending circle to S values greater than 1.0.

Note that either of the starting and ending circles may be larger than the other. If the shading is extended at the smaller end, the family of blend circles continues as far as that value of s for which the radius of the blend circle r(S) = 0. If the shading is extended at the larger end, the blend circles continue as far as that s value for which r(S) is large enough to encompass the shading’s bounding box (PdfShadingPatternBoundingBox). Extending the shading can thus cause painting to extend beyond the areas defined by the two circles themselves. The following examples depict the results of extending the shading at the smaller and larger ends, respectively.

C#
private static void RadialPatternExample(PdfPage page, bool isExtendStart, float rStart, float rEnd)
{
    //Create function
    int numOfInputs = 1;
    int numOfOutputs = 3;                   //As a 3 components for a DeviceRGB  color space
    float exponent = 1;                     //linear interpolation
    float[] domain = { 0, 1 };              //domain of an input argument
    float[] range = { 0, 1, 0, 1, 0, 1 };   //domain of each output value
    float[] valuesAtStart = FS_COLOR.Yellow.ToDeviceRgb();
    float[] valuesAtEnd = FS_COLOR.Coral.ToDeviceRgb();
    var function = new PdfFuncExponential(numOfInputs, numOfOutputs, exponent, domain, range, valuesAtStart, valuesAtEnd);

    //Create rectangular path object and add it to the page content
    var rectObj = PdfPathObject.Create(FillModes.Winding, true);
    rectObj.Path.AppendRect(new FS_RECTF(0, 100, 150, 0));
    page.PageObjects.Add(rectObj);

    //Pattern definition. Radial Shading.
    var startCircle = new FS_CIRCLEF(50, 50, rStart);
    var endCircle = new FS_CIRCLEF(100, 50, rEnd);
    var pattern = new RadialPattern(page.Document, startCircle, endCircle, function, PdfColorSpace.DeviceRGB());
    pattern.ExtendStart = isExtendStart;

    //set pattern as the fill color of the rectangular path object.
    rectObj.SetFillColor(pattern);

    //Generate page content.
    page.GenerateContent();
}
Example 1
using (var doc = PdfDocument.Load("sample.pdf"))
{
    var page = doc.Pages[0];
    bool isExtendStart = false;
    float radiusStart = 23;
    float raduisEnd = 48;
    RadialPatternExample(page, isExtendStart, radiusStart, raduisEnd);
}
Example 2
using (var doc = PdfDocument.Load("sample.pdf"))
{
    var page = doc.Pages[0];
    bool isExtendStart = true;
    float radiusStart = 23;
    float raduisEnd = 48;
    RadialPatternExample(page, isExtendStart, radiusStart, raduisEnd);
}
Example 3
using (var doc = PdfDocument.Load("sample.pdf"))
{
    var page = doc.Pages[0];
    bool isExtendStart = false;
    float radiusStart = 48;
    float raduisEnd = 23;
    RadialPatternExample(page, isExtendStart, radiusStart, raduisEnd);
}
Example 4
using (var doc = PdfDocument.Load("sample.pdf"))
{
    var page = doc.Pages[0];
    bool isExtendStart = true;
    float radiusStart = 48;
    float raduisEnd = 23;
    RadialPatternExample(page, isExtendStart, radiusStart, raduisEnd);
}
Results of the first example.
radial 01
Results of the second example
radial 02
Results of the third example
radial 03
Results of the fourth example
radial 04

Type 4 Shadings (Free-Form Gouraud-Shaded Triangle Meshes)

Type 4 shadings (free-form Gouraud-shaded triangle meshes) are commonly used to represent complex colored and shaded three-dimensional shapes. The area to be shaded is defined by a path composed entirely of triangles. The color at each vertex of the triangles is specified, and a technique known as Gouraud interpolation is used to color the interiors. The interpolation functions defining the shading may be linear or nonlinear.

This type of shading is identified by the FreeFormPattern class and its Vertices property contains a sequence of vertex coordinates and color data that defines the triangle mesh.

All vertex coordinates are expressed in the shading’s target coordinate space. If the Functions property is set, only a single parametric value, t, is permitted for each vertex in place of the color components c1 ... cn in the FreeFormPatternVertexColor array.

The edge flag (TriangleEdge) associated with each vertex determines the way it connects to the other vertices of the triangle mesh. A vertex Va with an edge flag value fa = New begins a new triangle, unconnected to any other. At least two more vertices (Vb and Vc) must be provided, but their edge flags are ignored. These three vertices define a triangle (VaVbVc), as shown in the below figure.

new triangle

Subsequent triangles are defined by a single new vertex combined with two vertices of the preceding triangle. Given triangle (VaVbVс), where vertex Va precedes vertex Vb in the Vertices collection and Vb precedes Vc, a new vertex Vd can form a new triangle on side Vbc or side Vac, as shown below. (Side Vab is assumed to be shared with a preceding triangle and therefore is not available for continuing the mesh.) If the edge flag is fd = BC, the next vertex forms the triangle (Vb Vc Vd); if the edge flag is fd = AC, the next vertex forms the triangle (Va Vc Vd). An edge flag of fd = New would start a new triangle, as described above.

new triangles

Complex shapes can be created by using the edge flags to control the edge on which subsequent triangles are formed. The Vertices collection must provide vertex data for a whole number of triangles with appropriate edge flags; otherwise, an error occurs.

C#
using (var doc = PdfDocument.Load("sample.pdf"))
{
    var page = doc.Pages[0];

    //Create rectangular path object and add it to the page content
    var rectObj = PdfPathObject.Create(FillModes.Winding, true);
    rectObj.Path.AppendRect(new FS_RECTF(0, 100, 225, 0));
    page.PageObjects.Add(rectObj);

    //Pattern definition. Free Form Shading.
    var vertices = new FreeFormPattern.Vertex[]
    {
        //fd = New
        new FreeFormPattern.Vertex(TriangleEdge.New, 25, 100, FS_COLOR.Red.ToDeviceRgb()),
        new FreeFormPattern.Vertex(TriangleEdge.New, 0, 50, FS_COLOR.Green.ToDeviceRgb()),
        new FreeFormPattern.Vertex(TriangleEdge.New, 50, 50, FS_COLOR.Blue.ToDeviceRgb()),
        new FreeFormPattern.Vertex(TriangleEdge.New, 50, 50, FS_COLOR.Yellow.ToDeviceRgb()),
        new FreeFormPattern.Vertex(TriangleEdge.New, 25, 0, FS_COLOR.Cyan.ToDeviceRgb()),
        new FreeFormPattern.Vertex(TriangleEdge.New, 75, 0, FS_COLOR.Purple.ToDeviceRgb()),

        //fd = BC
        new FreeFormPattern.Vertex(TriangleEdge.New, 100, 100, FS_COLOR.Red.ToDeviceRgb()),
        new FreeFormPattern.Vertex(TriangleEdge.New, 75, 50, FS_COLOR.Green.ToDeviceRgb()),
        new FreeFormPattern.Vertex(TriangleEdge.New, 125, 50, FS_COLOR.Blue.ToDeviceRgb()),
        new FreeFormPattern.Vertex(TriangleEdge.BC, 100, 0, FS_COLOR.Yellow.ToDeviceRgb()),

        //fd = AC
        new FreeFormPattern.Vertex(TriangleEdge.New, 175, 100, FS_COLOR.Red.ToDeviceRgb()),
        new FreeFormPattern.Vertex(TriangleEdge.New, 150, 50, FS_COLOR.Green.ToDeviceRgb()),
        new FreeFormPattern.Vertex(TriangleEdge.New, 200, 50, FS_COLOR.Blue.ToDeviceRgb()),
        new FreeFormPattern.Vertex(TriangleEdge.AC, 225, 100, FS_COLOR.Yellow.ToDeviceRgb()),
    };
    var pattern = new FreeFormPattern(page.Document, PdfColorSpace.DeviceRGB(), vertices);

    //set pattern as the fill color of the rectangular path object.
    rectObj.SetFillColor(pattern);

    //Generate page content.
    page.GenerateContent();
}
Results of the example
freeform 01

Unlike shading types 1 to 3, types 4 to 7 are represented as streams. Each stream contains a sequence of vertex coordinates and color data that defines the triangle mesh. Such a stream is decoded into the Vertices collection. And also the Vertices collection is encoded into the stream. In a FreeFormPattern, each vertex is specified by the following values, in the order shown below and stored in the Stream property.

f x y c1 ... cn

where

f is the vertex’s edge flag, expressed in BitsPerFlag bits
x and y are its horizontal and vertical coordinates, expressed in BitsPerCoordinate bits each
c1...cn are its color components where n is the number of components in the shading’s color space, expressed in BitsPerComponent bits each, in the order expected by the ColorSpace

Each set of vertex data must occupy a whole number of bytes. If the total number of bits required is not divisible by 8, the last data byte for each vertex is padded at the end with extra bits, which are ignored.

The coordinates and color values are encoded/decoded according to the XMin, XMax, YMin, YMax, ColorMin, and ColorMax values.

For example, for the X coordinate the decoding formula can be written as follows:

Xo = Xmin + Xi * (Xmax - Xmin) / (2n - 1)

where

n is the value of BitsPerComponent
Xi is the input value from the Stream, in the domain 0 to 2n − 1
Xmin and Xmax are the values specified by the XMin and XMax properties.
Xo is the output value

Tip  Tip

When the Vertices collection is used to set vertices, vertex-to-stream encoding is always done with the following settings: BitsPerFlag = 8, BitsPerCoordinate = 32, BitsPerComponent = 16

Type 5 Shadings (Lattice-Form Gouraud-Shaded Triangle Meshes)

Type 5 shadings (lattice-form Gouraud-shaded triangle meshes) are similar to type 4, but instead of using free-form geometry, their vertices are arranged in a pseudorectangular lattice, which is topologically equivalent to a rectangular grid. The vertices are organized into rows, which need not be geometrically linear.

lattice-form

This type of shading is identified by the LatticeFormPattern class and its Vertices property contains a sequence of vertex coordinates and color data that defines the triangle mesh.

The class properties and data stream for LatticeFormPattern has the same format as for FreeFormPattern described above, except that LatticeFormPattern does not use edge flags to define the geometry of the triangle mesh. And the VerticesPerRow property gives the number of vertices in each row of the lattice. All of the vertices in a row are specified sequentially, followed by those for the next row. Given m rows of k vertices each, the triangles of the mesh are constructed using the following triplets of vertices, as shown in the above figure:

(Vi,j Vi, j+1 Vi+1, j)
(Vi,j+1 Vi+1,j Vi+1,j+1)
for 0 ≤ i ≤ m - 2,
0 ≤ j ≤ k - 2

C#
using (var doc = PdfDocument.Load("sample.pdf"))
{
    var page = doc.Pages[0];

    //Create rectangular path object and add it to the page content
    var rectObj = PdfPathObject.Create(FillModes.Winding, true);
    rectObj.Path.AppendRect(new FS_RECTF(0, 100, 150, 0));
    page.PageObjects.Add(rectObj);

    //Pattern definition. Free Form Shading.
    FS_COLOR[] colors = {
        FS_COLOR.Red, FS_COLOR.Green, FS_COLOR.Blue, FS_COLOR.Yellow,
        FS_COLOR.Magenta, FS_COLOR.CadetBlue, FS_COLOR.Orange, FS_COLOR.Purple,
        FS_COLOR.Gold, FS_COLOR.Black, FS_COLOR.WhiteSmoke, FS_COLOR.Violet,
    };
    var vertices = new LatticeFormPattern.Vertex[12];
    int verticesPerRow = 4;
    for (int i = 0, k = 0; i < 3; i++)
        for (int j = 0; j < verticesPerRow; j++)
        {
            float x = j * 50;
            float y = i * 50;
            vertices[k] = new LatticeFormPattern.Vertex(x, y, colors[k++].ToDeviceRgb());
        }
    var pattern = new LatticeFormPattern(page.Document, PdfColorSpace.DeviceRGB(), vertices, verticesPerRow);

    //set pattern as the fill color of the rectangular path object.
    rectObj.SetFillColor(pattern);

    //Generate page content.
    page.GenerateContent();
}
Results of the example
latticeform 01

Type 6 Shadings (Coons Patch Meshes)

Type 6 shadings (Coons patch meshes) are constructed from one or more color patches, each bounded by four cubic Bézier curves. Degenerate Bézier curves are allowed and are useful for certain graphical effects. At least one complete patch must be specified.

This type of shading is identified by the CubicBezierPattern class. The CubicBezierPatternPatch collection provides a sequence of Bézier control points and color values that define the shape and colors of each patch.

As in FreeFormPattern, each patch has an edge flag (PatchEdge) that indicates which edge, if any, it shares with the previous patch. An edge flag of New begins a new patch, unconnected to any other. This must be followed by 12 pairs of coordinates, x1 y1 x2 y2 … x12 y12 in the Points array, which specify the Bézier control points that define the four boundary curves. The below figure shows how these control points correspond to the cubic Bézier curves in the patch. Color values are given for the four corners of the patch, in the same order as the control points corresponding to the corners. Thus, c1 is the color at coordinates (x1, y1), c2 at (x4, y4), c3 at (x7, y7), and c4 at (x10, y10), as shown in the figure.

If the Functions property is set, the color data for each corner of a patch must be specified by a single parametric value t rather than by n separate color components c1...cn. All linear interpolation within the mesh is done using the t values. After interpolation, the results are passed to the function(s) specified in the Functions property to determine the color at each point.

cubic-bezier

The above figure also shows how other values of the edge flag (Second, Third, or Fourth) connect a new patch to one of the edges of the previous patch. In this case, some of the previous patch’s control points serve implicitly as control points for the new patch as well, and therefore are ignored.

cubic-bezier-connect
C#
using (var doc = PdfDocument.Load("sample.pdf"))
{
    var page = doc.Pages[0];

    //Create rectangular path object and add it to the page content
    var rectObj = PdfPathObject.Create(FillModes.Winding, true);
    rectObj.Path.AppendRect(new FS_RECTF(0, 100, 150, 0));
    page.PageObjects.Add(rectObj);

    //Pattern definition. Type 6 Shadings (Coons Patch Meshes)
    CubicBezierPattern.Patch[] patches =
    {
        new CubicBezierPattern.Patch(PatchEdge.New,
            25, 25,  0, 50, 50, 50,
            25, 75, 50, 100, 50, 50,
            75, 75, 50, 50, 100, 50,
            75, 25, 50, 0, 50, 50,
            FS_COLOR.Red.ToDeviceRgb(),
            FS_COLOR.Gold.ToDeviceRgb(),
            FS_COLOR.Bisque.ToDeviceRgb(),
            FS_COLOR.Violet.ToDeviceRgb()),
        new CubicBezierPattern.Patch(PatchEdge.Third,
            0, 0, 0, 0, 0, 0, 0, 0,                     //(x1, y1) (x2, y2) (x3, y3) (x3, x4) are ignored since we connect to the third edge of the previous patch
            75, 25, 125, 25,
            125, 25, 125, 25, 125, 75,
            125, 75, 125, 75, 75, 75,
            new float[]{0, 0, 0}, new float[]{0, 0, 0}, //color 1 and color 2 are ignored since we connect to the third edge of the previous patch
            FS_COLOR.GreenYellow.ToDeviceRgb(),
            FS_COLOR.BlueViolet.ToDeviceRgb()
        )
    };
    var pattern = new CubicBezierPattern(page.Document, PdfColorSpace.DeviceRGB(), patches);

    //set pattern as the fill color of the rectangular path object.
    rectObj.SetFillColor(pattern);

    //Generate page content.
    page.GenerateContent();
}
Results of the example
bezier 01

The below table summarizes the required data values for various values of the edge flag

Edge flag

Next set of data values

f = New

x1 y1 x2 y2 x3 y3 x4 y4 x5 y5 x6 y6 x7 y7 x8 y8 x9 y9 x10 y10 x11 y11 x12 y12
c1 c2 c3 c4

New patch; no implicit values

f = Second

x5 y5 x6 y6 x7 y7 x8 y8 x9 y9 x10 y10 x11 y11 x12 y12
c3 c4

Implicit values:

(x1, y1) = (x4, y4) previous
(x2, y2) = (x5, y5) previous
(x3, y3) = (x6, y6) previous
(x4, y4) = (x7, y7) previous
c1 = c2 previous
c2 = c3 previous

f = Third

x5 y5 x6 y6 x7 y7 x8 y8 x9 y9 x10 y10 x11 y11 x12 y12
c3 c4

Implicit values:

(x1, y1) = (x7, y7) previous
(x2, y2) = (x8, y8) previous
(x3, y3) = (x9, y9) previous
(x4, y4) = (x10, y10) previous
c1 = c3 previous
c2 = c4 previous

f = Fourth

x5 y5 x6 y6 x7 y7 x8 y8 x9 y9 x10 y10 x11 y11 x12 y12
c3 c4

Implicit values:

(x1, y1) = (x10, y10) previous
(x2, y2) = (x11, y11) previous
(x3, y3) = (x12, y12) previous
(x4, y4) = (x1, y1) previous
c1 = c4 previous
c2 = c1 previous

Type 7 Shadings (Tensor-Product Patch Meshes)

This type of shading is identified by the TensorPattern class. TensorPattern are identical to CubicBezierPattern, except that it is based on a bicubic tensor-product patch (TensorPatternPatch) defined by 16 control points instead of the 12 control points that define a cubic bezier patch. Although the CubicBezierPattern is more concise and easier to use, the TensorPattern affords greater control over color mapping.

Like the cubic bezier patch mapping, the tensor-product patch mapping is controlled by the location and shape of four cubic Bézier curves marking the boundaries of the patch. However, the tensor-product patch has four additional, “internal” control points to adjust the mapping.

tensor
C#
using (var doc = PdfDocument.Load("sample.pdf"))
{
    var page = doc.Pages[0];

    //Create rectangular path object and add it to the page content
    var rectObj = PdfPathObject.Create(FillModes.Winding, true);
    rectObj.Path.AppendRect(new FS_RECTF(0, 150, 160, 0));
    page.PageObjects.Add(rectObj);

    //Pattern definition. Type 7 Shadings (Tensor-Product Patch Meshes)
    TensorPattern.Patch[] patches =
    {
        new TensorPattern.Patch(PatchEdge.New,
            50,30, 30,10, 10,70,
            30,110, 60,90, 100,150,
            130,130, 100,90, 160,80,
            140,50, 110,60, 80,50,
            60,60, 50,80, 110,80, 100, 60,
            FS_COLOR.Yellow.ToDeviceRgb(),
            FS_COLOR.Red.ToDeviceRgb(),
            FS_COLOR.Coral.ToDeviceRgb(),
            FS_COLOR.LightGreen.ToDeviceRgb()
            )
    };
    var pattern = new TensorPattern(page.Document, PdfColorSpace.DeviceRGB(), patches);

    //set pattern as the fill color of the rectangular path object.
    rectObj.SetFillColor(pattern);

    //Generate page content.
    page.GenerateContent();
}
Results of the example
tensor 01

The geometry of the tensor-product patch can be visualized in terms of a cubic Bézier curve moving from the bottom boundary of the patch to the top. At the bottom and top, the control points of this curve coincide with those of the patch’s bottom (P00…P30) and top (P03…P33) boundary curves, respectively. As the curve moves from the bottom edge of the patch to the top, each of its four control points follows a trajectory that is in turn a cubic Bézier curve defined by the four control points in the corresponding column of the array. That is, the starting point of the moving curve follows the trajectory defined by control points P00…P03, the trajectory of the ending point is defined by points P30 P33, and those of the two intermediate control points by P10…P13 and P20…P23. Equivalently, the patch can be considered to be traced by a cubic Bézier curve moving from the left edge to the right, with its control points following the trajectories defined by the rows of the coordinate array instead of the columns.

The coordinates of the control points in a tensor-product patch are actually specified in the shading’s data Stream in the following order:

P00 P01 P02 P03 P13 P23 P33 P32 P31 P30 P20 P10 P11 P12 P22 P21

All control point coordinates are expressed in the shading’s target coordinate space. These are followed by the color values for the four corners of the patch, in the same order as the corners themselves. If the patch’s edge flag f is New, all 16 control points and four corner colors must be explicitly specified in the data stream. If f is Second, Third, or Fourth, the control points and colors for the patch’s shared edge are implicitly understood to be the same as those along the specified edge of the previous patch and are not repeated in the data stream. The below table summarizes the data values for various values of the edge flag f, expressed in terms of the row and column indices used in Figure above. See “Type 4 Shadings (Free-Form Gouraud-Shaded Triangle Meshes)” for further details on the format of the data.

Edge flag

Next set of data values

f = New

x00 y00 x01 y01 x02 y02 x03 y03 x13 y13 x23 y23 x33 y33 x32 y32 x31 y31 x30 y30 x20 y20 x10 y10 x11 y11 x12 y12 x22 y22 x21 y21
c00 c03 c33 c30

New patch; no implicit values

f = Second

x13 y13 x23 y23 x33 y33 x32 y32 x31 y31 x30 y30 x20 y20 x10 y10 x11 y11 x12 y12 x22 y22 x21 y21
c33 c30

Implicit values:

(x00 y00) = (x03 y03) previous
(x01 y01) = (x13 y13) previous
(x02 y02) = (x23 y23) previous
(x03 y03) = (x33 y33) previous
c00 = c03 previous
c03 = c33 previous

f = Third

x13 y13 x23 y23 x33 y33 x32 y32 x31 y31 x30 y30 x20 y20 x10 y10 x11 y11 x12 y12 x22 y22 x21 y21
c33 c30

Implicit values:

(x00 y00) = (x33 y33) previous
(x01 y01) = (x32 y32) previous
(x02 y02) = (x31 y31) previous
(x03 y03) = (x30 y30) previous
c00 = c33 previous
c03 = c30 previous

f = Fourth

x13 y13 x23 y23 x33 y33 x32 y32 x31 y31 x30 y30 x20 y20 x10 y10 x11 y11 x12 y12 x22 y22 x21 y21
c33 c30

Implicit values:

(x00 y00) = (x30 y30) previous
(x01 y01) = (x20 y20) previous
(x02 y02) = (x10 y10) previous
(x03 y03) = (x00 y00) previous
c00 = c30 previous
c03 = c00 previous

See Also