1. ueofill

Interprets a user path definition and fills using the even-odd rule.

1.1. Syntax

userpath ueofill → -

1.2. Stack Effects

Table 1. Before
Level Object

0

userpath (array, packed array, or string)

Table 2. After
Level Object

(empty)

No results

1.3. Description

ueofill is similar to ufill, but uses the even-odd rule instead of the non-zero winding number rule to determine which areas are inside the path. The entire operation is effectively enclosed by gsave and grestore, so ueofill has no lasting effect on the graphics state.

ueofill is equivalent to:

gsave newpath uappend eofill grestore

The even-odd rule determines whether a point is inside by counting path crossings: an odd number means inside, an even number means outside. This makes it ideal for creating shapes with holes.

1.4. PostScript Level

Level 2 and later

1.5. Examples

Simple user path with even-odd fill
[
  50 50 250 250 setbbox
  100 100 moveto
  200 100 lineto
  200 200 lineto
  100 200 lineto
  closepath
] ueofill
Creating a donut shape
[
  ucache
  100 100 300 300 setbbox
  200 200 80 0 360 arc
  closepath
  200 200 40 0 360 arc
  closepath
] ueofill  % Creates ring with hole in center
Frame with even-odd fill
[
  ucache
  50 50 250 250 setbbox
  % Outer rectangle
  50 50 moveto
  250 50 lineto
  250 250 lineto
  50 250 lineto
  closepath
  % Inner rectangle (creates hole)
  100 100 moveto
  200 100 lineto
  200 200 lineto
  100 200 lineto
  closepath
] ueofill

1.6. Common Use Cases

1.6.1. Typography with Counters

% Letter 'O' with counter (hole)
/letterO [
  ucache
  0 0 100 120 setbbox
  50 60 40 0 360 arc     % Outer
  closepath
  50 60 25 0 360 arc     % Inner (counter)
  closepath
] def

letterO ueofill

1.6.2. Complex Shapes with Holes

/target [
  ucache
  50 50 250 250 setbbox
  150 150 90 0 360 arc closepath  % Ring 1
  150 150 70 0 360 arc closepath
  150 150 50 0 360 arc closepath  % Ring 2
  150 150 30 0 360 arc closepath
  150 150 10 0 360 arc closepath  % Center dot
] def

target ueofill  % Concentric rings pattern

1.6.3. Self-Intersecting Paths

/pentagram [
  ucache
  50 50 250 250 setbbox
  % Five-pointed star with intersecting lines
  150 230 moveto
  182 126 lineto
  238 170 lineto
  62 170 lineto
  118 126 lineto
  closepath
] def

pentagram ueofill  % Even-odd handles intersections

1.7. Common Pitfalls

Different Results from ufill - The even-odd rule produces different results than the non-zero winding number rule.
/samePath [
  0 0 200 200 setbbox
  50 50 moveto
  150 50 lineto
  150 150 lineto
  50 150 lineto
  closepath
  75 75 moveto
  125 75 lineto
  125 125 lineto
  75 125 lineto
  closepath
] def

gsave
  samePath ufill    % Both rectangles filled
grestore
samePath ueofill    % Inner is a hole
Path Direction Irrelevant - Unlike ufill, path direction doesn’t affect the result with ueofill.
% Clockwise or counterclockwise - same result
[
  0 0 300 300 setbbox
  150 150 100 0 360 arc closepath   % Outer
  150 150 50 0 360 arc closepath    % Inner
] ueofill  % Always creates hole regardless of arc direction
Ideal for Shapes with Holes - Use ueofill when you need predictable holes regardless of path direction:
/windowFrame [
  ucache
  0 0 200 300 setbbox
  % Frame outline
  10 10 moveto
  190 10 lineto
  190 290 lineto
  10 290 lineto
  closepath
  % Window panes (4 holes)
  20 20 moveto 90 20 lineto 90 140 lineto 20 140 lineto closepath
  110 20 moveto 180 20 lineto 180 140 lineto 110 140 lineto closepath
  20 160 moveto 90 160 lineto 90 280 lineto 20 280 lineto closepath
  110 160 moveto 180 160 lineto 180 280 lineto 110 280 lineto closepath
] def

windowFrame ueofill

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)

[stackunderflow]

No operand on stack

[typecheck]

Operand is not a valid user path

1.9. Implementation Notes

  • The even-odd rule is generally simpler to compute than non-zero winding

  • Path direction does not affect the fill result

  • Multiple overlapping subpaths create alternating filled and unfilled regions

  • Cached user paths with ucache provide significant performance benefits

  • The bounding box enables optimization

1.10. Comparison with Other Fill Operators

Standard fill (fill)
  • Uses non-zero winding number rule

  • Path direction matters

  • No graphics state isolation

Even-odd fill (eofill)
  • Uses even-odd rule

  • Path direction doesn’t matter

  • No graphics state isolation

User path fill (ufill)
  • Uses non-zero winding number rule

  • Efficient user path format

  • Automatic graphics state save/restore

  • Can be cached

User path even-odd fill (ueofill)
  • Uses even-odd rule

  • Efficient user path format

  • Automatic graphics state save/restore

  • Can be cached

  • Best for shapes with holes

1.11. Best Practices

1.11.1. Use for Predictable Holes

% Good: holes work regardless of construction
/buttonWithHole [
  ucache
  0 0 100 40 setbbox
  % Button body
  5 5 moveto
  95 5 lineto
  95 35 lineto
  5 35 lineto
  closepath
  % Icon hole in center
  45 15 moveto
  55 15 lineto
  55 25 lineto
  45 25 lineto
  closepath
] def

buttonWithHole ueofill

1.11.2. Cache Frequently Used Paths

/starIcon [
  ucache  % Enable caching
  0 0 50 50 setbbox
  25 45 moveto
  29 30 lineto
  44 25 lineto
  29 20 lineto
  25 5 lineto
  21 20 lineto
  6 25 lineto
  21 30 lineto
  closepath
] def

% Efficient reuse
10 {
  starIcon ueofill
  60 0 translate
} repeat

1.11.3. Combine with Other Operations

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

% Fill
0.7 setgray
ringPath ueofill

% Stroke
0 setgray
1 setlinewidth
ringPath ustroke

1.12. Performance Considerations

  • Even-odd rule calculation is generally faster than non-zero winding

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

  • The bounding box enables rendering optimizations

  • Very complex paths with many crossings may slow processing

  • User paths are more efficient than traditional path operators

1.13. See Also

  • eofill - Even-odd fill traditional path

  • ufill - Fill user path with non-zero winding rule

  • ustroke - Stroke user path

  • eoclip - Clip using even-odd rule

  • setbbox - Set bounding box

  • ucache - Enable user path caching

  • uappend - Append user path to current path

  • 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.