1. kshow
Show text with kerning procedure between characters.
1.3. Description
kshow paints the characters of string in a manner similar to show, but allowing program intervention between characters.
If the character codes in string are c₀, c₁, … cₙ, kshow proceeds as follows:
-
Shows c₀ at the current point, updating the current point by c₀'s width
-
Pushes character codes c₀ and c₁ on the operand stack (as integers)
-
Executes
proc -
Continues by showing c₁, pushing c₁ and c₂, executing
proc, and so on -
Finishes by pushing cₙ₋₁ and cₙ, executing
proc, and showing cₙ
When proc is called for the first time, the graphics state (in particular, the CTM) is the same as it was at the time kshow was invoked, except that the current point has been updated by the width of c₀. Execution of proc is permitted to have any side effects, including changes to the graphics state. Such changes persist from one call of proc to the next and may affect graphical output for the remainder of kshow's execution and afterward.
The name kshow is derived from "kern-show." To kern characters is to adjust the spacing between adjacent pairs of characters in order to achieve a visually pleasing result. The kshow operator enables user-defined kerning and other manipulations, because arbitrary computations can be performed between each pair of characters.
1.4. Parameters
proc (procedure)
: Procedure to execute between each character pair; receives two character codes on stack
string (string)
: The text to display
1.5. Procedure Arguments
When proc is called, the stack contains:
char(n-1) char(n)
Where:
- char(n-1) is the character just shown
- char(n) is the next character to be shown
1.6. Examples
1.6.1. Simple Kerning Table
% Define kerning pairs
/kernPairs <<
/AV -2 % Kern A-V pair by -2 units
/Aw -1 % Kern A-w pair by -1 unit
/To -1.5 % Kern T-o pair by -1.5 units
/We -1 % Kern W-e pair by -1 unit
>> def
% Kerning procedure
/kern { % char1 char2 kern -
% Convert to name
2 copy
=string cvs exch =string cvs
exch concatstrings cvn
% Look up kerning
kernPairs exch known {
kernPairs exch get
0 rmoveto
} {
pop pop
} ifelse
} def
/Helvetica findfont 24 scalefont setfont
100 700 moveto
/kern load (WAVE) kshow
1.6.2. Inter-Character Effects
% Add dots between characters
/dotProc { % char1 char2 dotProc -
pop pop % Ignore character codes
currentpoint
0.5 0 rmoveto
0 0 1 0 360 arc fill
moveto
1 0 rmoveto % Extra space after dot
} def
100 700 moveto
/dotProc load (SPACED) kshow
1.6.3. Dynamic Spacing Based on Character Pairs
% Tighter spacing for lowercase, wider for uppercase
/adaptiveKern { % char1 char2 adaptiveKern -
% Check if both are uppercase (65-90)
dup 65 ge 1 index 90 le and
2 index 65 ge 3 index 90 le and and {
% Both uppercase: add space
pop pop
1 0 rmoveto
} {
% At least one lowercase: reduce space
pop pop
-0.3 0 rmoveto
} ifelse
} def
100 700 moveto
/adaptiveKern load (MixedCase TEXT) kshow
1.6.4. Tracking Adjustment
% Progressively increase spacing through string
/progressiveSpacing { % char1 char2 progressiveSpacing -
pop pop
currentpoint /y exch def /x exch def
/spacing spacing 0.1 add def
x spacing add y moveto
} def
/spacing 0 def
100 700 moveto
/progressiveSpacing load (EXPANDING) kshow
1.7. Errors
invalidaccess : Font or string has restricted access
invalidfont : Current font is not valid or is a composite font
nocurrentpoint : Current point is not defined
stackunderflow : Fewer than two operands on stack
typecheck
: proc is not a procedure or string is not a string
1.8. Procedure Execution Context
The proc procedure:
Can access:
- All graphics state parameters
- Character codes being processed
- Current point (via currentpoint)
Can modify:
- Current point (via rmoveto, moveto)
- Graphics state (colors, line width, etc.)
- Any PostScript state
Receives: - Two integers on stack (previous and next character codes)
Should return: - No specific return value required - Stack should be clean (pop operands or leave results intentionally)
1.9. Common Kerning Patterns
1.9.1. Letter Pair Kerning
Common pairs that benefit from kerning:
| Pair | Adjustment | Reason |
|---|---|---|
AV, AW, Av, Aw |
Negative |
Diagonal creates visual gap |
To, Tr, Tu |
Negative |
Overhang opportunity |
LT, LY |
Negative |
Height difference |
ff, fi, fl |
Negative |
Ligature-like pairs |
WA, Wa |
Negative |
Diagonal intersection |
1.9.2. Optical Kerning
% Kern based on character shapes, not just codes
/opticalKern { % char1 char2 opticalKern -
% Check for diagonal-straight combinations
exch dup 65 eq exch 86 eq or % A or V
1 index dup 84 eq exch 87 eq or % T or W
and {
-1.5 0 rmoveto
} {
pop
} ifelse
} def
/Helvetica findfont 18 scalefont setfont
100 700 moveto
/opticalKern load (WAVES TRAVEL) kshow
1.10. Performance Considerations
-
Most expensive text operator due to procedure calls
-
Called
length(string) - 1times -
Procedure invocation overhead per character pair
-
Graphics state changes persist
-
Use only when necessary for typographic quality
Performance comparison:
show - Fastest
ashow - Fast (simple arithmetic)
widthshow - Fast (conditional check)
awidthshow - Moderate (two conditionals)
kshow - Slowest (procedure calls)
1.11. Kerning Best Practices
Define kerning tables: - Store kerning pairs in dictionaries - Precompute common adjustments - Use efficient lookup structures
Minimize procedure complexity:
- Keep proc as simple as possible
- Avoid unnecessary calculations
- Cache computed values when possible
Test with target fonts: - Kerning values are font-specific - Verify with actual font metrics - Adjust for different point sizes
1.12. Limitations
Character boundaries: : Procedure is called between characters, not within character rendering
Stack management: : Procedure must properly manage the character code operands
1.13. See Also
-
show- Basic text painting -
ashow- Uniform character spacing -
widthshow- Selective character width adjustment -
awidthshow- Combine ashow and widthshow -
cshow- Show with procedure per character (Level 2) -
stringwidth- Calculate text width