---
name: "PDF::Builder::Content"
section: "3pm"
platform: "linux"
package: "perl-pdf-builder"
version: "3.028-1"
release: "Arch Linux 2026-11-01"
platforms: ["linux"]
url: "https://new.carta.tech/PDF::Builder::Content"
---

# PDF::Builder::Content(3pm)

Methods for adding graphics and text to a PDF Inherits from PDF::Builder::Basic::PDF::Dict

## NAME

PDF::Builder::Content - Methods for adding graphics and text to a PDF

Inherits from PDF::Builder::Basic::PDF::Dict

## SYNOPSIS

```
    # Start with a PDF page (new or opened)
    my $pdf = PDF::Builder->new();
    my $page = $pdf->page();
    # Add new content object(s)
    my $content = $page->graphics();  # or gfx()
    #   and/or (as separate object name)
    my $content = $page->text();
    # Then call the methods below to add graphics and text to the page.
    # Note that negative coordinates can have unpredictable effects, so
    # keep your coordinates non-negative!
```

These methods add content to *streams* output for text or graphics objects. Unless otherwise restricted by a check that we are in or out of text mode, many methods listed here apply equally to text and graphics streams. It is possible that there *are* some which have no effect in one stream type or the other, but are currently lacking a check to prevent them from being  inserted into an inapplicable stream.

## METHODS

All public methods listed, *except as otherwise noted,* return `$self`, for ease of chaining calls.

### Coordinate Transformations

The methods in this section change the coordinate system for the current content object relative to the rest of the document. **Note:** the changes are relative to the *original* page coordinates (and  thus, absolute), not to the previous position! Thus, `"translate(10, 10); ` `translate(10, 10);"` ends up only moving the origin to `"[10, 10]"`, rather than  to `"[20, 20]"`. There is one call, `transform_rel()`, which makes your changes  *relative* to the previous position.

If you call more than one of these methods, the PDF specification recommends calling them in the following order: translate, rotate, scale, skew.  Each change builds on the last, and you can get unexpected results when calling them in a different order.

**CAUTION:** a *text* object ($content) behaves a bit differently. Individual translate, rotate, scale, and skew calls *cancel out* any previous settings. If you want to combine multiple transformations for text, use the `"transform"` call.

*translate*

```
    $content->translate($dx,$dy)
```

Moves the origin along the x and y axes to  `$dx` and `$dy` respectively.

*rotate*

```
    $content->rotate($degrees)
```

Rotates the coordinate system counter-clockwise (anti-clockwise) around the current origin. Use a negative argument to rotate clockwise. Note that 360  degrees will be treated as 0 degrees.

**Note:** Unless you have already moved (translated) the origin, it is, and will remain, at the lower left corner of the visible sheet. It will *not* automatically shift to another corner. For example, a rotation of +90 degrees (counter-clockwise) will leave the entire visible sheet in negative Y territory (0 at the left edge, -original\_width at the right edge), while X remains in positive territory (0 at bottom, +original\_height at the top edge).

This `rotate()` call permits any angle. Do not confuse it with the *page* rotation `"rotate"` call, which only permits increments of 90 degrees (with opposite sign!), but *does* shift the origin to another corner of the sheet.

*scale*

```
    $content->scale($sx,$sy)
```

Scales (stretches) the coordinate systems along the x and y axes. Separate multipliers are provided for x and y.

*skew*

```
    $content->skew($skx,$sky)
```

Skews the coordinate system by `$skx` degrees  (counter-clockwise/anti-clockwise) from the x axis *and* `$sky` degrees (clockwise) from the y axis. Note that 360 degrees will be treated the same as 0 degrees.

*transform*

```
    $content->transform(%opts)
```

Use one or more of the given `%opts:`

```
    $content->transform(
        'translate' => [$dx,$dy],
        'rotate'    => $degrees,
        'scale'     => [$sx,$sy],
        'skew'      => [$skx,$sky],
        'matrix'    => [$a, $b, $c, $d, $e, $f],
        'point'     => [$x,$y]
        'repeat'    => $boolean
    )
```

A six element list may be given (`"matrix"`) for a  further transformation matrix:

```
    $a = cos(rot) * scale factor for X
    $b = sin(rot) * tan(skew for X)
    $c = -sin(rot) * tan(skew for Y)
    $d = cos(rot) * scale factor for Y
    $e = translation for X
    $f = translation for Y
```

Performs multiple coordinate transformations in one call, in the order recommended by the PDF specification (translate, rotate, scale, skew). This is equivalent to making each transformation separately, *in the* *indicated order*. A matrix of 6 values may also be given (`"matrix"`). The transformation matrix  is updated.  A `"point"` may be given (a point to be multiplied \[transformed\] by the  completed matrix). Omitted options will be unchanged.

If `"repeat"` is true, and if this is not the first call to a transformation method, the previous transformation will be performed again, modified by any other provided arguments.

*transform\_rel*

```
    $content->transform_rel(%opts)
```

Makes transformations similarly to `"transform"`, except that it *adds* to the previously set values, rather than *replacing* them (except for  *scale*, which **multiplies** the new values with the old).

Unlike `"transform"`, `"matrix"` and `"point"` are not supported.

*matrix*

```
    $content->matrix($a, $b, $c, $d, $e, $f)
```

*(Advanced)* Sets the current transformation matrix manually. Unless you have a particular need to enter transformations manually, you should use the `"transform"` method instead.

```
    $a = cos(rot) * scale factor for X
    $b = sin(rot) * tan(skew for X)
    $c = -sin(rot) * tan(skew for Y)
    $d = cos(rot) * scale factor for Y
    $e = translation for X
    $f = translation for Y
```

In text mode, the text matrix is **returned**.  In graphics mode, `$self` is **returned**.

### Graphics State Parameters

The following calls also affect the **text** state.

*linewidth, line\_width*

```
    $content->linewidth($width)
```

Sets the width of the stroke (in points). This is the line drawn in graphics  mode, or the *outline* of a character in text mode (with appropriate `"render"`  mode). If no `$width` is given, the current setting is **returned**. If the  width is being set, `$self` is **returned** so that calls may be chained.

**Alternate name:** `"line_width"`

This is provided for compatibility with PDF::API2.

*linecap, line\_cap*

```
    $content->linecap($style)
```

Sets the style to be used at the end of a stroke. This applies to lines which come to a free-floating end, *not* to "joins" ("corners") in  polylines (see `"linejoin"`).

**Alternate name:** `"line_cap"`

This is provided for compatibility with PDF::API2.

- "butt" or "b" or 0 = Butt Cap (default)

  The stroke ends at the end of the path, with no projection.

- "round" or "r" or 1 = Round Cap

  A semicircular arc is drawn around the end of the path with a diameter equal to the line width, and is filled in.

- "square" or "s" or 2 = Projecting Square Cap

  The stroke continues past the end of the path for half the line width.

If no `$style` is given, the current setting is **returned**. If the style is being set, `$self` is **returned** so that calls may be chained.

Either a number or a string (case-insensitive) may be given.

*linejoin, line\_join*

```
    $content->linejoin($style)
```

Sets the style of join to be used at corners of a path (within a multisegment polyline).

**Alternate name:** `"line_join"`

This is provided for compatibility with PDF::API2.

- "miter" or "m" or 0 = Miter Join, default

  The outer edges of the strokes extend until they meet, up to the limit specified by *miterlimit*. If the limit would be surpassed, a *bevel* join is used instead. For a given linewidth, the more acute the angle is (closer to 0 degrees), the higher the ratio of miter length to linewidth will be, and  that's what *miterlimit* controls -- a very "pointy" join is replaced by a bevel.

- "round" or "r" or 1 = Round Join

  A filled circle with a diameter equal to the *linewidth* is drawn around the corner point, producing a rounded corner. The arc will meet up with the sides of the line in a smooth tangent.

- "bevel" or "b" or 2 = Bevel Join

  A filled triangle is drawn to fill in the notch between the two strokes.

If no `$style` is given, the current setting is **returned**. If the style is being set, `$self` is **returned** so that calls may be chained.

Either a number or a string (case-insensitive) may be given.

*miterlimit, miter\_limit*

```
    $content->miterlimit($ratio)
```

Sets the miter limit when the line join style is a *miter* join.

The ratio is the maximum length of the miter (inner to outer corner) divided  by the line width. Any miter above this ratio will be converted to a *bevel*  join. The practical effect is that lines meeting at shallow angles are chopped off instead of producing long pointed corners.

The default miter limit is 10.0 (approximately 11.5 degree cutoff angle). The smaller the limit, the larger the cutoff angle.

If no `$ratio` is given, the current setting is **returned**. If the ratio is being set, `$self` is **returned** so that calls may be chained.

**Alternate name:** `"miter_limit"`

This is provided for compatibility with PDF::API2. Long ago, in a distant galaxy, this method was misnamed *meterlimit*, but that was removed a while ago. Any code using that name should be updated!

*linedash, line\_dash\_pattern*

```
    $content->linedash()
    $content->linedash($length)
    $content->linedash($dash_length, $gap_length, ...)
    $content->linedash('pattern' => [$dash_length, $gap_length, ...], 'shift' => $offset)
```

Sets the line dash pattern.

If called without any arguments, a solid line will be drawn.

If called with one argument, the dashes and gaps (strokes and spaces) will have equal lengths.

If called with two or more arguments, the arguments represent alternating dash and gap lengths.

If called with a hash of arguments, the *pattern* array may have one or more elements, specifying the dash and gap lengths.  A dash phase may be set (*shift*), which is a **positive integer** specifying the distance into the pattern at which to start the dashed line. Note that if you wish to give a *shift* amount, using `"shift"`, you need to use `"pattern"` instead of one or two elements.

If an **odd** number of dash array elements are given, the list is repeated by  the reader software to form an even number of elements (pairs).

If a single argument of **-1** is given, the current setting is **returned**.  This is an array consisting of two elements: an anonymous array containing the  dash pattern (default: empty), and the shift (offset) amount (default: 0).  It may be used directly in a **linedash()** call, as linedash will recognize the  special pattern \[ array, number \].

If the dash pattern is being *set*, `$self` is **returned** so that calls may  be chained.

**Alternate name:** `"line_dash_pattern"`

This is provided for compatibility with PDF::API2.

*flatness, flatness\_tolerance*

```
    $content->flatness($tolerance)
```

*(Advanced)* Sets the maximum variation in output pixels when drawing curves. The defined range of `$tolerance` is 0 to 100, with 0 meaning *use*  *the device default flatness*. According to the PDF specification, you should  not try to force visible line segments (the curve's approximation); results  will be unpredictable. Usually, results for different flatness settings will be  indistinguishable to the eye.

The `$tolerance` value is silently clamped to be between 0 and 100.

If no `$tolerance` is given, the current setting is **returned**. If the  tolerance is being set, `$self` is **returned** so that calls may be chained.

**Alternate name:** `"flatness_tolerance"`

This is provided for compatibility with PDF::API2.

*egstate*

```
    $content->egstate($object)
```

*(Advanced)* Adds an Extended Graphic State **object** containing additional state parameters.

### Path Construction (Drawing)

*move*

```
    $content->move($x,$y)
```

Starts a new path at the specified coordinates. Note that multiple x,y pairs *can* be given, although this isn't that useful (only the last pair would have an effect).

*close*

```
    $content->close()
```

Closes and ends the current path by extending a line from the current position to the starting position.

*Straight line constructs*

**Note:** None of these will actually be *visible* until you call `"stroke"`,  `"fill"`, or `"fillstroke"`. They are merely setting up the path to draw.

line

```
    $content->line($x,$y)
    $content->line($x,$y, $x2,$y2,...)
```

Extends the path in a line from the *current* coordinates to the specified coordinates, and updates the current position to be the new coordinates.

Multiple additional `"[$x,$y]"` pairs are permitted, to draw joined multiple  line segments. Note that this is **not** equivalent to a polyline (see `"poly"`), because the first `"[$x,$y]"` pair in a polyline is a *move* operation. Also, the `"linecap"` setting will be used rather than the `"linejoin"` setting for treating the ends of segments.

hline, vline

```
    $content->hline($x)
    $content->vline($y)
```

Shortcuts for drawing horizontal and vertical lines from the current position. They are like `line()`, but to the new x and current y (`"hline"`), or to the the current x and new y (`"vline"`).

polyline

```
    $content->polyline($x1,$y1, ..., $xn,$yn)
```

This is a shortcut for creating a polyline path from the current position. It  extends the path in line segments along the specified coordinates. The current position is changed to the last `"[$x,$y]"` pair given.

A critical distinction between the `"polyline"` method and the `"poly"` method  is that in this (`"polyline"`), the first pair of coordinates are treated as a *draw* order (unlike the *move* order in `"poly"`).

Thus, while this is provided for compatibility with PDF::API2, it is *not* really an alias or alternate name for `"poly"`!

poly

```
    $content->poly($x1,$y1, ..., $xn,$yn)
```

This is a shortcut for creating a polyline path. It moves to `"[$x1,$y1]"`, and then extends the path in line segments along the specified coordinates. The current position is changed to the last `"[$x,$y]"` pair given.

The difference between a polyline and a `"line"` with multiple `"[$x,$y]"` pairs is that the first pair in a polyline are a *move*, while in a line they are a *draw*. Also, `"line_join"` instead of `"line_cap"` is used to control the appearance of the ends of line segments.

A critical distinction between the `"polyline"` method and the `"poly"` method  is that in this (`"poly"`), the first pair of coordinates are treated as a *move* order.

rectangle

```
    $content = $content->rectangle($x1, $y1, $x2, $y2)
```

Creates a new rectangle-shaped path, between the two corner points `"[$x1, $y1]"` and `"[$x2, $y2]"`. The corner points are swapped if necessary, to make "1" the lower left and "2" the upper right (x2 \> x1 and y2 \> y1). The object (here, `$content`) is returned, to permit chaining.

**Note** that this is *not* an alias or alternate name for `"rect"`. It handles only one rectangle, and takes corner coordinates for corner "2", rather than the width and height.

rect

```
    $content = $content->rect($x,$y, $w,$h)
    $content = $content->rect($x1,$y1, $w1,$h1, ..., $xn,$yn, $wn,$hn)
```

This creates paths for one or more rectangles, with their lower left points at `"[$x,$y]"` and specified widths (+x direction) and heights (+y direction).  Negative widths and heights are permitted, which draw to the left (-x) and  below (-y) the given corner point, respectively.  The current position is changed to the `"[$x,$y]"` of the last rectangle given. Note that this is the *starting* point of the rectangle, not the end point. The object (here, `$content`) is returned, to permit chaining.

**Note** that this differs from the `"rectangle"` method in that multiple rectangles may be drawn in one call, and the second pair for each rectangle are the width and height, not the opposite corner coordinates.

rectxy

```
    $content->rectxy($x1,$y1, $x2,$y2)
```

This creates a rectangular path, with `"[$x1,$y1]"` and `"[$x2,$y2]"` specifying *opposite* corners. They can be Lower Left and Upper Right, *or* Upper Left and Lower Right, in either order, so long as they are diagonally opposite each other.  The current position is changed to the `"[$x1,$y1]"` (first) pair.

This is not *quite* an alias or alternate name for `"rectangle"`, as it  permits the corner points to be specified in any order.

*Curved line constructs*

**Note:** None of these will actually be *visible* until you call `"stroke"`, `"fill"`, or `"fillstroke"`. They are merely setting up the path to draw.

circle

```
    $content->circle($xc,$yc, $radius)
```

This creates a circular path centered on `"[$xc,$yc]"` with the specified radius. It does **not** change the current position.

ellipse

```
    $content->ellipse($xc,$yc, $rx,$ry)
```

This creates a closed elliptical path centered on `"[$xc,$yc]"`, with axis radii (semidiameters) specified by `$rx` (x axis) and `$ry` (y axis), respectively. It does not change the current position.

arc

```
    $content->arc($xc,$yc, $rx,$ry, $alpha,$beta, $move, $dir)
    $content->arc($xc,$yc, $rx,$ry, $alpha,$beta, $move)
```

This extends the path along an arc of an ellipse centered at `"[$xc,$yc]"`. The semidiameters of the elliptical curve are `$rx` (x axis) and `$ry`  (y axis), respectively, and the arc sweeps from `$alpha` degrees to `$beta` degrees. The current position is then set to the endpoint of the arc.

Set `$move` to a *true* value if this arc is the beginning of a new path instead of the continuation of an existing path. Either way, the  current position will be updated to the end of the arc. Use `"$rx == $ry"` for a circular arc.

The optional `$dir` arc sweep direction defaults to 0 (*false*), for a counter-clockwise/anti-clockwise sweep. Set to 1 (*true*) for a clockwise sweep.

pie

```
    $content->pie($xc,$yc, $rx,$ry, $alpha,$beta, $dir)
    $content->pie($xc,$yc, $rx,$ry, $alpha,$beta)
```

Creates a pie-shaped path from an ellipse centered on `"[$xc,$yc]"`. The x-axis and y-axis semidiameters of the ellipse are `$rx` and `$ry`, respectively, and the arc sweeps from `$alpha` degrees to `$beta` degrees.  It does not change the current position. Depending on the sweep angles and direction, this can draw either the pie "slice" or the remaining pie (with slice removed). Use `"$rx == $ry"` for a circular pie. Use a different `"[$xc,$yc]"` for the slice, to offset it from the remaining pie.

The optional `$dir` arc sweep direction defaults to 0 (*false*), for a counter-clockwise/anti-clockwise sweep. Set to 1 (*true*) for a clockwise sweep.

This is a shortcut to draw a section of elliptical (or circular) arc and connect it to the center of the ellipse or circle, to form a pie shape.

curve

```
    $content->curve($cx1,$cy1, $cx2,$cy2, $x,$y)
```

This extends the path in a curve from the current point to `"[$x,$y]"`, using the two specified *control* points to create a **cubic Bezier curve**, and updates the current position to be the new point (`"[$x,$y]"`).

Within a **text** object, the text's baseline follows the Bezier curve.

Note that while multiple sets of three `"[x,y]"` pairs are permitted, these are treated as *independent* cubic Bezier curves. There is no attempt made to smoothly blend one curve into the next!

qbspline, spline

```
    $content->qbspline($cx1,$cy1, $x,$y)
```

This extends the path in a curve from the current point to `"[$x,$y]"`, using the two specified points to create a quadratic Bezier curve, and updates  the current position to be the new point.

Internally, these splines are one or more cubic Bezier curves (see `"curve"`)  with the two control points synthesized from the two given points (a control  point and the end point of a *quadratic* Bezier curve).

Note that while multiple sets of two `"[x,y]"` pairs are permitted, these are treated as *independent* quadratic Bezier curves. There is no attempt  made to smoothly blend one curve into the next!

Further note that this "spline" does not match the common definition of a spline being a *continuous* curve passing *through* **all** the given  points! It is a piecewise non-continuous cubic Bezier curve. Use with care, and  do not make assumptions about splines for you or your readers. You may wish to use the `"bspline"` call to have a continuously smooth spline to pass through all given points.

Pairs of points (control point and end point) are consumed in a loop. If one  point or coordinate is left over at the end, it is discarded (as usual practice for excess data to a routine). There is no check for duplicate points or other  degeneracies.

**Alternate name:** `"spline"`

This method is still named `"spline"` in PDF::API2, so for compatibility, that name is usable here. Since there are both quadratic and cubic splines available in PDF, it is preferred to use more descriptive names such as `"qbspline"` and `"cbspline"` to minimize confusion.

bspline, cbspline

```
    $content->bspline($ptsRef, %opts)
```

This extends the path in a curve from the current point to the end of a list of coordinate pairs in the array referenced by `$ptsRef`. Smoothly continuous cubic Bezier splines are used to create a curve that passes through *all* the given points. Multiple control points are synthesized; they are not  supplied in the call. The current position is updated to the last point.

Internally, these splines are one cubic Bezier curve (see `"curve"`) per pair of input points, with the two control points synthesized from the tangent  through each point as set by the polyline that would connect each point to its neighbors. The intent is that the resulting curve should follow reasonably  closely a polyline that would connect the points, and should avoid any major  excursions. See the discussions below for the handling of the control points at the endpoints (current point and last input point). The point at the end of the last line or curve drawn becomes the new current point.

Options `%opts:`

- 'firstseg' =\> '*mode*'

  where *mode* is

  - curve

    This is the **default** behavior. This forces the first segment (from the current point to the first given point) to be drawn as a cubic Bezier curve. This means that the direction of the curve coming off the current point is unconstrained (it will end up being a reflection of the tangent at the first given point).

  - line1

    This forces the first segment (from the current point to the first given point) to be drawn as a curve, with the tangent at the current point to be constrained  as parallel to the polyline segment.

  - line2

    This forces the first segment (from the current point to the first given point) to be drawn as a line segment. This also sets the tangent through the first given point as a continuation of the line, as well as constraining the direction of the line at the current point.

  - constraint1

    This forces the first segment (from the current point to the first given point) to **not** be drawn, but to be an invisible curve (like mode=line1) to leave the tangent at the first given point unconstrained. A *move* will be made to  the first given point, and the current point is otherwise ignored.

  - constraint2

    This forces the first segment (from the current point to the first given point) to **not** be drawn, but to be an invisible line (like mode=line2) to constrain the tangent at the first given point. A *move* will be made to the first given point, and the current point is otherwise ignored.

- 'lastseg' =\> '*mode*'

  where *mode* is

  - curve

    This is the **default** behavior. This forces the last segment (to the last given input point) to be drawn as a cubic Bezier curve. This means that the direction of the curve going to the last point is unconstrained (it will end up being a reflection of the tangent at the next-to-last given point).

  - line1

    This forces the last segment (to the last given input point) to be drawn as a  curve with the the tangent through the last given point parallel to the  polyline segment, thus constraining the direction of the line at the last  point.

  - line2

    This forces the last segment (to the last given input point) to be drawn as a line segment. This also sets the tangent through the  next-to-last given point as a back continuation of the line, as well as  constraining the direction of the line at the last point.

  - constraint1

    This forces the last segment (to the last given input point) to **not** be drawn, but to be an invisible curve (like mode=line1) to leave the tangent at the next-to-last given point unconstrained. The last given  input point is ignored, and next-to-last point becomes the new current point.

  - constraint2

    This forces the last segment (to the last given input point) to **not** be drawn, but to be an invisible line (like mode=line2) to constrain the tangent at the next-to-last given point. The last given input point is ignored, and next-to-last point becomes the new current point.

- 'ratio' =\> *n*

  *n* is the ratio of the length from a point to a control point to the length of the polyline segment on that side of the given point. It must be greater than 0.1, and the default is 0.3333 (1/3).

- 'colinear' =\> '*mode*'

  This describes how to handle the middle segment when there are four or more  colinear points in the input set. A *mode* of 'line' specifies that a line  segment will be drawn between each of the interior colinear points. A *mode*  of 'curve' (this is the default) will draw a Bezier curve between each of those  points.

  `"colinear"` applies only to interior runs of colinear points, between curves.  It does not apply to runs at the beginning or end of the point list, which are drawn as line segments or linear constraints regardless of *firstseg* and  *lastseg* settings.

- 'debug' =\> *N*

  If *N* is 0 (the default), only the spline is returned. If it is greater than 0, a number of additional items will be drawn: (N\>0) the points, (N\>1) a green  solid polyline connecting them, (N\>2) blue original tangent lines at each  interior point, and (N\>3) red dashed lines and hollow points representing the  Bezier control points.

  **Special cases**

  Adjacent points which are duplicates are consolidated.  An extra coordinate at the end of the input point list (not a full  `"[x,y]"` pair) will, as usual, be ignored.

- 0 given points (after duplicate consolidation)

  This leaves only the current point (unchanged), so it is a no-op.

- 1 given point (after duplicate consolidation)

  This leaves the current point and one point, so it is rendered as a line, regardless of `%opt` flags.

- 2 given points (after duplicate consolidation)

  This leaves the current point, an intermediate point, and the end point. If the three points are colinear, two line segments will be drawn. Otherwise, both segments are curves (through the tangent at the intermediate point). If either end segment mode is requested to be a line or constraint, it is treated as a  **line1** mode request instead.

- *N* colinear points at beginning or end

  *N* colinear points at beginning or end of the point set causes *N-1* line  segments (`"line2"` or `"constraint2"`, regardless of the settings of  `"firstseg"`, `"lastseg"`, and `"colinear"`.

  **Alternate name:** `"cbspline"`

  This is to emphasize that it is a *cubic* Bezier spline, as opposed to a *quadratic* Bezier spline (see `"qbspline"` above).

bogen

```
    $content->bogen($x1,$y1, $x2,$y2, $radius, $move, $larger, $reverse)
    $content->bogen($x1,$y1, $x2,$y2, $radius, $move, $larger)
    $content->bogen($x1,$y1, $x2,$y2, $radius, $move)
    $content->bogen($x1,$y1, $x2,$y2, $radius)
```

(*bogen* is German for *bow*, as in a segment (arc) of a circle. This is a  segment of a circle defined by the intersection of two circles of a given  radius, with the two intersection points as inputs. There are **four** possible  resulting arcs, which can be selected with `$larger` and `$reverse`.)

This extends the path along an arc of a circle of the specified radius between `"[$x1,$y1]"` to `"[$x2,$y2]"`. The current position is then set to the endpoint of the arc (`"[$x2,$y2]"`).

Set `$move` to a *true* value if this arc is the beginning of a new path instead of the continuation of an existing path. Note that the default  (`$move` = *false*) is *not* a straight line to *P1* and then the arc, but a blending into the curve from the current point. It will often *not* pass through *P1*!

Set `$larger` to a *true* value to draw the larger ("outer") arc between the  two points, instead of the smaller one. Both arcs are drawn *clockwise* from  *P1* to *P2*. The default value of *false* draws the smaller arc. Note that the "other" circle's larger arc is used (the center point is  "flipped" across the line between *P1* and *P2*), rather than using the  "remainder" of the smaller arc's circle (which would necessitate reversing the direction of travel along the arc -- see `$reverse`).

Set `$reverse` to a *true* value to draw the mirror image of the specified arc (flip it over, so that its center point is on the other side of the line connecting the two points). Both arcs are drawn *counter-clockwise* from *P1* to *P2*. The default (*false*) draws  clockwise arcs. An arc is **always** drawn from *P1* to *P2*; the direction (clockwise or counter-clockwise) may be chosen.

The `$radius` value cannot be smaller than **half** the distance from  `"[$x1,$y1]"` to `"[$x2,$y2]"`. If it is too small, the radius will be set to half the distance between the points (resulting in an arc that is a semicircle). This is a silent error, as even if the points are correct, due to rounding etc. they may not fall *exactly* on the two circles.

You can think of "looking" from *P1* to *P2*. In the degenerate case, where the radius is exactly half the distance between the points, there is no difference between "small" and "large" arcs, and both circles will coincide with their center half way between *P1* and *P2*. Only the direction matters. Once the radius is any larger, the two circles become distinct. The primary  circle is centered to your right, whose small arc is CW on your left; the  secondary circle is centered to your left, whose small arc is CCW on your  right. The "large" arcs are the arcs using the remainder of the circles: CW  large is part of the left (secondary) circle, and CCW large is part of the  right (primary) circle.

### Path Painting (Drawing)

*stroke*

```
    $content->stroke()
```

Strokes the current path. That is, it is drawing solid or dashed *lines*, but **not** filling areas.

*fill*

```
    $content->fill($use_even_odd_fill)
    $content->fill('rule' => $rule)
    $content->fill()  # use default nonzero rule
```

Fill the current path's enclosed *area*.  It does *not* stroke the enclosing path around the area.

- $user\_even\_odd\_fill = 0 or *false* (**default**)

  - $rule = 'nonzero'

  If the path intersects with itself, the *nonzero* winding rule will be used to determine which part of the path is filled in. This basically fills in *everything* inside the path, except in some situations depending on the direction of the path.

- $user\_even\_odd\_fill = 1 (non-zero value) or *true*

  - $rule = 'even-odd'

  If the path intersects with itself, the *even-odd* winding rule will be used to determine which part of the path is filled in. In most cases, this means that the filling state alternates each time the path is intersected. This basically will fill alternating closed sub-areas.

See the PDF Specification, section 8.5.3.3 (in version 1.7),  for more details on filling.

The "rule" parameter is added for PDF::API2 compatibility.

*fillstroke, paint, fill\_stroke*

```
    $content->fillstroke($use_even_odd_fill)
    $content->fillstroke('rule' => $rule)
    $content->fillstroke()  # use default nonzero rule
```

**Fill** the current path's enclosed *area* and then **stroke** the enclosing  path around the area (possibly with a different color).

- $user\_even\_odd\_fill = 0 or *false* (**default**)

  - $rule = 'nonzero'

  If the path intersects with itself, the *nonzero* winding rule will be used to determine which part of the path is filled in. This basically fills in *everything* inside the path, except in some situations depending on the direction of the path.

- $user\_even\_odd\_fill = 1 (non-zero value) or *true*

  - $rule = 'even-odd'

  If the path intersects with itself, the *even-odd* winding rule will be used to determine which part of the path is filled in. In most cases, this means that the filling state alternates each time the path is intersected. This basically will fill alternating closed sub-areas.

See the PDF Specification, section 8.5.3.3 (in version 1.7),  for more details on filling.

The "rule" parameter is added for PDF::API2 compatibility.

**Alternate names:** `"paint"` and `"fill_stroke"`

`"paint"` is for compatibility with PDF::API2, while `"fill_stroke"` is added for compatibility with many other PDF::API2-related renamed methods.

*clip*

```
    $content->clip($use_even_odd_fill)
    $content->clip('rule' => $rule)
    $content->clip()  # use default nonzero rule
```

Modifies the current clipping path by intersecting it with the current path. Initially (a fresh page), the clipping path is the entire media. Each definition of a path, and a `clip()` call, intersects the new path with the existing clip path, so the resulting clip path is no larger than the new path,  and may even be empty if the intersection is null.

- $user\_even\_odd\_fill = 0 or *false* (**default**)

  - $rule = 'nonzero'

  If the path intersects with itself, the *nonzero* winding rule will be used to determine which part of the path is included (clipped in or out).  This basically includes *everything* inside the path, except in some  situations depending on the direction of the path.

- $user\_even\_odd\_fill = 1 (non-zero value) or *true*

  - $rule = 'even-odd'

  If the path intersects with itself, the *even-odd* winding rule will be used to determine which part of the path is included. In most cases, this means that the inclusion state alternates each time the path is intersected. This basically will include alternating closed sub-areas.

It is common usage to make the  `endpath()` call (**n**) after the `clip()` call, to clear the path (unless  you want to reuse that path, such as to fill and/or stroke it to show the clip  path). If you want to clip text glyphs, it gets rather complicated, as a clip port cannot be created within a text object (that will have an effect on text).  See the object discussion in "Rendering Order" in PDF::Builder::Docs.

```
    my $grfxC1 = $page->gfx();
    my $textC  = $page->text();
    my $grfxC2 = $page->gfx();
     ...
    $grfxC1->save();
    $grfxC1->endpath();
    $grfxC1->rect(...);
    $grfxC1->clip();
    $grfxC1->endpath();
     ...
    $textC->  output text to be clipped
     ...
    $grfxC2->restore();
```

The "rule" parameter is added for PDF::API2 compatibility.

*endpath, end*

```
    $content->endpath()
```

Ends the current path without explicitly enclosing it. That is, unlike `"close"`, there is **no** line segment  drawn back to the starting position. This is often used to end the current path without filling or stroking, for the side effect of changing the current clipping path.

**Alternate name:** `"end"`

This is provided for compatibility with PDF::API2. Do not confuse it with the `"$pdf->end()"` method!

*shade*

```
    $content->shade($shade, @coord)
```

Sets the shading matrix.

- $shade

  A hash reference that includes a `name()` method for the shade name.

- @coord

  An array of 4 items: X-translation, Y-translation,  X-scaled and translated, Y-scaled and translated.

### Colors

*fillcolor, fill\_color, strokecolor, stroke\_color*

```
    $content->fillcolor($color)
    $content->strokecolor($color)
```

Sets the fill (enclosed area) or stroke (path) color. The interior of text characters are *filled*, and (*if* ordered by `"render"`) the outline is *stroked*.

```
    # Use a named color
    # -> RGB color model
    # there are many hundreds of named colors defined in
    # PDF::Builder::Resource::Colors
    $content->fillcolor('blue');
    # Use an RGB color (# followed by 3, 6, 9, or 12 hex digits)
    # -> RGB color model
    # This maps to 0-1.0 values for red, green, and blue
    $content->fillcolor('#FF0000');   # red
    # Use a CMYK color (% followed by 4, 8, 12, or 16 hex digits)
    # -> CMYK color model
    # This maps to 0-1.0 values for cyan, magenta, yellow, and black
    $content->fillcolor('%FF000000');   # cyan
    # Note: you might wish to make use of packages such as
    #  HashData::Color::PantoneToCMYK to map "Pantone" color names/codes to a
    #  set of CMYK values
    # Use an HSV color (! followed by 3, 6, 9, or 12 hex digits)
    # -> RGB color model
    # This maps to 0-360 degrees for the hue, and 0-1.0 values for
    # saturation and value
    $content->fillcolor('!FF0000');
    # Use an HSL color (& followed by 3, 6, 9, or 12 hex digits)
    # -> L*a*b color model
    # This maps to 0-360 degrees for the hue, and 0-1.0 values for
    # saturation and lightness. Note that 360 degrees = 0 degrees (wraps)
    $content->fillcolor('&FF0000');
    # Use an L*a*b color ($ followed by 3, 6, 9, or 12 hex digits)
    # -> L*a*b color model
    # This maps to 0-100 for L, -100 to 100 for a and b
    $content->fillcolor('$FF0000');
```

In all cases, if too few digits are given, the given digits are silently right-padded with 0's (zeros). If an incorrect number  of digits are given, the next lowest number of expected digits are used, and the remaining digits are silently ignored.

```
    # A single number between 0.0 (black) and 1.0 (white) is an alternate way
    # of specifying a gray scale.
    $content->fillcolor(0.5);
    # Three array elements between 0.0 and 1.0 is an alternate way of specifying
    # an RGB color.
    $content->fillcolor(0.3, 0.59, 0.11);
    # Four array elements between 0.0 and 1.0 is an alternate way of specifying
    # a CMYK color.
    $content->fillcolor(0.1, 0.9, 0.3, 1.0);
```

In all cases, if a number is less than 0, it is silently turned into a 0. If a number is greater than 1, it is silently turned into a 1. This "clamps" all values to the range 0.0-1.0.

```
    # A single reference is treated as a pattern or shading space.
    # Two or more entries with the first element a Perl reference, is treated
    # as either an indexed colorspace reference plus color-index(es), or
    # as a custom colorspace reference plus parameter(s).
```

If no value was passed in, the current fill color (or stroke color) *array*  is **returned**, otherwise `$self` is **returned**.

**Alternate names:** `"fill_color"` and `"stroke_color"`.

These are provided for PDF::API2 compatibility.

### External Objects

*image*

```
    $content->image($image_object, $x,$y, $width,$height)
    $content->image($image_object, $x,$y, $scale)
    $content->image($image_object, $x,$y)
    $content->image($image_object)
    # Example
    my $image_object = $pdf->image_jpeg($my_image_file);
    $content->image($image_object, 100, 200);
```

Places an image on the page in the specified location (specifies the lower  left corner of the image). The default location is `"[0,0]"`.

If coordinate transformations have been made (see *Coordinate* *Transformations* above), the position and scale will be relative to the updated coordinates. Otherwise, `"[0,0]"` will represent the bottom left corner of the page, and `$width` and `$height` will be measured at 72dpi.

For example, if you have a 600x600 image that you would like to be shown at 600dpi (i.e., one inch square), set the width and height to 72. (72 Big Points is one inch)

If passed the output of `image_svg()`, `image()` will simply pass it on to the `object()` method, with adjusted parameters. Note that this usage  requires that the `"width"` and `"height"` are replaced by `"scale_x"` and `"scale_y"` values (optionally).

*formimage*

```
    $content->formimage($form_object, $x,$y, $scaleX, $scaleY)
    $content->formimage($form_object, $x,$y, $scale)
    $content->formimage($form_object, $x,$y)
    $content->formimage($form_object)
```

Places an XObject on the page in the specified location (giving the lower left corner of the image) and scale (applied to the image's native height and width). If no scale is given, use 1 for both X and Y. If one scale is  given, use for both X and Y.  If two scales given, they are for (separately)  X and Y. In general, you should not greatly distort an image by using greatly  different scaling factors in X and Y, although it is now possible for when  that effect is desirable. The `"$x,$y"` default is `"[0,0]"`.

**Note** that while this method is named form *image*, it is also used for the  pseudoimages created by the barcode routines. Images are naturally dimensionless (1 point square) and need at some point to be scaled up to the desired point  size. Barcodes are naturally sized in points, and should be scaled at  approximately *1*. Therefore, it would greatly overscale barcodes to multiply  by image width and height *within* `"formimage"`, and require scaling of  1/width and 1/height in the call. So, we leave scaling alone within  `"formimage"` and have the user manually scale *images* by the image width and  height (in pixels) in the call to `"formimage"`.

*object*

```
    $content->object($object, $x,$y, $scale_x,$scale_y)
    $content->object($object, $x,$y, $scale)
    $content->object($object, $x,$y)
    $content->object($object)
```

Places an image or other external object (a.k.a. XObject) on the page in the specified location (giving the upper left corner of the object). Note that this positioning is *different* from `image()` and `formimage()`, which give the *lower left* corner!

Up to four optional arguments may be given, with their defaults as described below.

`$x` and `$y` are the *upper left* corner of the object. If they are  omitted, the object will be placed with its *lower left* corner at `"[0, 0]"`. **Note** that if the object's bounding box has the fourth value (maximum ascender) greater than 0, you may need to subtract that value from `"y"` to get the desired vertical position! A typical application will have a bounding box of `"[0, -height, width, 0]"`, and no correction is needed. If the bounding box is `"[0, -max_descender, width, max_ascender]"`, you may need to add the correction.

For images, `$scale_x` and `$scale_y` represent the width and height of the image on the page, in points. If `$scale_x` is omitted, it will default to 72 pixels per inch. If `$scale_y` is omitted, the image will be scaled proportionally, based on the image dimensions.

For other external objects, including **SVG images**, the scale is a  multiplier, where 1 (the default) represents 100% (i.e., no change).

If coordinate transformations have been made (see Coordinate Transformations above), the position and scale will be relative to the updated coordinates.

If no coordinate transformations are needed, this method can be called directly from the PDF::Builder::Page object instead.

If an SVG XObject array (output from `image_svg()`) is passed in, only the first \[0th\] element will be displayed. Any others will be ignored.

### Text

*Text State Parameters*

All of the following parameters that take a size are applied before any scaling takes place, so you don't need to adjust values to counteract scaling.

charspace, character\_spacing, char\_space

```
    $spacing = $content->charspace($spacing)
```

Sets additional **horizontal** spacing between **characters** in a line. Vertical  writing systems are not supported. This is in *points* and is initially zero. It may be positive to give an *expanded* effect to words, or it may be negative to give a *condensed* effect to words. If `$spacing` is given, the current setting is replaced by that value and `$self` is **returned** (to permit chaining). If `$spacing` is not given, the current setting is **returned**.

One use for character spacing is to adjust *tracking* in a line of text. It is common to adjust inter-word spacing (e.g., TeX "glue" length) to justify  a line (see `"wordspace"`), but in cases where the result is words too close  together (or too far apart), you may want to adjust tracking in order to force  spaces back to a more "reasonable" standard size. For example, if you have a  fairly "loose" line, with wide spaces between words, you could add a little  character spacing between the letters of words, and shrink the spaces down to a  more reasonable size. Don't overdo it, and make the words themselves difficult to read! You also would want to take care to "drive" the resulting spaces  towards a consistent width throughout a document (or at least, a paragraph).

You may also choose to use character spacing for special effects, such as a high-level heading expanded with extra space. This is a decorative effect, and should be used with restraint.

Note that interword spaces (x20) *also* receive additional character space, in addition to any additional word space (`"wordspace"`) defined!

**CAUTION:** be careful about using `"charspace"` if you are using a connected ("script") font. This might include Arabic, Devanagari, Latin cursive  handwriting, and so on. You don't want to leave gaps between characters, or  cause overlaps. For such fonts and typefaces, you *may* need to explicitly set  the `"charspace"` spacing to 0, if you have set it to non-zero elsewhere.  PDF::Builder may not be able to determine that a given font is a connected script font, and automatically suppress non-zero character spacing.

**Alternate names:** `"character_spacing"` and `"char_space"`

*character\_spacing* is provided for compatibility with PDF::API2, while *char\_space* is provided to be consistent with many other method name changes in PDF::API2.

wordspace, word\_spacing, word\_space

```
    $spacing = $content->wordspace($spacing)
```

Sets additional **horizontal** spacing between **words** in a line. Vertical  writing systems are not supported. This is in *points* and is initially zero  (i.e., just the width of the space, without anything extra). It may be negative to close up sentences a bit.  If `$spacing` is given, the current setting is replaced by that value and `$self` is **returned** (to permit chaining). If `$spacing` is not given, the current setting is **returned**.

See the note in `"charspace"` in regards to *tracking* adjustment, and its effect on `"wordspace"`. The two calls may often be used together for optimal results (although resulting in a somewhat increased PDF file size).

Note that it is a limitation of the PDF specification (as of version 1.7,  section 9.3.3) that only spacing with an ASCII space (x20) is adjusted. Neither required blanks (xA0) nor any multiple-byte spaces (including thin and wide spaces) are currently adjusted. **However,** multiple *spaces* between words *each* are expanded. E.g., if you have a double x20 space between words, it will receive *twice* the expansion of a single space! Furthermore, character spacing (Tc) is also added to each space, in *addition* to word spacing (Tw).

**alternate names:** `"word_spacing"` and `"word_space"`

*word\_spacing* is provided for compatibility with PDF::API2, while *word\_space* is provided to be consistent with many other method name changes in PDF::API2.

hscale

```
    $scale = $content->hscale($scale)
```

Sets the percentage of horizontal text scaling (relative sizing, *not*  spacing). This is initially 100 (percent, i.e., no scaling). A scale of greater  than 100 will stretch the text, while less than 100 will compress it. If `$scale` is given, the current setting is replaced by that value and `$self` is **returned** (to permit chaining). If `$scale` is not given, the current setting is **returned**.

Note that scaling affects all of the character widths, interletter spacing, and interword spacing. It is inadvisable to stretch or compress text by a large  amount, as it will quickly make the text unreadable. If your objective is to  justify text, you will usually be better off using `"charspace"` and `"wordspace"` to expand (or slightly condense) a line to fill a desired width. Also see  the `text_justify()` calls for this purpose.

leading

```
    $leading = $content->leading($leading)
    $leading = $content->leading()
```

Sets the text leading, which is the distance between baselines. This is initially **zero** (i.e., the lines will be printed on top of each other). The unit of leading is points. If `$leading` is given, the current setting is replaced by that value and `$self` is **returned** (to permit chaining). If `$leading` is not given, the current setting is **returned**.

Note that `"leading"` here is defined as used in electronic typesetting and the PDF specification, which is the full interline spacing (text baseline to text baseline distance, in points). In cold metal typesetting, *leading* was  usually the *extra* spacing between lines beyond the font height itself,  created by inserting lead (type alloy) shims.

render

```
    $mode = $content->render($mode)
```

Sets the text rendering mode.

- 0 = Fill text

  - 1 = Stroke text (outline)

  - 2 = Fill, then stroke text

  - 3 = Neither fill nor stroke text (invisible)

  - 4 = Fill text and add to path for clipping

  - 5 = Stroke text and add to path for clipping

  - 6 = Fill, then stroke text and add to path for clipping

  - 7 = Add text to path for clipping

  If `$mode` is given, the current setting is replaced by that value and `$self` is **returned** (to permit chaining). If `$mode` is not given, the current setting is **returned**.

rise

```
    $dist = $content->rise($dist)
```

Adjusts the baseline up or down from its current location.  This is initially zero. A `$dist` greater than 0 moves the baseline **up** the page (y increases).

Use this for creating superscripts or subscripts (usually along with an adjustment to the font size). If `$dist` is given, the current setting is replaced by that value and `$self` is **returned** (to permit chaining). If `$dist` is not given, the current setting is **returned**.

textstate

```
    %state = $content->textstate('charspace'=>$value, 'wordspace'=>$value, ...)
```

This is a shortcut for setting multiple text state parameters at once. If any parameters are set, an *empty* hash is **returned**. This can also be used without arguments to retrieve the current text state settings (a hash of the state is **returned**).

**Note:** This does not work with the `"save"` and `"restore"` commands.

font

```
    $content->font($font_object, $size)  # Set
    ($font_object, $size) = $content->font()  # Get
```

Sets or gets the font and font size. `$font` is an object created by calling "font" in PDF::Builder to add the font to the document.

```
    # Example (12 point Helvetica)
    my $pdf = PDF::Builder->new();
    my $font = $pdf->font('Helvetica');
    $text->font($font, 24);
    $text->position(72, 720);
    $text->text('Hello, World!');
    $pdf->save('sample.pdf');
```

Or, get the current font object and size setting:

```
    my ($font, $size) = $text->font();
```

Results ($font and `$size`) are indeterminate if **font()** was not previously called using them.

*Positioning Text*

position

```
    $content = $content->position($x, $y) # Set (also returns object, for ease of chaining)
    ($x, $y) = $content->position()  # Get
```

If called *with* arguments (Set), moves to the start of the current line of  text, offset by `$x` and `$y` (right and up for positive values).

If called *without* arguments (Get), returns the current position of the  cursor (before the effects of any coordinate transformation methods).

Note that this is very similar in function to `distance()`, added recently  to PDF::API2 and added here for compatibility.

textpos, (see also) position

```
    ($tx,$ty) = $content->textpos()
```

**Returns** the current text position on the page (where next write will happen)  as an array.

**Note:** This does not affect the PDF in any way. It only tells you where the the next write will occur.

**Alternate name:** `"position"` (added for compatibility with PDF::API2)

distance

```
    $content->distance($dx,$dy)
```

This moves to the start of the previously-written line, plus an offset by the  given amounts, which are both required. `"[0,0]"` would overwrite the previous  line, while `"[0,36]"` would place the new line 36pt *above* the old line  (higher y). The `$dx` moves to the right, if positive.

`"distance"` is analogous to graphic's `"move"`, except that it is relative to the beginning of the previous text write, not to the coordinate origin. **Note** that subsequent text writes will be relative to this new starting (left) point and Y position! E.g., if you give a non-zero `$dx`, subsequent lines will be indented by that amount.

cr

```
    $content->cr()
    $content->cr($vertical_offset)
    $content->cr(0)
```

If passed without an argument, moves (down) to the start of the *next* line  (distance set by `"leading"`). This is similar to `nl()`.

If passed *with* an argument, the `"leading"` distance is ignored and the next  line starts that far *up* the page (positive value) or *down* the page  (negative value) from the current line. "Y" increases upward, so a negative value would normally be used to get to the next line down.

An argument of *0* would simply return to the start of the present line, overprinting it with new text. That is, it acts as a simple carriage return, without a linefeed.

Note that any setting for `"leading"` is ignored. If you wish to account for the `"leading"` setting, you may wish to use the `"crlf"` method instead.

nl

```
    $content->nl()
    $content->nl($indent)
    $content->nl(0)
```

Moves to the start of the next line (see `"leading"`). If `$indent` is not given, or is 0, there is no indentation. Otherwise, indent by that amount (*out*dent if a negative value). The unit of measure is hundredths of a "unit of text space", or roughly 88 per em.

Note that any setting for `"leading"` is ignored. If you wish to account for the `"leading"` setting, you may wish to use the `"crlf"` method instead.

crlf

```
    $content = $content->crlf()
```

Moves to the start of the next line, based on the "leading" setting. It returns its own object, for ease of chaining.

If leading isn't set, a default distance of 120% of the font size will be used.

Added for compatibility with PDF::API2 changes; may be used to replace both `"cr"` and `"nl"` methods.

advancewidth, text\_width

```
    $width = $content->advancewidth($string, %opts)
```

Returns the number of points that will be used (horizontally) by the input string. This assumes all on one line (no line breaking).

Options `%opts:`

- 'font' =\> $f3\_TimesRoman

  Change the font used, overriding `$self`-\>{' font'}. The font must have been previously created (i.e., is not the name). Example: use Times-Roman.

- 'fontsize' =\> 12

  Change the font size, overriding `$self`-\>{' fontsize'}. Example: 12 pt font.

- 'wordspace' =\> 0.8

  Change the additional word spacing, overriding `$self`-\>**wordspace()**.  Example: add 0.8 pt between words.

- 'charspace' =\> -2.1

  Change the additional character spacing, overriding `$self`-\>**charspace()**.  Example: subtract 2.1 pt between letters, to condense the text.

- 'hscale' =\> 125

  Change the horizontal scaling factor, overriding `$self`-\>**hscale()**.  Example: stretch text to 125% of its natural width.

**Returns** the **width of the $string** (when set as a line of type), based  on all currently set text-state attributes. These can optionally be overridden with `%opts`. *Note that these* *values temporarily* ***replace*** *the existing values,* ***not*** *scaling them up or* *down.* For example, if the existing charspace is 2, and you give in options a value of 3, the value used is 3, not 5.

**Note:** This does not affect the PDF in any way. It only tells you how much horizontal space a text string will take up.

**Alternate name:** `"text_width"`

This is provided for compatibility with PDF::API2.

*Rendering Text*

Single Lines

text

```
    $width = $content->text($text, %opts)
```

Adds text to the page (left justified by default).  The width used (in points) is **returned**.

Options:

- 'align' =\> position

  Align the text, assuming left-to-right writing direction (RTL/bidirectional is not currently supported).

  - 'l' or 'left' (case insensitive).

    **default.** Text *begins* at the current text position.

  - 'c' or 'center' (case insensitive).

    Text is *centered* at the current text position.

  - 'r' or 'right' (case insensitive).

    Text *ends* (is right justified to) at the current text position.

  In all cases, the ending text position is at the (right) end of the text. If mixing various alignments, you should explicitly place the current text position so as to not overwrite earlier text.

- 'indent' =\> $distance

  Indents the text by the number of points (A value less than 0 gives an *outdent*). The indentation amount moves the text left (negative indentation) or right  (positive indentation), regardless of alignment. This allows desired alignment effects (for centered and right) that aren't exactly aligned on the current  position. For example, consider a column of decimal numbers centered on a desired *x* position, but aligned on their decimal points. The `"indent"` would be on a per-line basis, adjusted by the length of the number and the decimal position.

- 'underline' =\> 'none'

  - 'underline' =\> 'auto'

  - 'underline' =\> $distance

  - 'underline' =\> \[$distance, $thickness, ...\]

  Underlines the text. `$distance` is the number of units beneath the baseline, and `$thickness` is the width of the line. Multiple underlines can be made by passing several distances and thicknesses.  A value of 'none' means no underlining (is the default).

  Example:

  ```
      # 3 underlines:
      #   distance 4, thickness 1, color red
      #   distance 7, thickness 1.5, color yellow
      #   distance 11, thickness 2, color (strokecolor default)
      'underline' => [4,[1,'red'],7,[1.5,'yellow'],11,2],
  ```

- 'strikethru' =\> 'none'

  - 'strikethru' =\> 'auto'

  - 'strikethru' =\> $distance

  - 'strikethru' =\> \[$distance, $thickness, ...\]

  Strikes through the text (like HTML *s* tag). A value of 'auto' places the line about 30% of the font size above the baseline, or a specified `$distance` (above the baseline) and `$thickness` (in points). Multiple strikethroughs can be made by passing several distances and thicknesses. A value of 'none' means no strikethrough. It is the default.

  Example:

  ```
      # 2 strikethroughs:
      #   distance 4, thickness 1, color red
      #   distance 7, thickness 1.5, color yellow
      'strikethru' => [4,[1,'red'],7,[1.5,'yellow']],
  ```

- 'strokecolor' =\> color\_spec

  Defines the underline or strikethru line color, if different from the text color.

textHS

```
    $width = $content->textHS($HSarray, $settings, %opts)
```

Takes an array of hashes produced by HarfBuzz::Shaper and outputs them to the PDF output file. HarfBuzz outputs glyph CIDs and positioning information.  It may rearrange and swap characters (glyphs), and the result may bear no resemblance to the original Unicode point list. You should see  examples/HarfBuzz.pl, which shows a number of examples with Latin and non-Latin  text, as well as vertical writing.  https://www.catskilltech.com/Examples has a sample available in case you want  to see some examples of what HarfBuzz can do, and don't yet have  HarfBuzz::Shaper installed.

- $HSarray

  This is the reference to array of hashes produced by HarfBuzz::Shaper, normally  unchanged after being created (but *can* be modified). See  "Using Shaper" in PDF::Builder::Docs for some things that can be done.

- $settings

  This a reference to a hash of various pieces of information that `textHS()`  needs in order to function. They include:

  - 'script' =\> 'script\_name'

    This is the standard 4 letter code (e.g., 'Latn') for the script (alphabet and writing system) you're using. Currently, only Latn (Western writing systems) do kerning, and 'Latn' is the default. HarfBuzz::Shaper will usually be able to  figure out from the Unicode points used what the script is, and you might be  able to use the `set_script()` call to override its guess. However,  PDF::Builder and HarfBuzz::Shaper do not talk to each other about the script  being used.

  - 'features' =\> array\_of\_features

    This item is **required**, but may be empty, e.g.,  `"$settings->{'features'} = ();"`. It can include switches using the standard HarfBuzz naming, and a + or - switch, such as '-liga' to turn **off** ligatures. '-liga' and '-kern', to turn off ligatures and kerning, are the only features supported currently. **Note** that this is separate from any switches for features that you send to  HarfBuzz::Shaper (with `"$hb->add_features()"`, etc.) when you run it  (before `textHS()`).

  - 'language' =\> 'language\_code'

    This item is optional and currently does not appear to have any substantial effect with HarfBuzz::Shaper. It is the standard code for the language to be used, such as 'en' or 'en\_US'. You might need to define this for HarfBuzz::Shaper, in case that system can't surmise the language rules to be  used.

  - 'dir' =\> 'flag'

    Tell `textHS()` whether this text is to be written in a Left-To-Right manner  (**L**, the **default**), Right-To-Left (**R**), Top-To-Bottom (**T**), or  Bottom-To-Top (**B**). From the script used (Unicode points), HarfBuzz::Shaper  can usually figure out what direction to write text in. Also, HarfBuzz::Shaper  does not share its information with PDF::Builder -- you need to separately  specify the direction, unless you want to accept the default LTR direction. You  *can* use HarfBuzz::Shaper's `get_direction()` call (in addition to  `get_language()` and `get_script()`) to see what HarfBuzz thinks is the  correct text direction. `set_direction()` may be used to override Shaper's guess as to the direction.

    By the way, if the direction is RTL, HarfBuzz will reverse the text and return  an array with the last character first (to be written LTR). Likewise, for BTT,  HarfBuzz will reverse the text and return a string to be written from the top  down. Languages which are normally written horizontally are usually set  vertically with direction TTB. If setting text vertically, ligatures and  kerning, as well as character connectivity for cursive scripts, are  automatically turned off, so don't let the direction default to LTR or RTL in  the Shaper call, and then try to fix it up in `textHS()`.

  - align =\> 'flag'

    Given the current output location, align the text at the **B**eginning of the line (left for LTR, right for RTL), **C**entered at the location, or at the **E**nd of the line (right for LTR, left for RTL). The default is **B**. **C**entered is analogous to using `text_center()`, and **E**nd is analogous to using `text_right()`. Similar alignments are done for TTB and BTT.

  - 'dump' =\> flag

    Set to 1, it prints out positioning and glyph CID information (to STDOUT) for each glyph in the chunk. The default is 0 (no information dump).

  - 'minKern' =\> amount (default 1)

    If the amount of kerning (font character width **differs from** glyph *ax*  value) is *larger* than this many character grid units, use the unaltered ax  for the width (`textHS()` will output a kern amount in the TJ operation).  Otherwise, ignore kerning and use ax of the actual character width. The intent  is to avoid bloating the PDF code with unnecessary tiny kerning adjustments in  the TJ operation.

- %opts

  This a hash of options.

  - 'underline' =\> underlining\_instructions

    See `text()` for available instructions.

  - 'strikethru' =\> strikethrough\_instructions

    See `text()` for available instructions.

  - 'strokecolor' =\> line\_color

    Color specification (e.g., 'green', '#FF3377') for underline or strikethrough, if not given in an array with their instructions.

Text is sent *separately* to HarfBuzz::Shaper in 'chunks' ('segments') of a  single script (alphabet), a single direction (LTR, RTL, TTB, or BTT), a single font file,  and a single font size. A  chunk may consist of a large amount of text, but at present, `textHS()` can  only output a single line. For long lines that need to be split into  column-width lines, the best way may be to take the array of hashes returned by HarfBuzz::Shaper and split it into smaller chunks at spaces and other  whitespace. You may have to query the font to see what the glyph CIDs are for  space and anything else used.

It is expected that when `textHS()` is called, that the font and font size have already been set in PDF::Builder code, as this information is needed to interpret what HarfBuzz::Shaper is returning, and to write it to the PDF file. Needless to say, the font should be opened from the same file as was given to HarfBuzz::Shaper (`ttfont()` only, with .ttf or .otf files), and the font size must be the same. The appropriate location on the page must also already have been specified.

advancewidthHS, text\_widthHS

```
    $width = $content->advancewidthHS($HSarray, $settings, %opts)
```

Returns text chunk width (in points) for Shaper-defined glyph array. This is the horizontal width for LTR and RTL direction, and the vertical height for TTB and BTT direction. **Note:** You must define the font and font size *before* calling  `advancewidthHS()`.

- $HSarray

  The array reference of glyphs created by the HarfBuzz::Shaper call.  See `textHS()` for details.

- $settings

  the hash reference of settings. See `textHS()` for details.

  - 'dir' =\> 'L' etc.

    the direction of the text, to know which "advance" value to sum up.

- %opts

  Options. Unlike `advancewidth()`, you cannot override the font, font size, etc. used by HarfBuzz::Shaper to calculate the glyph list.

  - 'doKern' =\> flag (default 1)

    If 1, cancel minor kerns per `"minKern"` setting. This flag should be 0 (false) if **-kern** was passed to HarfBuzz::Shaper (do not kern text). This is treated as 0 if an ax override setting is given.

  - 'minKern' =\> amount (default 1)

    If the amount of kerning (font character width **differs from** glyph *ax*  value) is *larger* than this many character grid units, use the unaltered *ax* for the width (`textHS()` will output a kern amount in the TJ operation).  Otherwise, ignore kerning and use ax of the actual character width. The intent  is to avoid bloating the PDF code with unnecessary tiny kerning adjustments in  the TJ operation.

Returns total width in points.

**Alternate name:** `"text_widthHS"`

### Advanced Methods

*save*

```
    $content->save()
```

Saves the current *graphics* state on a PDF stack. See PDF definition 8.4.2  through 8.4.4 for details. This includes the line width, the line cap style,  line join style, miter limit, line dash pattern, stroke color, fill color, current transformation matrix, current clipping port, flatness, and dictname.

This method applies to *only* *gfx/graphics* objects. If attempted with *text* objects, you will receive a one-time (per run) warning message, and should update your code **not** to do **save()** and **restore()** on a text object. Only **save()** generates the message, as presumably each **restore()** has already had a **save()** performed.

*restore*

```
    $content->restore()
```

Restores the most recently saved graphics state (see `"save"`), removing it from the stack. You cannot *restore* the graphics state (pop it off the stack) unless you have done at least one *save* (pushed it on the stack). This method applies to both *text* and *gfx/graphics* objects.

*add*

```
    $content->add(@content)
```

Add raw content (arbitrary string(s)) to the PDF stream.  You will generally want to use the other methods in this class instead, unless this is in order to implement some PDF operation that PDF::Builder does not natively support. An array of multiple strings may be given;  they will be concatenated with spaces between them.

Be careful when doing this, as you are dabbling in the black arts,  directly setting PDF operations!

One interesting use is to split up an overly long object stream that is giving  your editor problems when exploring a PDF file. Add a newline **add("\\n")**  every few hundred bytes of output or so, to do this. Note that you must use  double quotes (quotation marks), rather than single quotes (apostrophes).

Use extreme care if inserting **BT** and **ET** markers into the PDF stream. You may want to use `textstart()` and `textend()` calls instead, and even then, there are many side effects either way. It is generally not useful  to suspend text mode with ET/**textend()** and BT/**textstart()**, but it is possible,  if you *really* need to do it.

Another, useful, case is when your input PDF is from the **Chrome browser**  printing a page to PDF with headers and/or footers. In some versions, this leaves the PDF page with a strange scaling (such as the page height in points divided by 3300) and the  Y-axis flipped so 0 is at the top. This causes problems when trying to add additional text or graphics in a new text or graphics record, where text is  flipped (mirrored) upside down and at the wrong end of the page. If this  happens, you might be able to cure it by adding

```
    $scale = .23999999; # example, 792/3300, examine PDF or experiment!
     ...
    if ($scale != 1) {
        my @pageDim = $page->mediabox();     # e.g., 0 0 612 792
        my $size_page = $pageDim[3]/$scale;  # 3300 = 792/.23999999
        my $invScale = 1.0/$scale;           # 4.16666684
        $text->add("$invScale 0 0 -$invScale 0 $size_page cm");
    }
```

as the first output to the `$text` stream. Unfortunately, it is difficult to predict exactly what `$scale` should be, as it may be 3300 units per page, or a fixed amount. You may need to examine an uncompressed PDF file stream to  see what is being used. It *might* be possible to get the input (original)  PDF into a string and look for a certain pattern of "cm" output

```
    .2399999 0 0 -.23999999 0 792 cm
```

or similar, which is not within a save/restore (q/Q). If the stream is  already compressed, this might not be possible.

*addNS*

```
    $content->addNS(@content)
```

Like `add()`, but does **not** make sure there is a space between each element and before and after the new content. It is up to *you* to ensure that any necessary spaces in the PDF stream are placed there explicitly!

*compressFlate*

```
    $content->compressFlate()
```

Marks content for compression on output.  This is done automatically in nearly all cases, so you shouldn't need to call this yourself.

The `new()` call can set the **compress** parameter to 'flate' (default) to compress all object streams, or 'none' to suppress compression and allow you to examine the output in an editor.

*textstart*

```
    $content->textstart()
```

Starts a text object (ignored if already in a text object). You will likely  want to use the `text()` method (text *context*, not text output) instead.

Note that calling this method, besides outputting a **BT** marker, will reset most text settings to their default values. In addition, **BT** itself will reset some transformation matrices.

*textend*

```
    $content->textend()
```

Ends a text object (ignored if not in a text object).

Note that calling this method, besides outputting an **ET** marker, will output any accumulated *poststream* content.
