summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--base/gxdownscale.c38
-rw-r--r--base/gxdownscale.h11
-rw-r--r--devices/devs.mak2
-rw-r--r--devices/gdevchameleon.c304
-rw-r--r--pcl/pcl/pctop.c15
-rw-r--r--pcl/pxl/pxtop.c18
6 files changed, 277 insertions, 111 deletions
diff --git a/base/gxdownscale.c b/base/gxdownscale.c
index f2eb9522e..1f8138cb5 100644
--- a/base/gxdownscale.c
+++ b/base/gxdownscale.c
@@ -3596,9 +3596,8 @@ int gx_downscaler_create_post_render_link(gx_device *dev, gsicc_link_t **link)
return_error(gs_error_undefined);
*link = NULL;
- if (profile_struct->postren_profile == NULL) {
+ if (profile_struct->postren_profile == NULL)
return 0;
- }
rendering_params.black_point_comp = gsBLACKPTCOMP_ON;
rendering_params.graphics_type_tag = GS_UNKNOWN_TAG;
@@ -3620,3 +3619,38 @@ int gx_downscaler_create_post_render_link(gx_device *dev, gsicc_link_t **link)
}
return 0;
}
+
+int gx_downscaler_create_icc_link(gx_device *dev, gsicc_link_t **link, cmm_profile_t *icc_profile)
+{
+ gsicc_rendering_param_t rendering_params;
+ cmm_dev_profile_t *profile_struct;
+ int code = dev_proc(dev, get_profile)(dev, &profile_struct);
+
+ *link = NULL;
+
+ if (code < 0)
+ return code;
+
+ if (icc_profile == NULL)
+ return 0; /* Should be an error, maybe? */
+
+ rendering_params.black_point_comp = gsBLACKPTCOMP_ON;
+ rendering_params.graphics_type_tag = GS_UNKNOWN_TAG;
+ rendering_params.override_icc = false;
+ rendering_params.preserve_black = gsBLACKPRESERVE_OFF;
+ rendering_params.rendering_intent = gsRELATIVECOLORIMETRIC;
+ rendering_params.cmm = gsCMM_DEFAULT;
+ *link = gsicc_alloc_link_dev(dev->memory,
+ profile_struct->device_profile[GS_DEFAULT_DEVICE_PROFILE],
+ icc_profile,
+ &rendering_params);
+ if (*link == NULL)
+ return_error(gs_error_VMerror);
+
+ /* If it is identity, release it now and set link to NULL */
+ if ((*link)->is_identity) {
+ gsicc_free_link_dev(*link);
+ *link = NULL;
+ }
+ return 0;
+}
diff --git a/base/gxdownscale.h b/base/gxdownscale.h
index b8b9fc9a4..7a99caeac 100644
--- a/base/gxdownscale.h
+++ b/base/gxdownscale.h
@@ -249,8 +249,19 @@ int gx_downscaler_write_params(gs_param_list *plist,
int features);
/* A helper function for creating the post render ICC link.
+ * This maps from the device space to the space given by the
+ * post render profile entry in the device icc struct.
* This should be destroyed using gsicc_free_link_dev.*/
int gx_downscaler_create_post_render_link(gx_device *dev,
gsicc_link_t **link);
+/* A helper function for creating an ICC link. This maps
+ * from the device space to the space given by the
+ * supplied ICC profile.
+ * This should be destroyed using gsicc_free_link_dev.*/
+int
+gx_downscaler_create_icc_link(gx_device *dev,
+ gsicc_link_t **link,
+ cmm_profile_t *profile);
+
#endif
diff --git a/devices/devs.mak b/devices/devs.mak
index a7838a7ed..941c76d33 100644
--- a/devices/devs.mak
+++ b/devices/devs.mak
@@ -1166,7 +1166,7 @@ $(DD)chameleon.dev : $(chameleon_) $(GLD)page.dev $(GLD)cielib.dev $(GDEV) \
$(DEVOBJ)gdevchameleon.$(OBJ) : $(DEVSRC)gdevchameleon.c $(PDEVH)\
$(gsparam_h) $(gdevdcrd_h) $(gscrd_h) $(gscrdp_h) $(gxlum_h) $(gxdcconv_h)\
- $(gsutil_h) $(DEVS_MAK) $(MAKEDIRS)
+ $(gsutil_h) $(gsicc_manage_h) $(DEVS_MAK) $(MAKEDIRS)
$(DEVCC) $(DEVO_)gdevchameleon.$(OBJ) $(C_) $(DEVSRC)gdevchameleon.c
### ------------------------- .BMP file formats ------------------------- ###
diff --git a/devices/gdevchameleon.c b/devices/gdevchameleon.c
index 6d7ba87c1..789a5b019 100644
--- a/devices/gdevchameleon.c
+++ b/devices/gdevchameleon.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -25,6 +25,7 @@
#include "gdevdcrd.h"
#include "gxdownscale.h"
#include "gxdevsop.h"
+#include "gsicc_manage.h"
/* Define the device parameters. */
#ifndef X_DPI
@@ -45,6 +46,13 @@ static dev_proc_get_params(chameleon_get_params);
static dev_proc_put_params(chameleon_put_params);
static dev_proc_print_page(chameleon_print_page);
static dev_proc_dev_spec_op(chameleon_spec_op);
+static dev_proc_close_device(chameleon_close);
+
+typedef enum {
+ linktype_none = 0,
+ linktype_postrender,
+ linktype_device
+} linktype_t;
struct gx_device_chameleon_s {
gx_device_common;
@@ -56,10 +64,21 @@ struct gx_device_chameleon_s {
int output_as_pxm;
bool language_uses_rops;
gx_downscaler_params downscale;
+ gsicc_link_t *icclink;
+ linktype_t linktype;
+ cmm_profile_t *default_device_profile;
};
typedef struct gx_device_chameleon_s gx_device_chameleon;
static void
+chameleon_finalize(gx_device *dev)
+{
+ gx_device_chameleon *pcdev = (gx_device_chameleon *)dev;
+
+ gsicc_adjust_profile_rc(pcdev->default_device_profile, -1, "chameleon_finalize");
+}
+
+static void
chameleon_initialize_device_procs(gx_device *dev)
{
gdev_prn_initialize_device_procs_bg(dev);
@@ -72,6 +91,8 @@ chameleon_initialize_device_procs(gx_device *dev)
set_dev_proc(dev, encode_color, chameleon_rgb_encode_color);
set_dev_proc(dev, decode_color, chameleon_rgb_decode_color);
set_dev_proc(dev, dev_spec_op, chameleon_spec_op);
+ set_dev_proc(dev, close_device, chameleon_close);
+ dev->finalize = chameleon_finalize;
}
const gx_device_chameleon gs_chameleon_device =
@@ -208,62 +229,143 @@ chameleon_cmyk_decode_color(gx_device * dev, gx_color_index color, gx_color_valu
#undef cvalue
}
-/* # So long, oh, I hate to see you go */
+static int
+fixup_icc_struct(gx_device_chameleon *pcdev, gsicc_colorbuffer_t cs, char *profile)
+{
+ if (pcdev->icc_struct &&
+ pcdev->icc_struct->device_profile[gsDEFAULTPROFILE] &&
+ pcdev->icc_struct->device_profile[gsDEFAULTPROFILE]->data_cs == cs)
+ return 0; /* Already the right profile type */
+
+ rc_decrement(pcdev->icc_struct, "fixup_icc_struct(chameleon)");
+
+ pcdev->icc_struct = gsicc_new_device_profile_array((gx_device *)pcdev);
+ if (pcdev->icc_struct == NULL)
+ return gs_error_VMerror;
+
+ return gsicc_set_device_profile((gx_device *)pcdev, pcdev->memory,
+ profile, gsDEFAULTPROFILE);
+}
+
+static void reset_icclink(gx_device_chameleon *pcdev)
+{
+ gsicc_free_link_dev(pcdev->icclink);
+ pcdev->icclink = NULL;
+ pcdev->linktype = linktype_none;
+}
+
static void
+stash_default_device_profile(gx_device_chameleon *pcdev)
+{
+ if (pcdev->default_device_profile != NULL)
+ return;
+
+ pcdev->default_device_profile = pcdev->icc_struct->device_profile[gsDEFAULTPROFILE];
+ gsicc_adjust_profile_rc(pcdev->default_device_profile, 1, "stash_default_device_profile");
+}
+
+/* # So long, oh, I hate to see you go */
+static int
reconfigure_baby(gx_device_chameleon *pcdev)
{
int bpc = pcdev->dst_bpc;
int num_comps = pcdev->dst_num_components;
+ int code;
+
+ stash_default_device_profile(pcdev);
if (pcdev->language_uses_rops) {
bpc = 8;
num_comps = 3;
}
- if (pcdev->bpc != bpc ||
- pcdev->num_components != num_comps) {
-
- gs_closedevice((gx_device *)pcdev);
-
- pcdev->bpc = bpc;
- pcdev->num_components = num_comps;
-
- switch (num_comps * bpc) {
- case 1*1: case 1*2: case 1*4: case 1*8:
- case 4*4: case 4*8:
- pcdev->color_info.depth = bpc * num_comps;
- break;
- case 3*1:
- pcdev->color_info.depth = 4;
- break;
- case 3*2:
- pcdev->color_info.depth = 8;
- break;
- case 3*4:
- pcdev->color_info.depth = 16;
- break;
- }
- pcdev->color_info.max_gray = pcdev->color_info.max_color =
- (pcdev->color_info.dither_grays = pcdev->color_info.dither_colors = 1<<bpc) - 1;
-
- set_dev_proc(pcdev, map_cmyk_color, NULL);
- set_dev_proc(pcdev, map_rgb_color, NULL);
- set_dev_proc(pcdev, map_color_rgb, NULL);
- set_dev_proc(pcdev, encode_color,
- num_comps == 1 ? chameleon_mono_encode_color :
- num_comps == 4 ? chameleon_cmyk_encode_color :
- chameleon_rgb_encode_color);
- set_dev_proc(pcdev, decode_color,
- num_comps == 1 ? chameleon_mono_decode_color :
- num_comps == 4 ? chameleon_cmyk_decode_color :
- chameleon_rgb_decode_color);
-
- /* Reset the separable and linear shift, masks, bits. */
- set_linear_color_bits_mask_shift((gx_device *)pcdev);
- pcdev->color_info.separable_and_linear = GX_CINFO_SEP_LIN;
- pcdev->bpc = bpc;
- pcdev->num_components = num_comps;
+ if (pcdev->bpc == bpc && pcdev->num_components == num_comps)
+ return 0; /* Nothing needs to change! */
+
+ gs_closedevice((gx_device *)pcdev);
+
+ pcdev->bpc = bpc;
+ pcdev->num_components = num_comps;
+
+ switch (num_comps * bpc) {
+ case 1*1: case 1*2: case 1*4: case 1*8:
+ case 3*8:
+ case 4*4: case 4*8:
+ pcdev->color_info.depth = bpc * num_comps;
+ break;
+ case 3*1:
+ pcdev->color_info.depth = 4;
+ break;
+ case 3*2:
+ pcdev->color_info.depth = 8;
+ break;
+ case 3*4:
+ pcdev->color_info.depth = 16;
+ break;
}
+ pcdev->color_info.num_components = num_comps;
+ pcdev->color_info.max_components = num_comps;
+ pcdev->color_info.max_gray = pcdev->color_info.max_color =
+ (pcdev->color_info.dither_grays = pcdev->color_info.dither_colors = 1<<bpc) - 1;
+
+ switch (num_comps) {
+ case 1:
+ set_dev_proc(pcdev, encode_color, chameleon_mono_encode_color);
+ set_dev_proc(pcdev, decode_color, chameleon_mono_decode_color);
+ set_dev_proc(pcdev, get_color_mapping_procs,
+ gx_default_DevGray_get_color_mapping_procs);
+ set_dev_proc(pcdev, get_color_comp_index,
+ gx_default_DevGray_get_color_comp_index);
+ pcdev->color_info.polarity = GX_CINFO_POLARITY_ADDITIVE;
+ pcdev->color_info.cm_name = "DeviceGray";
+ pcdev->color_info.gray_index = 0;
+ code = fixup_icc_struct(pcdev, gsGRAY, DEFAULT_GRAY_ICC);
+ if (code < 0)
+ return code;
+ break;
+ case 3:
+ set_dev_proc(pcdev, encode_color, chameleon_rgb_encode_color);
+ set_dev_proc(pcdev, decode_color, chameleon_rgb_decode_color);
+ set_dev_proc(pcdev, get_color_mapping_procs,
+ gx_default_DevRGB_get_color_mapping_procs);
+ set_dev_proc(pcdev, get_color_comp_index,
+ gx_default_DevRGB_get_color_comp_index);
+ pcdev->color_info.polarity = GX_CINFO_POLARITY_ADDITIVE;
+ pcdev->color_info.cm_name = "DeviceRGB";
+ pcdev->color_info.gray_index = GX_CINFO_COMP_NO_INDEX;
+ code = fixup_icc_struct(pcdev, gsRGB, DEFAULT_RGB_ICC);
+ if (code < 0)
+ return code;
+ break;
+ case 4:
+ set_dev_proc(pcdev, encode_color, chameleon_cmyk_encode_color);
+ set_dev_proc(pcdev, decode_color, chameleon_cmyk_decode_color);
+ set_dev_proc(pcdev, get_color_mapping_procs,
+ gx_default_DevCMYK_get_color_mapping_procs);
+ set_dev_proc(pcdev, get_color_comp_index,
+ gx_default_DevCMYK_get_color_comp_index);
+ pcdev->color_info.polarity = GX_CINFO_POLARITY_SUBTRACTIVE;
+ pcdev->color_info.cm_name = "DevicCMYK";
+ pcdev->color_info.gray_index = 3;
+ code = fixup_icc_struct(pcdev, gsCMYK, DEFAULT_CMYK_ICC);
+ if (code < 0)
+ return code;
+ break;
+ }
+ set_dev_proc(pcdev, map_color_rgb, dev_proc(pcdev, decode_color));
+ set_dev_proc(pcdev, map_cmyk_color, dev_proc(pcdev, encode_color));
+ set_dev_proc(pcdev, map_rgb_color, dev_proc(pcdev, encode_color));
+
+ /* Reset the separable and linear shift, masks, bits. */
+ set_linear_color_bits_mask_shift((gx_device *)pcdev);
+ pcdev->color_info.separable_and_linear = GX_CINFO_SEP_LIN;
+ pcdev->bpc = bpc;
+ pcdev->num_components = num_comps;
+
+ /* Invalidate the link. */
+ reset_icclink(pcdev);
+
+ return 0;
}
/* Get parameters. We provide a default CRD. */
@@ -357,9 +459,7 @@ chameleon_put_params(gx_device * pdev, gs_param_list * plist)
pcdev->output_as_pxm = pxm;
pcdev->language_uses_rops = language_uses_rops;
- reconfigure_baby(pcdev);
-
- return 0;
+ return reconfigure_baby(pcdev);
}
static int
@@ -374,35 +474,6 @@ chameleon_spec_op(gx_device *dev_, int op, void *data, int datasize)
}
static int
-craprgbtocmyk(void *arg,
- byte **dst,
- byte **src,
- int w,
- int h,
- int raster)
-{
- byte *d = *dst;
- byte *s = *src;
-
- while (w--) {
- int c = 255-*s++;
- int m = 255-*s++;
- int y = 255-*s++;
- int k = c;
- if (k > m)
- k = m;
- if (k > y)
- k = y;
- *d++ = c - k;
- *d++ = m - k;
- *d++ = y - k;
- *d++ = k;
- }
-
- return 0;
-}
-
-static int
header_4x1(gp_file *file, gx_device_chameleon *pcdev)
{
gp_fprintf(file, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 4\nMAXVAL 255\nTUPLTYPE CMYK\nENDHDR\n",
@@ -448,12 +519,20 @@ header_3x8(gp_file *file, gx_device_chameleon *pcdev)
}
static int
+header_4x8(gp_file *file, gx_device_chameleon *pcdev)
+{
+ gp_fprintf(file, "P7\nWIDTH %d\nHEIGHT %d\nDEPTH 4\nMAXVAL 255\nTUPLTYPE CMYK\nENDHDR\n",
+ pcdev->width, pcdev->height);
+ return 0;
+}
+
+static int
do_fwrite(const byte *data, int n, gp_file *file)
{
return gp_fwrite(data, 1, (n+7)>>3, file);
}
-static int tiff_chunky_post_cm(void *arg, byte **dst, byte **src, int w, int h,
+static int chunky_post_cm(void *arg, byte **dst, byte **src, int w, int h,
int raster)
{
gsicc_bufferdesc_t input_buffer_desc, output_buffer_desc;
@@ -517,8 +596,6 @@ chameleon_print_page(gx_device_printer * pdev, gp_file * prn_stream)
int (*write)(const byte *, int, gp_file *) = do_fwrite;
int (*header)(gp_file *, gx_device_chameleon *) = NULL;
int bitwidth;
- gx_downscale_cm_fn *col_convert = NULL;
- void *col_convert_arg = NULL;
switch (pcdev->dst_num_components * pcdev->dst_bpc) {
case 1*1: case 1*2: case 1*4: case 1*8:
@@ -552,6 +629,8 @@ chameleon_print_page(gx_device_printer * pdev, gp_file * prn_stream)
case 4:
if (pcdev->dst_bpc == 1)
header = header_4x1, write = write_4x1;
+ else if (pcdev->dst_bpc == 8)
+ header = header_4x8;
break;
case 3:
if (pcdev->dst_bpc == 8)
@@ -565,18 +644,48 @@ chameleon_print_page(gx_device_printer * pdev, gp_file * prn_stream)
* components, then use that. */
if (pcdev->icc_struct->postren_profile &&
pcdev->icc_struct->postren_profile->num_comps == pcdev->dst_num_components) {
- col_convert = tiff_chunky_post_cm;
- col_convert_arg = pcdev->icc_struct->postren_profile;
- }
- /* Can we get away with no conversion? */
- else if (pcdev->num_components == pcdev->dst_num_components &&
- pcdev->bpc == pcdev->dst_bpc) {
+ if (pcdev->linktype != linktype_postrender) {
+ reset_icclink(pcdev);
+ code = gx_downscaler_create_post_render_link((gx_device *)pdev,
+ &pcdev->icclink);
+ if (code < 0)
+ return code;
+ pcdev->linktype = linktype_postrender;
+ }
+ } else if (pcdev->num_components == pcdev->dst_num_components &&
+ pcdev->bpc == pcdev->dst_bpc) {
/* Nothing to do */
- }
- /* Otherwise, use some inbuilt crap conversions */
- else if (pcdev->num_components == 3 && pcdev->bpc == 8 && pcdev->dst_num_components == 4) {
- col_convert = craprgbtocmyk;
- col_convert_arg = NULL;
+ reset_icclink(pcdev);
+ } else if (pcdev->bpc == 8 && pcdev->dst_num_components == 4) {
+ if (pcdev->linktype != linktype_device) {
+ reset_icclink(pcdev);
+ code = gx_downscaler_create_icc_link((gx_device *)pdev,
+ &pcdev->icclink,
+ pcdev->default_device_profile);
+ if (code < 0)
+ return code;
+ pcdev->linktype = linktype_device;
+ }
+ } else if (pcdev->bpc == 8 && pcdev->dst_num_components == 3) {
+ if (pcdev->linktype != linktype_device) {
+ reset_icclink(pcdev);
+ code = gx_downscaler_create_icc_link((gx_device *)pdev,
+ &pcdev->icclink,
+ pcdev->default_device_profile);
+ if (code < 0)
+ return code;
+ pcdev->linktype = linktype_device;
+ }
+ } else if (pcdev->bpc == 8 && pcdev->dst_num_components == 1) {
+ if (pcdev->linktype != linktype_device) {
+ reset_icclink(pcdev);
+ code = gx_downscaler_create_icc_link((gx_device *)pdev,
+ &pcdev->icclink,
+ pcdev->default_device_profile);
+ if (code < 0)
+ return code;
+ pcdev->linktype = linktype_device;
+ }
} else {
emprintf(pdev->memory, "Chameleon device doesn't support this color conversion.\n");
return gs_error_rangecheck;
@@ -589,7 +698,8 @@ chameleon_print_page(gx_device_printer * pdev, gp_file * prn_stream)
pcdev->num_components,
&pcdev->downscale,
NULL, 0, /* Adjust width */
- col_convert, col_convert_arg, /* Color Management */
+ pcdev->icclink ? chunky_post_cm : NULL,
+ pcdev->icclink, /* Color Management */
pcdev->dst_num_components,
default_ht);
if (code < 0)
@@ -613,3 +723,13 @@ cleanup:
gs_free_object(pdev->memory, in_alloc, "chameleon_print_page(in)");
return code;
}
+
+static int
+chameleon_close(gx_device *pdev)
+{
+ gx_device_chameleon *pcdev = (gx_device_chameleon *)pdev;
+
+ gsicc_free_link_dev(pcdev->icclink);
+ pcdev->icclink = NULL;
+ return gdev_prn_close(pdev);
+}
diff --git a/pcl/pcl/pctop.c b/pcl/pcl/pctop.c
index ad4ebf4cc..224614d5d 100644
--- a/pcl/pcl/pctop.c
+++ b/pcl/pcl/pctop.c
@@ -346,6 +346,14 @@ pcl_impl_init_job(pl_interp_implementation_t * impl, /* interp instance to
if ((code = gs_setdevice_no_erase(pcli->pcs.pgs, device)) < 0) /* can't erase yet */
goto pisdEnd;
+ /* Warn the device we use ROPs. Do this early, as it may cause the
+ * device to change color model. */
+ code = put_param1_bool(&pcli->pcs, "LanguageUsesROPs", true);
+ if (!device->is_open)
+ code = gs_opendevice(device);
+ if (code < 0)
+ return code;
+
stage = Sinitg;
/* Do inits of gstate that may be reset by setdevice */
/* PCL no longer uses the graphic library transparency mechanism */
@@ -417,13 +425,6 @@ pcl_impl_init_job(pl_interp_implementation_t * impl, /* interp instance to
break;
}
- /* Warn the device we use ROPs */
- if (code == 0) {
- code = put_param1_bool(&pcli->pcs, "LanguageUsesROPs", true);
- if (!device->is_open)
- code = gs_opendevice(device);
- }
-
return code;
}
diff --git a/pcl/pxl/pxtop.c b/pcl/pxl/pxtop.c
index 93435ceef..b9a6291f3 100644
--- a/pcl/pxl/pxtop.c
+++ b/pcl/pxl/pxtop.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001-2021 Artifex Software, Inc.
+/* Copyright (C) 2001-2022 Artifex Software, Inc.
All Rights Reserved.
This software is provided AS-IS with no warranty, either express or
@@ -277,6 +277,14 @@ pxl_impl_init_job(pl_interp_implementation_t * impl,
if ((code = gs_setdevice_no_erase(pxli->pgs, device)) < 0) /* can't erase yet */
goto pisdEnd;
+ /* Warn the device that PXL uses ROPs. */
+ if (code == 0) {
+ code = put_param_bool(pxli, "LanguageUsesROPs", true);
+
+ if (!device->is_open)
+ code = gs_opendevice(device);
+ }
+
/* Init XL graphics */
stage = Sinitg;
if ((code = px_initgraphics(pxli->pxs)) < 0)
@@ -322,14 +330,6 @@ pxl_impl_init_job(pl_interp_implementation_t * impl,
break;
}
- /* Warn the device that PXL uses ROPs. */
- if (code == 0) {
- code = put_param_bool(pxli, "LanguageUsesROPs", true);
-
- if (!device->is_open)
- code = gs_opendevice(device);
- }
-
return code;
}