Table of Contents

1. Graphics State

The graphics state contains all parameters that affect the appearance of rendered graphics. Managing the graphics state effectively is essential for consistent and predictable output.

1.1. Overview

The graphics state is a collection of parameters that control how graphics are rendered:

  • Current path - The path being constructed

  • Current position - The position within the path

  • Color - Current color for fill and stroke operations

  • Line attributes - Width, cap style, join style, dash pattern

  • Transformation matrix - Coordinate system transformations

  • Clipping path - Region where graphics can appear

  • Font - Current font and size

These parameters persist until explicitly changed or the graphics state is restored.

1.2. The Graphics State Stack

1.2.1. Saving State with gsave

The gsave operator pushes the current graphics state onto the stack:

% Set some graphics parameters
1 0 0 setrgbcolor    % Red
2 setlinewidth        % 2-point line

% Save current state
gsave

% Modify state
0 1 0 setrgbcolor    % Green
5 setlinewidth        % 5-point line

% Draw something
0 0 100 100 rectfill

% State is still modified here

1.2.2. Restoring State with grestore

The grestore operator pops the graphics state from the stack:

gsave
  % Set temporary state
  0 1 0 setrgbcolor
  5 setlinewidth

  % Draw
  0 0 100 100 rectfill
grestore

% Color and line width are restored to pre-gsave values
% Back to red and 2-point lines
0 0 moveto
200 0 lineto
stroke

1.2.3. Nested State Management

Graphics state operations can be nested:

% Initial state: black, 1-point line
gsave                    % Level 1
  1 0 0 setrgbcolor     % Red

  gsave                 % Level 2
    0 1 0 setrgbcolor   % Green
    3 setlinewidth
    % Draw green with thick line
  grestore              % Back to level 1: red, 1-point

  % Draw red with 1-point line
grestore                % Back to initial: black, 1-point

1.2.4. The grestoreall Operator

Restores to the bottom of the graphics state stack:

gsave
  gsave
    gsave
      % Deeply nested
    % grestore would go back one level
    grestoreall  % Goes back to initial state
  % Never executed
grestore

1.3. Color Parameters

1.3.1. Gray Color

Set grayscale values (0 = black, 1 = white):

% Set gray for fill and stroke
0 setgray        % Black
0.5 setgray      % 50% gray
1 setgray        % White

% Query current gray
currentgray      % Returns current gray value (0-1)

1.3.2. RGB Color

Set red-green-blue color components (each 0-1):

% RGB: red green blue
1 0 0 setrgbcolor      % Pure red
0 1 0 setrgbcolor      % Pure green
0 0 1 setrgbcolor      % Pure blue
0.5 0.5 0.5 setrgbcolor % Gray
1 1 0 setrgbcolor      % Yellow
0 1 1 setrgbcolor      % Cyan

% Query current RGB
currentrgbcolor        % Returns: r g b

Creating custom colors:

% Define color constants
/Navy { 0 0 0.5 setrgbcolor } def
/Orange { 1 0.647 0 setrgbcolor } def
/Purple { 0.502 0 0.502 setrgbcolor } def

% Use them
Navy
0 0 100 100 rectfill

Orange
200 0 100 100 rectfill

1.3.3. CMYK Color

Set cyan-magenta-yellow-black components (each 0-1):

% CMYK: cyan magenta yellow black
0 0 0 1 setcmykcolor    % Pure black
1 0 0 0 setcmykcolor    % Pure cyan
0 1 0 0 setcmykcolor    % Pure magenta
0 0 1 0 setcmykcolor    % Pure yellow

% Query current CMYK
currentcmykcolor        % Returns: c m y k

1.3.4. HSB Color

Set hue-saturation-brightness (hue: 0-360, saturation and brightness: 0-1):

% HSB: hue saturation brightness
0 1 1 sethsbcolor      % Pure red
120 1 1 sethsbcolor    % Pure green
240 1 1 sethsbcolor    % Pure blue
60 1 1 sethsbcolor     % Yellow

% Pastel colors (low saturation)
0 0.3 1 sethsbcolor    % Pastel red

% Query current HSB
currenthsbcolor        % Returns: h s b

1.4. Line Attributes

1.4.1. Line Width

Set the width of stroked lines (in user space units):

% Set line width
0.5 setlinewidth       % Thin line
1 setlinewidth         % Default
5 setlinewidth         % Thick line
10 setlinewidth        % Very thick line

% Query current line width
currentlinewidth       % Returns current width

% Example
newpath
1 setlinewidth
0 100 moveto 100 100 lineto stroke

5 setlinewidth
0 110 moveto 100 110 lineto stroke

10 setlinewidth
0 120 moveto 100 120 lineto stroke

1.4.2. Line Cap Style

Controls the shape of line endpoints:

% Line cap styles:
% 0 = butt cap (default) - square end at endpoint
% 1 = round cap - semicircular end
% 2 = projecting square cap - extends beyond endpoint

0 setlinecap     % Butt cap
1 setlinecap     % Round cap
2 setlinecap     % Square cap

% Query current line cap
currentlinecap   % Returns 0, 1, or 2

Visual comparison:

10 setlinewidth

% Butt cap
0 setlinecap
0 100 moveto 100 100 lineto stroke

% Round cap
1 setlinecap
0 120 moveto 100 120 lineto stroke

% Square cap
2 setlinecap
0 140 moveto 100 140 lineto stroke

1.4.3. Line Join Style

Controls how line segments connect:

% Line join styles:
% 0 = miter join (default) - pointed join
% 1 = round join - circular join
% 2 = bevel join - beveled join

0 setlinejoin    % Miter join
1 setlinejoin    % Round join
2 setlinejoin    % Bevel join

% Query current line join
currentlinejoin  % Returns 0, 1, or 2

Visual comparison with angles:

10 setlinewidth

% Miter join
0 setlinejoin
newpath
0 100 moveto
50 150 lineto
100 100 lineto
stroke

% Round join
1 setlinejoin
newpath
0 120 moveto
50 170 lineto
100 120 lineto
stroke

% Bevel join
2 setlinejoin
newpath
0 140 moveto
50 190 lineto
100 140 lineto
stroke

1.4.4. Miter Limit

Controls when miter joins are beveled (only applies to miter joins):

% Miter limit (default is 10)
% Ratio of miter length to line width
% Smaller values bevel sharper angles

10 setmiterlimit    % Default
4 setmiterlimit     % More aggressive beveling
1 setmiterlimit     % Very aggressive

% Query current miter limit
currentmiterlimit   % Returns current limit

Practical example:

20 setlinewidth
0 setlinejoin       % Miter join

% Sharp angle with high miter limit
10 setmiterlimit
newpath
0 100 moveto
50 150 lineto
100 100 lineto
stroke

% Same angle with low miter limit (will bevel)
1 setmiterlimit
newpath
0 200 moveto
50 250 lineto
100 200 lineto
stroke

1.4.5. Dash Pattern

Creates dashed or dotted lines:

% setdash: array offset setdash
% array = [on off on off ...]
% offset = starting offset into pattern

% Solid line (default)
[] 0 setdash

% Simple dash pattern
[5 3] 0 setdash    % 5 on, 3 off
0 100 moveto 200 100 lineto stroke

% Dash-dot pattern
[10 5 2 5] 0 setdash
0 110 moveto 200 110 lineto stroke

% Dotted line
[1 3] 0 setdash
0 120 moveto 200 120 lineto stroke

% Query current dash
currentdash        % Returns: array offset

Pattern with offset:

[10 5] 0 setdash
0 100 moveto 200 100 lineto stroke

% Same pattern, different offset
[10 5] 5 setdash
0 110 moveto 200 110 lineto stroke

1.5. Clipping

1.5.1. Setting the Clipping Path

The clipping path restricts where graphics can appear:

% Create a clipping path
gsave
  newpath
  100 100 100 0 360 arc
  clip               % Set as clipping path
  newpath            % Start new path (don't stroke clip path)

  % Only visible inside circle
  0 0 200 200 rectfill
grestore

1.5.2. Even-Odd Clipping

Alternative clipping rule:

gsave
  % Create complex path with holes
  newpath
  50 50 150 0 360 arc
  100 100 50 0 360 arc

  eoclip            % Even-odd clip
  newpath

  % Fill shows holes
  0 0 300 300 rectfill
grestore

1.5.3. Rectangular Clipping

Faster clipping for rectangles:

% rectclip: x y width height rectclip
gsave
  50 50 200 150 rectclip

  % Only visible in rectangle
  0 0 moveto
  300 300 lineto
  stroke
grestore

1.5.4. Getting the Clipping Path

% Get current clipping path as a new path
clippath

% Common pattern: stroke the clipping boundary
gsave
  clippath
  0.5 setlinewidth
  1 0 0 setrgbcolor
  stroke
grestore

1.6. Font State

1.6.1. Setting the Current Font

% Find and scale font
/Times-Roman findfont
12 scalefont
setfont

% Query current font
currentfont        % Returns font dictionary

Combined font selection:

% All in one line
/Helvetica-Bold findfont 24 scalefont setfont
100 100 moveto
(Hello) show

1.6.2. Font Transformations

% Create transformed font
/Times-Roman findfont
[20 0 0 10 0 0] makefont  % Narrow font (20 wide, 10 tall)
setfont

% Slanted font
/Courier findfont
[12 0 6 12 0 0] makefont  % Slanted 12pt
setfont

1.7. Transformation Matrix

1.7.1. Current Transformation Matrix

The CTM is part of the graphics state:

gsave
  % Modify CTM
  100 100 translate
  45 rotate
  2 2 scale

  % Query CTM
  matrix currentmatrix  % Returns current matrix

  % Draw in transformed space
  0 0 50 0 360 arc stroke
grestore
% CTM restored

1.7.2. Setting the Matrix

% Set a specific matrix
[2 0 0 2 100 100] concat

% Or create and set matrix
matrix
dup 0 2 put      % a = 2
dup 3 2 put      % d = 2
dup 4 100 put    % tx = 100
dup 5 100 put    % ty = 100
setmatrix

1.8. Graphics State Objects (Level 2)

1.8.1. Creating a Graphics State Object

Save parameters in a reusable object:

% Create gstate object
gstate              % Creates empty gstate
currentgstate       % Fills with current state

% Store for later use
/myState currentgstate def

1.8.2. Using Graphics State Objects

% Save current state
/savedState currentgstate def

% Modify state
1 0 0 setrgbcolor
5 setlinewidth
45 rotate

% Restore from saved state
savedState setgstate
% Back to state when we saved it

Practical example - switching between two states:

% Define two different states
/redThick gstate def
redThick currentgstate pop
redThick /PaintType 1 0 0 setrgbcolor
redThick /LineWidth 5 setlinewidth

/blueThin gstate def
blueThin currentgstate pop
blueThin /PaintType 0 0 1 setrgbcolor
blueThin /LineWidth 1 setlinewidth

% Use them
redThick setgstate
0 100 moveto 200 100 lineto stroke

blueThin setgstate
0 110 moveto 200 110 lineto stroke

redThick setgstate
0 120 moveto 200 120 lineto stroke

1.9. Practical Graphics State Patterns

1.9.1. Pattern 1: Temporary Style Changes

% Draw with temporary style
/withStyle {  % ... procedure ... -> -
  gsave
    % Set style
    1 0 0 setrgbcolor
    3 setlinewidth
    [5 3] 0 setdash

    % Execute procedure
    exec
  grestore
} def

% Usage
{
  0 0 moveto
  100 100 lineto
  stroke
} withStyle

1.9.2. Pattern 2: Style Inheritance

% Base style
/baseStyle {
  /Helvetica findfont 12 scalefont setfont
  0 setgray
  1 setlinewidth
} def

% Heading style (inherits from base)
/headingStyle {
  baseStyle
  /Helvetica-Bold findfont 18 scalefont setfont
} def

% Use them
baseStyle
100 100 moveto (Body text) show

headingStyle
100 120 moveto (Heading) show

1.9.3. Pattern 3: State Snapshot

% Take snapshot of current state
/snapshot {
  20 dict begin
    /savedGray currentgray def
    /savedLineWidth currentlinewidth def
    /savedLineCap currentlinecap def
    /savedLineJoin currentlinejoin def
    /savedDash currentdash def
    /savedFont currentfont def
    % ... other parameters
  currentdict end
} def

% Restore snapshot
/restore {
  begin
    savedGray setgray
    savedLineWidth setlinewidth
    savedLineCap setlinecap
    savedLineJoin setlinejoin
    savedDash aload pop setdash
    savedFont setfont
  end
} def

1.9.4. Pattern 4: Scoped Drawing

% Execute code with isolated graphics state
/isolated {  % proc -> -
  gsave
    exec
  grestore
} def

% Usage
{
  200 200 translate
  45 rotate
  1 0 0 setrgbcolor
  0 0 100 100 rectfill
} isolated

% State is unchanged here

1.10. Common Graphics State Tasks

1.10.1. Drawing with Multiple Styles

% Draw border and fill with different styles
gsave
  % Fill
  0.9 0.9 1 setrgbcolor
  100 100 200 150 rectfill
grestore

gsave
  % Border
  0 0 0.5 setrgbcolor
  2 setlinewidth
  100 100 200 150 rectstroke
grestore

1.10.2. Creating Gradients (Manual)

% Horizontal gradient (simplified)
/gradient {  % y1 y2 -> -
  10 {
    dup 10 div setgray
    100 2 index 200 1 rectfill
    1 add
  } repeat
  pop pop
} def

100 200 gradient

1.10.3. Style-based Drawing Functions

% Draw rectangle with specified style
/styledRect {  % x y w h style -> -
  5 dict begin
    /style exch def
    /h exch def
    /w exch def
    /y exch def
    /x exch def

    gsave
      style exec
      x y w h rectfill
    grestore
  end
} def

% Define styles
/redStyle { 1 0 0 setrgbcolor } def
/blueStyle { 0 0 1 setrgbcolor } def

% Use them
100 100 50 50 redStyle styledRect
200 100 50 50 blueStyle styledRect

1.11. Best Practices

1.11.1. Always Balance gsave/grestore

% Good: balanced
gsave
  % ...
grestore

% Bad: unbalanced
gsave
  % ... missing grestore
gsave
  % ... too many gsave

1.11.2. Use Meaningful State Boundaries

% Good: logical grouping
gsave
  % Set up for drawing shape
  1 0 0 setrgbcolor
  2 setlinewidth

  % Draw shape
  100 100 50 0 360 arc
  stroke
grestore

% Bad: arbitrary boundaries
gsave
  1 0 0 setrgbcolor
grestore
gsave
  2 setlinewidth
  100 100 50 0 360 arc
grestore

1.11.3. Initialize State Explicitly

% Good: explicit initialization
/initialize {
  initgraphics     % Reset to default
  0 setgray
  1 setlinewidth
  [] 0 setdash
  0 setlinecap
  0 setlinejoin
  /Helvetica findfont 12 scalefont setfont
} def

initialize
% Known starting state

1.11.4. Document State Requirements

% drawFancyBorder: requires current path to be set
% Assumes: line width, color already set
% Modifies: dash pattern
% Preserves: path, other state
/drawFancyBorder {
  gsave
    [5 3] 0 setdash
    stroke
  grestore
} def

1.12. Debugging Graphics State

/printState {
  (=== Graphics State ===) print
  (Gray: ) print currentgray =
  (RGB: ) print currentrgbcolor pop pop =
  (Line Width: ) print currentlinewidth =
  (Line Cap: ) print currentlinecap =
  (Line Join: ) print currentlinejoin =
  (Dash: ) print currentdash pop =
  (Font: ) print currentfont /FontName get =
} def

% Usage
printState

1.12.2. Track State Changes

% Wrap state-changing operators
/setgray {
  dup (Setting gray to: ) print =
  systemdict /setgray get exec
} def

% Now all setgray calls are logged
0.5 setgray  % Prints: Setting gray to: 0.5

1.12.3. Visualize State Stack Depth

/showStackDepth {
  countdictstack (Dict stack depth: ) exch =string cvs print () print
  count (Operand stack depth: ) exch =string cvs print () print
} def

gsave
  gsave
    showStackDepth  % Shows nesting level
  grestore
grestore

1.13. Common Pitfalls

1.13.1. Modifying State Without Saving

% Wrong: permanent change
1 0 0 setrgbcolor
% Everything after this is red!

% Correct: temporary change
gsave
  1 0 0 setrgbcolor
  % Draw red things
grestore
% Color restored

1.13.2. Forgetting to Reset Path After Clip

% Wrong: path becomes clipping path
newpath
100 100 100 0 360 arc
clip
% Path is now empty and also the clip path

% Correct: reset path
newpath
100 100 100 0 360 arc
clip
newpath  % Start fresh path for drawing

1.13.3. Accumulating Transformations

% Wrong: transformations accumulate
/drawSomething {
  45 rotate
  % Draw
} def

drawSomething  % Rotated 45°
drawSomething  % Rotated 90° total!

% Correct: save/restore
/drawSomething {
  gsave
    45 rotate
    % Draw
  grestore
} def

1.14. See Also


Back to top

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