// 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]; }
// 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]; }
// Handles extra channels copying alpha if requested by the flags void _cmsHandleExtraChannels(_cmsTRANSFORM* p, const void* in, void* out, cmsUInt32Number PixelsPerLine, cmsUInt32Number LineCount, const cmsStride* Stride) { size_t i, j, k; cmsUInt32Number nExtra; cmsUInt32Number SourceStartingOrder[cmsMAXCHANNELS]; cmsUInt32Number SourceIncrements[cmsMAXCHANNELS]; cmsUInt32Number DestStartingOrder[cmsMAXCHANNELS]; cmsUInt32Number DestIncrements[cmsMAXCHANNELS]; cmsUInt32Number SourceStrideIncrements[cmsMAXCHANNELS]; cmsUInt32Number DestStrideIncrements[cmsMAXCHANNELS]; cmsUInt8Number* SourcePtr[cmsMAXCHANNELS]; cmsUInt8Number* DestPtr[cmsMAXCHANNELS]; cmsFormatterAlphaFn copyValueFn; // Make sure we need some copy if (!(p->dwOriginalFlags & cmsFLAGS_COPY_ALPHA)) return; // Make sure we have same number of alpha channels. If not, just reurn as this should be checked at transform creation time. nExtra = T_EXTRA(p->InputFormat); if (nExtra != T_EXTRA(p->OutputFormat)) return; // Anything to do? if (nExtra == 0) return; // Compute the increments ComputeComponentIncrements(p->InputFormat, Stride->BytesPerPlaneIn, SourceStartingOrder, SourceIncrements); ComputeComponentIncrements(p->OutputFormat, Stride->BytesPerPlaneOut, DestStartingOrder, DestIncrements); // Check for conversions 8, 16, half, float, dbl copyValueFn = _cmsGetFormatterAlpha(p->ContextID, p->InputFormat, p->OutputFormat); memset(SourceStrideIncrements, 0, sizeof(SourceStrideIncrements)); memset(DestStrideIncrements, 0, sizeof(DestStrideIncrements)); // The loop itself for (i = 0; i < LineCount; i++) { // Prepare pointers for the loop for (j = 0; j < nExtra; j++) { SourcePtr[j] = (cmsUInt8Number*)in + SourceStartingOrder[j] + SourceStrideIncrements[j]; DestPtr[j] = (cmsUInt8Number*)out + DestStartingOrder[j] + DestStrideIncrements[j]; } for (j = 0; j < PixelsPerLine; j++) { for (k = 0; k < nExtra; k++) { copyValueFn(DestPtr[k], SourcePtr[k]); SourcePtr[k] += SourceIncrements[k]; DestPtr[k] += DestIncrements[k]; } } for (j = 0; j < nExtra; j++) { SourceStrideIncrements[j] += Stride->BytesPerLineIn; DestStrideIncrements[j] += Stride->BytesPerLineOut; } } }
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; }