Пример #1
0
// This function creates a named color profile dumping all the contents of transform to a single profile
// In this way, LittleCMS may be used to "group" several named color databases into a single profile.
// It has, however, several minor limitations. PCS is always Lab, which is not very critic since this
// is the normal PCS for named color profiles.
static
cmsHPROFILE CreateNamedColorDevicelink(cmsHTRANSFORM xform)
{
    _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform;
    cmsHPROFILE hICC = NULL;
    int i, nColors;
    cmsNAMEDCOLORLIST *nc2 = NULL, *Original = NULL;

    // Create an empty placeholder
    hICC = cmsCreateProfilePlaceholder(v->ContextID);
    if (hICC == NULL) return NULL;

    // Critical information
    cmsSetDeviceClass(hICC, cmsSigNamedColorClass);
    cmsSetColorSpace(hICC, v ->ExitColorSpace);
    cmsSetPCS(hICC, cmsSigLabData);

    // Tag profile with information
    if (!SetTextTags(hICC, L"Named color devicelink")) goto Error;

    Original = cmsGetNamedColorList(xform);
    if (Original == NULL) goto Error;

    nColors = cmsNamedColorCount(Original);
    nc2     = cmsDupNamedColorList(Original);
    if (nc2 == NULL) goto Error;

    // Colorant count now depends on the output space
    nc2 ->ColorantCount = cmsPipelineOutputChannels(v ->Lut);

    // Make sure we have proper formatters
    cmsChangeBuffersFormat(xform, TYPE_NAMED_COLOR_INDEX,
        FLOAT_SH(0) | COLORSPACE_SH(_cmsLCMScolorSpace(v ->ExitColorSpace))
        | BYTES_SH(2) | CHANNELS_SH(cmsChannelsOf(v ->ExitColorSpace)));

    // Apply the transfor to colorants.
    for (i=0; i < nColors; i++) {
        cmsDoTransform(xform, &i, nc2 ->List[i].DeviceColorant, 1);
    }

    if (!cmsWriteTag(hICC, cmsSigNamedColor2Tag, (void*) nc2)) goto Error;
    cmsFreeNamedColorList(nc2);

    return hICC;

Error:
    if (hICC != NULL) cmsCloseProfile(hICC);
    return NULL;
}
Пример #2
0
/* Create a link to return device values inside the named color profile or link
   it with a destination profile and potentially a proofing profile.  If the
   output_colorspace and the proof_color space are NULL, then we will be
   returning the device values that are contained in the named color profile.
   i.e. in namedcolor_information.  Note that an ICC named color profile
    need NOT contain the device values but must contain the CIELAB values. */
void
gscms_get_name2device_link(gsicc_link_t *icclink,
                           gcmmhprofile_t  lcms_srchandle,
                           gcmmhprofile_t lcms_deshandle,
                           gcmmhprofile_t lcms_proofhandle,
                           gsicc_rendering_param_t *rendering_params,
                           gs_memory_t *memory)
{
    cmsHTRANSFORM hTransform;
    cmsUInt32Number dwOutputFormat;
    cmsUInt32Number lcms_proof_flag;
    int number_colors;

    /* NOTE:  We need to add a test here to check that we even HAVE
    device values in here and NOT just CIELAB values */
    if ( lcms_proofhandle != NULL ) {
        lcms_proof_flag = cmsFLAGS_GAMUTCHECK | cmsFLAGS_SOFTPROOFING;
    } else {
        lcms_proof_flag = 0;
    }
    /* Create the transform */
    /* ToDo:  Adjust rendering intent */
    hTransform = cmsCreateProofingTransformTHR(memory,
                 lcms_srchandle, TYPE_NAMED_COLOR_INDEX,
                 lcms_deshandle, TYPE_CMYK_8,
                 lcms_proofhandle,INTENT_PERCEPTUAL,
                 INTENT_ABSOLUTE_COLORIMETRIC,
                 lcms_proof_flag);
    /* In littleCMS there is no easy way to find out the size of the device
        space returned by the named color profile until after the transform is made.
        Hence we adjust our output format after creating the transform.  It is
        set to CMYK8 initially. */
    number_colors = cmsNamedColorCount(cmsGetNamedColorList(hTransform));
    /* NOTE: Output size of gx_color_value with no color space type check */
    dwOutputFormat =  (CHANNELS_SH(number_colors)|BYTES_SH(sizeof(gx_color_value)));
    /* Change the formatters */
    cmsChangeBuffersFormat(hTransform,TYPE_NAMED_COLOR_INDEX,dwOutputFormat);
    icclink->link_handle = hTransform;
    cmsCloseProfile(lcms_srchandle);
    if(lcms_deshandle) cmsCloseProfile(lcms_deshandle);
    if(lcms_proofhandle) cmsCloseProfile(lcms_proofhandle);
    return;
}
Пример #3
0
/* Transform a single color. We assume we have passed to us the proper number
   of elements of size gx_device_color. It is up to the caller to make sure
   the proper allocations for the colors are there. */
void
gscms_transform_color(gx_device *dev, gsicc_link_t *icclink, void *inputcolor,
                      void *outputcolor, int num_bytes)
{
    cmsHTRANSFORM hTransform = (cmsHTRANSFORM)icclink->link_handle;
    cmsUInt32Number dwInputFormat,dwOutputFormat;

    /* For a single color, we are going to use the link as it is
       with the exception of taking care of the word size. */
    /* numbytes = sizeof(gx_color_value); */
    if (num_bytes>2) num_bytes = 0;  /* littleCMS encodes float with 0 ToDO. */
    dwInputFormat = cmsGetTransformInputFormat(hTransform);
    dwOutputFormat = cmsGetTransformOutputFormat(hTransform);
    dwInputFormat = (dwInputFormat & (~LCMS_BYTES_MASK))  | BYTES_SH(num_bytes);
    dwOutputFormat = (dwOutputFormat & (~LCMS_BYTES_MASK)) | BYTES_SH(num_bytes);
    /* Change the formatters */
    cmsChangeBuffersFormat(hTransform,dwInputFormat,dwOutputFormat);
    /* Do conversion */
    cmsDoTransform(hTransform,inputcolor,outputcolor,1);
}
Пример #4
0
/******************************************************************************
 * TranslateBitmapBits              [MSCMS.@]
 *
 * Perform color translation.
 *
 * PARAMS
 *  transform    [I] Handle to a color transform.
 *  srcbits      [I] Source bitmap.
 *  input        [I] Format of the source bitmap.
 *  width        [I] Width of the source bitmap.
 *  height       [I] Height of the source bitmap.
 *  inputstride  [I] Number of bytes in one scanline.
 *  destbits     [I] Destination bitmap.
 *  output       [I] Format of the destination bitmap.
 *  outputstride [I] Number of bytes in one scanline. 
 *  callback     [I] Callback function.
 *  data         [I] Callback data. 
 *
 * RETURNS
 *  Success: TRUE
 *  Failure: FALSE
 */
BOOL WINAPI TranslateBitmapBits( HTRANSFORM handle, PVOID srcbits, BMFORMAT input,
    DWORD width, DWORD height, DWORD inputstride, PVOID destbits, BMFORMAT output,
    DWORD outputstride, PBMCALLBACKFN callback, ULONG data )
{
    BOOL ret = FALSE;
#ifdef HAVE_LCMS
    struct transform *transform = grab_transform( handle );

    TRACE( "( %p, %p, 0x%08x, 0x%08x, 0x%08x, 0x%08x, %p, 0x%08x, 0x%08x, %p, 0x%08x )\n",
           handle, srcbits, input, width, height, inputstride, destbits, output,
           outputstride, callback, data );

    if (!transform) return FALSE;
    cmsChangeBuffersFormat( transform->cmstransform, from_bmformat(input), from_bmformat(output) );

    cmsDoTransform( transform->cmstransform, srcbits, destbits, width * height );
    release_transform( transform );
    ret = TRUE;

#endif /* HAVE_LCMS */
    return ret;
}
Пример #5
0
/* Transform a single color. We assume we have passed to us the proper number
   of elements of size gx_device_color. It is up to the caller to make sure
   the proper allocations for the colors are there. */
void
gscms_transform_color(gx_device *dev, gsicc_link_t *icclink, void *inputcolor,
                      void *outputcolor, int num_bytes)
{
    cmsHTRANSFORM hTransform = (cmsHTRANSFORM) icclink->link_handle;
    DWORD dwInputFormat,dwOutputFormat,curr_input,curr_output;

    /* For a single color, we are going to use the link as it is
       with the exception of taking care of the word size. */
    _LPcmsTRANSFORM p = (_LPcmsTRANSFORM) (LPSTR) hTransform;
    curr_input = p->InputFormat;
    curr_output = p->OutputFormat;
    /* numbytes = sizeof(gx_color_value); */
    if (num_bytes>2) num_bytes = 0;  /* littleCMS encodes float with 0 ToDO. */
    dwInputFormat = (curr_input & (~LCMS_BYTES_MASK))  | BYTES_SH(num_bytes);
    dwOutputFormat = (curr_output & (~LCMS_BYTES_MASK)) | BYTES_SH(num_bytes);
    /* Change the formatters */
    cmsChangeBuffersFormat(hTransform,dwInputFormat,dwOutputFormat);
    /* Do conversion */
    cmsDoTransform(hTransform,inputcolor,outputcolor,1);
    return 0;
}
Пример #6
0
/* Transform an entire buffer */
void
gscms_transform_color_buffer(gsicc_link_t *icclink,
                             gsicc_bufferdesc_t *input_buff_desc,
                             gsicc_bufferdesc_t *output_buff_desc,
                             void *inputbuffer,
                             void *outputbuffer)
{

    cmsHTRANSFORM hTransform = (cmsHTRANSFORM) icclink->link_handle;
    DWORD dwInputFormat,dwOutputFormat,curr_input,curr_output;
    int planar,numbytes,big_endian,hasalpha,k;
    unsigned char *inputpos, *outputpos;
    int numchannels;
#if DUMP_CMS_BUFFER
    FILE *fid_in, *fid_out;
#endif
    /* Although little CMS does  make assumptions about data types in its
       transformations you can change it after the fact.  */
    /* Set us to the proper output type */
    /* Note, we could speed this up by passing back the encoded data type
        to the caller so that we could avoid having to go through this
        computation each time if they are doing multiple calls to this
        operation */
    _LPcmsTRANSFORM p = (_LPcmsTRANSFORM) (LPSTR) hTransform;

    curr_input = p->InputFormat;
    curr_output = p->OutputFormat;

    /* Color space MUST be the same */
    dwInputFormat = COLORSPACE_SH(T_COLORSPACE(curr_input));
    dwOutputFormat = COLORSPACE_SH(T_COLORSPACE(curr_output));

    /* Now set if we have planar, num bytes, endian case, and alpha data to skip */
    /* Planar -- pdf14 case for example */
    planar = input_buff_desc->is_planar;
    dwInputFormat = dwInputFormat | PLANAR_SH(planar);
    planar = output_buff_desc->is_planar;
    dwOutputFormat = dwOutputFormat | PLANAR_SH(planar);

    /* 8 or 16 byte input and output */
    numbytes = input_buff_desc->bytes_per_chan;
    if (numbytes>2) numbytes = 0;  /* littleCMS encodes float with 0 ToDO. */
    dwInputFormat = dwInputFormat | BYTES_SH(numbytes);
    numbytes = output_buff_desc->bytes_per_chan;
    if (numbytes>2) numbytes = 0;
    dwOutputFormat = dwOutputFormat | BYTES_SH(numbytes);

    /* endian */
    big_endian = !input_buff_desc->little_endian;
    dwInputFormat = dwInputFormat | ENDIAN16_SH(big_endian);
    big_endian = !output_buff_desc->little_endian;
    dwOutputFormat = dwOutputFormat | ENDIAN16_SH(big_endian);

    /* number of channels */
    numchannels = input_buff_desc->num_chan;
    dwInputFormat = dwInputFormat | CHANNELS_SH(numchannels);
    numchannels = output_buff_desc->num_chan;
    dwOutputFormat = dwOutputFormat | CHANNELS_SH(numchannels);

    /* alpha, which is passed through unmolested */
    /* ToDo:  Right now we always must have alpha last */
    /* This is really only going to be an issue when we have
       interleaved alpha data */
    hasalpha = input_buff_desc->has_alpha;
    dwInputFormat = dwInputFormat | EXTRA_SH(hasalpha);
    dwOutputFormat = dwOutputFormat | EXTRA_SH(hasalpha);

    /* Change the formaters */
    cmsChangeBuffersFormat(hTransform,dwInputFormat,dwOutputFormat);

    /* littleCMS knows nothing about word boundarys.  As such, we need to do
       this row by row adjusting for our stride.  Output buffer must already
       be allocated. ToDo:  Check issues with plane and row stride and word
       boundry */
    inputpos = (unsigned char *) inputbuffer;
    outputpos = (unsigned char *) outputbuffer;
    if(input_buff_desc->is_planar){
        /* Do entire buffer.  Care must be taken here
           with respect to row stride, word boundry and number
           of source versus output channels.  We may
           need to take a closer look at this. */
        cmsDoTransform(hTransform,inputpos,outputpos,
                        input_buff_desc->plane_stride);
    } else {
        /* Do row by row. */
        for(k = 0; k < input_buff_desc->num_rows ; k++){
            cmsDoTransform(hTransform,inputpos,outputpos,
                            input_buff_desc->pixels_per_row);
            inputpos += input_buff_desc->row_stride;
            outputpos += output_buff_desc->row_stride;
        }
    }
#if DUMP_CMS_BUFFER
    fid_in = fopen("CM_Input.raw","ab");
    fid_out = fopen("CM_Output.raw","ab");
    fwrite((unsigned char*) inputbuffer,sizeof(unsigned char),
                            input_buff_desc->row_stride,fid_in);
    fwrite((unsigned char*) outputbuffer,sizeof(unsigned char),
                            output_buff_desc->row_stride,fid_out);
    fclose(fid_in);
    fclose(fid_out);
#endif
}
Пример #7
0
/******************************************************************************
 * TranslateColors              [MSCMS.@]
 *
 * Perform color translation.
 *
 * PARAMS
 *  transform    [I] Handle to a color transform.
 *  input        [I] Array of input colors.
 *  number       [I] Number of colors to translate.
 *  input_type   [I] Input color format.
 *  output       [O] Array of output colors.
 *  output_type  [I] Output color format.
 *
 * RETURNS
 *  Success: TRUE
 *  Failure: FALSE
 */
BOOL WINAPI TranslateColors( HTRANSFORM handle, PCOLOR in, DWORD count,
                             COLORTYPE input_type, PCOLOR out, COLORTYPE output_type )
{
#ifdef HAVE_LCMS2
    BOOL ret = TRUE;
    struct transform *transform = grab_transform( handle );
    cmsHTRANSFORM xfrm;
    unsigned int i;

    TRACE( "( %p, %p, %d, %d, %p, %d )\n", handle, in, count, input_type, out, output_type );

    if (!transform) return FALSE;

    xfrm = transform->cmstransform;
    if (!cmsChangeBuffersFormat( xfrm, from_type(input_type), from_type(output_type) ))
        return FALSE;

    switch (input_type)
    {
    case COLOR_RGB:
    {
        switch (output_type)
        {
        case COLOR_RGB:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].rgb, &out[i].rgb, 1 ); goto done;
        case COLOR_Lab:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].rgb, &out[i].Lab, 1 ); goto done;
        case COLOR_GRAY: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].rgb, &out[i].gray, 1 ); goto done;
        case COLOR_CMYK: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].rgb, &out[i].cmyk, 1 ); goto done;
        case COLOR_XYZ:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].rgb, &out[i].XYZ, 1 ); goto done;
        default:
            FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
            ret = FALSE;
            break;
        }
        break;
    }
    case COLOR_Lab:
    {
        switch (output_type)
        {
        case COLOR_RGB:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].Lab, &out[i].rgb, 1 ); goto done;
        case COLOR_Lab:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].Lab, &out[i].Lab, 1 ); goto done;
        case COLOR_GRAY: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].Lab, &out[i].gray, 1 ); goto done;
        case COLOR_CMYK: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].Lab, &out[i].cmyk, 1 ); goto done;
        case COLOR_XYZ:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].Lab, &out[i].XYZ, 1 ); goto done;
        default:
            FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
            ret = FALSE;
            break;
        }
        break;
    }
    case COLOR_GRAY:
    {
        switch (output_type)
        {
        case COLOR_RGB:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].gray, &out[i].rgb, 1 ); goto done;
        case COLOR_Lab:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].gray, &out[i].Lab, 1 ); goto done;
        case COLOR_GRAY: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].gray, &out[i].gray, 1 ); goto done;
        case COLOR_CMYK: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].gray, &out[i].cmyk, 1 ); goto done;
        case COLOR_XYZ:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].gray, &out[i].XYZ, 1 ); goto done;
        default:
            FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
            ret = FALSE;
            break;
        }
        break;
    }
    case COLOR_CMYK:
    {
        switch (output_type)
        {
        case COLOR_RGB:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].cmyk, &out[i].rgb, 1 ); goto done;
        case COLOR_Lab:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].cmyk, &out[i].Lab, 1 ); goto done;
        case COLOR_GRAY: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].cmyk, &out[i].gray, 1 ); goto done;
        case COLOR_CMYK: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].cmyk, &out[i].cmyk, 1 ); goto done;
        case COLOR_XYZ:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].cmyk, &out[i].XYZ, 1 ); goto done;
        default:
            FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
            ret = FALSE;
            break;
        }
        break;
    }
    case COLOR_XYZ:
    {
        switch (output_type)
        {
        case COLOR_RGB:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].XYZ, &out[i].rgb, 1 ); goto done;
        case COLOR_Lab:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].XYZ, &out[i].Lab, 1 ); goto done;
        case COLOR_GRAY: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].XYZ, &out[i].gray, 1 ); goto done;
        case COLOR_CMYK: for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].XYZ, &out[i].cmyk, 1 ); goto done;
        case COLOR_XYZ:  for (i = 0; i < count; i++) cmsDoTransform( xfrm, &in[i].XYZ, &out[i].XYZ, 1 ); goto done;
        default:
            FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
            ret = FALSE;
            break;
        }
        break;
    }
    default:
        FIXME("unhandled input/output pair: %d/%d\n", input_type, output_type);
        ret = FALSE;
        break;
    }

done:
    release_transform( transform );
    return ret;

#else  /* HAVE_LCMS2 */
    return FALSE;
#endif /* HAVE_LCMS2 */
}
Пример #8
0
/*
 * Class:     sun_java2d_cmm_lcms_LCMS
 * Method:    colorConvert
 * Signature: (Lsun/java2d/cmm/lcms/LCMSTransform;Lsun/java2d/cmm/lcms/LCMSImageLayout;Lsun/java2d/cmm/lcms/LCMSImageLayout;)V
 */
JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_colorConvert
  (JNIEnv *env, jclass obj, jobject trans, jobject src, jobject dst)
{
    storeID_t sTrans;
    int size, inFmt, outFmt, srcDType, dstDType, outSize, renderType;
    int srcOffset, srcNextRowOffset, dstOffset, dstNextRowOffset;
    int width, height, i;
    void* inputBuffer;
    void* outputBuffer;
    char* inputRow;
    char* outputRow;
    jobject srcData, dstData;

    inFmt = (*env)->GetIntField (env, src, IL_pixelType_fID);
    outFmt = (*env)->GetIntField (env, dst, IL_pixelType_fID);
    srcOffset = (*env)->GetIntField (env, src, IL_offset_fID);
    srcNextRowOffset = (*env)->GetIntField (env, src, IL_nextRowOffset_fID);
    dstOffset = (*env)->GetIntField (env, dst, IL_offset_fID);
    dstNextRowOffset = (*env)->GetIntField (env, dst, IL_nextRowOffset_fID);
    width = (*env)->GetIntField (env, src, IL_width_fID);
    height = (*env)->GetIntField (env, src, IL_height_fID);
#ifdef _LITTLE_ENDIAN
    /* Reversing data packed into int for LE archs */
    if ((*env)->GetBooleanField (env, src, IL_isIntPacked_fID) == JNI_TRUE) {
        inFmt ^= DOSWAP_SH(1);
    }
    if ((*env)->GetBooleanField (env, dst, IL_isIntPacked_fID) == JNI_TRUE) {
        outFmt ^= DOSWAP_SH(1);
    }
#endif
    sTrans.j = (*env)->GetLongField (env, trans, Trans_ID_fID);
    cmsChangeBuffersFormat(sTrans.xf, inFmt, outFmt);


    if (sTrans.xf == NULL) {
        J2dRlsTraceLn(J2D_TRACE_ERROR, "LCMS_colorConvert: transform == NULL");
        JNU_ThrowByName(env, "java/awt/color/CMMException",
                        "Cannot get color transform");
        return;
    }


    inputBuffer = getILData (env, src, &srcDType, &srcData);

    if (inputBuffer == NULL) {
        J2dRlsTraceLn(J2D_TRACE_ERROR, "");
        JNU_ThrowByName(env, "java/awt/color/CMMException",
                        "Cannot get input data");
        return;
    }

    outputBuffer = getILData (env, dst, &dstDType, &dstData);

    if (outputBuffer == NULL) {
        releaseILData(env, inputBuffer, srcDType, srcData);
        JNU_ThrowByName(env, "java/awt/color/CMMException",
                        "Cannot get output data");
        return;
    }

    inputRow = (char*)inputBuffer + srcOffset;
    outputRow = (char*)outputBuffer + dstOffset;

    for (i = 0; i < height; i++) {
        cmsDoTransform(sTrans.xf, inputRow, outputRow, width);
        inputRow += srcNextRowOffset;
        outputRow += dstNextRowOffset;
    }

    releaseILData(env, inputBuffer, srcDType, srcData);
    releaseILData(env, outputBuffer, dstDType, dstData);
}
Пример #9
0
/* Transform an entire buffer */
void
gscms_transform_color_buffer(gx_device *dev, gsicc_link_t *icclink,
                             gsicc_bufferdesc_t *input_buff_desc,
                             gsicc_bufferdesc_t *output_buff_desc,
                             void *inputbuffer,
                             void *outputbuffer)
{
    cmsHTRANSFORM hTransform = (cmsHTRANSFORM)icclink->link_handle;
    cmsUInt32Number dwInputFormat, dwOutputFormat, num_src_lcms, num_des_lcms;
    int planar,numbytes, big_endian, hasalpha, k;
    unsigned char *inputpos, *outputpos;
#if DUMP_CMS_BUFFER
    FILE *fid_in, *fid_out;
#endif
    /* Although little CMS does  make assumptions about data types in its
       transformations you can change it after the fact.  */
    /* Set us to the proper output type */
    /* Note, we could speed this up by passing back the encoded data type
        to the caller so that we could avoid having to go through this
        computation each time if they are doing multiple calls to this
        operation */
    /* Color space MUST be the same */
    dwInputFormat = COLORSPACE_SH(T_COLORSPACE(cmsGetTransformInputFormat(hTransform)));
    dwOutputFormat = COLORSPACE_SH(T_COLORSPACE(cmsGetTransformOutputFormat(hTransform)));

    /* Now set if we have planar, num bytes, endian case, and alpha data to skip */
    /* Planar -- pdf14 case for example */
    planar = input_buff_desc->is_planar;
    dwInputFormat = dwInputFormat | PLANAR_SH(planar);
    planar = output_buff_desc->is_planar;
    dwOutputFormat = dwOutputFormat | PLANAR_SH(planar);

    /* 8 or 16 byte input and output */
    numbytes = input_buff_desc->bytes_per_chan;
    if (numbytes>2) numbytes = 0;  /* littleCMS encodes float with 0 ToDO. */
    dwInputFormat = dwInputFormat | BYTES_SH(numbytes);
    numbytes = output_buff_desc->bytes_per_chan;
    if (numbytes>2) numbytes = 0;
    dwOutputFormat = dwOutputFormat | BYTES_SH(numbytes);

    /* endian */
    big_endian = !input_buff_desc->little_endian;
    dwInputFormat = dwInputFormat | ENDIAN16_SH(big_endian);
    big_endian = !output_buff_desc->little_endian;
    dwOutputFormat = dwOutputFormat | ENDIAN16_SH(big_endian);

    /* number of channels.  This should not really be changing! */
    num_src_lcms = T_CHANNELS(cmsGetTransformInputFormat(hTransform));
    num_des_lcms = T_CHANNELS(cmsGetTransformOutputFormat(hTransform));
    if (num_src_lcms != input_buff_desc->num_chan ||
            num_des_lcms != output_buff_desc->num_chan) {
        /* We can't transform this. Someone is doing something odd */
        return;
    }
    dwInputFormat = dwInputFormat | CHANNELS_SH(num_src_lcms);
    dwOutputFormat = dwOutputFormat | CHANNELS_SH(num_des_lcms);

    /* alpha, which is passed through unmolested */
    /* ToDo:  Right now we always must have alpha last */
    /* This is really only going to be an issue when we have
       interleaved alpha data */
    hasalpha = input_buff_desc->has_alpha;
    dwInputFormat = dwInputFormat | EXTRA_SH(hasalpha);
    dwOutputFormat = dwOutputFormat | EXTRA_SH(hasalpha);

    /* Change the formatters */
    cmsChangeBuffersFormat(hTransform,dwInputFormat,dwOutputFormat);

    /* littleCMS knows nothing about word boundarys.  As such, we need to do
       this row by row adjusting for our stride.  Output buffer must already
       be allocated. ToDo:  Check issues with plane and row stride and word
       boundry */
    inputpos = (byte *) inputbuffer;
    outputpos = (byte *) outputbuffer;
    if(input_buff_desc->is_planar) {
        /* Determine if we can do this in one operation or if we have to break
           it up.  Essentially if the width * height = plane_stride then yes.  If
           we are doing some subsection of a plane then no. */
        if (input_buff_desc->num_rows * input_buff_desc->pixels_per_row ==
                input_buff_desc->plane_stride  &&
                output_buff_desc->num_rows * output_buff_desc->pixels_per_row ==
                output_buff_desc->plane_stride) {
            /* Do entire buffer.*/
            cmsDoTransform(hTransform, inputpos, outputpos,
                           input_buff_desc->plane_stride);
        } else {
            /* We have to do this row by row, with memory transfers */
            byte *temp_des, *temp_src;
            int source_size = input_buff_desc->bytes_per_chan *
                              input_buff_desc->pixels_per_row;

            int des_size = output_buff_desc->bytes_per_chan *
                           output_buff_desc->pixels_per_row;
            int y, i;

            temp_src = (byte*) gs_alloc_bytes(icclink->icc_link_cache->memory,
                                              source_size * input_buff_desc->num_chan,
                                              "gscms_transform_color_buffer");
            if (temp_src == NULL)
                return;
            temp_des = (byte*) gs_alloc_bytes(icclink->icc_link_cache->memory,
                                              des_size * output_buff_desc->num_chan,
                                              "gscms_transform_color_buffer");
            if (temp_des == NULL)
                return;
            for (y = 0; y < input_buff_desc->num_rows; y++) {
                byte *src_cm = temp_src;
                byte *src_buff = inputpos;
                byte *des_cm = temp_des;
                byte *des_buff = outputpos;

                /* Put into planar temp buffer */
                for (i = 0; i < input_buff_desc->num_chan; i ++) {
                    memcpy(src_cm, src_buff, source_size);
                    src_cm += source_size;
                    src_buff += input_buff_desc->plane_stride;
                }
                /* Transform */
                cmsDoTransform(hTransform, temp_src, temp_des,
                               input_buff_desc->pixels_per_row);
                /* Get out of temp planar buffer */
                for (i = 0; i < output_buff_desc->num_chan; i ++) {
                    memcpy(des_buff, des_cm, des_size);
                    des_cm += des_size;
                    des_buff += output_buff_desc->plane_stride;
                }
                inputpos += input_buff_desc->row_stride;
                outputpos += output_buff_desc->row_stride;
            }
            gs_free_object(icclink->icc_link_cache->memory, temp_src,
                           "gscms_transform_color_buffer");
            gs_free_object(icclink->icc_link_cache->memory, temp_des,
                           "gscms_transform_color_buffer");
        }
    } else {
        /* Do row by row. */
        for(k = 0; k < input_buff_desc->num_rows ; k++) {
            cmsDoTransform(hTransform, inputpos, outputpos,
                           input_buff_desc->pixels_per_row);
            inputpos += input_buff_desc->row_stride;
            outputpos += output_buff_desc->row_stride;
        }
    }
#if DUMP_CMS_BUFFER
    fid_in = gp_fopen("CM_Input.raw","ab");
    fid_out = gp_fopen("CM_Output.raw","ab");
    fwrite((unsigned char*) inputbuffer,sizeof(unsigned char),
           input_buff_desc->row_stride,fid_in);
    fwrite((unsigned char*) outputbuffer,sizeof(unsigned char),
           output_buff_desc->row_stride,fid_out);
    fclose(fid_in);
    fclose(fid_out);
#endif
}