示例#1
0
/* Get the link from the CMS, but include proofing and/or a device link
   profile.  Note also, that the source may be a device link profile, in
   which case we will not have a destination profile but could still have
   a proof profile or an additional device link profile */
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,
                             bool src_dev_link, int cmm_flags,
                             gs_memory_t *memory)
{
    cmsUInt32Number src_data_type,des_data_type;
    cmsColorSpaceSignature 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;
    unsigned int flag;

    /* Check if the rendering intent is something other than relative colorimetric
       and  if we have a proofing profile.  In this case we need to create the
       combined profile a bit different.  LCMS does not allow us to use different
       intents in the cmsCreateMultiprofileTransform transform.  Also, don't even
       think about doing this if someone has snuck in a source based device link
       profile into the mix */
    if (lcms_proofhandle != NULL &&
            rendering_params->rendering_intent != gsRELATIVECOLORIMETRIC &&
            !src_dev_link) {
        /* First handle the source to proof profile with its particular intent as
           a device link profile */
        cmsHPROFILE src_to_proof;
        cmsHTRANSFORM temptransform;

        temptransform = gscms_get_link(lcms_srchandle, lcms_proofhandle,
                                       rendering_params, cmm_flags, memory);
        /* Now mash that to a device link profile */
        flag = cmsFLAGS_HIGHRESPRECALC;
        if (rendering_params->black_point_comp == gsBLACKPTCOMP_ON ||
                rendering_params->black_point_comp == gsBLACKPTCOMP_ON_OR) {
            flag = (flag | cmsFLAGS_BLACKPOINTCOMPENSATION);
        }
        src_to_proof = cmsTransform2DeviceLink(temptransform, 3.4, flag);
        /* Free up the link handle */
        cmsDeleteTransform(temptransform);
        src_color_space  = cmsGetColorSpace(src_to_proof);
        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_devlinkhandle == NULL) {
            des_color_space = cmsGetColorSpace(lcms_deshandle);
        } else {
            des_color_space = cmsGetPCS(lcms_devlinkhandle);
        }
        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);
        des_data_type = (COLORSPACE_SH(lcms_des_color_space)|
                         CHANNELS_SH(des_nChannels)|BYTES_SH(2));
        /* Now, we need to go back through the proofing profile, to the
           destination and then to the device link profile if there was one. */
        hProfiles[nProfiles++] = src_to_proof;  /* Src to proof with special intent */
        hProfiles[nProfiles++] = lcms_proofhandle; /* Proof to CIELAB */
        if (lcms_deshandle != NULL) {
            hProfiles[nProfiles++] = lcms_deshandle;  /* Our destination */
        }
        /* The output device link profile */
        if (lcms_devlinkhandle != NULL) {
            hProfiles[nProfiles++] = lcms_devlinkhandle;
        }
        flag = cmsFLAGS_HIGHRESPRECALC;
        if (rendering_params->black_point_comp == gsBLACKPTCOMP_ON
                || rendering_params->black_point_comp == gsBLACKPTCOMP_ON_OR) {
            flag = (flag | cmsFLAGS_BLACKPOINTCOMPENSATION);
        }
        /* Use relative colorimetric here */
        temptransform = cmsCreateMultiprofileTransformTHR((cmsContext)memory,
                        hProfiles, nProfiles, src_data_type,
                        des_data_type, gsRELATIVECOLORIMETRIC, flag);
        cmsCloseProfile(src_to_proof);
        return temptransform;
    } else {
        /* First handle all the source stuff */
        src_color_space  = cmsGetColorSpace(lcms_srchandle);
        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_devlinkhandle == NULL) {
            if (src_dev_link) {
                des_color_space = cmsGetPCS(lcms_srchandle);
            } else {
                des_color_space = cmsGetColorSpace(lcms_deshandle);
            }
        } else {
            des_color_space = cmsGetPCS(lcms_devlinkhandle);
        }
        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);
        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;
        /* Note if source is device link, we cannot do any proofing */
        if (lcms_proofhandle != NULL && !src_dev_link) {
            hProfiles[nProfiles++] = lcms_proofhandle;
            hProfiles[nProfiles++] = lcms_proofhandle;
        }
        /* This should be NULL if we have a source device link */
        if (lcms_deshandle != NULL) {
            hProfiles[nProfiles++] = lcms_deshandle;
        }
        /* Someone could have a device link at the output, giving us possibly two
           device link profiles to smash together */
        if (lcms_devlinkhandle != NULL) {
            hProfiles[nProfiles++] = lcms_devlinkhandle;
        }
        flag = cmsFLAGS_HIGHRESPRECALC;
        if (rendering_params->black_point_comp == gsBLACKPTCOMP_ON
                || rendering_params->black_point_comp == gsBLACKPTCOMP_ON_OR) {
            flag = (flag | cmsFLAGS_BLACKPOINTCOMPENSATION);
        }
        return cmsCreateMultiprofileTransformTHR((cmsContext)memory,
                hProfiles, nProfiles, src_data_type,
                des_data_type, rendering_params->rendering_intent, flag);
    }
}
示例#2
0
gsicc_link_t*
gsicc_get_link_profile(gs_imager_state *pis, gx_device *dev,
                       cmm_profile_t *gs_input_profile,
                       cmm_profile_t *gs_output_profile,
                       gsicc_rendering_param_t *rendering_params,
                       gs_memory_t *memory, bool include_softproof)
{
    gsicc_hashlink_t hash;
    gsicc_link_t *link, *found_link;
    gcmmhlink_t link_handle = NULL;
    void **contextptr = NULL;
    gsicc_manager_t *icc_manager = pis->icc_manager;
    gsicc_link_cache_t *icc_link_cache = pis->icc_link_cache;
    gs_memory_t *cache_mem = pis->icc_link_cache->memory;

    gcmmhprofile_t *cms_input_profile;
    gcmmhprofile_t *cms_output_profile;

    /* First compute the hash code for the incoming case */
    /* If the output color space is NULL we will use the device profile for the output color space */
    gsicc_compute_linkhash(icc_manager, dev, gs_input_profile, gs_output_profile,
                            rendering_params, &hash);

    /* Check the cache for a hit.  Need to check if softproofing was used */
    found_link = gsicc_findcachelink(hash, icc_link_cache, include_softproof);

    /* Got a hit, return link (ref_count for the link was already bumped */
    if (found_link != NULL)
        return(found_link);  /* TO FIX: We are really not going to want to have the members
                          of this object visible outside gsiccmange */

    /* If not, then lets create a new one if there is room or return NULL */
    /* Caller will need to try later */

    /* First see if we can add a link */
    /* TODO: this should be based on memory usage, not just num_links */
    gx_monitor_enter(icc_link_cache->lock);
    while (icc_link_cache->num_links >= ICC_CACHE_MAXLINKS) {
        /* If not, see if there is anything we can remove from cache. */
	while ((link = gsicc_find_zeroref_cache(icc_link_cache)) == NULL) {
	    icc_link_cache->num_waiting++;
	    /* safe to unlock since above will make sure semaphore is signalled */
	    gx_monitor_leave(icc_link_cache->lock);
	    /* we get signalled (released from wait) when a link goes to zero ref */
	    gx_semaphore_wait(icc_link_cache->wait);

	    /* repeat the findcachelink to see if some other thread has	*/
	    /*already started building the link	we need			*/
	    found_link = gsicc_findcachelink(hash, icc_link_cache, include_softproof);

	    /* Got a hit, return link (ref_count for the link was already bumped */
	    if (found_link != NULL)
		return(found_link);  /* TO FIX: We are really not going to want to have the members
				  of this object visible outside gsiccmange */

	    gx_monitor_enter(icc_link_cache->lock);	    /* restore the lock */
	    /* we will re-test the num_links above while locked to insure */
	    /* that some other thread didn't grab the slot and max us out */
	}
	/* Remove the zero ref_count link profile we found.		*/
	/* Even if we remove this link, we may still be maxed out so	*/
	/* the outermost 'while' will check to make sure some other	*/
	/* thread did not grab the one we remove.			*/
	gsicc_remove_link(link, cache_mem);
        icc_link_cache->num_links--;
    }
    /* insert an empty link that we will reserve so we */
    /* can unlock while building the link contents     */
    link = gsicc_alloc_link(cache_mem->stable_memory, hash);
    link->icc_link_cache = icc_link_cache;
    link->next = icc_link_cache->head;
    icc_link_cache->head = link;
    icc_link_cache->num_links++;
    gx_monitor_leave(icc_link_cache->lock);	/* now that we own this link we can release */
					/* the lock since it is not valid */

    /* Now compute the link contents */
    cms_input_profile = gs_input_profile->profile_handle;
    if (cms_input_profile == NULL) {
        if (gs_input_profile->buffer != NULL) {
            cms_input_profile =
                gsicc_get_profile_handle_buffer(gs_input_profile->buffer,
                                                gs_input_profile->buffer_size);
            gs_input_profile->profile_handle = cms_input_profile;
        } else {
            /* See if we have a clist device pointer. */
            if ( gs_input_profile->dev != NULL ) {
                /* ICC profile should be in clist. This is
                   the first call to it.  Note that the profiles are not
                   really shared amongst threads like the links are.  Hence
                   the memory is for the local thread's chunk */
                cms_input_profile =
                    gsicc_get_profile_handle_clist(gs_input_profile,
                                                   gs_input_profile->memory);
                gs_input_profile->profile_handle = cms_input_profile;
            } else {
                /* Cant create the link.  No profile present,
                   nor any defaults to use for this.  Really
                   need to throw an error for this case. */
		gsicc_remove_link(link, cache_mem);
                icc_link_cache->num_links--;
                return(NULL);
            }
        }
    }

    cms_output_profile = gs_output_profile->profile_handle;
    if (cms_output_profile == NULL) {
        if (gs_output_profile->buffer != NULL) {
            cms_input_profile =
                gsicc_get_profile_handle_buffer(gs_input_profile->buffer,
                                                gs_input_profile->buffer_size);
            gs_output_profile->profile_handle = cms_output_profile;
        } else {
              /* See if we have a clist device pointer. */
            if ( gs_output_profile->dev != NULL ) {
                /* ICC profile should be in clist. This is
                   the first call to it. */
                cms_output_profile =
                    gsicc_get_profile_handle_clist(gs_output_profile,
                                                   gs_output_profile->memory);
                gs_output_profile->profile_handle = cms_output_profile;
            } else {
                /* Cant create the link.  No profile present,
                   nor any defaults to use for this.  Really
                   need to throw an error for this case. */
		gsicc_remove_link(link, cache_mem);
                icc_link_cache->num_links--;
                return(NULL);
            }
        }
    }
    link_handle = gscms_get_link(cms_input_profile, cms_output_profile,
                                    rendering_params);
    if (link_handle != NULL) {
	gsicc_set_link_data(link, link_handle, contextptr, hash, icc_link_cache->lock);
    } else {
	gsicc_remove_link(link, cache_mem);
        icc_link_cache->num_links--;
        return(NULL);
    }
    return(link);
}