[comp.lang.postscript] postscript code for justified text

ph@miro.Berkeley.EDU (Paul Heckbert) (02/14/91)

Have you ever wanted to generate postscript to label axes,
putting text above, below, to the left, or to the right of a given point
on the page?  And have you ever spent many iterations tweaking magic offset
parameters to get things to look right, only to have these parameters fail
when the point size was changed, or a proportional-spaced font was substituted?

I had, so I wrote a routine that facilitates these tasks.
It's a fancier version of "show".  I've found it very useful.

You specify the coordinates of a point in user space, and then you specify
another point in "character string space" relative to the lower left corner
of your string and to the current font and fontscale, and this "showpos"
routine places the string on the page so that those two points coincide.

This is best demonstrated with the following example file.
Let me know how you like it.  I don't read comp.lang.postscript regularly,
so please email.

Paul Heckbert, Computer Science Dept.
570 Evans Hall, UC Berkeley		INTERNET: ph@miro.berkeley.edu
Berkeley, CA 94720			UUCP: ucbvax!miro.berkeley.edu!ph

-------------------------------------
%!
% Demonstration of text justification routine "showpos"
%
% The 'invertmatrix' routine at the beginning is added only so that this file
% can be previewed with the SGI "psview" program.
% The essential definitions are defaultfontmatrixinv and showpos.
%
% Paul Heckbert, Jan 1989

% invertmatrix: invert matrix m1 into matrix m2
% this is a standard Postscript operator, but SGI's NEWS ain't got it
%
%      [a d 0]		 [  e    -d   0]
% m1 = [b e 0]   m1^-1 = [ -b     a   0]/(ae-bd)
%      [c f 1]		 [bf-ce cd-af 1]

/invertmatrix {			% m1 m2
    7 dict begin
    exch			% m2 m1
    aload pop			% m2 a d b e c f
    /f exch def
    /c exch def
    /e exch def
    /b exch def
    /d exch def
    /a exch def			% m2
    /x a e mul b d mul sub	% m2 /x det(m1)
    def
    e x div
    d neg x div
    b neg x div
    a x div
    b f mul c e mul sub x div
    c d mul a f mul sub x div
    % m2 e/x -d/x -b/x a/x (bf-ce)/x (cd-af)/x
    7 -1 roll
    % e/x -d/x -b/x a/x (bf-ce)/x (cd-af)/x m2
    astore			% m2
    end
} def

/defaultfontmatrixinv		% inverse of matrix for unscaled font
    /Helvetica findfont /FontMatrix get matrix invertmatrix
def

% showpos: draw string with character-relative positioning
% input: x y fx fy str
%
% where (x,y) is point in user space at which to position (fx,fy) of char space
% where char space has (0,0) at origin of string,
% (0,1) is interline spacing vector
% and (length(str),0) is end of string vector
%
% e.g.	(fx,fy)=(0,0) lower-left justifies,
%		(.5*length(str),.5) centers,
%		(length(str),1) upper-right justifies
%
/showpos {
				% x y fx fy str
    dup 6 1 roll		% str x y fx fy str
    dup length			% str x y fx fy str len
    4 -1 roll exch div		% str x y fy str fx/len	(relative fx)
    3 1 roll			% str x y fx' fy str

    % find vector (hx,hy) along width of string and scale it by fx':
    stringwidth			% str x y fx' fy hx hy
    3 index mul exch		% str x y fx' fy fx'*hy hx
    4 -1 roll mul		% str x y fy fx'*hy fx'*hx

    % find vector (vx,vy) along height of string and scale it by fy:
    0 1				% str x y fy hy' hx' 0 1
    currentfont /FontMatrix get	% .. FD		(font to device transform)
    defaultfontmatrixinv matrix % .. FD DU mat	(times device to user transform)
    concatmatrix		% .. FU	(equals relative,font to user transform)
				% str x y fy hy' hx' 0 1 FU
    transform			% str x y fy hy' hx' vx vy
    4 index mul exch		% str x y fy hy' hx' fy*vy vx
    5 -1 roll mul		% str x y hy' hx' fy*vy fy*vx
				% str x y hy hx vy vx	(drop the primes)

    % add the displacement vectors (hx,hy) and (vx,vy):
    3 -1 roll add		% str x y hy vy hx+vx
    3 1 roll add		% str x y hx+vx hy+vy
				% str x y dx dy		(abbrev)

    % subtract from reference point:
    3 -1 roll exch sub		% str x dx y-dy
    3 1 roll sub exch		% str x-dx y-dy
    moveto show			%			(yay!)
} def

% and here's a little demo

72 dup scale					% user space is inches
/Times-Roman findfont .5 scalefont setfont

.25 .25 0 0 (lower left) showpos		% lower-left justify
8.25 10.75 11 1 (upper right) showpos		% upper-right justify
8.25 10.25 23 1 (note how these line up!) showpos

/Times-Roman findfont 1 scalefont setfont
4.25 5.5 3 .5 (CENTER) showpos			% center

showpage