1. curveto

Adds a Bézier cubic curve segment to the current path.

1.1. Syntax

x1 y1 x2 y2 x3 y3 curveto → -

1.2. Stack Effects

Table 1. Before
Level Object

5

y3 (number - endpoint y-coordinate)

4

x3 (number - endpoint x-coordinate)

3

y2 (number - second control point y)

2

x2 (number - second control point x)

1

y1 (number - first control point y)

0

x1 (number - first control point x)

Table 2. After
Level Object

(empty)

Stack cleared of operands

1.3. Description

curveto adds a Bézier cubic section to the current path between the current point, referred to here as (x0, y0), and the point (x3, y3), using (x1, y1) and (x2, y2) as the Bézier cubic control points. After constructing the curve, curveto makes (x3, y3) the new current point.

If the current point is undefined because the current path is empty, curveto executes the [nocurrentpoint] error.

The four points define the shape of the curve geometrically:

  • The curve starts at (x0, y0), tangent to the line from (x0, y0) to (x1, y1)

  • The curve ends at (x3, y3), tangent to the line from (x2, y2) to (x3, y3)

  • The lengths of the control point lines represent the "velocity" at the endpoints

  • The curve is always entirely enclosed by the convex quadrilateral defined by the four points

1.4. PostScript Level

Level 1 and later

1.5. Examples

Simple S-curve
newpath
100 100 moveto
150 200 250 200 300 100 curveto
stroke
Drawing a smooth wave
newpath
50 150 moveto
100 50 150 50 200 150 curveto     % Up curve
250 250 300 250 350 150 curveto   % Down curve
stroke
Creating a heart shape
newpath
200 200 moveto
200 250 150 300 100 300 curveto   % Left top curve
50 300 0 250 0 200 curveto         % Left side
0 100 100 50 200 100 curveto       % Left bottom
300 50 400 100 400 200 curveto     % Right bottom
400 250 350 300 300 300 curveto    % Right side
250 300 200 250 200 200 curveto    % Right top curve
closepath
fill

1.6. Common Use Cases

1.6.1. Creating Smooth Connections

/smoothCurve {
  % x1 y1 x2 y2 (two points)
  /y2 exch def /x2 exch def
  /y1 exch def /x1 exch def

  currentpoint           % Get starting point
  /y0 exch def /x0 exch def

  % Calculate control points for smooth curve
  x0 x1 x0 sub 0.5 mul add y0 y1 y0 sub 0.5 mul add
  x1 x2 x1 sub 0.5 mul add y1 y2 y1 sub 0.5 mul add
  x2 y2
  curveto
} def

100 100 moveto
200 150 300 100 smoothCurve
stroke

1.6.2. Drawing Circular Approximations

% Approximate quarter circle with Bézier curve
/quarterCircle {
  % cx cy radius
  /r exch def
  /cy exch def
  /cx exch def
  /k 0.5522847498 r mul def  % Magic number for circle

  cx r add cy moveto
  cx r add cy k add  cx k add cy r add  cx cy r add curveto
} def

200 200 50 quarterCircle
stroke

1.6.3. Creating Custom Shapes

/drawLeaf {
  % size
  /s exch def
  newpath
  0 0 moveto
  s 3 div s 2 mul 3 div  s 2 mul 3 div s 2 mul 3 div  s s curveto
  s 2 mul 3 div s 3 div  s 3 div 0  0 0 curveto
  closepath
} def

100 100 translate
80 drawLeaf
fill

1.7. Common Pitfalls

Requires Current Point - curveto needs a current point as the curve starting point. Use moveto first.
newpath
100 100 150 150 200 100 curveto   % Error: nocurrentpoint
Control Point Order Matters - The first control point (x1, y1) affects the curve’s start, the second (x2, y2) affects the end. Swapping them changes the curve shape significantly.
Six Parameters Required - curveto requires all six parameters. Missing any causes [stackunderflow].
Use for Smooth Curves - Bézier curves provide smooth, aesthetically pleasing curves. For circles and arcs, consider arc for mathematical precision.

1.8. Mathematical Background

The curve is defined by the parametric cubic equations:

x(t) = (1-t)³·x0 + 3(1-t)²·t·x1 + 3(1-t)·t²·x2 + t³·x3
y(t) = (1-t)³·y0 + 3(1-t)²·t·y1 + 3(1-t)·t²·y2 + t³·y3

Where t ranges from 0 to 1, and (x0, y0) is the current point.

1.9. Error Conditions

Error Condition

[limitcheck]

Path becomes too complex for implementation

[nocurrentpoint]

Current path is empty (no current point defined)

[stackunderflow]

Fewer than 6 operands on stack

[typecheck]

Any operand is not a number

1.10. Implementation Notes

  • Curves are converted to device space after CTM transformation

  • PostScript may subdivide curves for rendering accuracy

  • Very tight curves may show artifacts at low resolutions

  • Control points can be outside the visible area

  • Curves are always smooth (C1 continuous at join points if designed properly)

1.11. Performance Considerations

  • More computationally expensive than lineto

  • Many curves can impact path complexity limits

  • Flatness parameter affects rendering speed

  • Simpler curves (fewer inflection points) render faster

1.12. See Also


Back to top

Copyright © 2025 Ribose. PostScript is a trademark of Adobe. Distributed under the MIT License.