Partial fix for 687706 Display device 8-bit native incorrectly dithers grays
"Russell Lang" <[email protected]> Wed, 29 Sep 2004 13:39:35 +1000
| Newsgroups | gmane.comp.printing.ghostscript.patches |
|---|---|
| Message-ID | <415ABB17.5795.396AF634@localhost> |
Fix for 687706 Display device 8-bit native incorrectly dithers grays. This is a partial fix and also need's Dan Coby's fixes to the post DeviceN halftoning. The DeviceRGBK color model is added. DETAILS: Prior to GS 8, the display device 8-bit native format would use 32 gray levels to avoid halftoning, and a 4x4x4 color cube which did use halftoning. The halftoning logic was changed with the introduction of DeviceN and in GS 8 both grays and colors were being halftoned. The DeviceRGBK color model is added and used by the display device native 8-bit format. The RGB color space to RGBK color model conversion converts pure RGB grays to the K (black/gray additive) component. This allows the 32 gray levels to be recognised by the halftoning logic as being sufficient to avoid halftoning. Russell Lang [email protected] Ghostgum Software Pty Ltd http://www.ghostgum.com.au/ _______________________________________________ gs-code-review mailing list [email protected] http://www.ghostscript.com/mailman/listinfo/gs-code-review
rgbk4.txt
(application/octet-stream, 13.7 KB)
diff -u l:/cvs/gs/src/gdevdsp.c src/gdevdsp.c
--- l:/cvs/gs/src/gdevdsp.c Sun Sep 26 21:59:35 2004
+++ src/gdevdsp.c Wed Sep 29 03:06:49 2004
@@ -71,8 +71,8 @@
private dev_proc_map_rgb_color(display_map_rgb_color_device4);
private dev_proc_map_color_rgb(display_map_color_rgb_device4);
-private dev_proc_map_rgb_color(display_map_rgb_color_device8);
-private dev_proc_map_color_rgb(display_map_color_rgb_device8);
+private dev_proc_encode_color(display_encode_color_device8);
+private dev_proc_decode_color(display_decode_color_device8);
private dev_proc_map_rgb_color(display_map_rgb_color_device16);
private dev_proc_map_color_rgb(display_map_color_rgb_device16);
private dev_proc_map_rgb_color(display_map_rgb_color_rgb);
@@ -377,26 +377,47 @@
}
/* DISPLAY_COLORS_NATIVE, 8bit/pixel */
-/* Map a r-g-b color to a color code */
+/* Map a r-g-b-k color to a color code */
private gx_color_index
-display_map_rgb_color_device8(gx_device * dev, const gx_color_value cv[])
+display_encode_color_device8(gx_device * dev, const gx_color_value cv[])
{
/* palette of 96 colors */
/* 0->63 = 00RRGGBB, 64->95 = 010YYYYY */
gx_color_value r = cv[0];
gx_color_value g = cv[1];
gx_color_value b = cv[2];
- if ((r == g) && (g == b))
- return ((r >> (gx_color_value_bits - 5)) + 0x40);
- return ((r >> (gx_color_value_bits - 2)) << 4) +
- ((g >> (gx_color_value_bits - 2)) << 2) +
- ((b >> (gx_color_value_bits - 2)));
+ gx_color_value k = cv[3]; /* 0 = black */
+ if ((r == 0) && (g == 0) && (b == 0)) {
+ k = ((k >> (gx_color_value_bits - 6)) + 1) >> 1;
+ if (k > 0x1f)
+ k = 0x1f;
+ return (k + 0x40);
+ }
+ if (k > 0) {
+ /* The RGB->RGBK color mapping shouldn't generate this. */
+ r = ((r+k) > gx_max_color_value) ? gx_max_color_value :
+ (gx_color_value)(r+k);
+ g = ((g+k) > gx_max_color_value) ? gx_max_color_value :
+ (gx_color_value)(g+k);
+ b = ((b+k) > gx_max_color_value) ? gx_max_color_value :
+ (gx_color_value)(b+k);
+ }
+ r = ((r >> (gx_color_value_bits - 3)) + 1) >> 1;
+ if (r > 0x3)
+ r = 0x3;
+ g = ((g >> (gx_color_value_bits - 3)) + 1) >> 1;
+ if (g > 0x3)
+ g = 0x3;
+ b = ((b >> (gx_color_value_bits - 3)) + 1) >> 1;
+ if (b > 0x3)
+ b = 0x3;
+ return (r << 4) + (g << 2) + b;
}
-/* Map a color code to r-g-b. */
+/* Map a color code to r-g-b-k. */
private int
-display_map_color_rgb_device8(gx_device * dev, gx_color_index color,
- gx_color_value prgb[3])
+display_decode_color_device8(gx_device * dev, gx_color_index color,
+ gx_color_value prgb[4])
{
gx_color_value one;
/* palette of 96 colors */
@@ -406,14 +427,15 @@
prgb[0] = (gx_color_value) (((color >> 4) & 3) * one);
prgb[1] = (gx_color_value) (((color >> 2) & 3) * one);
prgb[2] = (gx_color_value) (((color) & 3) * one);
+ prgb[3] = 0;
}
else if (color < 96) {
one = (gx_color_value) (gx_max_color_value / 31);
- prgb[0] = prgb[1] = prgb[2] =
- (gx_color_value) ((color & 0x1f) * one);
+ prgb[0] = prgb[1] = prgb[2] = 0;
+ prgb[3] = (gx_color_value) ((color & 0x1f) * one);
}
else {
- prgb[0] = prgb[1] = prgb[2] = 0;
+ prgb[0] = prgb[1] = prgb[2] = prgb[3] = 0;
}
return 0;
}
@@ -1331,12 +1353,21 @@
return 0;
}
+typedef enum DISPLAY_MODEL_e {
+ DISPLAY_MODEL_GRAY=0,
+ DISPLAY_MODEL_RGB=1,
+ DISPLAY_MODEL_RGBK=2,
+ DISPLAY_MODEL_CMYK=3,
+ DISPLAY_MODEL_SEP=4
+} DISPLAY_MODEL;
+
/*
* This is a utility routine to build the display device's color_info
* structure (except for the anti alias info).
*/
private void
-set_color_info(gx_device_color_info * pdci, int nc, int depth, int maxgray, int maxcolor)
+set_color_info(gx_device_color_info * pdci, DISPLAY_MODEL model,
+ int nc, int depth, int maxgray, int maxcolor)
{
pdci->num_components = pdci->max_components = nc;
pdci->depth = depth;
@@ -1346,23 +1377,29 @@
pdci->dither_grays = maxgray + 1;
pdci->dither_colors = maxcolor + 1;
pdci->separable_and_linear = GX_CINFO_UNKNOWN_SEP_LIN;
- switch (nc) {
- case 1:
+ switch (model) {
+ case DISPLAY_MODEL_GRAY:
pdci->polarity = GX_CINFO_POLARITY_ADDITIVE;
pdci->cm_name = "DeviceGray";
pdci->gray_index = 0;
break;
- case 3:
+ case DISPLAY_MODEL_RGB:
pdci->polarity = GX_CINFO_POLARITY_ADDITIVE;
pdci->cm_name = "DeviceRGB";
pdci->gray_index = GX_CINFO_COMP_NO_INDEX;
break;
- case 4:
+ case DISPLAY_MODEL_RGBK:
+ pdci->polarity = GX_CINFO_POLARITY_ADDITIVE;
+ pdci->cm_name = "DeviceRGBK";
+ pdci->gray_index = 3;
+ break;
+ case DISPLAY_MODEL_CMYK:
pdci->polarity = GX_CINFO_POLARITY_SUBTRACTIVE;
pdci->cm_name = "DeviceCMYK";
pdci->gray_index = 3;
break;
default:
+ case DISPLAY_MODEL_SEP:
/* Anything else is separations */
pdci->polarity = GX_CINFO_POLARITY_SUBTRACTIVE;
pdci->cm_name = "DeviceCMYK";
@@ -1422,6 +1459,20 @@
/*
* This is an utility routine to set up the color procs for the display
+ * device. This routine is used when the display device is RGBK.
+ */
+private void
+set_rgbk_color_procs(gx_device * pdev,
+ dev_t_proc_encode_color((*encode_color), gx_device),
+ dev_t_proc_decode_color((*decode_color), gx_device))
+{
+ set_color_procs(pdev, encode_color, decode_color,
+ gx_default_DevRGBK_get_color_mapping_procs,
+ gx_default_DevRGBK_get_color_comp_index);
+}
+
+/*
+ * This is an utility routine to set up the color procs for the display
* device. This routine is used when the display device is CMYK.
*/
private void
@@ -1483,33 +1534,33 @@
switch (nFormat & DISPLAY_DEPTH_MASK) {
case DISPLAY_DEPTH_1:
/* 1bit/pixel, black is 1, white is 0 */
- set_color_info(&dci, 1, 1, 1, 0);
+ set_color_info(&dci, DISPLAY_MODEL_GRAY, 1, 1, 1, 0);
dci.separable_and_linear = GX_CINFO_SEP_LIN_NONE;
set_gray_color_procs(pdev, gx_b_w_gray_encode,
gx_default_b_w_map_color_rgb);
break;
case DISPLAY_DEPTH_4:
/* 4bit/pixel VGA color */
- set_color_info(&dci, 3, 4, 1, 1);
+ set_color_info(&dci, DISPLAY_MODEL_RGB, 3, 4, 3, 2);
dci.separable_and_linear = GX_CINFO_SEP_LIN_NONE;
set_rgb_color_procs(pdev, display_map_rgb_color_device4,
display_map_color_rgb_device4);
break;
case DISPLAY_DEPTH_8:
/* 8bit/pixel 96 color palette */
- set_color_info(&dci, 3, 8, 31, 3);
+ set_color_info(&dci, DISPLAY_MODEL_RGBK, 4, 8, 31, 3);
dci.separable_and_linear = GX_CINFO_SEP_LIN_NONE;
- set_rgb_color_procs(pdev, display_map_rgb_color_device8,
- display_map_color_rgb_device8);
+ set_rgbk_color_procs(pdev, display_encode_color_device8,
+ display_decode_color_device8);
break;
case DISPLAY_DEPTH_16:
/* Windows 16-bit display */
/* Is maxgray = maxcolor = 63 correct? */
if ((ddev->nFormat & DISPLAY_555_MASK)
== DISPLAY_NATIVE_555)
- set_color_info(&dci, 3, 16, 31, 31);
+ set_color_info(&dci, DISPLAY_MODEL_RGB, 3, 16, 31, 31);
else
- set_color_info(&dci, 3, 16, 63, 63);
+ set_color_info(&dci, DISPLAY_MODEL_RGB, 3, 16, 63, 63);
set_rgb_color_procs(pdev, display_map_rgb_color_device16,
display_map_color_rgb_device16);
break;
@@ -1519,7 +1570,7 @@
dci.gray_index = GX_CINFO_COMP_NO_INDEX;
break;
case DISPLAY_COLORS_GRAY:
- set_color_info(&dci, 1, bpc, maxvalue, 0);
+ set_color_info(&dci, DISPLAY_MODEL_GRAY, 1, bpc, maxvalue, 0);
if (bpc == 1)
set_gray_color_procs(pdev, gx_default_gray_encode,
gx_default_w_b_map_color_rgb);
@@ -1532,7 +1583,7 @@
bpp = bpc * 3;
else
bpp = bpc * 4;
- set_color_info(&dci, 3, bpp, maxvalue, maxvalue);
+ set_color_info(&dci, DISPLAY_MODEL_RGB, 3, bpp, maxvalue, maxvalue);
if (((nFormat & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_8) &&
((nFormat & DISPLAY_ALPHA_MASK) == DISPLAY_ALPHA_NONE)) {
if ((nFormat & DISPLAY_ENDIAN_MASK) == DISPLAY_BIGENDIAN)
@@ -1550,7 +1601,7 @@
break;
case DISPLAY_COLORS_CMYK:
bpp = bpc * 4;
- set_color_info(&dci, 4, bpp, maxvalue, maxvalue);
+ set_color_info(&dci, DISPLAY_MODEL_CMYK, 4, bpp, maxvalue, maxvalue);
if ((nFormat & DISPLAY_ALPHA_MASK) != DISPLAY_ALPHA_NONE)
return_error(gs_error_rangecheck);
if ((nFormat & DISPLAY_ENDIAN_MASK) != DISPLAY_BIGENDIAN)
@@ -1569,7 +1620,8 @@
if ((nFormat & DISPLAY_ENDIAN_MASK) != DISPLAY_BIGENDIAN)
return_error(gs_error_rangecheck);
bpp = sizeof(gx_color_index)*8;
- set_color_info(&dci, bpp/bpc, bpp, maxvalue, maxvalue);
+ set_color_info(&dci, DISPLAY_MODEL_SEP, bpp/bpc, bpp,
+ maxvalue, maxvalue);
if ((nFormat & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_8) {
ddev->devn_params.bitspercomponent = bpc;
set_color_procs(pdev,
@@ -1594,6 +1646,8 @@
ddev->color_info.gray_index = GX_CINFO_COMP_NO_INDEX;
if ((nFormat & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_1)
ddev->color_info.gray_index = 0;
+ else if ((nFormat & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_8)
+ ddev->color_info.gray_index = 3;
break;
case DISPLAY_COLORS_RGB:
ddev->color_info.gray_index = GX_CINFO_COMP_NO_INDEX;
diff -u l:/cvs/gs/src/gxcmap.c src/gxcmap.c
--- l:/cvs/gs/src/gxcmap.c Fri Jul 02 09:38:28 2004
+++ src/gxcmap.c Tue Sep 28 11:15:39 2004
@@ -232,6 +232,43 @@
}
static void
+gray_cs_to_rgbk_cm(gx_device * dev, frac gray, frac out[])
+{
+ out[0] = out[1] = out[2] = frac_0;
+ out[3] = gray;
+}
+
+static void
+rgb_cs_to_rgbk_cm(gx_device * dev, const gs_imager_state *pis,
+ frac r, frac g, frac b, frac out[])
+{
+ if ((r == g) && (g == b)) {
+ out[0] = out[1] = out[2] = frac_0;
+ out[3] = r;
+ }
+ else {
+ out[0] = r;
+ out[1] = g;
+ out[2] = b;
+ out[3] = frac_0;
+ }
+}
+
+static void
+cmyk_cs_to_rgbk_cm(gx_device * dev, frac c, frac m, frac y, frac k, frac out[])
+{
+ frac rgb[3];
+ if ((c == frac_0) && (m == frac_0) && (y == frac_0)) {
+ out[0] = out[1] = out[2] = frac_0;
+ out[3] = frac_1 - k;
+ }
+ else {
+ color_cmyk_to_rgb(c, m, y, k, NULL, rgb);
+ rgb_cs_to_rgbk_cm(dev, NULL, rgb[0], rgb[1], rgb[2], out);
+ }
+}
+
+static void
gray_cs_to_cmyk_cm(gx_device * dev, frac gray, frac out[])
{
out[0] = out[1] = out[2] = frac_0;
@@ -294,6 +331,10 @@
gray_cs_to_cmyk_cm, rgb_cs_to_cmyk_cm, cmyk_cs_to_cmyk_cm
};
+static const gx_cm_color_map_procs DeviceRGBK_procs = {
+ gray_cs_to_rgbk_cm, rgb_cs_to_rgbk_cm, cmyk_cs_to_rgbk_cm
+};
+
/*
* These are the default handlers for returning the list of color space
* to color model conversion routines.
@@ -317,6 +358,12 @@
}
const gx_cm_color_map_procs *
+gx_default_DevRGBK_get_color_mapping_procs(const gx_device * dev)
+{
+ return &DeviceRGBK_procs;
+}
+
+const gx_cm_color_map_procs *
gx_error_get_color_mapping_procs(const gx_device * dev)
{
/*
@@ -372,6 +419,23 @@
return 1;
if (compare_color_names(pname, name_size, "Yellow"))
return 2;
+ if (compare_color_names(pname, name_size, "Black"))
+ return 3;
+ else
+ return -1; /* Indicate that the component name is "unknown" */
+}
+
+/* Default color component to index for a DeviceRGBK color model */
+int
+gx_default_DevRGBK_get_color_comp_index(gx_device * dev, const char * pname,
+ int name_size, int component_type)
+{
+ if (compare_color_names(pname, name_size, "Red"))
+ return 0;
+ if (compare_color_names(pname, name_size, "Green"))
+ return 1;
+ if (compare_color_names(pname, name_size, "Blue"))
+ return 2;
if (compare_color_names(pname, name_size, "Black"))
return 3;
else
diff -u l:/cvs/gs/src/gxcmap.h src/gxcmap.h
--- l:/cvs/gs/src/gxcmap.h Fri Jul 02 09:38:28 2004
+++ src/gxcmap.h Tue Sep 28 11:15:39 2004
@@ -242,6 +242,7 @@
dev_proc_get_color_comp_index(gx_default_DevGray_get_color_comp_index);
dev_proc_get_color_comp_index(gx_default_DevRGB_get_color_comp_index);
dev_proc_get_color_comp_index(gx_default_DevCMYK_get_color_comp_index);
+dev_proc_get_color_comp_index(gx_default_DevRGBK_get_color_comp_index);
/*
* These are the default routines for getting the color space conversion
@@ -251,6 +252,7 @@
dev_proc_get_color_mapping_procs(gx_default_DevGray_get_color_mapping_procs);
dev_proc_get_color_mapping_procs(gx_default_DevRGB_get_color_mapping_procs);
dev_proc_get_color_mapping_procs(gx_default_DevCMYK_get_color_mapping_procs);
+dev_proc_get_color_mapping_procs(gx_default_DevRGBK_get_color_mapping_procs);
/*
* These are the default routines for converting a colorant value list
diff -u l:/cvs/gs/src/zcolor.c src/zcolor.c
--- l:/cvs/gs/src/zcolor.c Sun Sep 26 21:59:37 2004
+++ src/zcolor.c Tue Sep 28 23:24:48 2004
@@ -487,23 +487,24 @@
gx_device *dev = gs_currentdevice(igs);
int ncomp = dev->color_info.num_components;
gx_color_index color;
+ os_ptr op = osp - (ncomp-1);
int i;
if (ref_stack_count(&o_stack) < ncomp)
return_error(e_stackunderflow);
for (i=0; i<ncomp; i++) {
- if (r_has_type(&osp[-i], t_real))
+ if (r_has_type(op+i, t_real))
cv[i] = (gx_color_value)
- (osp[-i].value.realval * gx_max_color_value);
- else if (r_has_type(&osp[-i], t_integer))
+ (op[i].value.realval * gx_max_color_value);
+ else if (r_has_type(op+i, t_integer))
cv[i] = (gx_color_value)
- (osp[-i].value.intval * gx_max_color_value);
+ (op[i].value.intval * gx_max_color_value);
else
return_error(e_typecheck);
}
color = (*dev_proc(dev, encode_color)) (dev, cv);
(*dev_proc(dev, decode_color)) (dev, color, cv);
for (i=0; i<ncomp; i++)
- make_real(&osp[-i], (float)cv[i] / (float)gx_max_color_value);
+ make_real(op+i, (float)cv[i] / (float)gx_max_color_value);
return 0;
}