summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Vrhel <michael.vrhel@artifex.com>2011-12-28 14:37:49 -0800
committerMichael Vrhel <michael.vrhel@artifex.com>2011-12-28 17:32:07 -0800
commit4e681a04de79896406946d5487efe0a37eb6d2b2 (patch)
treeadc30cdb9ee986326f97f14f3e0c46683e709fb8
parentd4625c5b5a262501fefabe68f2bbea000dcecb52 (diff)
downloadghostpdl-4e681a04de79896406946d5487efe0a37eb6d2b2.tar.gz
Proof and DeviceLink ICC profile support
This enables the use of the device link and/or a proofing profile. When present, the transformations are as follows src profile -> PCS -> proof -> PCS -> proof -> PCS -> device profile -> device link where PCS is the profile connection space. The CMM obviously would normally mash these together in a single transform. This is what occurs in lcms. This implies that the output color space for the device link profile must match the color model for the real target device and that the input color space for the device link profile must match the color space specified for the device profile. Still need to do some additional testing and update documentation.
-rw-r--r--gs/base/gsicc.c6
-rw-r--r--gs/base/gsicc_cache.c71
-rw-r--r--gs/base/gsicc_cache.h1
-rw-r--r--gs/base/gsicc_cms.h9
-rw-r--r--gs/base/gsicc_lcms.c65
-rw-r--r--gs/base/gsicc_lcms2.c8
-rw-r--r--gs/base/gsicc_manage.c13
-rw-r--r--gs/base/gxi12bit.c6
-rw-r--r--gs/base/gxicolor.c4
-rw-r--r--gs/base/gximono.c2
-rw-r--r--gs/base/gxiscale.c4
11 files changed, 144 insertions, 45 deletions
diff --git a/gs/base/gsicc.c b/gs/base/gsicc.c
index 39440948f..de231ca3b 100644
--- a/gs/base/gsicc.c
+++ b/gs/base/gsicc.c
@@ -273,7 +273,7 @@ gx_remap_concrete_ICC(const frac * pconc, const gs_color_space * pcs,
cmm_dev_profile_t *dev_profile;
code = dev_proc(dev, get_profile)(dev, &dev_profile);
- num_colorants = dev_profile->device_profile[0]->num_comps;
+ num_colorants = gsicc_get_device_profile_comps(dev_profile);
switch( num_colorants ) {
case 1:
code = gx_remap_concrete_DGray(pconc, pcs, pdc, pis, dev, select);
@@ -315,7 +315,7 @@ gx_remap_ICC(const gs_client_color * pcc, const gs_color_space * pcs,
cmm_dev_profile_t *dev_profile;
code = dev_proc(dev, get_profile)(dev, &dev_profile);
- num_des_comps = dev_profile->device_profile[0]->num_comps;
+ num_des_comps = gsicc_get_device_profile_comps(dev_profile);
rendering_params.black_point_comp = BP_ON;
rendering_params.graphics_type_tag = dev->graphics_type_tag;
/* Need to figure out which one rules here on rendering intent. The
@@ -400,7 +400,7 @@ gx_concretize_ICC(
cmm_dev_profile_t *dev_profile;
code = dev_proc(dev, get_profile)(dev, &dev_profile);
- num_des_comps = dev_profile->device_profile[0]->num_comps;
+ num_des_comps = gsicc_get_device_profile_comps(dev_profile);
/* Define the rendering intents. MJV to fix */
rendering_params.black_point_comp = BP_ON;
rendering_params.graphics_type_tag = dev->graphics_type_tag;
diff --git a/gs/base/gsicc_cache.c b/gs/base/gsicc_cache.c
index 2027c1245..5e49cae44 100644
--- a/gs/base/gsicc_cache.c
+++ b/gs/base/gsicc_cache.c
@@ -579,6 +579,8 @@ gsicc_get_link_profile(const gs_imager_state *pis, gx_device *dev,
gs_memory_t *cache_mem = pis->icc_link_cache->memory;
gcmmhprofile_t *cms_input_profile;
gcmmhprofile_t *cms_output_profile;
+ gcmmhprofile_t *cms_proof_profile = NULL;
+ gcmmhprofile_t *cms_devlink_profile = NULL;
int code;
bool include_softproof = false;
bool include_devicelink = false;
@@ -673,6 +675,40 @@ gsicc_get_link_profile(const gs_imager_state *pis, gx_device *dev,
}
}
}
+ if (include_softproof) {
+ cms_proof_profile = proof_profile->profile_handle;
+ if (cms_proof_profile == NULL) {
+ if (proof_profile->buffer != NULL) {
+ cms_proof_profile =
+ gsicc_get_profile_handle_buffer(proof_profile->buffer,
+ proof_profile->buffer_size);
+ proof_profile->profile_handle = cms_proof_profile;
+ gx_monitor_enter(proof_profile->lock);
+ } else {
+ /* Cant create the link */
+ gsicc_remove_link(link, cache_mem);
+ icc_link_cache->num_links--;
+ return(NULL);
+ }
+ }
+ }
+ if (include_devicelink) {
+ cms_devlink_profile = devlink_profile->profile_handle;
+ if (cms_devlink_profile == NULL) {
+ if (devlink_profile->buffer != NULL) {
+ cms_devlink_profile =
+ gsicc_get_profile_handle_buffer(devlink_profile->buffer,
+ devlink_profile->buffer_size);
+ devlink_profile->profile_handle = cms_devlink_profile;
+ gx_monitor_enter(devlink_profile->lock);
+ } else {
+ /* Cant create the link */
+ gsicc_remove_link(link, cache_mem);
+ icc_link_cache->num_links--;
+ return(NULL);
+ }
+ }
+ }
/* Profile reading of same structure not thread safe in lcms */
gx_monitor_enter(gs_input_profile->lock);
gx_monitor_enter(gs_output_profile->lock);
@@ -698,10 +734,23 @@ gsicc_get_link_profile(const gs_imager_state *pis, gx_device *dev,
cms_output_profile =
icc_manager->graytok_profile->profile_handle;
}
- /* Get the link with the proof and or device link profile worked in if
- they are specified and supported by the CMM */
- link_handle = gscms_get_link(cms_input_profile, cms_output_profile,
- rendering_params);
+ /* Get the link with the proof and or device link profile */
+ if (include_softproof || include_devicelink) {
+ link_handle = gscms_get_link_proof_devlink(cms_input_profile,
+ cms_proof_profile,
+ cms_output_profile,
+ cms_devlink_profile,
+ rendering_params);
+ if (include_softproof) {
+ gx_monitor_leave(proof_profile->lock);
+ }
+ if (include_devicelink) {
+ gx_monitor_leave(devlink_profile->lock);
+ }
+ } else {
+ link_handle = gscms_get_link(cms_input_profile, cms_output_profile,
+ rendering_params);
+ }
gx_monitor_leave(gs_output_profile->lock);
gx_monitor_leave(gs_input_profile->lock);
if (link_handle != NULL) {
@@ -1067,3 +1116,17 @@ gsicc_init_buffer(gsicc_bufferdesc_t *buffer_desc, unsigned char num_chan, unsig
buffer_desc->little_endian = true;
}
+
+/* Return the proper component numbers based upon the profiles of the device.
+ This is in here since it is usually called when creating and using a link
+ from the link cache. */
+int
+gsicc_get_device_profile_comps(cmm_dev_profile_t *dev_profile)
+{
+ if (dev_profile->link_profile == NULL) {
+ return dev_profile->device_profile[0]->num_comps;
+ } else {
+ return dev_profile->link_profile->num_comps_out;
+ }
+}
+
diff --git a/gs/base/gsicc_cache.h b/gs/base/gsicc_cache.h
index c55d30ba0..560ee3b67 100644
--- a/gs/base/gsicc_cache.h
+++ b/gs/base/gsicc_cache.h
@@ -59,5 +59,6 @@ int gsicc_transform_named_color(float tint_value, byte *color_name, uint name_si
cmm_profile_t *gs_output_profile,
gsicc_rendering_param_t *rendering_params,
bool include_softproof);
+int gsicc_get_device_profile_comps(cmm_dev_profile_t *dev_profile);
#endif
diff --git a/gs/base/gsicc_cms.h b/gs/base/gsicc_cms.h
index 86d138a96..c7c32bff6 100644
--- a/gs/base/gsicc_cms.h
+++ b/gs/base/gsicc_cms.h
@@ -51,10 +51,11 @@ void gscms_transform_color(gx_device *dev, gsicc_link_t *icclink, void *inputcol
gcmmhlink_t gscms_get_link(gcmmhprofile_t lcms_srchandle,
gcmmhprofile_t lcms_deshandle,
gsicc_rendering_param_t *rendering_params);
-gcmmhlink_t gscms_get_link_proof(gcmmhprofile_t lcms_srchandle,
- gcmmhprofile_t lcms_deshandle,
- gcmmhprofile_t lcms_proofhandle,
- gsicc_rendering_param_t *rendering_params);
+gcmmhlink_t gscms_get_link_proof_devlink(gcmmhprofile_t lcms_srchandle,
+ gcmmhprofile_t lcms_proofhandle,
+ gcmmhprofile_t lcms_deshandle,
+ gcmmhprofile_t lcms_devlinkhandle,
+ gsicc_rendering_param_t *rendering_params);
void gscms_create(void **contextptr);
void gscms_destroy(void **contextptr);
void gscms_release_link(gsicc_link_t *icclink);
diff --git a/gs/base/gsicc_lcms.c b/gs/base/gsicc_lcms.c
index a595ece62..0732c314c 100644
--- a/gs/base/gsicc_lcms.c
+++ b/gs/base/gsicc_lcms.c
@@ -269,9 +269,6 @@ gscms_get_link(gcmmhprofile_t lcms_srchandle,
int src_nChannels,des_nChannels;
int lcms_src_color_space, lcms_des_color_space;
- /* Check for case of request for a transfrom from a device link profile
- in that case, the destination profile is NULL */
-
/* First handle all the source stuff */
src_color_space = cmsGetColorSpace(lcms_srchandle);
lcms_src_color_space = _cmsLCMScolorSpace(src_color_space);
@@ -302,32 +299,60 @@ gscms_get_link(gcmmhprofile_t lcms_srchandle,
/* cmsFLAGS_HIGHRESPRECALC) cmsFLAGS_NOTPRECALC cmsFLAGS_LOWRESPRECALC*/
}
-/* Get the link from the CMS, but include proofing. */
+/* Get the link from the CMS, but include proofing and/or a device link
+ profile. */
gcmmhlink_t
-gscms_get_link_proof(gcmmhprofile_t lcms_srchandle,
- gcmmhprofile_t lcms_deshandle, gcmmhprofile_t lcms_proofhandle,
- gsicc_rendering_param_t *rendering_params)
+gscms_get_link_proof_devlink(gcmmhprofile_t lcms_srchandle,
+ gcmmhprofile_t lcms_proofhandle,
+ gcmmhprofile_t lcms_deshandle,
+ gcmmhprofile_t lcms_devlinkhandle,
+ gsicc_rendering_param_t *rendering_params)
{
DWORD src_data_type,des_data_type;
icColorSpaceSignature src_color_space,des_color_space;
int src_nChannels,des_nChannels;
+ int lcms_src_color_space, lcms_des_color_space;
+ cmsHPROFILE hProfiles[5];
+ int nProfiles = 0;
- /* Get the data types */
+ /* First handle all the source stuff */
src_color_space = cmsGetColorSpace(lcms_srchandle);
- des_color_space = cmsGetColorSpace(lcms_deshandle);
+ lcms_src_color_space = _cmsLCMScolorSpace(src_color_space);
+ /* littlecms returns -1 for types it does not (but should) understand */
+ if (lcms_src_color_space < 0) lcms_src_color_space = 0;
src_nChannels = _cmsChannelsOf(src_color_space);
+ /* For now, just do single byte data, interleaved. We can change this
+ when we use the transformation. */
+ src_data_type = (COLORSPACE_SH(lcms_src_color_space)|
+ CHANNELS_SH(src_nChannels)|BYTES_SH(2));
+ if (lcms_deshandle != NULL) {
+ des_color_space = cmsGetColorSpace(lcms_deshandle);
+ } else {
+ /* We must have a device link profile. */
+ des_color_space = cmsGetPCS(lcms_deshandle);
+ }
+ lcms_des_color_space = _cmsLCMScolorSpace(des_color_space);
+ if (lcms_des_color_space < 0) lcms_des_color_space = 0;
des_nChannels = _cmsChannelsOf(des_color_space);
- /* For now, just do single byte data, interleaved. We can change this when we
- use the transformation. */
- src_data_type= (CHANNELS_SH(src_nChannels)|BYTES_SH(1));
- des_data_type= (CHANNELS_SH(des_nChannels)|BYTES_SH(1));
- /* Create the link. Note the gamut check alarm */
- return(cmsCreateProofingTransform(lcms_srchandle, src_data_type,
- lcms_deshandle, des_data_type,
- lcms_proofhandle,
- rendering_params->rendering_intent,
- INTENT_ABSOLUTE_COLORIMETRIC,
- cmsFLAGS_GAMUTCHECK | cmsFLAGS_SOFTPROOFING ));
+ des_data_type = (COLORSPACE_SH(lcms_des_color_space)|
+ CHANNELS_SH(des_nChannels)|BYTES_SH(2));
+ /* lcms proofing transform has a clunky API and can't include the device
+ link profile if we have both. So use cmsCreateMultiprofileTransform
+ instead and round trip the proofing profile. */
+ hProfiles[nProfiles++] = lcms_srchandle;
+ if (lcms_proofhandle != NULL) {
+ hProfiles[nProfiles++] = lcms_proofhandle;
+ hProfiles[nProfiles++] = lcms_proofhandle;
+ }
+ hProfiles[nProfiles++] = lcms_deshandle;
+ if (lcms_devlinkhandle != NULL) {
+ hProfiles[nProfiles++] = lcms_devlinkhandle;
+ }
+ return(cmsCreateMultiprofileTransform(hProfiles, nProfiles, src_data_type,
+ des_data_type, rendering_params->rendering_intent,
+ (cmsFLAGS_BLACKPOINTCOMPENSATION |
+ cmsFLAGS_HIGHRESPRECALC |
+ cmsFLAGS_NOTCACHE)));
}
/* Do any initialization if needed to the CMS */
diff --git a/gs/base/gsicc_lcms2.c b/gs/base/gsicc_lcms2.c
index 957a2418a..2a1e524b8 100644
--- a/gs/base/gsicc_lcms2.c
+++ b/gs/base/gsicc_lcms2.c
@@ -357,9 +357,11 @@ gscms_get_link(gcmmhprofile_t lcms_srchandle,
transparency, that would only occur at the top of the stack
TODO: Add error checking */
gcmmhlink_t
-gscms_get_link_proof(gcmmhprofile_t lcms_srchandle,
- gcmmhprofile_t lcms_deshandle, gcmmhprofile_t lcms_proofhandle,
- gsicc_rendering_param_t *rendering_params)
+gscms_get_link_proof_devlink(gcmmhprofile_t lcms_srchandle,
+ gcmmhprofile_t lcms_proofhandle,
+ gcmmhprofile_t lcms_deshandle,
+ gcmmhprofile_t lcms_devlinkhandle,
+ gsicc_rendering_param_t *rendering_params)
{
cmsUInt32Number src_data_type,des_data_type;
cmsColorSpaceSignature src_color_space,des_color_space;
diff --git a/gs/base/gsicc_manage.c b/gs/base/gsicc_manage.c
index bd00eadab..9600a8d38 100644
--- a/gs/base/gsicc_manage.c
+++ b/gs/base/gsicc_manage.c
@@ -250,7 +250,6 @@ gsicc_new_devicen(gsicc_manager_t *icc_manager)
cmm_profile_t*
gsicc_finddevicen(const gs_color_space *pcs, gsicc_manager_t *icc_manager)
{
-
int k,j,i;
gsicc_devicen_entry_t *curr_entry;
int num_comps;
@@ -279,7 +278,6 @@ gsicc_finddevicen(const gs_color_space *pcs, gsicc_manager_t *icc_manager)
/* Get the character string and length for the component name. */
pcs->params.device_n.get_colorname_string(icc_manager->memory,
names[j], &pname, &name_size);
-
/* Compare to the jth entry in the ICC profile */
icc_spot_entry = curr_entry->iccprofile->spotnames->head;
for ( i = 0; i < num_comps; i++) {
@@ -1034,7 +1032,16 @@ gsicc_init_device_profile_struct(gx_device * dev,
profile_struct = dev->icc_struct;
if (profile_struct != NULL) {
/* Get the profile of interest */
- curr_profile = profile_struct->device_profile[profile_type];
+ if (profile_type < gsPROOFPROFILE) {
+ curr_profile = profile_struct->device_profile[profile_type];
+ } else {
+ /* The proof or the link profile */
+ if (profile_type == gsPROOFPROFILE) {
+ curr_profile = profile_struct->proof_profile;
+ } else {
+ curr_profile = profile_struct->link_profile;
+ }
+ }
/* See if we have the same profile in this location */
if (curr_profile != NULL) {
/* There is something there now. See if what we have coming in
diff --git a/gs/base/gxi12bit.c b/gs/base/gxi12bit.c
index 0818f08fc..bdfcee340 100644
--- a/gs/base/gxi12bit.c
+++ b/gs/base/gxi12bit.c
@@ -145,8 +145,8 @@ gs_image_class_2_fracs(gx_image_enum * penum)
cmm_dev_profile_t *dev_profile;
code = dev_proc(penum->dev, get_profile)(penum->dev, &dev_profile);
- num_des_comps = dev_profile->device_profile[0]->num_comps;
- penum->icc_setup.need_decode = false;
+ num_des_comps = gsicc_get_device_profile_comps(dev_profile);
+ penum->icc_setup.need_decode = false;
/* Check if we need to do any decoding. If yes, then that will slow us down */
for (k = 0; k < src_num_comp; k++) {
if ( penum->map[k].decoding != sd_none ) {
@@ -611,7 +611,7 @@ image_render_icc16(gx_image_enum * penum, const byte * buffer, int data_x,
pdevc->type = gx_dc_type_none;
pdevc_next->type = gx_dc_type_none;
code = dev_proc(dev, get_profile)(dev, &dev_profile);
- num_des_comps = dev_profile->device_profile[0]->num_comps;
+ num_des_comps = gsicc_get_device_profile_comps(dev_profile);
/* If the link is the identity, then we don't need to do any color
conversions except for potentially a decode. */
if (penum->icc_link->is_identity && !need_decode) {
diff --git a/gs/base/gxicolor.c b/gs/base/gxicolor.c
index aa729bf06..5205bc96e 100644
--- a/gs/base/gxicolor.c
+++ b/gs/base/gxicolor.c
@@ -117,7 +117,7 @@ gs_image_class_4_color(gx_image_enum * penum)
cmm_dev_profile_t *dev_profile;
code = dev_proc(penum->dev, get_profile)(penum->dev, &dev_profile);
- des_num_comp = dev_profile->device_profile[0]->num_comps;
+ des_num_comp = gsicc_get_device_profile_comps(dev_profile);
penum->icc_setup.need_decode = false;
/* Check if we need to do any decoding. If yes, then that will slow us down */
for (k = 0; k < src_num_comp; k++) {
@@ -300,7 +300,7 @@ image_color_icc_prep(gx_image_enum *penum_orig, const byte *psrc, uint w,
cmm_dev_profile_t *dev_profile;
code = dev_proc(dev, get_profile)(dev, &dev_profile);
- num_des_comps = dev_profile->device_profile[0]->num_comps;
+ num_des_comps = gsicc_get_device_profile_comps(dev_profile);
if (penum->icc_link == NULL) {
return gs_rethrow(-1, "ICC Link not created during image render color");
}
diff --git a/gs/base/gximono.c b/gs/base/gximono.c
index b2120369d..2ee8e4ee7 100644
--- a/gs/base/gximono.c
+++ b/gs/base/gximono.c
@@ -112,7 +112,7 @@ gs_image_class_3_mono(gx_image_enum * penum)
}
}
code = dev_proc(penum->dev, get_profile)(penum->dev, &dev_profile);
- num_des_comps = dev_profile->device_profile[0]->num_comps;
+ num_des_comps = gsicc_get_device_profile_comps(dev_profile);
/* Define the rendering intents */
rendering_params.black_point_comp = BP_ON;
rendering_params.graphics_type_tag = GS_IMAGE_TAG;
diff --git a/gs/base/gxiscale.c b/gs/base/gxiscale.c
index 185300dd7..ff225ae4e 100644
--- a/gs/base/gxiscale.c
+++ b/gs/base/gxiscale.c
@@ -103,7 +103,7 @@ gs_image_class_0_interpolate(gx_image_enum * penum)
profile output size. For example sep device with CMYK profile should
not go through the fast method */
code = dev_proc(penum->dev, get_profile)(penum->dev, &dev_profile);
- num_des_comps = dev_profile->device_profile[0]->num_comps;
+ num_des_comps = gsicc_get_device_profile_comps(dev_profile);
if (num_des_comps != penum->dev->color_info.num_components) {
use_icc = false;
}
@@ -830,7 +830,7 @@ image_render_interpolate_icc(gx_image_enum * penum, const byte * buffer,
int num_bytes_decode = pss->params.BitsPerComponentIn / 8;
code = dev_proc(dev, get_profile)(dev, &dev_profile);
- spp_cm = dev_profile->device_profile[0]->num_comps;
+ spp_cm = gsicc_get_device_profile_comps(dev_profile);
if (penum->matrix.yy > 0)
dy = 1;
else