1. stringwidth

Calculate text width and displacement.

1.1. Syntax

string stringwidth → wx wy

1.2. Stack Effects

Before:

string

After:

wx wy

1.3. Description

stringwidth calculates the change in the current point that would occur if string were given as the operand to show with the current font. wx and wy are computed by adding together the width vectors of all the individual characters in string and converting the result to user space.

They form a distance vector in x and y describing the width of the entire string in user space. To obtain the character widths, stringwidth may execute the descriptions of one or more of the characters in the current font and may cause the results to be placed in the font cache.

However, stringwidth prevents the graphics operators that are executed from painting anything into the current page.

Note that the "width" of a string is defined as movement of the current point. It has nothing to do with the dimensions of the character outlines (see charpath) and pathbbox.

1.4. Parameters

string (string) : The text to measure

1.5. Returns

wx (number) : X component of the total width vector in user space

wy (number) : Y component of the total width vector in user space

1.6. Examples

1.6.1. Basic Width Measurement

/Helvetica findfont 12 scalefont setfont
(Hello, World!) stringwidth
% Returns wx and wy
pop  % Usually only wx is needed

1.6.2. Centering Text

/centerText {  % string centerText -
  dup stringwidth pop  % Get width (wx)
  2 div neg            % Calculate offset
  0 rmoveto            % Move left by half width
  show                 % Show centered
} def

300 400 moveto
(Centered Text) centerText

1.6.3. Right-Aligned Text

/rightShow {  % string x y rightShow -
  moveto
  dup stringwidth pop neg 0 rmoveto
  show
} def

(Right aligned) 500 700 rightShow

1.6.4. Calculating Text Bounding Box

% Note: stringwidth gives displacement, not bounding box!
% For actual bbox, use charpath + pathbbox

/textBBox {  % string textBBox llx lly urx ury
  gsave
    newpath
    0 0 moveto
    true charpath  % Get character outlines
    pathbbox       % Get bounding box
  grestore
} def

(Text) textBBox  % Returns actual visual bounds

1.6.5. Fitting Text to Width

/fitToWidth {  % string targetWidth fitToWidth -
  1 index stringwidth pop  % Get current width
  1 index exch div         % Calculate scale factor

  % Scale font to fit
  currentfont
  exch scalefont setfont
  show
} def

100 700 moveto
(Text to fit) 300 fitToWidth

1.7. Errors

invalidaccess : Font or string has restricted access

invalidfont : Current font is not valid

rangecheck : Character code exceeds encoding bounds

stackunderflow : No operand on stack

typecheck : Operand is not a string

1.8. Width Vector Calculation

For a string "ABC":

stringwidth("ABC") = width(A) + width(B) + width(C)

Where each character width is a 2D vector:

width(c) = (wx(c), wy(c))

The total is the vector sum in user space.

1.9. Coordinate System

The width is returned in user space, not character space:

/Helvetica findfont 12 scalefont setfont
(ABC) stringwidth  % Returns user space width

% After CTM change, same string has different width
2 2 scale
(ABC) stringwidth  % Returns 2× larger values

1.10. Common Patterns

1.10.1. Multi-Line Text Width

/maxLineWidth {  % array-of-strings maxLineWidth width
  0  % Initialize max width
  exch {
    stringwidth pop  % Get width of each line
    2 copy lt { exch } if pop
  } forall
} def

[(Line 1)
 (Longer line 2)
 (Short)] maxLineWidth
% Returns width of widest line

1.10.2. Truncating Text to Fit

/truncateToFit {  % string maxWidth truncateToFit substring
  1 index stringwidth pop  % Check if fits
  1 index le {
    % Fits as-is
    pop
  } {
    % Too wide: truncate
    0 1 2 index length 1 sub {
      2 index 0 1 index getinterval
      dup stringwidth pop
      3 index lt { exit } if
      pop
    } for
    % Add ellipsis
    (...) concatstrings
    exch pop
  } ifelse
} def

(Very long text that needs truncation) 200 truncateToFit

1.10.3. Column Width Calculation

/calculateColumnWidth {  % array-of-paragraphs calculateColumnWidth width
  % Find maximum width needed for array of text
  0  % Initialize max
  {
    % For each paragraph (array of lines)
    {
      stringwidth pop
      2 copy lt { exch } if pop
    } forall
  } forall
} def

1.11. Width vs. Bounding Box

Measurement Purpose

stringwidth

Current point displacement (typographic width)

charpath + pathbbox

Visual bounding box (ink bounds)

Example difference:

% Typographic width (includes sidebearings)
(Text) stringwidth pop  % e.g., 120 units

% Visual width (actual ink)
gsave
  newpath 0 0 moveto
  (Text) true charpath
  pathbbox
grestore
pop exch pop sub  % e.g., 115 units (tighter)

1.12. Performance Considerations

  • Fast operation (similar cost to show)

  • May trigger character caching

  • Does not paint (no output overhead)

  • Can be called repeatedly without side effects

  • Useful for layout calculations before rendering

1.13. Vertical Writing Modes

For vertical writing fonts, wy may be non-zero:

% Vertical font example
/VerticalFont findfont 12 scalefont setfont
(縦書き) stringwidth
% wx may be small or zero
% wy contains the vertical advancement

1.14. See Also

  • show - Paint text string

  • charpath - Get character outlines as path

  • pathbbox - Get path bounding box

  • setfont - Establish current font

  • ashow - Show with spacing adjustment

  • widthshow - Show with selective adjustment


Back to top

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