Bug 695264 - PWG Raster output CMYK 16 bit per color not correct with attached PDF file
Summary: PWG Raster output CMYK 16 bit per color not correct with attached PDF file
Status: RESOLVED FIXED
Alias: None
Product: Ghostscript
Classification: Unclassified
Component: CUPS driver (show other bugs)
Version: 9.14
Hardware: PC Linux
: P4 normal
Assignee: Till Kamppeter
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-05-27 08:39 UTC by Till Kamppeter
Modified: 2014-06-03 08:25 UTC (History)
6 users (show)

See Also:
Customer:
Word Size: ---


Attachments
launch_leaflet.pdf (2.95 MB, application/pdf)
2014-05-27 08:39 UTC, Till Kamppeter
Details
pwg raster output after forcably #defining CUPS_RASTER_WRITE_PWG to 3 (27.60 MB, image/pwg-raster)
2014-05-27 15:29 UTC, James Cloos
Details
launch2.pdf (291.33 KB, application/pdf)
2014-05-30 08:57 UTC, Robin Watts
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Till Kamppeter 2014-05-27 08:39:13 UTC
Created attachment 10936 [details]
launch_leaflet.pdf

Attached is a PDF file and if I render it to CUPS/PWG Raster with Ghostscript it only works with 8 or less bits per color and with 16 bits per color only in RGB and Gray. With 16 bit CMYK I get wrong colors, but only in the text/vector parts of the file, images are correct.

I run the following GS command line:

/usr/bin/gs -dQUIET -dPARANOIDSAFER -dNOPAUSE -dBATCH -dNOINTERPOLATE -sDEVICE=cups -sstdout=%stderr -sOutputFile=%stdout -sMediaClass=PwgRaster -sOutputType=Automatic -r600x600 -dDEVICEWIDTHPOINTS=612 -dDEVICEHEIGHTPOINTS=792 -dcupsBitsPerColor=16 -dcupsColorOrder=0 -dcupsColorSpace=6 -dcupsBorderlessScalingFactor=0.0000 -dcupsInteger1=1 -dcupsInteger2=1 -scupsPageSizeName=na_letter_8.5x11in -I/usr/share/cups/fonts -c -f -_

The line takes the file on stdin and produces the raster file on stdout.

I display the raster file with rasterview (https://www.msweet.org/projects.php?Z7) and the metadata shown there is correct.

I am on 64-bit Intel Linux. Ghostscript is the current GIT state.

Probably the text/vector part of the file is another color space than the images and the "cups" output device does correctly with the images's color space and fails on the color space for the text/vector parts.
Comment 1 James Cloos 2014-05-27 15:16:14 UTC
While playing with the rastertopdf filter, I tried a couple of modifications to commit 0145175ab9d530a4ed2.

First, one can change the #if 0 to either 

  #if defined(CUPS_RASTER_WRITE_PWG)
of
  #if defined(CUPS_RASTER_HAVE_PWGRASTER)

The first since that is the defined needed, or the latter because raster.h says that is the define to test for for pwgraster support in libcups.

Neither of those got DEVICE=pwgraster to work.  Even though ./configure;make generated a binary linked against my system libcups, it must not have found my system cups/raster.h.

So instead I tried:

#if !defined(CUPS_RASTER_WRITE_PWG)
    #define CUPS_RASTER_WRITE_PWG 3
#endif

and that binary generates correct pwg raster files.  Even 16bit cmyk.

With Till’s command line, or with that changed to DEVICE=pwgraser, and the above #define, I get nice raster files:

launch_leaflet.pwg: Cups Raster version 2, Big Endian, 600x600 dpi, 6992x4961 pixels 16 bits/color 64 bits/pixel ColorOrder=Chunky ColorSpace=CMYK

(The upstream magic(5) file used by file(1) needs editing to get nice output like that.)
Comment 2 James Cloos 2014-05-27 15:29:23 UTC
Created attachment 10937 [details]
pwg raster output after forcably #defining CUPS_RASTER_WRITE_PWG to 3

Output of:

~/Projects/GS/pwg/gs/bin/gs -dNOPAUSE -dBATCH -dNOINTERPOLATE -sDEVICE=pwgraster -sstdout=%stderr -sOutputFile=launch_leaflet-200.pwg -sMediaClass=PwgRaster  -sOutputType=Automatic -r200 -dDEVICEWIDTHPOINTS=612 -dDEVICEHEIGHTPOINTS=792 -dcupsBitsPerColor=16 -dcupsColorOrder=0 -dcupsColorSpace=6 -dcupsBorderlessScalingFactor=0.0000 -dcupsInteger1=1 -dcupsInteger2=1 -scupsPageSizeName=na_letter_8.5x11in launch_leaflet.pdf

Cut down to 200dpi to keep the size reasonable.

File(1) says:
launch_leaflet-200.ras: Cups Raster version 2, Big Endian, 200x200 dpi, 2331x1654 pixels 16 bits/color 64 bits/pixel ColorOrder=Chunky ColorSpace=CMYK
Comment 3 Till Kamppeter 2014-05-28 01:12:06 UTC
James, thank you for the better #if and #define expressions.

Did you check the output files only via the "file" command? Or did you also a visual check with rasterview?

Note that the problem here is not GS erroring out or crashing, but it is simply that the colors of the output file are wrong. This one can only see by displaying the files with rasterview.

For me the colors are still wrong after your changes.
Comment 4 Till Kamppeter 2014-05-28 01:41:39 UTC
Bug 695266 is a similar bug.
Comment 5 James Cloos 2014-05-28 12:48:03 UTC
> Did you check the output files only via the "file" command? 
> Or did you also a visual check with rasterview?

I was going to post this on the OP list today.

The raster files (such as the one I attached) are properly converted to pdf by your rastertopdf filter.

So I used pdf viewers to confirm them.

And I took a look with od -t u4z on a big-endian box (gcc110).
Comment 6 James Cloos 2014-05-28 14:32:46 UTC
I see commit d5065760d06ba7 incorporates both of the changes I tested, but I only tested them as alternatives.

IF CUPS_RASTER_HAVE_PWGRASTER is #defined, then CUPS_RASTER_WRITE_PWG also always should be.  In that case, the block:

#if !defined(CUPS_RASTER_WRITE_PWG)
    #define CUPS_RASTER_WRITE_PWG 3
#endif

is a no-op.

OTOH, when linked to a version of libcups which doesn’t know CUPS_RASTER_WRITE_PWG, passing the value 3 will get the same results as passing CUPS_RASTER_WRITE: compression will not get used, the magic will be cupsraster rather than pwgraster and the output will be native rather than big endian.

It only worked for me because I got a binary linked against my system libcups (1.7.something) but the compilation didn’t get cups/raster.h from /usr/include
for some unsolved reason.

My apologies for any ambiguity on that point in my earlier post.
Comment 7 James Cloos 2014-05-28 20:23:11 UTC
I misstated that a bit.

Because commit 0145175ab9d530a4ed2 requires that CUPS_RASTER_HAVE_PWGRASTER be #defined in order to try to use CUPS_RASTER_WRITE_PWG, in the case where libcups doesn’t know CUPS_RASTER_WRITE_PWG, 0145175ab9d530a4ed2 would never try it.

So defining CUPS_RASTER_WRITE_PWG in that commit is always a no-op.

But gs will only produce actual pwg raster files in when CUPS_RASTER_WRITE_PWG is usable and used, so perhaps the pwgraster device should not be provided unless CUPS_RASTER_HAVE_PWGRASTER is #defined?

Then the bug reports will be “Why don’t I have pwgraster?” rather than “Why doesn’t pwgraster produce files which validate as PWG Raster or work with my IPP-Everywhere printer?” when gs is compiled against older versions of cups.

If you want to avoid requiring recent cups to generate pwgraster, my library at https://gitorious.org/libraster, while not complete, does support writing pwg raster files and could make the basis for a non-cups pwgraster device.
Comment 8 Till Kamppeter 2014-05-29 01:01:34 UTC
James, thank you very much for discussion of the problem that PWG Raster requires very recent CUPS libraries and how to assure that GS builds also with old CUPS libraries. Currently, I have committed a still not perfect solution based on your comment #1. This makes GS always build but the 'pwgraster' output only produces correct PWG Raster if the used CUPS library supports PWG Raster but does not error out or not build the device if the CUPS library is too old. This is what still needs to be done.

James but note that this is not the bug which I reported here, so your issue needs a separate bug report.

My bug report is about 16-bit CMYK coming out wrongly for the attached PDF, but I have the current libcups installed so I get generally correct PWG Raster.

Fixing the problem of detecting the libcups version and building with or without "pwgraster" output needs to be fixed, too, but it does not solve my color output problem which I have reported here.
Comment 9 James Cloos 2014-05-29 12:41:29 UTC
Allergies were *bad* yesterday — obviously worse than I recognized.

Forcing gdevcups to use call libcups with CUPS_RASTER_WRITE_PWG succeeded in generating proper page headers, but is not enough to force the bitmap also to be big-endian.

I saw accurate colours from Till’s commandline and pdf after converting the raster to pdf only because the rastertopdf filter (as I had already posted) uses a cups api which auto-converts the bitmaps into native endian as it reads them, and as the header was big, it though the bitmaps were, too.  [SIGH]

Here is a simple ps which shows the error:

%!
3 4 div 1 3 div 2 3 div 1 24 div setcmykcolor
0 0 612 792 rectfill
showpage

at 8 bit, the cmyk raster should have the colours bf 55 aa 0b, and at 16 bit they should be bfff 5555 aaaa 0aaa.

If you run that ps through the command line above, and view the result with od(1) like this:

  :; od -j1800 -Ax -t x1z green-cs06-d16.pwg | head

you should see ff (representing 256 rows of:) and then a sequence of 7f (128 pixels of:) bf ff (C=0xbfff) 55 55 (M=0x5555) aa aa (Y=0xaaaa) 0a aa (K=0x0aaa)

Instead you get a sequence of 7f ff bf 55 55 aa aa aa 0a.

gdevcups uses the libcups api to write the bitstream, so this ought to work.

But it fails.

Enabling CUPS_DEBUG2, I see:

  COLOR 24570, 10920, 21840, 1365

which are all my CMYK × 32760.  That much is right.

But that is followed by:

  cv[0]=49151 -> ffbf5555aaaaaa0a

49151 is right, but ffbf is not.

It looks like cups_encode_color() needs to check cups->header.MediaClass and when shift==16 force each color component to bigendian.
Comment 10 Till Kamppeter 2014-05-30 01:31:38 UTC
James, I have played around with your test file and got the desired output by commenting out the code between #if !ARCH_IS_BIG_ENDIAN and #endif /* !ARCH_IS_BIG_ENDIAN */ in cups_set_color_info(), but with launch_leaflet.pdf I still get the same wrong colors as before.
Comment 11 Robin Watts 2014-05-30 08:57:30 UTC
Created attachment 10952 [details]
launch2.pdf

Simplified file.

The problem appears to be with overprint enabled. In the attached file, if you remove the /OP true (or the /OPM 1) line from within "1 0 obj...endobj" at the top of the file then the colors come out correctly.
Comment 12 Robin Watts 2014-05-30 09:10:37 UTC
Generally, I think it's considered good form that encode_color and decode_color should be complementary operations :)

devcups uses EncodeLUT to implement encode_color, and DecodeLUT to implement decode_color.

In the case of little endian 16bit, it packs a endian reversal into EncodeLUT. It leaves DecodeLUT undiddled though.

Diddling DecodeLUT in the equivalent manner seems (superficially at least) to solve the problem.

diff --git a/gs/cups/gdevcups.c b/gs/cups/gdevcups.c
index c5f719f..6db45a7 100644
--- a/gs/cups/gdevcups.c
+++ b/gs/cups/gdevcups.c
@@ -4201,7 +4201,16 @@ cups_set_color_info(gx_device *pdev)     /* I - Device info */
 #endif /* CUPS_DEBUG */

   for (i = 0; i < cups->color_info.dither_grays; i ++)
-    cups->DecodeLUT[i] = gx_max_color_value * i / max_lut;
+  {
+      j = gx_max_color_value * i / max_lut;
+
+#if !ARCH_IS_BIG_ENDIAN
+    if (max_lut > 255)
+      j = ((j & 255) << 8) | ((j >> 8) & 255);
+#endif /* !ARCH_IS_BIG_ENDIAN */
+
+    cups->DecodeLUT[i] = j;
+  }

 #ifdef CUPS_DEBUG
   dmprintf2(pdev->memory, "DEBUG: num_components = %d, depth = %d\n",
Comment 13 Till Kamppeter 2014-06-02 08:39:40 UTC
Thanks, Robin, for this patch. This indeed corrects the color output in CMYK 16-bit and now, at least according to rasterview, the output of the three color spaces black, RGB, and CMYK in 16 bit is correct.

Committed to the GIT as rev. e054f1e08f.
Comment 14 Till Kamppeter 2014-06-02 08:42:24 UTC
I have slightly modified the patch, as on encoding you first calculate the color value in the output color space and then swap bytes for big endian and on decoding you have first to swap the bytes and then to calculate the color value for Ghostscript.
Comment 15 Till Kamppeter 2014-06-03 08:25:22 UTC
Thanks, James and Robin, for all your help for fixing this bug. It seems to be all sorted out now, as not only with rasterview gives me correct output but also the new rastertopdf filter in cups-filters.

So I am closing this bug report as fixed.