1. ustroke

Interprets a user path definition and strokes the resulting path.

1.1. Syntax

userpath ustroke → -
userpath matrix ustroke → -

1.2. Stack Effects

Table 1. First form (no matrix)
Level Object

0

userpath (array, packed array, or string)

Table 2. Second form (with matrix)
Level Object

1

matrix (array)

0

userpath (array, packed array, or string)

Table 3. After (both forms)
Level Object

(empty)

No results

1.3. Description

ustroke interprets a user path definition and strokes the resulting path as if by stroke. The entire operation is effectively enclosed by gsave and grestore, so ustroke has no lasting effect on the graphics state.

In the first form (with no matrix operand), ustroke is equivalent to:

gsave newpath uappend stroke grestore

In the second form, ustroke concatenates matrix to the CTM after interpreting userpath, but before executing stroke. The matrix applies to the line width and the dash pattern, if any, but not to the path itself. This form is equivalent to:

gsave
newpath
exch uappend     % Interpret userpath
concat           % Concat matrix to CTM
stroke
grestore

The main use of the second form is to compensate for variations in line width and dash pattern that occur if the CTM has been scaled by different amounts in x and y.

1.4. PostScript Level

Level 2 and later

1.5. Examples

Simple user path stroke
[
  50 50 250 250 setbbox
  100 100 moveto
  200 100 lineto
  200 200 lineto
  100 200 lineto
  closepath
] ustroke
User path with line parameters
5 setlinewidth
1 setlinecap
1 setlinejoin

[
  ucache
  50 50 250 250 setbbox
  100 150 moveto
  200 150 lineto
] ustroke
Using matrix for uniform line width
% Scale coordinate system
2 1 scale  % x scaled by 2

% Compensate in stroke
[
  0 0 100 100 setbbox
  10 50 moveto
  90 50 lineto
]
[0.5 0 0 1 0 0]  % Inverse of x scaling
ustroke  % Line appears uniform width

1.6. Common Use Cases

1.6.1. Efficient Repeated Strokes

/linePath [
  ucache
  0 0 200 10 setbbox
  10 5 moveto
  190 5 lineto
] def

% Draw multiple strokes efficiently
2 setlinewidth
0 1 9 {
  linePath ustroke
  0 20 translate
} for

1.6.2. Dashed User Path Stroke

[5 3] 0 setdash
3 setlinewidth

[
  ucache
  50 50 250 250 setbbox
  100 100 moveto
  200 100 lineto
  200 200 lineto
  100 200 lineto
  closepath
] ustroke

[] 0 setdash  % Reset

1.6.3. Compensating for Scaled CTM

% Non-uniform scale
3 1 scale

/boxPath [
  0 0 100 100 setbbox
  10 10 moveto
  90 10 lineto
  90 90 lineto
  10 90 lineto
  closepath
] def

2 setlinewidth

% Without compensation - line appears 3x wider horizontally
boxPath ustroke

% With compensation - uniform line width
boxPath
[0.333 0 0 1 0 0]  % Inverse of x scale
ustroke

1.7. Common Pitfalls

Graphics State Not Modified - ustroke automatically saves and restores graphics state.
2 setlinewidth
[
  0 0 100 100 setbbox
  10 10 moveto
  90 90 lineto
] ustroke
% Line width still 2, path is empty
Matrix Affects Line Width, Not Path - The optional matrix parameter affects stroke rendering, not path coordinates.
% Wrong interpretation
[
  0 0 100 100 setbbox
  50 50 moveto
  100 50 lineto
]
[2 0 0 2 0 0]  % This does NOT scale the path
ustroke  % Path position unchanged, only line rendering affected
Must Include setbbox - User paths require setbbox.
% Wrong - no setbbox
[
  100 100 moveto
  200 200 lineto
] ustroke  % Error: rangecheck

% Correct
[
  50 50 250 250 setbbox
  100 100 moveto
  200 200 lineto
] ustroke
Use Matrix for Uniform Strokes Under Scaling - When CTM has non-uniform scaling, use matrix to maintain consistent line appearance:
/uniformStroke {
  % userpath sx sy uniformStroke
  /sy exch def
  /sx exch def
  [1 sx div 0 0 1 sy div 0 0]
  ustroke
} def

2 1 scale  % Non-uniform scale
/myPath [
  0 0 100 100 setbbox
  50 50 moveto
  90 50 lineto
] def

myPath 2 1 uniformStroke  % Compensates for scale

1.8. Error Conditions

Error Condition

[invalidaccess]

User path array is not executable or has insufficient access

[limitcheck]

Path becomes too complex for implementation

[rangecheck]

User path is malformed (missing setbbox, coordinates out of bounds, invalid matrix)

[stackunderflow]

Insufficient operands on stack

[typecheck]

Operand is not a valid user path or matrix

1.9. Implementation Notes

  • User paths provide efficient stroke rendering

  • Cached user paths (with ucache) improve performance for reuse

  • The bounding box enables rendering optimization

  • Matrix parameter allows compensation for CTM scaling

  • Very complex paths may exceed implementation limits

1.10. Graphics State Interaction

ustroke uses these graphics state parameters:

The graphics state is automatically saved before and restored after the operation.

1.11. Comparison with Traditional Stroke

Traditional stroke approach
gsave
newpath
100 100 moveto
200 100 lineto
200 200 lineto
closepath

2 setlinewidth
stroke
grestore
User path approach (ustroke)
2 setlinewidth
[
  50 50 250 250 setbbox
  100 100 moveto
  200 100 lineto
  200 200 lineto
  closepath
] ustroke

Benefits of user paths:

  • More compact representation

  • Can be cached for efficiency

  • Automatic graphics state management

  • Optional matrix for stroke compensation

1.12. Best Practices

1.12.1. Set Line Parameters Before ustroke

% Set all stroke parameters first
3 setlinewidth
1 setlinecap
1 setlinejoin
[5 3] 0 setdash

% Then stroke user path
[
  0 0 100 100 setbbox
  10 50 moveto
  90 50 lineto
] ustroke

1.12.2. Use ucache for Repeated Paths

/borderPath [
  ucache  % Cache for reuse
  0 0 120 80 setbbox
  5 5 moveto
  115 5 lineto
  115 75 lineto
  5 75 lineto
  closepath
] def

% Efficient reuse
2 setlinewidth
10 {
  borderPath ustroke
  0 90 translate
} repeat

1.12.3. Compensate for Non-Uniform Scaling

% When CTM has non-uniform scale
currentmatrix                    % Save original CTM
2 1 scale                        % Non-uniform scale

/path [
  0 0 100 50 setbbox
  50 25 moveto
  90 25 lineto
] def

% Calculate inverse scale matrix
[0.5 0 0 1 0 0]                  % Inverse of 2,1 scale
path exch ustroke                % Uniform line width

setmatrix                        % Restore CTM

1.12.4. Combine with Other User Path Operations

/shapePath [
  ucache
  0 0 100 100 setbbox
  50 50 40 0 360 arc
  closepath
] def

% Fill
0.8 setgray
shapePath ufill

% Stroke
0 setgray
2 setlinewidth
shapePath ustroke

1.13. Performance Considerations

  • User paths are generally faster than traditional path construction

  • Cached user paths (ucache) provide significant performance improvement

  • Matrix parameter adds minimal overhead

  • Dashed lines are slower than solid lines

  • Wide lines are slower than thin lines

  • Complex paths with many segments take longer

1.14. See Also

  • stroke - Traditional stroke operator

  • ufill - Fill user path

  • ustrokepath - Convert user path stroke to outline

  • strokepath - Convert stroke to outline path

  • setbbox - Set bounding box

  • ucache - Enable user path caching

  • uappend - Append user path to current path

  • setlinewidth - Set line width

  • setlinecap - Set line cap

  • setlinejoin - Set line join

  • setdash - Set dash pattern

  • gsave - Save graphics state

  • grestore - Restore graphics state


Back to top

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