1. dtransform

Transforms a distance vector from user space to device space.

1.1. Syntax

dx dy dtransform → dx' dy'
dx dy matrix dtransform → 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, dtransform (delta transform) transforms the distance vector (dx, dy) by the CTM to produce the corresponding distance vector (dx', dy') in device space.

If the matrix operand is supplied, dtransform transforms the distance vector by matrix rather than by the CTM.

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

This is useful for determining how distances map from user space to device space, such as for line widths, dash patterns, or measuring transformed lengths.

1.4. PostScript Level

Level 1 and later

1.5. Examples

Basic distance transformation
initmatrix
100 200 dtransform
% → 100.0 200.0 (no transformation)

2 2 scale
100 200 dtransform
% → 200.0 400.0 (scaled but not translated)
Translation ignored
100 100 translate  % Translation
100 100 dtransform
% → 100.0 100.0 (translation ignored)

100 100 transform
% → 200.0 200.0 (translation included)
Computing line width in device space
2 2 scale
1 0 dtransform     % Transform unit x-vector
/deviceWidth exch def pop
% deviceWidth = 2.0 (line width in device pixels)

1.6. Common Use Cases

1.6.1. Determining Device Line Width

% Current line width in device pixels
currentlinewidth 0 dtransform
/deviceHeight exch def
/deviceWidth exch def
deviceWidth dup mul deviceHeight dup mul add sqrt
/deviceLineWidth exch def

1.6.2. Computing Dash Pattern Scale

% How much is a dash pattern scaled?
2 3 scale
10 0 dtransform pop
% → 20.0 (10-point dash becomes 20 device units)

1.6.3. Measuring Transformed Distances

% Length of transformed vector
/vectorLength {  % dx dy -> length
  dtransform
  dup mul exch dup mul add sqrt
} def

100 100 translate
2 2 scale
10 10 vectorLength
% → 28.28... (√((10×2)² + (10×2)²))

1.6.4. Font Scaling Analysis

% Determine actual font size in device space
/Helvetica findfont 12 scalefont setfont
0 1 dtransform
/fontHeightDevice exch def pop
% fontHeightDevice shows actual pixel height

1.7. Common Pitfalls

Position-Independent - dtransform ignores translation. Use transform for points.
100 100 translate

% For points (positions):
50 50 transform    % → 150 150 (correct)
50 50 dtransform   % → 50 50 (wrong - no translation)

% For distances (vectors):
50 50 dtransform   % → 50 50 (correct)
50 50 transform    % → 150 150 (wrong - includes translation)
Not for Coordinate Conversion - Don’t use for absolute positions.
% Wrong - finding device position:
100 100 dtransform  % Ignores translation!

% Right:
100 100 transform   % Includes translation
Use for Scale-Dependent Parameters - Perfect for parameters affected by scaling:
% Adjust line width for scale
2 2 scale
0.5 setlinewidth  % Thin line in user space
1 0 dtransform abs  % Check device width
% → 1.0 (half point becomes 1 device unit after 2x scale)
Direction Vectors - Use for transforming directions without position:
% Unit vector in x direction
1 0 dtransform
% Shows how x-axis is transformed (direction and scale)

% Unit vector in y direction
0 1 dtransform
% Shows how y-axis is transformed

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

1.9. Implementation Notes

  • Translation components (tx, ty) are ignored

  • Only the linear transformation part [a b c d] is used

  • Very fast operation (simpler than full transform)

  • No risk of [undefinedresult] error (unlike itransform)

  • The inverse operation is idtransform

1.10. Transformation Formula

For CTM = [a b c d tx ty]:

dx' = a×dx + c×dy
dy' = b×dx + d×dy

Note: tx and ty are not used.

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

(10, 20) delta transforms to:
dx' = 2×10 + 0×20 = 20
dy' = 0×10 + 3×20 = 60
→ (20, 60)

1.11. Distance vs Position

Operation Use For Example

transform

Absolute positions, points

100 100 moveto

dtransform

Distances, vectors, offsets

Line width, dash lengths

itransform

Device to user positions

Mouse coordinates

idtransform

Device to user distances

Device pixel size

1.12. Understanding the Difference

100 100 translate
2 2 scale

% Point transformation (includes translation):
50 50 transform    % → 200 200

% Distance transformation (no translation):
50 50 dtransform   % → 100 100

% The difference:
% - transform moves (50,50) to translated+scaled position
% - dtransform just scales the distance (50,50)

1.13. Practical Applications

1.13.1. Adaptive Line Width

% Maintain 1-pixel line width regardless of scale
/setDeviceLineWidth {  % deviceWidth
  1 0 idtransform exch abs exch abs max
  setlinewidth
} def

1 setDeviceLineWidth  % Always 1 device pixel wide

1.13.2. Computing Transformed Lengths

% Actual length of line after transformation
/pathLength {  % x1 y1 x2 y2 -> length
  4 2 roll sub    % dx
  3 1 roll sub    % dy
  dtransform      % Transform to device
  dup mul exch dup mul add sqrt
} def

0 0 100 100 pathLength

1.14. Performance Considerations

  • Faster than transform (no translation component)

  • Simple matrix multiplication

  • Can be called frequently

  • No memory allocation

1.15. See Also


Back to top

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