1. itransform

Transforms coordinates from device space to user space (inverse transform).

1.1. Syntax

x' y' itransform → x y
x' y' matrix itransform → x y

1.2. Stack Effects

Table 1. Before
Level Object

1

y' (number)

0

x' (number)

Table 2. After
Level Object

1

y (number)

0

x (number)

1.3. Description

With no matrix operand, itransform (inverse transform) transforms the device space coordinate (x', y') by the inverse of the current transformation matrix (CTM) to produce the corresponding user space coordinate (x, y).

If the matrix operand is supplied, itransform transforms (x', y') by the inverse of matrix rather than by the inverse of CTM.

This is the inverse operation of transform. It converts device coordinates (pixel positions) back to user coordinates (the coordinate system used for drawing).

1.4. PostScript Level

Level 1 and later

1.5. Examples

Basic inverse transformation
100 100 translate
2 2 scale

% Forward transformation
50 50 transform
% → 200.0 200.0

% Inverse transformation
200 200 itransform
% → 50.0 50.0 (back to original)
Using explicit matrix
/m [2 0 0 2 100 100] def
200 200 m itransform
% → 50.0 50.0
% Inverse of (x-100)/2, (y-100)/2
Mouse coordinate conversion
% Convert device coordinates (pixels) to user coordinates
/deviceX 300 def
/deviceY 400 def
deviceX deviceY itransform
% → user space coordinates

1.6. Common Use Cases

1.6.1. Hit Testing

% Check if device point is inside user space rectangle
/deviceClick {  % deviceX deviceY -> bool
  itransform  % Convert to user space
  % Check bounds in user space
  dup 0 ge exch 100 le and
  exch dup 0 ge exch 100 le and
  and
} def

250 300 deviceClick  % Check if click is in rectangle

1.6.2. Event Handling

% Convert mouse events to drawing coordinates
/handleMouseDown {  % deviceX deviceY
  gsave
    % Current transformations in effect
    itransform
    /userY exch def
    /userX exch def
    % Process in user coordinates
    userX userY processClick
  grestore
} def

1.6.3. Coordinate System Analysis

% Understand current transformation
initmatrix
72 72 scale  % 1 unit = 1 inch

% Where is device pixel (100, 100)?
100 100 itransform
% → 1.388... 1.388... (in inches)

1.6.4. Undoing Transformations

% Get user coordinates from transformed device coordinates
gsave
  100 100 translate
  2 2 scale

  % Point in current user space
  50 50 transform  % → 200 200 in device space

  % Convert back
  itransform       % → 50 50 in user space
grestore

1.7. Common Pitfalls

Includes Translation - itransform uses the full inverse transformation including translation. Use idtransform for distance vectors.
100 100 translate

% For points:
150 200 itransform  % → 50 100 (correct)

% For distances:
100 100 itransform  % → 0 0 (wrong - includes translation)
100 100 idtransform % → 100 100 (correct - distance)
Singular Matrices - If CTM or matrix is singular (determinant = 0), itransform fails.
0 0 scale  % Creates singular matrix (determinant = 0)
100 100 itransform  % Error: undefinedresult
Precision Loss - Very large transformations may cause precision loss in the inverse.
1000000 1000000 scale
1 1 itransform
% May not return exactly 0.000001 0.000001
% due to floating-point precision
Use for Interactive Graphics - Essential for converting mouse/touch coordinates:
% In drawing application
/handleClick {  % deviceX deviceY
  gsave
    % Apply all user transformations
    panX panY translate
    zoom zoom scale
    rotation rotate

    % Convert click to drawing coordinates
    itransform
    /drawY exch def
    /drawX exch def

    % Process click in drawing coordinates
    drawX drawY addPoint
  grestore
} def
Verify Round-Trip - Test that transform/itransform are inverses:
/testTransform {
  % userX userY
  2 copy transform itransform
  % Should return original values
  3 -1 roll sub abs 0.001 lt
  3 1 roll exch sub abs 0.001 lt and
  { (OK) } { (Error!) } ifelse print
} def

100 200 testTransform

1.8. Error Conditions

Error Condition

[rangecheck]

Matrix operand does not have exactly 6 elements

[stackunderflow]

Fewer than 2 operands on stack (first form) or fewer than 3 (second form)

[typecheck]

Operands are not numbers, or matrix operand is not an array

[undefinedresult]

CTM or matrix is singular (determinant = 0) and cannot be inverted

1.9. Implementation Notes

  • Requires computing the matrix inverse

  • More expensive than transform (forward transformation)

  • The inverse CTM is not cached; computed each time

  • Precision depends on CTM condition number

  • Used automatically by many interactive operators

1.10. Transformation Formula

For CTM = [a b c d tx ty], the inverse transformation is:

det = a×d - b×c

x = (d×(x' - tx) - c×(y' - ty)) / det
y = (a×(y' - ty) - b×(x' - tx)) / det

Example with CTM = [2 0 0 2 100 100]:

det = 2×2 - 0×0 = 4

(200, 200) inverse transforms to:
x = (2×(200-100) - 0×(200-100)) / 4 = 200/4 = 50
y = (2×(200-100) - 0×(200-100)) / 4 = 200/4 = 50
→ (50, 50)

1.11. Relationship to Other Operators

% Forward and inverse are opposites:
userX userY transform itransform
% → userX userY (round-trip)

deviceX deviceY itransform transform
% → deviceX deviceY (round-trip)

% Using explicit matrix:
x y m transform m itransform
% → x y

% Equivalent to using inverse matrix:
m matrix invertmatrix  % Get inverse
x y transform          % Transform by inverse

1.12. Use in Interactive Applications

% Typical pattern for interactive graphics
/processInput {  % deviceX deviceY eventType
  /event exch def
  itransform  % Convert to user space
  event (mousedown) eq {
    handleMouseDown
  } if
  event (mousemove) eq {
    handleMouseMove
  } if
} def

1.13. Performance Considerations

  • Slightly slower than transform (requires matrix inversion)

  • Still very fast for occasional use

  • If called frequently with same matrix, consider precomputing inverse:

% Inefficient:
{
  deviceX deviceY itransform
  % ... process ...
} repeat

% Efficient:
matrix currentmatrix matrix invertmatrix
/inverseMatrix exch def
{
  deviceX deviceY inverseMatrix transform
  % ... process ...
} repeat

1.14. See Also


Back to top

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