1. idtransform

Transforms a distance vector from device space to user space (inverse delta transform).

1.1. Syntax

dx' dy' idtransform → dx dy
dx' dy' matrix idtransform → dx dy

1.2. Stack Effects

Table 1. Before
Level Object

1

dy' (number)

0

dx' (number)

Table 2. After
Level Object

1

dy (number)

0

dx (number)

1.3. Description

With no matrix operand, idtransform (inverse delta transform) transforms the device space distance vector (dx', dy') by the inverse of the CTM to produce the corresponding distance vector (dx, dy) in user space.

If the matrix operand is supplied, idtransform transforms the distance vector by the inverse of matrix rather than by the inverse of CTM.

A delta transformation is similar to a normal transformation, but the translation components (tx and ty) of the transformation matrix are not used, making the distance vectors position-independent in both user space and device space.

idtransform is the inverse of dtransform. It is useful for determining how distances map from device space to user space.

1.4. PostScript Level

Level 1 and later

1.5. Examples

Basic inverse delta transformation
2 2 scale
100 200 dtransform
% → 200.0 400.0

200 400 idtransform
% → 100.0 200.0 (back to original)
Translation ignored
100 100 translate
2 2 scale

% Distance transformation ignores translation
100 100 idtransform
% → 50.0 50.0 (only scaling reversed)
Device pixel size
72 72 scale  % 72 points per inch
1 1 idtransform
% → 0.0138... 0.0138... (1 pixel ≈ 1/72 inch)

1.6. Common Use Cases

1.6.1. Converting Device Units to User Units

% How much is 1 device pixel in user space?
2 2 scale
1 0 idtransform pop
% → 0.5 (1 device pixel = 0.5 user units)

1.6.2. Computing User Space Line Width

% What line width in user space gives 1 device pixel?
/deviceLineWidth 1 def
deviceLineWidth 0 idtransform abs exch abs max
setlinewidth
% Now line appears as 1 device pixel regardless of scale

1.6.3. Measuring in Device Units

% How many device pixels in 10 user units?
10 0 dtransform abs
% Then convert back to understand scale:
dup 0 exch idtransform abs
% Returns 10.0 (round-trip)

1.6.4. Stroke Width Adjustment

% Ensure minimum line width in device space
/minDeviceWidth 1 def  % At least 1 pixel
currentlinewidth 0 dtransform abs
minDeviceWidth lt {
  % Line is too thin, adjust
  minDeviceWidth 0 idtransform abs
  setlinewidth
} if

1.7. Common Pitfalls

For Distances Only - idtransform is for distance vectors, not positions.
100 100 translate
2 2 scale

% Wrong - for point coordinates:
300 400 idtransform  % → 150 200 (incorrect)
300 400 itransform   % → 100 150 (correct)

% Right - for distances:
200 400 idtransform  % → 100 200 (correct distance)
Singular Matrices - If CTM or matrix is singular, idtransform fails.
0 0 scale  % Singular matrix (determinant = 0)
100 100 idtransform  % Error: undefinedresult
Different from itransform - These are not the same!
100 100 translate
100 100 itransform   % → 0 0 (point transformation)
100 100 idtransform  % → 100 100 (distance transformation)
Use for Scale-Independent Sizing - Compute sizes that remain constant in device space:
% Draw circle with fixed device radius
/drawDeviceCircle {  % deviceRadius
  0 exch idtransform  % Convert to user space
  /radiusY exch def
  /radiusX exch def
  % Draw ellipse if non-uniform scaling
  0 0 radiusX radiusY scale
  0 0 1 0 360 arc
} def

5 drawDeviceCircle  % Always 5 device pixels radius
Round-Trip Testing - Verify inverse relationship:
/testDelta {  % dx dy
  2 copy dtransform idtransform
  3 -1 roll sub abs 0.001 lt
  3 1 roll exch sub abs 0.001 lt and
} def

100 200 testDelta  % Should return true

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

  • More expensive than dtransform (requires inverse computation)

  • Translation components are explicitly ignored

  • The inverse uses only [a b c d] components

  • Precision depends on matrix condition number

  • No caching of inverse matrix

1.10. Transformation Formula

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

det = a×d - b×c

dx = (d×dx' - c×dy') / det
dy = (a×dy' - b×dx') / det

Note: tx and ty are not used.

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

det = 2×3 - 0×0 = 6

(20, 60) inverse delta transforms to:
dx = (3×20 - 0×60) / 6 = 60/6 = 10
dy = (2×60 - 0×20) / 6 = 120/6 = 20
→ (10, 20)

1.11. Delta Transform Pairs

Operation Direction Translation

dtransform

User → Device

Ignored

idtransform

Device → User

Ignored

transform

User → Device

Included

itransform

Device → User

Included

1.12. Computing Device Pixel Size

% Determine size of device pixel in current user space
/getPixelSize {
  % Returns width and height of device pixel
  1 0 idtransform abs exch abs  % X direction
  0 1 idtransform abs exch abs  % Y direction
} def

2 3 scale
getPixelSize
% → 0.5 0.333... (pixel is 0.5×0.333 user units)

1.13. Relationship to Graphics Parameters

Many graphics parameters are affected by transformations:

% Line width:
% User space width → dtransform → device width
% Device width → idtransform → user space width

% Dash pattern:
% User space lengths → dtransform → device lengths
% Device lengths → idtransform → user space lengths

% Character widths:
% Font space → dtransform → device pixels
% Device pixels → idtransform → font space

1.14. Performance Considerations

  • Requires matrix inversion computation

  • More expensive than dtransform

  • Still very fast for occasional use

  • Consider caching inverse matrix for repeated use:

% Inefficient:
{
  deviceDX deviceDY idtransform
  % ... process ...
} repeat

% Efficient:
matrix currentmatrix matrix invertmatrix
/inverseMatrix exch def
{
  deviceDX deviceDY inverseMatrix dtransform
  % ... process ...
} repeat

1.15. See Also


Back to top

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