Implementation of 687496 transparency and CMYK support
"Dan Coby" <[email protected]> Sat, 31 Jul 2004 00:09:09 -0700
| Newsgroups | gmane.comp.printing.ghostscript.patches |
|---|---|
| Message-ID | <[email protected]> |
A note to Raph: I had to remove the color management from the test files that you sent. It was causing problems. However I think that it is really a separate problem related to our handling of color management. Log message: Implementation of 687496 transparency and CMYK support. DETAILS: This change extends our current implementation of the PDF 1.4 transparency to include blending in a DeviceCMYK color space. There is also a partial implementation of a DeviceGray blending space. However I do not have a method of generating test data for a DeviceGray blending space. Currently the choice of a blending color space is based upon the process color model of the output device. Dan _______________________________________________ gs-code-review mailing list [email protected] http://www.ghostscript.com/mailman/listinfo/gs-code-review
687496.txt
(text/plain, 31.1 KB)
Index: src/gdevp14.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gdevp14.c,v
retrieving revision 1.23
diff -u -r1.23 gdevp14.c
--- src/gdevp14.c 26 May 2004 04:10:58 -0000 1.23
+++ src/gdevp14.c 31 Jul 2004 05:30:18 -0000
@@ -39,6 +39,8 @@
#include "gzstate.h"
#include "gdevp14.h"
#include "gsovrc.h"
+#include "gxcmap.h"
+#include "gscolor1.h"
/* #define DUMP_TO_PNG */
@@ -52,6 +54,12 @@
#define PDF14_MAX_PLANES 16
+typedef enum {
+ DeviceGray = 0,
+ DeviceRGB = 1,
+ DeviceCMYK = 2
+} pdf14_default_colorspace_t;
+
typedef struct pdf14_buf_s pdf14_buf;
typedef struct pdf14_ctx_s pdf14_ctx;
@@ -89,6 +97,7 @@
pdf14_buf *maskbuf;
gs_memory_t *memory;
gs_int_rect rect;
+ bool additive;
int n_chan;
};
@@ -129,6 +138,8 @@
private int pdf14_open(gx_device * pdev);
private dev_proc_close_device(pdf14_close);
private int pdf14_output_page(gx_device * pdev, int num_copies, int flush);
+private dev_proc_encode_color(pdf14_encode_color);
+private dev_proc_decode_color(pdf14_decode_color);
private dev_proc_fill_rectangle(pdf14_fill_rectangle);
private dev_proc_fill_path(pdf14_fill_path);
private dev_proc_stroke_path(pdf14_stroke_path);
@@ -145,61 +156,74 @@
/* 24-bit color. */
-private const gx_device_procs pdf14_procs =
-{
- pdf14_open, /* open */
- NULL, /* get_initial_matrix */
- NULL, /* sync_output */
- pdf14_output_page, /* output_page */
- pdf14_close, /* close */
- gx_default_rgb_map_rgb_color,
- gx_default_rgb_map_color_rgb,
- pdf14_fill_rectangle, /* fill_rectangle */
- NULL, /* tile_rectangle */
- NULL, /* copy_mono */
- NULL, /* copy_color */
- NULL, /* draw_line */
- NULL, /* get_bits */
- NULL, /* get_params */
- NULL, /* put_params */
- NULL, /* map_cmyk_color */
- NULL, /* get_xfont_procs */
- NULL, /* get_xfont_device */
- NULL, /* map_rgb_alpha_color */
-#if 0
- gx_page_device_get_page_device, /* get_page_device */
-#else
- NULL, /* get_page_device */
-#endif
- NULL, /* get_alpha_bits */
- NULL, /* copy_alpha */
- NULL, /* get_band */
- NULL, /* copy_rop */
- pdf14_fill_path, /* fill_path */
- pdf14_stroke_path, /* stroke_path */
- NULL, /* fill_mask */
- NULL, /* fill_trapezoid */
- NULL, /* fill_parallelogram */
- NULL, /* fill_triangle */
- NULL, /* draw_thin_line */
- NULL, /* begin_image */
- NULL, /* image_data */
- NULL, /* end_image */
- NULL, /* strip_tile_rectangle */
- NULL, /* strip_copy_rop, */
- NULL, /* get_clipping_box */
- pdf14_begin_typed_image, /* begin_typed_image */
- NULL, /* get_bits_rectangle */
- NULL, /* map_color_rgb_alpha */
- pdf14_create_compositor, /* create_compositor */
- NULL, /* get_hardware_params */
- pdf14_text_begin, /* text_begin */
- NULL, /* finish_copydevice */
- pdf14_begin_transparency_group,
- pdf14_end_transparency_group,
- pdf14_begin_transparency_mask,
- pdf14_end_transparency_mask
-};
+#define pdf14_procs(get_color_mapping_procs, get_color_comp_index) \
+{\
+ pdf14_open, /* open */\
+ NULL, /* get_initial_matrix */\
+ NULL, /* sync_output */\
+ pdf14_output_page, /* output_page */\
+ pdf14_close, /* close */\
+ pdf14_encode_color, /* rgb_map_rgb_color */\
+ pdf14_decode_color, /* gx_default_rgb_map_color_rgb */\
+ pdf14_fill_rectangle, /* fill_rectangle */\
+ NULL, /* tile_rectangle */\
+ NULL, /* copy_mono */\
+ NULL, /* copy_color */\
+ NULL, /* draw_line */\
+ NULL, /* get_bits */\
+ NULL, /* get_params */\
+ NULL, /* put_params */\
+ NULL, /* map_cmyk_color */\
+ NULL, /* get_xfont_procs */\
+ NULL, /* get_xfont_device */\
+ NULL, /* map_rgb_alpha_color */\
+ NULL, /* get_page_device */\
+ NULL, /* get_alpha_bits */\
+ NULL, /* copy_alpha */\
+ NULL, /* get_band */\
+ NULL, /* copy_rop */\
+ pdf14_fill_path, /* fill_path */\
+ pdf14_stroke_path, /* stroke_path */\
+ NULL, /* fill_mask */\
+ NULL, /* fill_trapezoid */\
+ NULL, /* fill_parallelogram */\
+ NULL, /* fill_triangle */\
+ NULL, /* draw_thin_line */\
+ NULL, /* begin_image */\
+ NULL, /* image_data */\
+ NULL, /* end_image */\
+ NULL, /* strip_tile_rectangle */\
+ NULL, /* strip_copy_rop, */\
+ NULL, /* get_clipping_box */\
+ pdf14_begin_typed_image, /* begin_typed_image */\
+ NULL, /* get_bits_rectangle */\
+ NULL, /* map_color_rgb_alpha */\
+ pdf14_create_compositor, /* create_compositor */\
+ NULL, /* get_hardware_params */\
+ pdf14_text_begin, /* text_begin */\
+ NULL, /* finish_copydevice */\
+ pdf14_begin_transparency_group,\
+ pdf14_end_transparency_group,\
+ pdf14_begin_transparency_mask,\
+ pdf14_end_transparency_mask,\
+ NULL, /* discard_transparency_layer */\
+ get_color_mapping_procs, /* get_color_mapping_procs */\
+ get_color_comp_index, /* get_color_comp_index */\
+ pdf14_encode_color, /* encode_color */\
+ pdf14_decode_color /* decode_color */\
+}
+
+private const gx_device_procs pdf14_Gray_procs =
+ pdf14_procs(gx_default_DevGray_get_color_mapping_procs,
+ gx_default_DevGray_get_color_comp_index);
+
+private const gx_device_procs pdf14_RGB_procs =
+ pdf14_procs(gx_default_DevRGB_get_color_mapping_procs,
+ gx_default_DevRGB_get_color_comp_index);
+
+private const gx_device_procs pdf14_CMYK_procs =
+ pdf14_procs(gx_default_DevCMYK_get_color_mapping_procs,
+ gx_default_DevCMYK_get_color_comp_index);
typedef struct pdf14_device_s {
gx_device_common;
@@ -215,10 +239,24 @@
pdf14_device_enum_ptrs, pdf14_device_reloc_ptrs,
gx_device_finalize);
-const pdf14_device gs_pdf14_device = {
- std_device_color_stype_body(pdf14_device, &pdf14_procs, "pdf14",
+const pdf14_device gs_pdf14_Gray_device = {
+ std_device_color_stype_body(pdf14_device, &pdf14_Gray_procs, "pdf14gray",
+ &st_pdf14_device,
+ XSIZE, YSIZE, X_DPI, Y_DPI, 8, 255, 255),
+ { 0 }
+};
+
+const pdf14_device gs_pdf14_RGB_device = {
+ std_device_color_stype_body(pdf14_device, &pdf14_RGB_procs, "pdf14RGB",
&st_pdf14_device,
- XSIZE, YSIZE, X_DPI, Y_DPI, 24, 255, 0),
+ XSIZE, YSIZE, X_DPI, Y_DPI, 24, 255, 255),
+ { 0 }
+};
+
+const pdf14_device gs_pdf14_CMYK_device = {
+ std_device_std_color_full_body_type(pdf14_device, &pdf14_CMYK_procs,
+ "PDF14cmyk", &st_pdf14_device, XSIZE, YSIZE, X_DPI, Y_DPI, 32,
+ 0, 0, 0, 0, 0, 0),
{ 0 }
};
@@ -240,57 +278,74 @@
private dev_proc_fill_rectangle(pdf14_mark_fill_rectangle);
private dev_proc_fill_rectangle(pdf14_mark_fill_rectangle_ko_simple);
-private const gx_device_procs pdf14_mark_procs =
-{
- NULL, /* open */
- NULL, /* get_initial_matrix */
- NULL, /* sync_output */
- NULL, /* output_page */
- NULL, /* close */
- gx_default_rgb_map_rgb_color,
- gx_default_rgb_map_color_rgb,
- NULL, /* fill_rectangle */
- NULL, /* tile_rectangle */
- NULL, /* copy_mono */
- NULL, /* copy_color */
- NULL, /* draw_line */
- NULL, /* get_bits */
- NULL, /* get_params */
- NULL, /* put_params */
- NULL, /* map_cmyk_color */
- NULL, /* get_xfont_procs */
- NULL, /* get_xfont_device */
- NULL, /* map_rgb_alpha_color */
-#if 0
- gx_page_device_get_page_device, /* get_page_device */
-#else
- NULL, /* get_page_device */
-#endif
- NULL, /* get_alpha_bits */
- NULL, /* copy_alpha */
- NULL, /* get_band */
- NULL, /* copy_rop */
- NULL, /* fill_path */
- NULL, /* stroke_path */
- NULL, /* fill_mask */
- NULL, /* fill_trapezoid */
- NULL, /* fill_parallelogram */
- NULL, /* fill_triangle */
- NULL, /* draw_thin_line */
- NULL, /* begin_image */
- NULL, /* image_data */
- NULL, /* end_image */
- NULL, /* strip_tile_rectangle */
- NULL, /* strip_copy_rop, */
- NULL, /* get_clipping_box */
- NULL, /* begin_typed_image */
- NULL, /* get_bits_rectangle */
- NULL, /* map_color_rgb_alpha */
- NULL, /* create_compositor */
- NULL, /* get_hardware_params */
- NULL, /* text_begin */
- NULL /* finish_copydevice */
-};
+#define pdf14_mark_procs(get_color_mapping_procs, get_color_comp_index) \
+{\
+ NULL, /* open */\
+ NULL, /* get_initial_matrix */\
+ NULL, /* sync_output */\
+ NULL, /* output_page */\
+ NULL, /* close */\
+ pdf14_encode_color,\
+ pdf14_decode_color,\
+ NULL, /* fill_rectangle */\
+ NULL, /* tile_rectangle */\
+ NULL, /* copy_mono */\
+ NULL, /* copy_color */\
+ NULL, /* draw_line */\
+ NULL, /* get_bits */\
+ NULL, /* get_params */\
+ NULL, /* put_params */\
+ NULL, /* map_cmyk_color */\
+ NULL, /* get_xfont_procs */\
+ NULL, /* get_xfont_device */\
+ NULL, /* map_rgb_alpha_color */\
+ NULL, /* get_page_device */\
+ NULL, /* get_alpha_bits */\
+ NULL, /* copy_alpha */\
+ NULL, /* get_band */\
+ NULL, /* copy_rop */\
+ NULL, /* fill_path */\
+ NULL, /* stroke_path */\
+ NULL, /* fill_mask */\
+ NULL, /* fill_trapezoid */\
+ NULL, /* fill_parallelogram */\
+ NULL, /* fill_triangle */\
+ NULL, /* draw_thin_line */\
+ NULL, /* begin_image */\
+ NULL, /* image_data */\
+ NULL, /* end_image */\
+ NULL, /* strip_tile_rectangle */\
+ NULL, /* strip_copy_rop, */\
+ NULL, /* get_clipping_box */\
+ NULL, /* begin_typed_image */\
+ NULL, /* get_bits_rectangle */\
+ NULL, /* map_color_rgb_alpha */\
+ NULL, /* create_compositor */\
+ NULL, /* get_hardware_params */\
+ NULL, /* text_begin */\
+ NULL, /* finish_copydevice */\
+ NULL, /* begin_transparency_group */\
+ NULL, /* end_transparency_group */\
+ NULL, /* begin_transparency_mask */\
+ NULL, /* end_transparency_mask */\
+ NULL, /* discard_transparency_layer */\
+ get_color_mapping_procs, /* get_color_mapping_procs */\
+ get_color_comp_index, /* get_color_comp_index */\
+ pdf14_encode_color, /* encode_color */\
+ pdf14_decode_color /* decode_color */\
+}
+
+private const gx_device_procs pdf14_mark_Gray_procs =
+ pdf14_mark_procs(gx_default_DevGray_get_color_mapping_procs,
+ gx_default_DevGray_get_color_comp_index);
+
+private const gx_device_procs pdf14_mark_RGB_procs =
+ pdf14_mark_procs(gx_default_DevRGB_get_color_mapping_procs,
+ gx_default_DevRGB_get_color_comp_index);
+
+private const gx_device_procs pdf14_mark_CMYK_procs =
+ pdf14_mark_procs(gx_default_DevCMYK_get_color_mapping_procs,
+ gx_default_DevCMYK_get_color_comp_index);
typedef struct pdf14_mark_device_s {
gx_device_common;
@@ -305,11 +360,24 @@
gs_private_st_simple_final(st_pdf14_mark_device, pdf14_mark_device,
"pdf14_mark_device", gx_device_finalize);
-const pdf14_mark_device gs_pdf14_mark_device = {
- std_device_color_stype_body(pdf14_mark_device, &pdf14_mark_procs,
- "pdf14_mark",
- &st_pdf14_mark_device,
- XSIZE, YSIZE, X_DPI, Y_DPI, 24, 255, 0),
+const pdf14_mark_device gs_pdf14_mark_Gray_device = {
+ std_device_color_stype_body(pdf14_mark_device, &pdf14_mark_Gray_procs,
+ "pd14_mark_gray", &st_pdf14_mark_device,
+ XSIZE, YSIZE, X_DPI, Y_DPI, 8, 255, 255),
+ { 0 }
+};
+
+const pdf14_mark_device gs_pdf14_mark_RGB_device = {
+ std_device_color_stype_body(pdf14_mark_device, &pdf14_mark_RGB_procs,
+ "pd14_mark_RGB", &st_pdf14_mark_device,
+ XSIZE, YSIZE, X_DPI, Y_DPI, 24, 255, 255),
+ { 0 }
+};
+
+const pdf14_mark_device gs_pdf14_mark_CMYK_device = {
+ std_device_std_color_full_body_type(pdf14_mark_device, &pdf14_mark_CMYK_procs,
+ "PDF14_mark_cmyk", &st_pdf14_mark_device, XSIZE, YSIZE, X_DPI, Y_DPI, 32,
+ 0, 0, 0, 0, 0, 0),
{ 0 }
};
@@ -381,7 +449,7 @@
}
private pdf14_ctx *
-pdf14_ctx_new(gs_int_rect *rect, int n_chan, gs_memory_t *memory)
+pdf14_ctx_new(gs_int_rect *rect, int n_chan, bool additive, gs_memory_t *memory)
{
pdf14_ctx *result;
pdf14_buf *buf;
@@ -405,6 +473,7 @@
result->n_chan = n_chan;
result->memory = memory;
result->rect = *rect;
+ result->additive = additive;
return result;
}
@@ -515,6 +584,7 @@
pdf14_buf *nos = tos->saved;
pdf14_buf *maskbuf = ctx->maskbuf;
int n_chan = ctx->n_chan;
+ int num_comp = n_chan - 1;
byte alpha = tos->alpha;
byte shape = tos->shape;
byte blend_mode = tos->blend_mode;
@@ -544,6 +614,7 @@
int nos_shape_offset = n_chan * nos_planestride;
bool nos_has_shape = nos->has_shape;
byte *mask_tr_fn = NULL; /* Quiet compiler. */
+ bool additive = ctx->additive;
if (nos == NULL)
return_error(gs_error_rangecheck);
@@ -566,13 +637,25 @@
for (y = y0; y < y1; ++y) {
for (x = 0; x < width; ++x) {
byte pix_alpha = alpha;
- for (i = 0; i < n_chan; ++i) {
- tos_pixel[i] = tos_ptr[x + i * tos_planestride];
- nos_pixel[i] = nos_ptr[x + i * nos_planestride];
+
+ /* Complement the components for subtractive color spaces */
+ if (additive) {
+ for (i = 0; i < n_chan; ++i) {
+ tos_pixel[i] = tos_ptr[x + i * tos_planestride];
+ nos_pixel[i] = nos_ptr[x + i * nos_planestride];
+ }
+ }
+ else {
+ for (i = 0; i < num_comp; ++i) {
+ tos_pixel[i] = 255 - tos_ptr[x + i * tos_planestride];
+ nos_pixel[i] = 255 - nos_ptr[x + i * nos_planestride];
+ }
+ tos_pixel[num_comp] = tos_ptr[x + num_comp * tos_planestride];
+ nos_pixel[num_comp] = nos_ptr[x + num_comp * nos_planestride];
}
if (mask_ptr != NULL) {
- int mask_alpha = mask_ptr[x + 3 * mask_planestride];
+ int mask_alpha = mask_ptr[x + num_comp * mask_planestride];
int tmp;
byte mask;
@@ -584,7 +667,7 @@
int t2 = (mask_ptr[x] - mask_bg_alpha) * mask_alpha + 0x80;
mask = mask_bg_alpha + ((t2 + (t2 >> 8)) >> 8);
}
- mask = mask_tr_fn[mask];
+ mask = mask_tr_fn[mask];
tmp = pix_alpha * mask + 0x80;
pix_alpha = (tmp + (tmp >> 8)) >> 8;
}
@@ -619,8 +702,16 @@
shape);
}
- for (i = 0; i < n_chan; ++i) {
- nos_ptr[x + i * nos_planestride] = nos_pixel[i];
+ /* Complement the results for subtractive color spaces */
+ if (additive) {
+ for (i = 0; i < n_chan; ++i) {
+ nos_ptr[x + i * nos_planestride] = nos_pixel[i];
+ }
+ }
+ else {
+ for (i = 0; i < num_comp; ++i)
+ nos_ptr[x + i * nos_planestride] = 255 - nos_pixel[i];
+ nos_ptr[x + num_comp * nos_planestride] = nos_pixel[num_comp];
}
if (nos_alpha_g_ptr != NULL)
++nos_alpha_g_ptr;
@@ -690,10 +781,44 @@
rect.p.y = 0;
rect.q.x = dev->width;
rect.q.y = dev->height;
- pdev->ctx = pdf14_ctx_new(&rect, 4, dev->memory);
+ pdev->ctx = pdf14_ctx_new(&rect, dev->color_info.num_components + 1,
+ pdev->color_info.polarity != GX_CINFO_POLARITY_SUBTRACTIVE, dev->memory);
if (pdev->ctx == NULL)
return_error(gs_error_VMerror);
+ return 0;
+}
+/*
+ * Encode a list of colorant values into a gx_color_index_value.
+ */
+private gx_color_index
+pdf14_encode_color(gx_device *dev, const gx_color_value colors[])
+{
+ int drop = sizeof(gx_color_value) * 8 - 8;
+ gx_color_index color = 0;
+ int i;
+ int ncomp = dev->color_info.num_components;
+
+ for (i = 0; i < ncomp; i++) {
+ color <<= 8;
+ color |= (colors[i] >> drop);
+ }
+ return (color == gx_no_color_index ? color ^ 1 : color);
+}
+
+/*
+ * Decode a gx_color_index value back to a list of colorant values.
+ */
+private int
+pdf14_decode_color(gx_device * dev, gx_color_index color, gx_color_value * out)
+{
+ int i;
+ int ncomp = dev->color_info.num_components;
+
+ for (i = 0; i < ncomp; i++) {
+ out[ncomp - i - 1] = (gx_color_value) ((color & 0xff) * 0x101);
+ color >>= 8;
+ }
return 0;
}
@@ -818,11 +943,12 @@
gs_imager_state *pis = (gs_imager_state *)pgs;
int y;
pdf14_buf *buf = pdev->ctx->stack;
-
int planestride = buf->planestride;
+ int num_comp = buf->n_chan - 1;
byte *buf_ptr = buf->data;
byte *linebuf;
gs_color_space cs;
+ const byte bg = pdev->ctx->additive ? 255 : 0;
#ifdef DUMP_TO_PNG
dump_planar_rgba(buf_ptr, width, height,
@@ -836,10 +962,27 @@
gs_setdevice_no_init(pgs, target);
#endif
- /* Set color space to RGB, in preparation for sending an RGB image. */
- gs_setrgbcolor(pgs, 0, 0, 0);
-
- gs_cspace_init_DeviceRGB(&cs);
+ /*
+ * Set color space to either Gray, RGB, or CMYK in preparation for sending
+ * an image.
+ */
+ switch (num_comp) {
+ case 1: /* DeviceGray */
+ gs_setgray(pgs, 0);
+ gs_cspace_init_DeviceGray(&cs);
+ break;
+ case 3: /* DeviceRGB */
+ gs_setrgbcolor(pgs, 0, 0, 0);
+ gs_cspace_init_DeviceRGB(&cs);
+ break;
+ case 4: /* DeviceCMYK */
+ gs_setcmykcolor(pgs, 0, 0, 0, 0);
+ gs_cspace_init_DeviceCMYK(&cs);
+ break;
+ default: /* Should never occur */
+ return_error(gs_error_rangecheck);
+ break;
+ }
gx_set_dev_color(pgs);
gs_image_t_init_adjust(&image, &cs, false);
image.ImageMatrix.xx = (float)width;
@@ -861,54 +1004,42 @@
if (code < 0)
return code;
- linebuf = gs_alloc_bytes(pdev->memory, width * 3, "pdf14_put_image");
+ linebuf = gs_alloc_bytes(pdev->memory, width * num_comp, "pdf14_put_image");
for (y = 0; y < height; y++) {
gx_image_plane_t planes;
int x;
int rows_used;
for (x = 0; x < width; x++) {
- const byte bg_r = 0xff, bg_g = 0xff, bg_b = 0xff;
- byte r, g, b, a;
- int tmp;
+ byte comp, a;
+ int tmp, comp_num;
- /* composite RGBA pixel with over solid background */
- a = buf_ptr[x + planestride * 3];
+ /* composite RGBA (or CMYKA, etc.) pixel with over solid background */
+ a = buf_ptr[x + planestride * num_comp];
if ((a + 1) & 0xfe) {
- r = buf_ptr[x];
- g = buf_ptr[x + planestride];
- b = buf_ptr[x + planestride * 2];
a ^= 0xff;
-
- tmp = ((bg_r - r) * a) + 0x80;
- r += (tmp + (tmp >> 8)) >> 8;
- linebuf[x * 3] = r;
-
- tmp = ((bg_g - g) * a) + 0x80;
- g += (tmp + (tmp >> 8)) >> 8;
- linebuf[x * 3 + 1] = g;
-
- tmp = ((bg_b - b) * a) + 0x80;
- b += (tmp + (tmp >> 8)) >> 8;
- linebuf[x * 3 + 2] = b;
+ for (comp_num = 0; comp_num < num_comp; comp_num++) {
+ comp = buf_ptr[x + planestride * comp_num];
+ tmp = ((bg - comp) * a) + 0x80;
+ comp += (tmp + (tmp >> 8)) >> 8;
+ linebuf[x * num_comp + comp_num] = comp;
+ }
} else if (a == 0) {
- linebuf[x * 3] = bg_r;
- linebuf[x * 3 + 1] = bg_g;
- linebuf[x * 3 + 2] = bg_b;
+ for (comp_num = 0; comp_num < num_comp; comp_num++) {
+ linebuf[x * num_comp + comp_num] = bg;
+ }
} else {
- r = buf_ptr[x];
- g = buf_ptr[x + planestride];
- b = buf_ptr[x + planestride * 2];
- linebuf[x * 3 + 0] = r;
- linebuf[x * 3 + 1] = g;
- linebuf[x * 3 + 2] = b;
+ for (comp_num = 0; comp_num < num_comp; comp_num++) {
+ comp = buf_ptr[x + planestride * comp_num];
+ linebuf[x * num_comp + comp_num] = comp;
+ }
}
}
planes.data = linebuf;
planes.data_x = 0;
- planes.raster = width * 3;
+ planes.raster = width * num_comp;
info->procs->plane_data(info, &planes, 1, &rows_used);
/* todo: check return value */
@@ -999,10 +1130,25 @@
pdf14_device *pdev = (pdf14_device *)dev;
pdf14_buf *buf = pdev->ctx->stack;
pdf14_mark_device *mdev;
- int code = gs_copydevice((gx_device **)&mdev,
- (const gx_device *)&gs_pdf14_mark_device,
- dev->memory);
+ const pdf14_mark_device * dev_proto;
+ int num_comp = buf->n_chan - 1;
+ int code;
+ switch (num_comp) {
+ case 1: /* DeviceGray */
+ dev_proto = &gs_pdf14_mark_Gray_device;
+ break;
+ case 3: /* DeviceRGB */
+ dev_proto = &gs_pdf14_mark_RGB_device;
+ break;
+ case 4: /* DeviceCMYK */
+ dev_proto = &gs_pdf14_mark_CMYK_device;
+ break;
+ default: /* Should not occur */
+ return NULL;
+ }
+ code = gs_copydevice((gx_device **)&mdev,
+ (const gx_device *)dev_proto, dev->memory);
if (code < 0)
return NULL;
@@ -1205,7 +1351,7 @@
bg_alpha = (int)(255 * ptmp->Background[0] + 0.5);
if_debug1('v', "begin transparency mask, bg_alpha = %d\n", bg_alpha);
for (i = 0; i < 256; i++) {
- float in = i * (1.0 / 255.0);
+ float in = (float)(i * (1.0 / 255.0));
float out;
ptmp->TransferFunction(in, &out, ptmp->TransferFunction_data);
@@ -1237,18 +1383,32 @@
byte src[PDF14_MAX_PLANES];
byte dst[PDF14_MAX_PLANES];
gs_blend_mode_t blend_mode = mdev->blend_mode;
+ bool additive = pdev->ctx->additive;
int rowstride = buf->rowstride;
int planestride = buf->planestride;
bool has_alpha_g = buf->has_alpha_g;
bool has_shape = buf->has_shape;
- int shape_off = buf->n_chan * planestride;
+ int num_chan = buf->n_chan;
+ int num_comp = num_chan - 1;
+ int shape_off = num_chan * planestride;
int alpha_g_off = shape_off + (has_shape ? planestride : 0);
byte shape = 0; /* Quiet compiler. */
+ byte src_alpha;
- src[0] = color >> 16;
- src[1] = (color >> 8) & 0xff;
- src[2] = color & 0xff;
- src[3] = (byte)floor (255 * mdev->alpha + 0.5);
+ /* Complement the components for subtractive color spaces */
+ if (additive) {
+ for (i = num_comp - 1; i >= 0; i--) {
+ src[i] = (byte)(color & 0xff);
+ color >>= 8;
+ }
+ }
+ else {
+ for (i = num_comp - 1; i >= 0; i--) {
+ src[i] = (byte)(0xff - (color & 0xff));
+ color >>= 8;
+ }
+ }
+ src_alpha = src[num_comp] = (byte)floor (255 * mdev->alpha + 0.5);
if (has_shape)
shape = (byte)floor (255 * mdev->shape + 0.5);
@@ -1267,13 +1427,29 @@
for (j = 0; j < h; ++j) {
dst_ptr = line;
for (i = 0; i < w; ++i) {
- for (k = 0; k < 4; ++k)
- dst[k] = dst_ptr[k * planestride];
- art_pdf_composite_pixel_alpha_8(dst, src, 3, blend_mode);
- for (k = 0; k < 4; ++k)
- dst_ptr[k * planestride] = dst[k];
+ /* Complement the components for subtractive color spaces */
+ if (additive) {
+ for (k = 0; k < num_chan; ++k)
+ dst[k] = dst_ptr[k * planestride];
+ }
+ else { /* Complement the components for subtractive color spaces */
+ for (k = 0; k < num_comp; ++k)
+ dst[k] = 255 - dst_ptr[k * planestride];
+ dst[num_comp] = dst_ptr[num_comp * planestride];
+ }
+ art_pdf_composite_pixel_alpha_8(dst, src, num_comp, blend_mode);
+ /* Complement the results for subtractive color spaces */
+ if (additive) {
+ for (k = 0; k < num_chan; ++k)
+ dst_ptr[k * planestride] = dst[k];
+ }
+ else {
+ for (k = 0; k < num_comp; ++k)
+ dst_ptr[k * planestride] = 255 - dst[k];
+ dst_ptr[num_comp * planestride] = dst[num_comp];
+ }
if (has_alpha_g) {
- int tmp = (255 - dst_ptr[alpha_g_off]) * (255 - src[3]) + 0x80;
+ int tmp = (255 - dst_ptr[alpha_g_off]) * (255 - src_alpha) + 0x80;
dst_ptr[alpha_g_off] = 255 - ((tmp + (tmp >> 8)) >> 8);
}
if (has_shape) {
@@ -1300,14 +1476,27 @@
byte dst[PDF14_MAX_PLANES];
int rowstride = buf->rowstride;
int planestride = buf->planestride;
- int shape_off = buf->n_chan * planestride;
+ int num_chan = buf->n_chan;
+ int num_comp = num_chan - 1;
+ int shape_off = num_chan * planestride;
bool has_shape = buf->has_shape;
byte opacity;
+ bool additive = pdev->ctx->additive;
- src[0] = color >> 16;
- src[1] = (color >> 8) & 0xff;
- src[2] = color & 0xff;
- src[3] = (byte)floor (255 * mdev->shape + 0.5);
+ /* Complement the components for subtractive color spaces */
+ if (additive) {
+ for (i = num_comp - 1; i >= 0; i--) {
+ src[i] = (byte)(color & 0xff);
+ color >>= 8;
+ }
+ }
+ else {
+ for (i = num_comp - 1; i >= 0; i--) {
+ src[i] = (byte)(0xff - (color & 0xff));
+ color >>= 8;
+ }
+ }
+ src[num_comp] = (byte)floor (255 * mdev->alpha + 0.5);
opacity = (byte)floor (255 * mdev->opacity + 0.5);
if (x < buf->rect.p.x) x = buf->rect.p.x;
@@ -1325,12 +1514,28 @@
for (j = 0; j < h; ++j) {
dst_ptr = line;
for (i = 0; i < w; ++i) {
- for (k = 0; k < 4; ++k)
- dst[k] = dst_ptr[k * planestride];
- art_pdf_composite_knockout_simple_8(dst, has_shape ? dst_ptr + shape_off : NULL,
- src, 3, opacity);
- for (k = 0; k < 4; ++k)
- dst_ptr[k * planestride] = dst[k];
+ /* Complement the components for subtractive color spaces */
+ if (additive) {
+ for (k = 0; k < num_chan; ++k)
+ dst[k] = dst_ptr[k * planestride];
+ }
+ else {
+ for (k = 0; k < num_comp; ++k)
+ dst[k] = 255 - dst_ptr[k * planestride];
+ dst[num_comp] = dst_ptr[num_comp * planestride];
+ }
+ art_pdf_composite_knockout_simple_8(dst,
+ has_shape ? dst_ptr + shape_off : NULL, src, num_comp, opacity);
+ /* Complement the results for subtractive color spaces */
+ if (additive) {
+ for (k = 0; k < num_chan; ++k)
+ dst_ptr[k * planestride] = dst[k];
+ }
+ else {
+ for (k = 0; k < num_comp; ++k)
+ dst_ptr[k * planestride] = 255 - dst[k];
+ dst_ptr[num_comp * planestride] = dst[num_comp];
+ }
++dst_ptr;
}
line += rowstride;
@@ -1585,16 +1790,58 @@
return &pdf14_cmap_many;
}
+/*
+ * The default color space for PDF 1.4 blend modes is based upon the process
+ * color model of the output device.
+ */
+private pdf14_default_colorspace_t
+pdf14_determine_default_blend_cs(gx_device * pdev)
+{
+ if (pdev->color_info.polarity == GX_CINFO_POLARITY_SUBTRACTIVE)
+ /* Use DeviceCMYK for all subrtactive process color models. */
+ return DeviceCMYK;
+ else {
+ /*
+ * Note: We do not allow the SeparationOrder device parameter for
+ * additive devices. Thus we always have 1 colorant for DeviceGray
+ * and 3 colorants for DeviceRGB. We do not currently support
+ * blending in a DeviceGray color space. Thus we oniy use DeviceRGB.
+ */
+ return DeviceRGB;
+ }
+}
+
private int
gs_pdf14_device_filter_push(gs_device_filter_t *self, gs_memory_t *mem,
gs_state *pgs, gx_device **pdev, gx_device *target)
{
+ const pdf14_device * dev_proto;
pdf14_device *p14dev;
int code;
+ pdf14_default_colorspace_t dev_cs =
+ pdf14_determine_default_blend_cs(target);
+ /*
+ * the PDF 1.4 transparency spec says that color space for blending
+ * operations can be based upon either a color space specified in the
+ * group or a default value based upon the output device. We are
+ * currently only using a color space based upon the device.
+ */
+ switch (dev_cs) {
+ case DeviceGray:
+ dev_proto = &gs_pdf14_Gray_device;
+ break;
+ case DeviceRGB:
+ dev_proto = &gs_pdf14_RGB_device;
+ break;
+ case DeviceCMYK:
+ dev_proto = &gs_pdf14_CMYK_device;
+ break;
+ default: /* Should not occur */
+ return_error(gs_error_rangecheck);
+ }
code = gs_copydevice((gx_device **) &p14dev,
- (const gx_device *) &gs_pdf14_device,
- mem);
+ (const gx_device *) dev_proto, mem);
if (code < 0)
return code;
Index: src/gxblend.c
===================================================================
RCS file: /cvs/ghostscript/gs/src/gxblend.c,v
retrieving revision 1.5
diff -u -r1.5 gxblend.c
--- src/gxblend.c 10 Jul 2003 18:42:02 -0000 1.5
+++ src/gxblend.c 31 Jul 2004 05:30:19 -0000
@@ -35,6 +35,10 @@
int delta_y;
int r, g, b;
+ /*
+ * From section 7.4 of the PDF 1.5 specification, for RGB, the luminosity
+ * is: Y = 0.30 R + 0.59 G + 0.11 B)
+ */
delta_y = ((rs - rb) * 77 + (gs - gb) * 151 + (bs - bb) * 28 + 0x80) >> 8;
r = rb + delta_y;
g = gb + delta_y;
@@ -66,6 +70,34 @@
dst[2] = b;
}
+/*
+ * The PDF 1.4 spec. does not give the details of the math involved in the
+ * luminosity blending. All we are given is:
+ * "Creates a color with the luminance of the source color and the hue
+ * and saturation of the backdrop color. This produces an inverse
+ * effect to that of the Color mode."
+ * From section 7.4 of the PDF 1.5 specification, which is duscussing soft
+ * masks, we are given that, for CMYK, the luminosity is:
+ * Y = 0.30 (1 - C)(1 - K) + 0.59 (1 - M)(1 - K) + 0.11 (1 - Y)(1 - K)
+ * However the results of this equation do not match the results seen from
+ * Illustrator CS. Very different results are obtained if process gray
+ * (.5, .5, .5, 0) is blended over pure cyan, versus gray (0, 0, 0, .5) over
+ * the same pure cyan. The first gives a medium cyan while the later gives a
+ * medium gray. This routine seems to match Illustrator's actions. C, M and Y
+ * are treated similar to RGB in the previous routine and black is treated
+ * separately.
+ *
+ * Our component values have already been complemented, i.e. (1 - X).
+ */
+static void
+art_blend_luminosity_cmyk_8(byte *dst, const byte *backdrop,
+ const byte *src)
+{
+ /* Treat CMY the same as RGB. */
+ art_blend_luminosity_rgb_8(dst, backdrop, src);
+ dst[3] = src[3];
+}
+
static void
art_blend_saturation_rgb_8(byte *dst, const byte *backdrop,
const byte *src)
@@ -131,6 +163,16 @@
dst[2] = b;
}
+/* Our component values have already been complemented, i.e. (1 - X). */
+static void
+art_blend_saturation_cmyk_8(byte *dst, const byte *backdrop,
+ const byte *src)
+{
+ /* Treat CMY the same as RGB */
+ art_blend_saturation_rgb_8(dst, backdrop, src);
+ dst[3] = backdrop[3];
+}
+
/* This array consists of floor ((x - x * x / 255.0) * 65536 / 255 +
0.5) for x in [0..255]. */
const unsigned int art_blend_sq_diff_8[256] = {
@@ -328,20 +370,73 @@
}
break;
case BLEND_MODE_Luminosity:
- art_blend_luminosity_rgb_8(dst, backdrop, src);
+ switch (n_chan) {
+ case 1: /* DeviceGray */
+ dlprintf(
+ "art_blend_pixel_8: DeviceGray luminosity blend mode not implemented\n");
+ break;
+ case 3: /* DeviceRGB */
+ art_blend_luminosity_rgb_8(dst, backdrop, src);
+ break;
+ case 4: /* DeviceCMYK */
+ art_blend_luminosity_cmyk_8(dst, backdrop, src);
+ break;
+ default: /* Should not happen */
+ break;
+ }
break;
case BLEND_MODE_Color:
- art_blend_luminosity_rgb_8(dst, src, backdrop);
+ switch (n_chan) {
+ case 1: /* DeviceGray */
+ dlprintf(
+ "art_blend_pixel_8: DeviceGray color blend mode not implemented\n");
+ break;
+ case 3: /* DeviceRGB */
+ art_blend_luminosity_rgb_8(dst, src, backdrop);
+ break;
+ case 4: /* DeviceCMYK */
+ art_blend_luminosity_cmyk_8(dst, src, backdrop);
+ break;
+ default: /* Should not happen */
+ break;
+ }
break;
case BLEND_MODE_Saturation:
- art_blend_saturation_rgb_8(dst, backdrop, src);
+ switch (n_chan) {
+ case 1: /* DeviceGray */
+ dlprintf(
+ "art_blend_pixel_8: DeviceGray saturation blend mode not implemented\n");
+ break;
+ case 3: /* DeviceRGB */
+ art_blend_saturation_rgb_8(dst, backdrop, src);
+ break;
+ case 4: /* DeviceCMYK */
+ art_blend_saturation_cmyk_8(dst, backdrop, src);
+ break;
+ default: /* Should not happen */
+ break;
+ }
break;
case BLEND_MODE_Hue:
{
- byte tmp[3];
+ byte tmp[4];
- art_blend_luminosity_rgb_8(tmp, src, backdrop);
- art_blend_saturation_rgb_8(dst, tmp, backdrop);
+ switch (n_chan) {
+ case 1: /* DeviceGray */
+ dlprintf(
+ "art_blend_pixel_8: DeviceGray hue blend mode not implemented\n");
+ break;
+ case 3: /* DeviceRGB */
+ art_blend_luminosity_rgb_8(tmp, src, backdrop);
+ art_blend_saturation_rgb_8(dst, tmp, backdrop);
+ break;
+ case 4: /* DeviceCMYK */
+ art_blend_luminosity_cmyk_8(tmp, src, backdrop);
+ art_blend_saturation_cmyk_8(dst, tmp, backdrop);
+ break;
+ default: /* Should not happen */
+ break;
+ }
}
break;
default: