static int WriteNamedColorCRD(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, int Intent, cmsUInt32Number dwFlags) { cmsHTRANSFORM xform; int i, nColors, nColorant; cmsUInt32Number OutputFormat; char ColorName[32]; char Colorant[128]; cmsNAMEDCOLORLIST* NamedColorList; OutputFormat = cmsFormatterForColorspaceOfProfile(hNamedColor, 2, FALSE); nColorant = T_CHANNELS(OutputFormat); xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX, NULL, OutputFormat, Intent, dwFlags); if (xform == NULL) return 0; NamedColorList = cmsGetNamedColorList(xform); if (NamedColorList == NULL) return 0; _cmsIOPrintf(m, "<<\n"); _cmsIOPrintf(m, "(colorlistcomment) (%s) \n", "Named profile"); _cmsIOPrintf(m, "(Prefix) [ (Pantone ) (PANTONE ) ]\n"); _cmsIOPrintf(m, "(Suffix) [ ( CV) ( CVC) ( C) ]\n"); nColors = cmsNamedColorCount(NamedColorList); for (i=0; i < nColors; i++) { cmsUInt16Number In[1]; cmsUInt16Number Out[cmsMAXCHANNELS]; In[0] = (cmsUInt16Number) i; if (!cmsNamedColorInfo(NamedColorList, i, ColorName, NULL, NULL, NULL, NULL)) continue; cmsDoTransform(xform, In, Out, 1); BuildColorantList(Colorant, nColorant, Out); _cmsIOPrintf(m, " (%s) [ %s ]\n", ColorName, Colorant); } _cmsIOPrintf(m, " >>"); if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) { _cmsIOPrintf(m, " /Current exch /HPSpotTable defineresource pop\n"); } cmsDeleteTransform(xform); return 1; }
// This function computes the distance from each component to the next one in bytes. static void ComputeIncrementsForChunky(cmsUInt32Number Format, cmsUInt32Number ComponentStartingOrder[], cmsUInt32Number ComponentPointerIncrements[]) { cmsUInt32Number channels[cmsMAXCHANNELS]; int extra = T_EXTRA(Format); int nchannels = T_CHANNELS(Format); int total_chans = nchannels + extra; int i; int channelSize = trueBytesSize(Format); int pixelSize = channelSize * total_chans; // Sanity check if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS) return; memset(channels, 0, sizeof(channels)); // Separation is independent of starting point and only depends on channel size for (i = 0; i < extra; i++) ComponentPointerIncrements[i] = pixelSize; // Handle do swap for (i = 0; i < total_chans; i++) { if (T_DOSWAP(Format)) { channels[i] = total_chans - i - 1; } else { channels[i] = i; } } // Handle swap first (ROL of positions), example CMYK -> KCMY | 0123 -> 3012 if (T_SWAPFIRST(Format) && total_chans > 1) { cmsUInt32Number tmp = channels[0]; for (i = 0; i < total_chans-1; i++) channels[i] = channels[i + 1]; channels[total_chans - 1] = tmp; } // Handle size if (channelSize > 1) for (i = 0; i < total_chans; i++) { channels[i] *= channelSize; } for (i = 0; i < extra; i++) ComponentStartingOrder[i] = channels[i + nchannels]; }
// Detect Total area coverage of the profile cmsFloat64Number CMSEXPORT cmsDetectTAC(cmsHPROFILE hProfile) { cmsTACestimator bp; cmsUInt32Number dwFormatter; cmsUInt32Number GridPoints[MAX_INPUT_DIMENSIONS]; cmsHPROFILE hLab; cmsContext ContextID = cmsGetProfileContextID(hProfile); // TAC only works on output profiles if (cmsGetDeviceClass(hProfile) != cmsSigOutputClass) { return 0; } // Create a fake formatter for result dwFormatter = cmsFormatterForColorspaceOfProfile(hProfile, 4, TRUE); bp.nOutputChans = T_CHANNELS(dwFormatter); bp.MaxTAC = 0; // Initial TAC is 0 // for safety if (bp.nOutputChans >= cmsMAXCHANNELS) return 0; hLab = cmsCreateLab4ProfileTHR(ContextID, NULL); if (hLab == NULL) return 0; // Setup a roundtrip on perceptual intent in output profile for TAC estimation bp.hRoundTrip = cmsCreateTransformTHR(ContextID, hLab, TYPE_Lab_16, hProfile, dwFormatter, INTENT_PERCEPTUAL, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE); cmsCloseProfile(hLab); if (bp.hRoundTrip == NULL) return 0; // For L* we only need black and white. For C* we need many points GridPoints[0] = 6; GridPoints[1] = 74; GridPoints[2] = 74; if (!cmsSliceSpace16(3, GridPoints, EstimateTAC, &bp)) { bp.MaxTAC = 0; } cmsDeleteTransform(bp.hRoundTrip); // Results in % return bp.MaxTAC; }
// On planar configurations, the distance is the stride added to any non-negative static void ComputeIncrementsForPlanar(cmsUInt32Number Format, cmsUInt32Number BytesPerPlane, cmsUInt32Number ComponentStartingOrder[], cmsUInt32Number ComponentPointerIncrements[]) { cmsUInt32Number channels[cmsMAXCHANNELS]; int extra = T_EXTRA(Format); int nchannels = T_CHANNELS(Format); int total_chans = nchannels + extra; int i; int channelSize = trueBytesSize(Format); // Separation is independent of starting point and only depends on channel size for (i = 0; i < extra; i++) ComponentPointerIncrements[i] = channelSize; // Handle do swap for (i = 0; i < total_chans; i++) { if (T_DOSWAP(Format)) { channels[i] = total_chans - i - 1; } else { channels[i] = i; } } // Handle swap first (ROL of positions), example CMYK -> KCMY | 0123 -> 3012 if (T_SWAPFIRST(Format)) { cmsUInt32Number tmp = channels[0]; for (i = 0; i < total_chans - 1; i++) channels[i] = channels[i + 1]; channels[total_chans - 1] = tmp; } // Handle size for (i = 0; i < total_chans; i++) { channels[i] *= BytesPerPlane; } for (i = 0; i < extra; i++) ComponentStartingOrder[i] = channels[i + nchannels]; }
static int WriteInputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32Number dwFlags) { cmsHPROFILE hLab; cmsHTRANSFORM xform; cmsUInt32Number nChannels; cmsUInt32Number InputFormat; int rc; cmsHPROFILE Profiles[2]; cmsCIEXYZ BlackPointAdaptedToD50; // Does create a device-link based transform. // The DeviceLink is next dumped as working CSA. InputFormat = cmsFormatterForColorspaceOfProfile(hProfile, 2, FALSE); nChannels = T_CHANNELS(InputFormat); cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, Intent, 0); // Adjust output to Lab4 hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL); Profiles[0] = hProfile; Profiles[1] = hLab; xform = cmsCreateMultiprofileTransform(Profiles, 2, InputFormat, TYPE_Lab_DBL, Intent, 0); cmsCloseProfile(hLab); if (xform == NULL) { cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Cannot create transform Profile -> Lab"); return 0; } // Only 1, 3 and 4 channels are allowed switch (nChannels) { case 1: { cmsToneCurve* Gray2Y = ExtractGray2Y(m ->ContextID, hProfile, Intent); EmitCIEBasedA(m, Gray2Y, &BlackPointAdaptedToD50); cmsFreeToneCurve(Gray2Y); } break; case 3: case 4: { cmsUInt32Number OutFrm = TYPE_Lab_16; cmsPipeline* DeviceLink; _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform; DeviceLink = cmsPipelineDup(v ->Lut); if (DeviceLink == NULL) return 0; dwFlags |= cmsFLAGS_FORCE_CLUT; _cmsOptimizePipeline(&DeviceLink, Intent, &InputFormat, &OutFrm, &dwFlags); rc = EmitCIEBasedDEF(m, DeviceLink, Intent, &BlackPointAdaptedToD50); cmsPipelineFree(DeviceLink); } break; default: cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Only 3, 4 channels supported for CSA. This profile has %d channels.", nChannels); return 0; } cmsDeleteTransform(xform); return 1; }
static int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32Number dwFlags) { cmsHPROFILE hLab; cmsHTRANSFORM xform; int i, nChannels; cmsUInt32Number OutputFormat; _cmsTRANSFORM* v; cmsPipeline* DeviceLink; cmsHPROFILE Profiles[3]; cmsCIEXYZ BlackPointAdaptedToD50; cmsBool lDoBPC = (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION); cmsBool lFixWhite = !(dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP); cmsUInt32Number InFrm = TYPE_Lab_16; int RelativeEncodingIntent; cmsColorSpaceSignature ColorSpace; hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL); if (hLab == NULL) return 0; OutputFormat = cmsFormatterForColorspaceOfProfile(hProfile, 2, FALSE); nChannels = T_CHANNELS(OutputFormat); ColorSpace = cmsGetColorSpace(hProfile); // For absolute colorimetric, the LUT is encoded as relative in order to preserve precision. RelativeEncodingIntent = Intent; if (RelativeEncodingIntent == INTENT_ABSOLUTE_COLORIMETRIC) RelativeEncodingIntent = INTENT_RELATIVE_COLORIMETRIC; // Use V4 Lab always Profiles[0] = hLab; Profiles[1] = hProfile; xform = cmsCreateMultiprofileTransformTHR(m ->ContextID, Profiles, 2, TYPE_Lab_DBL, OutputFormat, RelativeEncodingIntent, 0); cmsCloseProfile(hLab); if (xform == NULL) { cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Cannot create transform Lab -> Profile in CRD creation"); return 0; } // Get a copy of the internal devicelink v = (_cmsTRANSFORM*) xform; DeviceLink = cmsPipelineDup(v ->Lut); if (DeviceLink == NULL) return 0; // We need a CLUT dwFlags |= cmsFLAGS_FORCE_CLUT; _cmsOptimizePipeline(&DeviceLink, RelativeEncodingIntent, &InFrm, &OutputFormat, &dwFlags); _cmsIOPrintf(m, "<<\n"); _cmsIOPrintf(m, "/ColorRenderingType 1\n"); cmsDetectBlackPoint(&BlackPointAdaptedToD50, hProfile, Intent, 0); // Emit headers, etc. EmitWhiteBlackD50(m, &BlackPointAdaptedToD50); EmitPQRStage(m, hProfile, lDoBPC, Intent == INTENT_ABSOLUTE_COLORIMETRIC); EmitXYZ2Lab(m); // FIXUP: map Lab (100, 0, 0) to perfect white, because the particular encoding for Lab // does map a=b=0 not falling into any specific node. Since range a,b goes -128..127, // zero is slightly moved towards right, so assure next node (in L=100 slice) is mapped to // zero. This would sacrifice a bit of highlights, but failure to do so would cause // scum dot. Ouch. if (Intent == INTENT_ABSOLUTE_COLORIMETRIC) lFixWhite = FALSE; _cmsIOPrintf(m, "/RenderTable "); WriteCLUT(m, cmsPipelineGetPtrToFirstStage(DeviceLink), "<", ">\n", "", "", lFixWhite, ColorSpace); _cmsIOPrintf(m, " %d {} bind ", nChannels); for (i=1; i < nChannels; i++) _cmsIOPrintf(m, "dup "); _cmsIOPrintf(m, "]\n"); EmitIntent(m, Intent); _cmsIOPrintf(m, ">>\n"); if (!(dwFlags & cmsFLAGS_NODEFAULTRESOURCEDEF)) { _cmsIOPrintf(m, "/Current exch /ColorRendering defineresource pop\n"); } cmsPipelineFree(DeviceLink); cmsDeleteTransform(xform); return 1; }
static int TransformImage(TIFF* in, TIFF* out, const char *cDefInpProf, const char *cOutProf) { cmsHPROFILE hIn, hOut, hProof, hInkLimit = NULL; cmsHTRANSFORM xform; DWORD wInput, wOutput; int OutputColorSpace; int bps = (Width16 ? 2 : 1); DWORD dwFlags = 0; int nPlanes; // Observer adaptation state (only meaningful on absolute colorimetric intent) cmsSetAdaptationState(ObserverAdaptationState); if (EmbedProfile && cOutProf) DoEmbedProfile(out, cOutProf); if (BlackWhiteCompensation) dwFlags |= cmsFLAGS_WHITEBLACKCOMPENSATION; if (PreserveBlack) { dwFlags |= cmsFLAGS_PRESERVEBLACK; if (PrecalcMode == 0) PrecalcMode = 1; } switch (PrecalcMode) { case 0: dwFlags |= cmsFLAGS_NOTPRECALC; break; case 2: dwFlags |= cmsFLAGS_HIGHRESPRECALC; break; case 3: dwFlags |= cmsFLAGS_LOWRESPRECALC; break; case 1: break; default: FatalError("Unknown precalculation mode '%d'", PrecalcMode); } if (GamutCheck) dwFlags |= cmsFLAGS_GAMUTCHECK; hProof = NULL; hOut = NULL; if (lIsDeviceLink) { hIn = cmsOpenProfileFromFile(cDefInpProf, "r"); } else { hIn = GetTIFFProfile(in); if (hIn == NULL) hIn = OpenStockProfile(cDefInpProf); hOut = OpenStockProfile(cOutProf); if (cProofing != NULL) { hProof = OpenStockProfile(cProofing); dwFlags |= cmsFLAGS_SOFTPROOFING; } } // Take input color space wInput = GetInputPixelType(in); // Assure both, input profile and input TIFF are on same colorspace if (_cmsLCMScolorSpace(cmsGetColorSpace(hIn)) != (int) T_COLORSPACE(wInput)) FatalError("Input profile is not operating in proper color space"); if (!lIsDeviceLink) OutputColorSpace = _cmsLCMScolorSpace(cmsGetColorSpace(hOut)); else OutputColorSpace = _cmsLCMScolorSpace(cmsGetPCS(hIn)); wOutput = ComputeOutputFormatDescriptor(wInput, OutputColorSpace, bps); WriteOutputTags(out, OutputColorSpace, bps); CopyOtherTags(in, out); // Ink limit if (InkLimit != 400.0 && (OutputColorSpace == PT_CMYK || OutputColorSpace == PT_CMY)) { cmsHPROFILE hProfiles[10]; int nProfiles = 0; hInkLimit = cmsCreateInkLimitingDeviceLink(cmsGetColorSpace(hOut), InkLimit); hProfiles[nProfiles++] = hIn; if (hProof) { hProfiles[nProfiles++] = hProof; hProfiles[nProfiles++] = hProof; } hProfiles[nProfiles++] = hOut; hProfiles[nProfiles++] = hInkLimit; xform = cmsCreateMultiprofileTransform(hProfiles, nProfiles, wInput, wOutput, Intent, dwFlags); } else { xform = cmsCreateProofingTransform(hIn, wInput, hOut, wOutput, hProof, Intent, ProofingIntent, dwFlags); } // Planar stuff if (T_PLANAR(wInput)) nPlanes = T_CHANNELS(wInput) + T_EXTRA(wInput); else nPlanes = 1; // TIFF Lab of 8 bits need special handling if (wInput == TYPE_Lab_8 && !InputLabUsingICC && cInpProf != NULL && stricmp(cInpProf, "*Lab") == 0) { cmsSetUserFormatters(xform, TYPE_Lab_8, UnrollTIFFLab8, TYPE_Lab_8, NULL); } if (wOutput == TYPE_Lab_8 && cOutProf != NULL && stricmp(cOutProf, "*Lab") == 0) { cmsSetUserFormatters(xform, TYPE_Lab_8, NULL, TYPE_Lab_8, PackTIFFLab8); } // Handle tile by tile or strip by strip if (TIFFIsTiled(in)) { TileBasedXform(xform, in, out, nPlanes); } else { StripBasedXform(xform, in, out, nPlanes); } cmsDeleteTransform(xform); cmsCloseProfile(hIn); cmsCloseProfile(hOut); if (hInkLimit) cmsCloseProfile(hInkLimit); if (hProof) cmsCloseProfile(hProof); TIFFWriteDirectory(out); return 1; }
// Use darker colorants to obtain black point. This works in the relative colorimetric intent and // assumes more ink results in darker colors. No ink limit is assumed. static cmsBool BlackPointAsDarkerColorant(cmsHPROFILE hInput, cmsUInt32Number Intent, cmsCIEXYZ* BlackPoint, cmsUInt32Number dwFlags) { cmsUInt16Number *Black; cmsHTRANSFORM xform; cmsColorSpaceSignature Space; cmsUInt32Number nChannels; cmsUInt32Number dwFormat; cmsHPROFILE hLab; cmsCIELab Lab; cmsCIEXYZ BlackXYZ; cmsContext ContextID = cmsGetProfileContextID(hInput); // If the profile does not support input direction, assume Black point 0 if (!cmsIsIntentSupported(hInput, Intent, LCMS_USED_AS_INPUT)) { BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; return FALSE; } // Create a formatter which has n channels and floating point dwFormat = cmsFormatterForColorspaceOfProfile(hInput, 2); // Try to get black by using black colorant Space = cmsGetColorSpace(hInput); // This function returns darker colorant in 16 bits for several spaces if (!_cmsEndPointsBySpace(Space, NULL, &Black, &nChannels)) { BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; return FALSE; } if (nChannels != T_CHANNELS(dwFormat)) { BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; return FALSE; } // Lab will be used as the output space, but lab2 will avoid recursion hLab = cmsCreateLab2ProfileTHR(ContextID, NULL); if (hLab == NULL) { BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; return FALSE; } // Create the transform xform = cmsCreateTransformTHR(ContextID, hInput, dwFormat, hLab, TYPE_Lab_DBL, Intent, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_NOCACHE); cmsCloseProfile(hLab); if (xform == NULL) { // Something went wrong. Get rid of open resources and return zero as black BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0; return FALSE; } // Convert black to Lab cmsDoTransform(xform, Black, &Lab, 1); // Force it to be neutral, clip to max. L* of 50 Lab.a = Lab.b = 0; if (Lab.L > 50) Lab.L = 50; // Free the resources cmsDeleteTransform(xform); // Convert from Lab (which is now clipped) to XYZ. cmsLab2XYZ(NULL, &BlackXYZ, &Lab); if (BlackPoint != NULL) *BlackPoint = BlackXYZ; return TRUE; cmsUNUSED_PARAMETER(dwFlags); }
void gscms_get_link_dim(gcmmhlink_t link, int *num_inputs, int *num_outputs) { *num_inputs = T_CHANNELS(cmsGetTransformInputFormat(link)); *num_outputs = T_CHANNELS(cmsGetTransformOutputFormat(link)); }
/* 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 }