[comp.lang.postscript] Postscript Bug

piet@ruuinf (Piet van Oostrum) (03/02/89)

We have a problem with an Apple LaserWriter (plus). Some characters are
printed on the wrong pixel. 

Output is generated from TEX by dvi2ps. This is done by sending bitmaps to
the laserprinter and imaging them in a 1/300 inch coordinate system.

The error appears when printing a dash (-) followed by an arrow (->). In
the bitmaps these align properly, but on paper they are one pixel different
in vertical position. Sometimes the same misalignment appears in vertical
bars.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% This file is not correctly printed on the laserwriter. See lines
%%%% starting with %%%%

/TeXDict 200 dict def
TeXDict begin
/Resolution 300 def
/Inch{Resolution mul}def
/Mtrx 6 array def
/@a4
{a4 initmatrix
72 Resolution div dup neg scale
270 -3215 translate
Mtrx currentmatrix pop
}def
/@letter
{letter initmatrix
72 Resolution div dup neg scale
340 -3005 translate
Mtrx currentmatrix pop
}def
/@note
{note initmatrix
72 Resolution div dup neg scale
340 -3005 translate
Mtrx currentmatrix pop
}def
/@landscape
{letter initmatrix
72 Resolution div dup neg scale
Mtrx currentmatrix 0 0.0 put
Mtrx 1 -1.0 put
Mtrx 2 1.0 put
Mtrx 3 0.0 put
Mtrx  setmatrix
300 340  translate
Mtrx currentmatrix pop
}def
/@legal
{legal initmatrix
72 Resolution div dup neg scale
295 -3880 translate
Mtrx currentmatrix pop
}def
/@manualfeed
{statusdict /manualfeed true put
}def
/@copies
{/#copies exch def
}def
/@restore /restore load def
/restore
{vmstatus pop
dup @VMused lt{pop @VMused}if
exch pop exch @restore /@VMused exch def
}def
/@pri
{
( ) print
(                                       ) cvs print
}def
/@FontMatrix [1 0 0 -1 0 0] def
/@FontBBox [0 0 1 1] def
/@newfont
{/newname exch def
newname 7 dict def
newname load begin
/FontType 3 def
/FontMatrix @FontMatrix def
/FontBBox @FontBBox def
/BitMaps 128 array def
/BuildChar{CharBuilder}def
/Encoding 128 array def
0 1 127{Encoding exch /.undef put}for
end
newname newname load definefont pop
}def
/ch-image{ch-data 0 get}def
/ch-width{ch-data 1 get}def
/ch-height{ch-data 2 get}def
/ch-xoff{ch-data 3 get}def
/ch-yoff{ch-data 4 get}def
/ch-tfmw{ch-data 5 get}def
/CharBuilder
{save 3 1 roll exch /BitMaps get exch get /ch-data exch def
ch-data null ne
{
%%%% The setcachedevice gives a wrong image. The dash will be one pixel lower
%%%% than the arrow
%ch-tfmw 0 ch-xoff neg ch-yoff neg ch-width ch-xoff sub ch-height ch-yoff sub
%setcachedevice

%%%%% But if we use setcharwidth everything prints OK
ch-tfmw 0 setcharwidth


ch-width ch-height true [1 0  0 1  ch-xoff ch-yoff]
{ch-image}imagemask
}if
restore
}def
/@sf
{setfont
}def
/@dc
{/ch-code exch def
dup 0 get
length 2 lt
{pop [ <00> 1 1 0 0 8.00 ]}
if
/ch-data exch def
currentfont /BitMaps get ch-code ch-data put
currentfont /Encoding get ch-code
dup (   ) cvs cvn
put
}def
/@pc
{pop
/ch-data exch def
currentpoint translate
ch-width ch-height true [1 0 0 -1 ch-xoff ch-yoff]
{ch-image}imagemask
}def
/@bop0
{pop
}def
/@bop1
{pop
erasepage initgraphics
Mtrx setmatrix
/SaveImage save def
}def
/@eop
{showpage
SaveImage restore
}def
/@start
{@a4
vmstatus pop /@VMused exch def pop
}def
/@end
end
}def
/p
{moveto
}def
/r
{0 rmoveto
}def
/s
{show
}def
/c
{c-string exch 0 exch put
c-string s
}def
/c-string ( ) def
/ru
{/dy exch neg def
/dx exch def
/x currentpoint /y exch def def
newpath x y moveto
dx 0 rlineto
0 dy rlineto
dx neg 0 rlineto
closepath fill
x y moveto
}def
/@SpecialDefaults
{/hs 8.5 Inch def
/vs 11 Inch def
/ho 0 def
/vo 0 def
/hsc 1 def
/vsc 1 def
/CLIP false def
}def
/@hsize{/hs exch def /CLIP true def}def
/@vsize{/vs exch def /CLIP true def}def
/@hoffset{/ho exch def}def
/@voffset{/vo exch def}def
/@hscale{/hsc exch def}def
/@vscale{/vsc exch def}def
/@setclipper
{hsc vsc scale
CLIP
{newpath 0 0 moveto hs 0 rlineto 0 vs rlineto hs neg 0 rlineto closepath clip}
if
}def
/@beginspecial
{gsave /SpecialSave save def
currentpoint transform initgraphics itransform translate
@SpecialDefaults
/showpage{}def
}def
/@setspecial
{ho vo translate @setclipper}
def
/@endspecial
{SpecialSave restore
grestore
}def
end
statusdict /waittimeout 300 put
TeXDict begin @start
%%Title: test.dvi
%%Creator: dvips 2.40
%%EndProlog
1 @bop0
/cmsy10.300 @newfont
cmsy10.300 @sf
%%%% define dash
[<FFFFFF80FFFFFF80> 25 2 -3 -9 32] 0 @dc
%%%% define arrow
[<000000040000000002000000000200000000010000000000800000000040FFFFFFFFF8FFFFFFFFF800000000400000000080
  0000000100000000020000000002000000000400> 37 14 -2 -3 42] 33 @dc
1 @bop1
cmsy10.300 @sf
%%%% print ---
324 307 p 0 c
%%%% print -->
-7 r 33 c
@eop
@end

%%%% end of postscript

I did some experimentation and found the following things:

I suspect the LaserWriter. I changed the setcachedevice call in the
postscript to setcharwidth and lo and behold: The output was correct.

Our laserwriter has version 42.2.

Anybody got a clue?
-- 
Piet van Oostrum, Dept of Computer Science, University of Utrecht
Padualaan 14, P.O. Box 80.089, 3508 TB Utrecht, The Netherlands
Telephone: +31-30-531806. piet@cs.ruu.nl (mcvax!hp4nl!ruuinf!piet)

butt@umd5.umd.edu (Edgar Butt) (03/02/89)

I have found a bizarre bug in Postscript 47.0 on a Laserwriter II NT.
Is this a known bug?  Is there is a rom update available from Apple?
Does it occur on other printers or versions?

I sent a table genereated by TeX to a Laserwriter II NT (Postscript
version 47.0) and noticed that line segments forming the vertical rules
were slightly out of alignment.  Experimentation determined that the
horizontal position of a line segment (rectangle) was affected by its
vertical dimension.  The same result was obtained on a second 
Laserwriter II NT.

The same postscript file produced perfectly aligned rules on a 
Laserwriter Plus (Postscript 38.0) and on a DEC PrintServer 40
(Postscript 48.1).

Below is a short Postscript program to illustrate the problem.
It generates eight pairs of joined vertical line segments.
The leftmost four pairs are out of alignment by one pixel, the rest
are not.  The bottom eight line segments are all 88 pixels high.
The top line segments vary from 73 to 80 pixels high.  Between 76 and
77 pixels, the horizontal alignment changes.

----- Postscript Program Follows -----
%!
/resolution 300 def % Try 288, 299, 301 for different results.
/Mtrx 6 array def   % Save the CTM
gsave

72 resolution div dup neg scale
0  resolution 11 mul neg translate 

newpath
  892 1249 moveto 2 0 rlineto 0 -72 rlineto -2 0 rlineto closepath fill
  892 1336 moveto 2 0 rlineto 0 -88 rlineto -2 0 rlineto closepath fill
  992 1249 moveto 2 0 rlineto 0 -73 rlineto -2 0 rlineto closepath fill
  992 1336 moveto 2 0 rlineto 0 -88 rlineto -2 0 rlineto closepath fill
 1092 1249 moveto 2 0 rlineto 0 -74 rlineto -2 0 rlineto closepath fill
 1092 1336 moveto 2 0 rlineto 0 -88 rlineto -2 0 rlineto closepath fill
 1192 1249 moveto 2 0 rlineto 0 -75 rlineto -2 0 rlineto closepath fill
 1192 1336 moveto 2 0 rlineto 0 -88 rlineto -2 0 rlineto closepath fill
 1292 1249 moveto 2 0 rlineto 0 -76 rlineto -2 0 rlineto closepath fill
 1292 1336 moveto 2 0 rlineto 0 -88 rlineto -2 0 rlineto closepath fill
 1392 1249 moveto 2 0 rlineto 0 -77 rlineto -2 0 rlineto closepath fill
 1392 1336 moveto 2 0 rlineto 0 -88 rlineto -2 0 rlineto closepath fill
 1492 1249 moveto 2 0 rlineto 0 -78 rlineto -2 0 rlineto closepath fill
 1492 1336 moveto 2 0 rlineto 0 -88 rlineto -2 0 rlineto closepath fill
 1592 1249 moveto 2 0 rlineto 0 -79 rlineto -2 0 rlineto closepath fill
 1592 1336 moveto 2 0 rlineto 0 -88 rlineto -2 0 rlineto closepath fill
 1692 1249 moveto 2 0 rlineto 0 -80 rlineto -2 0 rlineto closepath fill
 1692 1336 moveto 2 0 rlineto 0 -88 rlineto -2 0 rlineto closepath fill

% The damage is done, the rest is for information

Mtrx currentmatrix
grestore
/Times-Roman findfont 12 scalefont setfont
72 288 moveto (Resolution is ) show resolution 10 string cvs show
72 252 moveto (Transform is ) show
   Mtrx 0 get 10 string cvs show (, ) show
   Mtrx 1 get 10 string cvs show (, ) show
   Mtrx 2 get 10 string cvs show (, ) show
   Mtrx 3 get 10 string cvs show (, ) show
   Mtrx 4 get 10 string cvs show (, ) show
   Mtrx 5 get 10 string cvs show
72 216 moveto (Postscript version ) show version show
showpage
----- Postscript Program Precedes -----

Edgar Butt (301) 454-2946 butt@umd2.umd.edu

greid@adobe.com (Glenn Reid) (03/04/89)

In article <4571@umd5.umd.edu> butt@umd5.umd.edu (Edgar Butt) writes:
>I have found a bizarre bug in Postscript 47.0 on a Laserwriter II NT.
>Is this a known bug?  Is there is a rom update available from Apple?
>Does it occur on other printers or versions?
>
...
>Below is a short Postscript program to illustrate the problem.
>It generates eight pairs of joined vertical line segments.
>The leftmost four pairs are out of alignment by one pixel, the rest
>are not.  The bottom eight line segments are all 88 pixels high.
>The top line segments vary from 73 to 80 pixels high.  Between 76 and
>77 pixels, the horizontal alignment changes.

Both this message and one following it (to do with bitmap fonts)
mentioned "bugs" in PostScript printers because output was off by a
pixel somewhere.

Both of these effects are due to numerical methods.  In each, the scale
factor was essentially 1/resolution, which loses much of the accuracy
of the numeric operations.

I haven't been able to determine from either example exactly where the
roundoff is happening, but it's in there somewhere.

Another useful way to avoid round-off problems in position on an
integer grid is to redefine the "moveto" operator (and possibly also
the "lineto" and other path construction operators) like this:

    /moveto { transform round exch round exch itransform moveto } bind def

This will make sure that the position is aligned with a pixel boundary
before the imaging takes place, minimizing one-pixel errors.

Remember that the PostScript language coordinate system is an "ideal",
and is device-independent.  The same program can run on printers of
arbitrary resolution, and if you try too hard to tailor it to a bitmap
grid, you often get undesirable results.

I hope this helps.

Glenn Reid
Adobe Systems
PostScript Developer Tools & Strategies

butt@umd5.umd.edu (Edgar Butt) (03/07/89)

In article <577@adobe.UUCP>, greid@adobe.com (Glenn Reid) writes
in reply to <4571@umd5.umd.edu> butt@umd5.umd.edu (Edgar Butt):

> Both this message and one following it (to do with bitmap fonts)
> mentioned "bugs" in PostScript printers because output was off by a
> pixel somewhere.
> 
> Both of these effects are due to numerical methods.  In each, the scale
> factor was essentially 1/resolution, which loses much of the accuracy
> of the numeric operations.
...
> Remember that the PostScript language coordinate system is an "ideal",
> and is device-independent.  The same program can run on printers of
> arbitrary resolution, and if you try too hard to tailor it to a bitmap
> grid, you often get undesirable results.

The program I posted illustrated that on a particular implementation
of Postscript, namely, version 47.0 on a Laserwriter II NT, varying
the height (y-dimension) of a rectangle caused its horizontal position
(x-position) to change.  Whatever numerical method is used to map the
"ideal" coordinate system onto an actual device, it should be consistent
and rounding off a y-dimension should not affect x-positioning.
The other two incarnations of Postscript on which I ran the program
gave what I consider to be correct results.

I believe the program I posted demonstrated a bug, not a lack of
understanding.

Edgar Butt (301) 454-2946 butt@umd2.umd.edu

piet@ruuinf (Piet van Oostrum) (03/08/89)

In article <577@adobe.UUCP>, greid@adobe (Glenn Reid) writes:
 `
 `Both this message and one following it (to do with bitmap fonts)
 `mentioned "bugs" in PostScript printers because output was off by a
 `pixel somewhere.
 `
 `Both of these effects are due to numerical methods.  In each, the scale
 `factor was essentially 1/resolution, which loses much of the accuracy
 `of the numeric operations.
 `

If the operations are done in floating point (as I assume they are), why
would you lose so much accuracy? Or is another representation used? If so,
what are the rules to use when you don't want to get problems?

 `I haven't been able to determine from either example exactly where the
 `roundoff is happening, but it's in there somewhere.
 `
Would you mind looking into it to show where it is. I don't see it!

 `Another useful way to avoid round-off problems in position on an
 `integer grid is to redefine the "moveto" operator (and possibly also
 `the "lineto" and other path construction operators) like this:
 `
 `    /moveto { transform round exch round exch itransform moveto } bind def
 `
 `This will make sure that the position is aligned with a pixel boundary
 `before the imaging takes place, minimizing one-pixel errors.
 `
I tried this and it did not help.
I would ask you, PLEASE investigate the possibility of a bug being present.
The fact in both examples that one coordinate that has the same value in
two cases gets positioned different would indicate that it is not a pure
rounding problem. Moreover, in my example (Message-ID: <1166@ruuinf.UUCP>)
the result is correct if I don't use the 'setcachedevice' operator,
suggesting something in the cacheing mechanism. Would you mind looking into
this, as I fail to understand how the caching should give rounding
problems.

 `Remember that the PostScript language coordinate system is an "ideal",
 `and is device-independent.  The same program can run on printers of
 `arbitrary resolution, and if you try too hard to tailor it to a bitmap
 `grid, you often get undesirable results.
 `
But if you must be aware of rounding problems, what does
device-independence mean?

 `I hope this helps.
 `
It didn't and I hope Adobe will be a little bit more helpful.

 `Glenn Reid
 `Adobe Systems
 `PostScript Developer Tools & Strategies
-- 
Piet van Oostrum, Dept of Computer Science, University of Utrecht
Padualaan 14, P.O. Box 80.089, 3508 TB Utrecht, The Netherlands
Telephone: +31-30-531806. piet@cs.ruu.nl (mcvax!hp4nl!ruuinf!piet)

greid@adobe.com (Glenn Reid) (03/09/89)

In article <4583@umd5.umd.edu> butt@umd5.umd.edu (Edgar Butt) writes:

>The program I posted illustrated that on a particular implementation
>of Postscript, namely, version 47.0 on a Laserwriter II NT, varying
>the height (y-dimension) of a rectangle caused its horizontal position
>(x-position) to change.  Whatever numerical method is used to map the
>"ideal" coordinate system onto an actual device, it should be consistent
>and rounding off a y-dimension should not affect x-positioning.
>The other two incarnations of Postscript on which I ran the program
>gave what I consider to be correct results.
>
>I believe the program I posted demonstrated a bug, not a lack of
>understanding.
>
>Edgar Butt (301) 454-2946 butt@umd2.umd.edu


Well, maybe the lack of understanding was on my part, in which case I
apologize.  I have forwarded your original message to our QA
department.  I still believe that it is related to numeric round-off,
but perhaps the roundoff is happening in the interpreter rather than
being inherent in the source program.

Thanks for clarifying.

Glenn Reid
Adobe Systems

piet@ruuinf (Piet van Oostrum) (03/10/89)

In article <617@adobe.UUCP>, greid@adobe (Glenn Reid) writes:

	       I still believe that it is related to numeric round-off,
 `but perhaps the roundoff is happening in the interpreter rather than
 `being inherent in the source program.
 `
Maybe this helps:

	The errors disappear if an extra translate of .5 pixel is specified
in the program. It looks like the pixel painting software is not rounding
but truncating pixel coordinates.
-- 
Piet van Oostrum, Dept of Computer Science, University of Utrecht
Padualaan 14, P.O. Box 80.089, 3508 TB Utrecht, The Netherlands
Telephone: +31-30-531806. piet@cs.ruu.nl (mcvax!hp4nl!ruuinf!piet)

ralerche@lindy.Stanford.EDU (Robert A. Lerche) (03/10/89)

Since this is getting a touch hot, I just wanted to enter my opinion that
Adobe Systems and Glenn Reid are to be commended for their responsiveness
here on the net.