Bug 689230

Summary: Resolution setting in the pxlmono/pxlcolor drivers does not work
Product: Ghostscript Reporter: Till Kamppeter <till.kamppeter>
Component: Printer DriverAssignee: Ray Johnston <ray.johnston>
Status: NOTIFIED FIXED    
Severity: normal CC: ralph.giles
Priority: P4    
Version: master   
Hardware: All   
OS: All   
Customer: Word Size: ---
Attachments: Patch to let pxlmono/pxlcolor drivers insert PJL code for the resolution

Description Till Kamppeter 2007-05-11 09:00:01 UTC
This is a long-standiung bug, but probably no one has perceived it because I
have worked around it with Foomatic.

The problem is that if one sets the resolution by means of the following option
in the PPD file

---------------------------------------------------------------------------------
*OpenUI *Resolution/Output Resolution: PickOne
*OrderDependency: 20 AnySetup *Resolution
*DefaultResolution: 600dpi
*Resolution 150dpi/150 DPI: "<</HWResolution[150 150]>>setpagedevice"
*Resolution 300dpi/300 DPI: "<</HWResolution[300 300]>>setpagedevice"
*Resolution 600dpi/600 DPI: "<</HWResolution[600 600]>>setpagedevice"
*Resolution 1200dpi/1200 DPI: "<</HWResolution[1200 1200]>>setpagedevice"
*CloseUI: *Resolution
---------------------------------------------------------------------------------

which means that CUPS, foomatic-rip, or a PPD-aware applicatiuon inserts a
command like "<</HWResolution[1200 1200]>>setpagedevice" into the PostScript
data stream the resolution is not correctly set.

The bitmap size gets set to be double with 1200 dpi and half with 300 dpi, but
the printer does not get set to requested resolution. It always prints with 600
dpi and so with 300 dpi selected one gets a shrinked page in the upper left
corner of the sheet and with 1200 dpi one gets the upper left quarter of the
page magnified to fill the whole sheet.

To get the resolution being set correctly one has to do two things

- Supply the resolution with the "-r..." option on the Ghostscript command line

- Insert a "@PJL SET RESOLUTION=..." line into the PJL header of the output

and the reolution setting must be the same for both.

Foomatic automates this with the "pxlmono" PPDs, but this is a hack. It would be
nice if the driver would do it by itself.

I have tried with a small patch (attached) to let the driver insert the "@PJL
SET RESOLUTION=..." line via the px_write_file_header() function in
src/gdevpxut.c. The problem is that if the above-mentioned PPD option is used,
the dev->HWResolution[] seems not to be set when px_write_file_header() is
called, but only later when the output pages are generated. So the printer gets
a header with 600 dpi being set as resolution and pages for the user-requested
resolution (300 dpi or 1200 dpi).

To reproduce, download the Ghostscript SVN branch of the ESP/GPL Ghostscript
merger via

svn co http://svn.ghostscript.com/ghostscript/branches/gs-esp-gpl-merger

with the pstopxl CUPS filter and one of the PPDs from the cups/ directory. Try
to print with 300, 600, and 1200 dpi. Problem occurs with all Ghostscript versions.



and set up a CUPS print
Comment 1 Till Kamppeter 2007-05-11 09:01:26 UTC
Created attachment 2955 [details]
Patch to let pxlmono/pxlcolor drivers insert PJL code for the resolution
Comment 2 Till Kamppeter 2007-06-28 05:13:43 UTC
Some additional note: The merger with ESP Ghostscript is in the trunk now and
the branch is removed. So take the trunk and the cups/ files from there for
further investigations now.
Comment 3 Henry Stiles 2007-07-11 23:23:58 UTC
Patch looks ok to me.

The pxl drivers are high level vector devices, not raster devices.  I don't
believe it appropriate to mix setpagedevice parameters in the stream for a
single job.  For example, pxl sets the resolution at the beginning of a job and
maintains that setting for all pages.  If changing resolutions is necessary a
new job must be created.  Unfortunately that could result in losing state
(downloaded fonts, color settings).  These devices could be written like the
raster devices, they would require one job (Session in XL terminology) per page
but then you would lose a lot performance-wise.

In short you have to use the -r option.  Or you can experiment using startjob or
exitserver to set options in advance.  Ray can help you with that if you go that
route.

Reassign it back to me if you want me to study it more.
Comment 4 Till Kamppeter 2008-09-02 01:22:28 UTC
So then I think the way to solve it is to apply my patch and to update the
documentation telling that the PostScript command insertion

<</HWResolution[XRES YRES]>>setpagedevice

is not valid for this driver and "-rXRESxYRES" is required to print with
resolutions other than 600 dpi.

To make it even better, the driver should ignore

<</HWResolution[XRES YRES]>>setpagedevice

commands.

If there are other high-level vector drivers with a similar problem, their
documentation should get fixed appropriately.
Comment 5 Till Kamppeter 2008-09-02 02:07:23 UTC
I have applied the patch to the SVN repositories now. So only the documentation
needs to get fixed now.
Comment 6 Ray Johnston 2008-09-02 07:35:38 UTC
One thing I do not understand about this patch, is that HWResolution _was_
being used in the PXL output to set the UnitsPerMeasure values. The output from
ghostpdl tools/pxl/pxldis.py shows:

` HP-PCL XL;1;1
uint16_xy 600 600 UnitsPerMeasure
ubyte 0 Measure // eInch=0
ubyte 3 ErrorReport // eBackChAndErrPage=3
// Op Pos: 1  Op fOff: 140  Op Hex: 41  Level: 0
BeginSession

Specifying resolution in PJL doesn't hurt, but I don't quite follow why
the UnitsPerMeasure attribute for 'BeginSession' wasn't adequate.
Comment 7 Till Kamppeter 2008-09-02 11:40:08 UTC
Ray, tests with actual printers show that the PJL command is required. Without
the command the printer stays on 600 dpi.

I have found a small bug in my patch, which I have fixed in the SVN now:

Modified: trunk/gs/base/gdevpxut.c
===================================================================
--- trunk/gs/base/gdevpxut.c	2008-09-02 09:06:41 UTC (rev 9060)
+++ trunk/gs/base/gdevpxut.c	2008-09-02 18:37:07 UTC (rev 9061)
@@ -81,7 +81,7 @@
     else 
         px_put_bytes(s, (const byte *)resolution_600,
 		     strlen(resolution_600));
-    if ((uint) (dev->HWResolution[0] + 0.5) !=
+    if ((uint) (dev->HWResolution[1] + 0.5) !=
 	(uint) (dev->HWResolution[0] + 0.5)) {
         px_put_bytes(s, (const byte *)"x", strlen("x"));
 	if ((uint) (dev->HWResolution[1] + 0.5) == 150)