2007-02-10

Here's an extreme example of the size differences between PostScript and PDF. I was experimenting with encodings and fonts and used this code to generate a table of glyphs sorted by index within the Helvetica TrueType font. The PostScript files are 4648 bytes including comments and the PDF output is 359691 bytes. Of course, most of the expansion comes from the extraction of data from a built-in resource, but it still amused me.

% print names of all glyphs in a given font encoding

/FZ 10 def
/Helvetica findfont FZ scalefont setfont
/iobuf 100 string def

% ----------------------------------------------------------------------
(QuickSort.ps) run	% from http://www.acumentraining.com/Resources.html
/strdup { dup length string copy } bind def	% Hard to believe this is not built in.

/mirror {	% given a dictionary, return a new dictionary mapping values back to keys
  dup length dict exch	% newdict olddict
  {			% newdict oldkey oldvalue
    exch		% newdict key2=oldvalue value2=oldkey
    2 index		% newdict key2 value2 newdict
    3 1 roll		% newdict newdict key2 value2
    put			% newdict
  } forall		% newdict
} bind def
/2dup { 1 index 1 index } bind def

% if the input array has trailing nulls, create a new, shorter array without them
/truncateArray {		% oldArray
  dup length {			% oldArray newLength
    dup 0 eq { exit } if	% all elements were null
    2dup 1 sub get		% oldArray newLength lastElement
    null eq { 1 sub } { exit } ifelse
  } loop			% oldArray desiredLength
  1 index length 1 index gt {	% new length less than old length?
    dup array exch		% oldArray newArray count
    1 sub -1 0 {		% oldArray newArray index
      1 index exch		% oldArray newArray newArray index
      3 index 1 index		% oldArray newArray newArray index oldArray index
      get put			% oldArray newArray
    } for			% oldArray newArray
    exch pop			% newArray
  } {				% oldArray count
    pop				% oldArray
  } ifelse
} bind def

% ----------------------------------------------------------------------

/cs /Helvetica findfont /CharStrings get def
/csm cs mirror def
/ca cs length array def
/z 0 def
% stack: charStringsDict
csm {
  pop ca exch z exch	% stack: ca z charCodeAsInt
% iobuf cvs strdup	% stack: ca z charCodeAsString
  put /z z 1 add def	% z++
} forall

/ca ca truncateArray QSortArray def

% ----------------------------------------------------------------------
/header {
  72 756 moveto (CharStrings in Helvetica font) show
  72 720 moveto
} def
/y { currentpoint exch pop } bind def

header
ca {
  dup iobuf cvs 	% stack: charCodeAsInt charCodeAsString
  dup stringwidth pop	% stack: charCodeAsInt charCodeAsString width
  36 exch sub 0 rmoveto show 
  144 y moveto
  csm 1 index get glyphshow
  216 y moveto		% stack: charCodeAsInt
  csm exch get		% stack: glyphNameAsLiteral
  iobuf cvs show
  72 y FZ sub moveto
  y 72 lt { showpage header } if
} forall
showpage