123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458 |
- //---------------------------------------------------------------------------------
- //
- // Little Color Management System
- // Copyright (c) 1998-2023 Marti Maria Saguer
- //
- // Permission is hereby granted, free of charge, to any person obtaining
- // a copy of this software and associated documentation files (the "Software"),
- // to deal in the Software without restriction, including without limitation
- // the rights to use, copy, modify, merge, publish, distribute, sublicense,
- // and/or sell copies of the Software, and to permit persons to whom the Software
- // is furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
- // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- //
- //---------------------------------------------------------------------------------
- //
- #include "lcms2_internal.h"
- // Transformations stuff
- // -----------------------------------------------------------------------
- #define DEFAULT_OBSERVER_ADAPTATION_STATE 1.0
- // The Context0 observer adaptation state.
- _cmsAdaptationStateChunkType _cmsAdaptationStateChunk = { DEFAULT_OBSERVER_ADAPTATION_STATE };
- // Init and duplicate observer adaptation state
- void _cmsAllocAdaptationStateChunk(struct _cmsContext_struct* ctx,
- const struct _cmsContext_struct* src)
- {
- static _cmsAdaptationStateChunkType AdaptationStateChunk = { DEFAULT_OBSERVER_ADAPTATION_STATE };
- void* from;
-
- if (src != NULL) {
- from = src ->chunks[AdaptationStateContext];
- }
- else {
- from = &AdaptationStateChunk;
- }
-
- ctx ->chunks[AdaptationStateContext] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsAdaptationStateChunkType));
- }
- // Sets adaptation state for absolute colorimetric intent in the given context. Adaptation state applies on all
- // but cmsCreateExtendedTransformTHR(). Little CMS can handle incomplete adaptation states.
- cmsFloat64Number CMSEXPORT cmsSetAdaptationStateTHR(cmsContext ContextID, cmsFloat64Number d)
- {
- cmsFloat64Number prev;
- _cmsAdaptationStateChunkType* ptr = (_cmsAdaptationStateChunkType*) _cmsContextGetClientChunk(ContextID, AdaptationStateContext);
- // Get previous value for return
- prev = ptr ->AdaptationState;
- // Set the value if d is positive or zero
- if (d >= 0.0) {
- ptr ->AdaptationState = d;
- }
- // Always return previous value
- return prev;
- }
- // The adaptation state may be defaulted by this function. If you don't like it, use the extended transform routine
- cmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d)
- {
- return cmsSetAdaptationStateTHR(NULL, d);
- }
- // -----------------------------------------------------------------------
- // Alarm codes for 16-bit transformations, because the fixed range of containers there are
- // no values left to mark out of gamut.
- #define DEFAULT_ALARM_CODES_VALUE {0x7F00, 0x7F00, 0x7F00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
- _cmsAlarmCodesChunkType _cmsAlarmCodesChunk = { DEFAULT_ALARM_CODES_VALUE };
- // Sets the codes used to mark out-out-gamut on Proofing transforms for a given context. Values are meant to be
- // encoded in 16 bits.
- void CMSEXPORT cmsSetAlarmCodesTHR(cmsContext ContextID, const cmsUInt16Number AlarmCodesP[cmsMAXCHANNELS])
- {
- _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(ContextID, AlarmCodesContext);
-
- _cmsAssert(ContextAlarmCodes != NULL); // Can't happen
-
- memcpy(ContextAlarmCodes->AlarmCodes, AlarmCodesP, sizeof(ContextAlarmCodes->AlarmCodes));
- }
- // Gets the current codes used to mark out-out-gamut on Proofing transforms for the given context.
- // Values are meant to be encoded in 16 bits.
- void CMSEXPORT cmsGetAlarmCodesTHR(cmsContext ContextID, cmsUInt16Number AlarmCodesP[cmsMAXCHANNELS])
- {
- _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(ContextID, AlarmCodesContext);
- _cmsAssert(ContextAlarmCodes != NULL); // Can't happen
- memcpy(AlarmCodesP, ContextAlarmCodes->AlarmCodes, sizeof(ContextAlarmCodes->AlarmCodes));
- }
- void CMSEXPORT cmsSetAlarmCodes(const cmsUInt16Number NewAlarm[cmsMAXCHANNELS])
- {
- _cmsAssert(NewAlarm != NULL);
- cmsSetAlarmCodesTHR(NULL, NewAlarm);
- }
- void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number OldAlarm[cmsMAXCHANNELS])
- {
- _cmsAssert(OldAlarm != NULL);
- cmsGetAlarmCodesTHR(NULL, OldAlarm);
- }
- // Init and duplicate alarm codes
- void _cmsAllocAlarmCodesChunk(struct _cmsContext_struct* ctx,
- const struct _cmsContext_struct* src)
- {
- static _cmsAlarmCodesChunkType AlarmCodesChunk = { DEFAULT_ALARM_CODES_VALUE };
- void* from;
-
- if (src != NULL) {
- from = src ->chunks[AlarmCodesContext];
- }
- else {
- from = &AlarmCodesChunk;
- }
-
- ctx ->chunks[AlarmCodesContext] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsAlarmCodesChunkType));
- }
- // -----------------------------------------------------------------------
- // Get rid of transform resources
- void CMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform)
- {
- _cmsTRANSFORM* p = (_cmsTRANSFORM*) hTransform;
- _cmsAssert(p != NULL);
- if (p -> GamutCheck)
- cmsPipelineFree(p -> GamutCheck);
- if (p -> Lut)
- cmsPipelineFree(p -> Lut);
- if (p ->InputColorant)
- cmsFreeNamedColorList(p ->InputColorant);
- if (p -> OutputColorant)
- cmsFreeNamedColorList(p ->OutputColorant);
- if (p ->Sequence)
- cmsFreeProfileSequenceDescription(p ->Sequence);
- if (p ->UserData)
- p ->FreeUserData(p ->ContextID, p ->UserData);
- _cmsFree(p ->ContextID, (void *) p);
- }
- static
- cmsUInt32Number PixelSize(cmsUInt32Number Format)
- {
- cmsUInt32Number fmt_bytes = T_BYTES(Format);
- // For double, the T_BYTES field is zero
- if (fmt_bytes == 0)
- return sizeof(cmsUInt64Number);
- // Otherwise, it is already correct for all formats
- return fmt_bytes;
- }
- // Apply transform.
- void CMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform,
- const void* InputBuffer,
- void* OutputBuffer,
- cmsUInt32Number Size)
- {
- _cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform;
- cmsStride stride;
- stride.BytesPerLineIn = 0; // Not used
- stride.BytesPerLineOut = 0;
- stride.BytesPerPlaneIn = Size * PixelSize(p->InputFormat);
- stride.BytesPerPlaneOut = Size * PixelSize(p->OutputFormat);
-
- p -> xform(p, InputBuffer, OutputBuffer, Size, 1, &stride);
- }
- // This is a legacy stride for planar
- void CMSEXPORT cmsDoTransformStride(cmsHTRANSFORM Transform,
- const void* InputBuffer,
- void* OutputBuffer,
- cmsUInt32Number Size, cmsUInt32Number Stride)
- {
- _cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform;
- cmsStride stride;
- stride.BytesPerLineIn = 0;
- stride.BytesPerLineOut = 0;
- stride.BytesPerPlaneIn = Stride;
- stride.BytesPerPlaneOut = Stride;
- p -> xform(p, InputBuffer, OutputBuffer, Size, 1, &stride);
- }
- // This is the "fast" function for plugins
- void CMSEXPORT cmsDoTransformLineStride(cmsHTRANSFORM Transform,
- const void* InputBuffer,
- void* OutputBuffer,
- cmsUInt32Number PixelsPerLine,
- cmsUInt32Number LineCount,
- cmsUInt32Number BytesPerLineIn,
- cmsUInt32Number BytesPerLineOut,
- cmsUInt32Number BytesPerPlaneIn,
- cmsUInt32Number BytesPerPlaneOut)
- {
- _cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform;
- cmsStride stride;
- stride.BytesPerLineIn = BytesPerLineIn;
- stride.BytesPerLineOut = BytesPerLineOut;
- stride.BytesPerPlaneIn = BytesPerPlaneIn;
- stride.BytesPerPlaneOut = BytesPerPlaneOut;
- p->xform(p, InputBuffer, OutputBuffer, PixelsPerLine, LineCount, &stride);
- }
- // Transform routines ----------------------------------------------------------------------------------------------------------
- // Float xform converts floats. Since there are no performance issues, one routine does all job, including gamut check.
- // Note that because extended range, we can use a -1.0 value for out of gamut in this case.
- static
- void FloatXFORM(_cmsTRANSFORM* p,
- const void* in,
- void* out,
- cmsUInt32Number PixelsPerLine,
- cmsUInt32Number LineCount,
- const cmsStride* Stride)
- {
- cmsUInt8Number* accum;
- cmsUInt8Number* output;
- cmsFloat32Number fIn[cmsMAXCHANNELS], fOut[cmsMAXCHANNELS];
- cmsFloat32Number OutOfGamut;
- cmsUInt32Number i, j, c, strideIn, strideOut;
- _cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride);
- strideIn = 0;
- strideOut = 0;
- memset(fIn, 0, sizeof(fIn));
- memset(fOut, 0, sizeof(fOut));
- for (i = 0; i < LineCount; i++) {
- accum = (cmsUInt8Number*)in + strideIn;
- output = (cmsUInt8Number*)out + strideOut;
- for (j = 0; j < PixelsPerLine; j++) {
- accum = p->FromInputFloat(p, fIn, accum, Stride->BytesPerPlaneIn);
- // Any gamut check to do?
- if (p->GamutCheck != NULL) {
- // Evaluate gamut marker.
- cmsPipelineEvalFloat(fIn, &OutOfGamut, p->GamutCheck);
- // Is current color out of gamut?
- if (OutOfGamut > 0.0) {
- // Certainly, out of gamut
- for (c = 0; c < cmsMAXCHANNELS; c++)
- fOut[c] = -1.0;
- }
- else {
- // No, proceed normally
- cmsPipelineEvalFloat(fIn, fOut, p->Lut);
- }
- }
- else {
- // No gamut check at all
- cmsPipelineEvalFloat(fIn, fOut, p->Lut);
- }
- output = p->ToOutputFloat(p, fOut, output, Stride->BytesPerPlaneOut);
- }
- strideIn += Stride->BytesPerLineIn;
- strideOut += Stride->BytesPerLineOut;
- }
- }
- static
- void NullFloatXFORM(_cmsTRANSFORM* p,
- const void* in,
- void* out,
- cmsUInt32Number PixelsPerLine,
- cmsUInt32Number LineCount,
- const cmsStride* Stride)
- {
- cmsUInt8Number* accum;
- cmsUInt8Number* output;
- cmsFloat32Number fIn[cmsMAXCHANNELS];
- cmsUInt32Number i, j, strideIn, strideOut;
- _cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride);
- strideIn = 0;
- strideOut = 0;
- memset(fIn, 0, sizeof(fIn));
- for (i = 0; i < LineCount; i++) {
- accum = (cmsUInt8Number*) in + strideIn;
- output = (cmsUInt8Number*) out + strideOut;
- for (j = 0; j < PixelsPerLine; j++) {
- accum = p->FromInputFloat(p, fIn, accum, Stride ->BytesPerPlaneIn);
- output = p->ToOutputFloat(p, fIn, output, Stride->BytesPerPlaneOut);
- }
- strideIn += Stride->BytesPerLineIn;
- strideOut += Stride->BytesPerLineOut;
- }
- }
- // 16 bit precision -----------------------------------------------------------------------------------------------------------
- // Null transformation, only applies formatters. No cache
- static
- void NullXFORM(_cmsTRANSFORM* p,
- const void* in,
- void* out,
- cmsUInt32Number PixelsPerLine,
- cmsUInt32Number LineCount,
- const cmsStride* Stride)
- {
- cmsUInt8Number* accum;
- cmsUInt8Number* output;
- cmsUInt16Number wIn[cmsMAXCHANNELS];
- cmsUInt32Number i, j, strideIn, strideOut;
- _cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride);
- strideIn = 0;
- strideOut = 0;
- memset(wIn, 0, sizeof(wIn));
- for (i = 0; i < LineCount; i++) {
- accum = (cmsUInt8Number*)in + strideIn;
- output = (cmsUInt8Number*)out + strideOut;
- for (j = 0; j < PixelsPerLine; j++) {
- accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn);
- output = p->ToOutput(p, wIn, output, Stride->BytesPerPlaneOut);
- }
- strideIn += Stride->BytesPerLineIn;
- strideOut += Stride->BytesPerLineOut;
- }
- }
- // No gamut check, no cache, 16 bits
- static
- void PrecalculatedXFORM(_cmsTRANSFORM* p,
- const void* in,
- void* out,
- cmsUInt32Number PixelsPerLine,
- cmsUInt32Number LineCount,
- const cmsStride* Stride)
- {
- CMSREGISTER cmsUInt8Number* accum;
- CMSREGISTER cmsUInt8Number* output;
- cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
- cmsUInt32Number i, j, strideIn, strideOut;
- _cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride);
- strideIn = 0;
- strideOut = 0;
- memset(wIn, 0, sizeof(wIn));
- memset(wOut, 0, sizeof(wOut));
- for (i = 0; i < LineCount; i++) {
- accum = (cmsUInt8Number*)in + strideIn;
- output = (cmsUInt8Number*)out + strideOut;
- for (j = 0; j < PixelsPerLine; j++) {
- accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn);
- p->Lut->Eval16Fn(wIn, wOut, p->Lut->Data);
- output = p->ToOutput(p, wOut, output, Stride->BytesPerPlaneOut);
- }
- strideIn += Stride->BytesPerLineIn;
- strideOut += Stride->BytesPerLineOut;
- }
- }
- // Auxiliary: Handle precalculated gamut check. The retrieval of context may be alittle bit slow, but this function is not critical.
- static
- void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p,
- const cmsUInt16Number wIn[],
- cmsUInt16Number wOut[])
- {
- cmsUInt16Number wOutOfGamut;
- p ->GamutCheck ->Eval16Fn(wIn, &wOutOfGamut, p ->GamutCheck ->Data);
- if (wOutOfGamut >= 1) {
- cmsUInt32Number i;
- _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(p->ContextID, AlarmCodesContext);
- for (i=0; i < p ->Lut->OutputChannels; i++) {
- wOut[i] = ContextAlarmCodes ->AlarmCodes[i];
- }
- }
- else
- p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
- }
- // Gamut check, No cache, 16 bits.
- static
- void PrecalculatedXFORMGamutCheck(_cmsTRANSFORM* p,
- const void* in,
- void* out,
- cmsUInt32Number PixelsPerLine,
- cmsUInt32Number LineCount,
- const cmsStride* Stride)
- {
- cmsUInt8Number* accum;
- cmsUInt8Number* output;
- cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
- cmsUInt32Number i, j, strideIn, strideOut;
- _cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride);
- strideIn = 0;
- strideOut = 0;
- memset(wIn, 0, sizeof(wIn));
- memset(wOut, 0, sizeof(wOut));
- for (i = 0; i < LineCount; i++) {
- accum = (cmsUInt8Number*)in + strideIn;
- output = (cmsUInt8Number*)out + strideOut;
- for (j = 0; j < PixelsPerLine; j++) {
- accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn);
- TransformOnePixelWithGamutCheck(p, wIn, wOut);
- output = p->ToOutput(p, wOut, output, Stride->BytesPerPlaneOut);
- }
- strideIn += Stride->BytesPerLineIn;
- strideOut += Stride->BytesPerLineOut;
- }
- }
- // No gamut check, Cache, 16 bits,
- static
- void CachedXFORM(_cmsTRANSFORM* p,
- const void* in,
- void* out,
- cmsUInt32Number PixelsPerLine,
- cmsUInt32Number LineCount,
- const cmsStride* Stride)
- {
- cmsUInt8Number* accum;
- cmsUInt8Number* output;
- cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
- _cmsCACHE Cache;
- cmsUInt32Number i, j, strideIn, strideOut;
- _cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride);
- // Empty buffers for quick memcmp
- memset(wIn, 0, sizeof(wIn));
- memset(wOut, 0, sizeof(wOut));
- // Get copy of zero cache
- memcpy(&Cache, &p->Cache, sizeof(Cache));
- strideIn = 0;
- strideOut = 0;
- for (i = 0; i < LineCount; i++) {
- accum = (cmsUInt8Number*)in + strideIn;
- output = (cmsUInt8Number*)out + strideOut;
- for (j = 0; j < PixelsPerLine; j++) {
- accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn);
- if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) {
- memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut));
- }
- else {
- p->Lut->Eval16Fn(wIn, wOut, p->Lut->Data);
- memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn));
- memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut));
- }
- output = p->ToOutput(p, wOut, output, Stride->BytesPerPlaneOut);
- }
- strideIn += Stride->BytesPerLineIn;
- strideOut += Stride->BytesPerLineOut;
- }
- }
- // All those nice features together
- static
- void CachedXFORMGamutCheck(_cmsTRANSFORM* p,
- const void* in,
- void* out,
- cmsUInt32Number PixelsPerLine,
- cmsUInt32Number LineCount,
- const cmsStride* Stride)
- {
- cmsUInt8Number* accum;
- cmsUInt8Number* output;
- cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
- _cmsCACHE Cache;
- cmsUInt32Number i, j, strideIn, strideOut;
- _cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride);
- // Empty buffers for quick memcmp
- memset(wIn, 0, sizeof(wIn));
- memset(wOut, 0, sizeof(wOut));
- // Get copy of zero cache
- memcpy(&Cache, &p->Cache, sizeof(Cache));
- strideIn = 0;
- strideOut = 0;
- for (i = 0; i < LineCount; i++) {
- accum = (cmsUInt8Number*)in + strideIn;
- output = (cmsUInt8Number*)out + strideOut;
- for (j = 0; j < PixelsPerLine; j++) {
- accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn);
- if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) {
- memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut));
- }
- else {
- TransformOnePixelWithGamutCheck(p, wIn, wOut);
- memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn));
- memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut));
- }
- output = p->ToOutput(p, wOut, output, Stride->BytesPerPlaneOut);
- }
- strideIn += Stride->BytesPerLineIn;
- strideOut += Stride->BytesPerLineOut;
- }
- }
- // Transform plug-ins ----------------------------------------------------------------------------------------------------
- // List of used-defined transform factories
- typedef struct _cmsTransformCollection_st {
- _cmsTransform2Factory Factory;
- cmsBool OldXform; // Factory returns xform function in the old style
- struct _cmsTransformCollection_st *Next;
- } _cmsTransformCollection;
- // The linked list head
- _cmsTransformPluginChunkType _cmsTransformPluginChunk = { NULL };
- // Duplicates the zone of memory used by the plug-in in the new context
- static
- void DupPluginTransformList(struct _cmsContext_struct* ctx,
- const struct _cmsContext_struct* src)
- {
- _cmsTransformPluginChunkType newHead = { NULL };
- _cmsTransformCollection* entry;
- _cmsTransformCollection* Anterior = NULL;
- _cmsTransformPluginChunkType* head = (_cmsTransformPluginChunkType*) src->chunks[TransformPlugin];
- // Walk the list copying all nodes
- for (entry = head->TransformCollection;
- entry != NULL;
- entry = entry ->Next) {
- _cmsTransformCollection *newEntry = ( _cmsTransformCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTransformCollection));
-
- if (newEntry == NULL)
- return;
- // We want to keep the linked list order, so this is a little bit tricky
- newEntry -> Next = NULL;
- if (Anterior)
- Anterior -> Next = newEntry;
-
- Anterior = newEntry;
- if (newHead.TransformCollection == NULL)
- newHead.TransformCollection = newEntry;
- }
- ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTransformPluginChunkType));
- }
- // Allocates memory for transform plugin factory
- void _cmsAllocTransformPluginChunk(struct _cmsContext_struct* ctx,
- const struct _cmsContext_struct* src)
- {
- if (src != NULL) {
- // Copy all linked list
- DupPluginTransformList(ctx, src);
- }
- else {
- static _cmsTransformPluginChunkType TransformPluginChunkType = { NULL };
- ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TransformPluginChunkType, sizeof(_cmsTransformPluginChunkType));
- }
- }
- // Adaptor for old versions of plug-in
- static
- void _cmsTransform2toTransformAdaptor(struct _cmstransform_struct *CMMcargo,
- const void* InputBuffer,
- void* OutputBuffer,
- cmsUInt32Number PixelsPerLine,
- cmsUInt32Number LineCount,
- const cmsStride* Stride)
- {
-
- cmsUInt32Number i, strideIn, strideOut;
- _cmsHandleExtraChannels(CMMcargo, InputBuffer, OutputBuffer, PixelsPerLine, LineCount, Stride);
- strideIn = 0;
- strideOut = 0;
- for (i = 0; i < LineCount; i++) {
- void *accum = (cmsUInt8Number*)InputBuffer + strideIn;
- void *output = (cmsUInt8Number*)OutputBuffer + strideOut;
- CMMcargo->OldXform(CMMcargo, accum, output, PixelsPerLine, Stride->BytesPerPlaneIn);
- strideIn += Stride->BytesPerLineIn;
- strideOut += Stride->BytesPerLineOut;
- }
- }
- // Register new ways to transform
- cmsBool _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Data)
- {
- cmsPluginTransform* Plugin = (cmsPluginTransform*) Data;
- _cmsTransformCollection* fl;
- _cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID,TransformPlugin);
- if (Data == NULL) {
- // Free the chain. Memory is safely freed at exit
- ctx->TransformCollection = NULL;
- return TRUE;
- }
- // Factory callback is required
- if (Plugin->factories.xform == NULL) return FALSE;
- fl = (_cmsTransformCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsTransformCollection));
- if (fl == NULL) return FALSE;
- // Check for full xform plug-ins previous to 2.8, we would need an adapter in that case
- if (Plugin->base.ExpectedVersion < 2080) {
- fl->OldXform = TRUE;
- }
- else
- fl->OldXform = FALSE;
- // Copy the parameters
- fl->Factory = Plugin->factories.xform;
- // Keep linked list
- fl ->Next = ctx->TransformCollection;
- ctx->TransformCollection = fl;
- // All is ok
- return TRUE;
- }
- void CMSEXPORT _cmsSetTransformUserData(struct _cmstransform_struct *CMMcargo, void* ptr, _cmsFreeUserDataFn FreePrivateDataFn)
- {
- _cmsAssert(CMMcargo != NULL);
- CMMcargo ->UserData = ptr;
- CMMcargo ->FreeUserData = FreePrivateDataFn;
- }
- // returns the pointer defined by the plug-in to store private data
- void * CMSEXPORT _cmsGetTransformUserData(struct _cmstransform_struct *CMMcargo)
- {
- _cmsAssert(CMMcargo != NULL);
- return CMMcargo ->UserData;
- }
- // returns the current formatters
- void CMSEXPORT _cmsGetTransformFormatters16(struct _cmstransform_struct *CMMcargo, cmsFormatter16* FromInput, cmsFormatter16* ToOutput)
- {
- _cmsAssert(CMMcargo != NULL);
- if (FromInput) *FromInput = CMMcargo ->FromInput;
- if (ToOutput) *ToOutput = CMMcargo ->ToOutput;
- }
- void CMSEXPORT _cmsGetTransformFormattersFloat(struct _cmstransform_struct *CMMcargo, cmsFormatterFloat* FromInput, cmsFormatterFloat* ToOutput)
- {
- _cmsAssert(CMMcargo != NULL);
- if (FromInput) *FromInput = CMMcargo ->FromInputFloat;
- if (ToOutput) *ToOutput = CMMcargo ->ToOutputFloat;
- }
- // returns original flags
- cmsUInt32Number CMSEXPORT _cmsGetTransformFlags(struct _cmstransform_struct* CMMcargo)
- {
- _cmsAssert(CMMcargo != NULL);
- return CMMcargo->dwOriginalFlags;
- }
- // Returns the worker callback for parallelization plug-ins
- _cmsTransform2Fn CMSEXPORT _cmsGetTransformWorker(struct _cmstransform_struct* CMMcargo)
- {
- _cmsAssert(CMMcargo != NULL);
- return CMMcargo->Worker;
- }
- // This field holds maximum number of workers or -1 to auto
- cmsInt32Number CMSEXPORT _cmsGetTransformMaxWorkers(struct _cmstransform_struct* CMMcargo)
- {
- _cmsAssert(CMMcargo != NULL);
- return CMMcargo->MaxWorkers;
- }
- // This field is actually unused and reserved
- cmsUInt32Number CMSEXPORT _cmsGetTransformWorkerFlags(struct _cmstransform_struct* CMMcargo)
- {
- _cmsAssert(CMMcargo != NULL);
- return CMMcargo->WorkerFlags;
- }
- // In the case there is a parallelization plug-in, let it to do its job
- static
- void ParalellizeIfSuitable(_cmsTRANSFORM* p)
- {
- _cmsParallelizationPluginChunkType* ctx = (_cmsParallelizationPluginChunkType*)_cmsContextGetClientChunk(p->ContextID, ParallelizationPlugin);
- _cmsAssert(p != NULL);
- if (ctx != NULL && ctx->SchedulerFn != NULL) {
- p->Worker = p->xform;
- p->xform = ctx->SchedulerFn;
- p->MaxWorkers = ctx->MaxWorkers;
- p->WorkerFlags = ctx->WorkerFlags;
- }
- }
- /**
- * An empty unroll to avoid a check with NULL on cmsDoTransform()
- */
- static
- cmsUInt8Number* UnrollNothing(CMSREGISTER _cmsTRANSFORM* info,
- CMSREGISTER cmsUInt16Number wIn[],
- CMSREGISTER cmsUInt8Number* accum,
- CMSREGISTER cmsUInt32Number Stride)
- {
- return accum;
- cmsUNUSED_PARAMETER(info);
- cmsUNUSED_PARAMETER(wIn);
- cmsUNUSED_PARAMETER(Stride);
- }
- static
- cmsUInt8Number* PackNothing(CMSREGISTER _cmsTRANSFORM* info,
- CMSREGISTER cmsUInt16Number wOut[],
- CMSREGISTER cmsUInt8Number* output,
- CMSREGISTER cmsUInt32Number Stride)
- {
- return output;
- cmsUNUSED_PARAMETER(info);
- cmsUNUSED_PARAMETER(wOut);
- cmsUNUSED_PARAMETER(Stride);
- }
- // Allocate transform struct and set it to defaults. Ask the optimization plug-in about if those formats are proper
- // for separated transforms. If this is the case,
- static
- _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
- cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags)
- {
- _cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID, TransformPlugin);
- _cmsTransformCollection* Plugin;
- // Allocate needed memory
- _cmsTRANSFORM* p = (_cmsTRANSFORM*)_cmsMallocZero(ContextID, sizeof(_cmsTRANSFORM));
- if (!p) {
- cmsPipelineFree(lut);
- return NULL;
- }
- // Store the proposed pipeline
- p->Lut = lut;
- // Let's see if any plug-in want to do the transform by itself
- if (p->Lut != NULL) {
- if (!(*dwFlags & cmsFLAGS_NOOPTIMIZE))
- {
- for (Plugin = ctx->TransformCollection;
- Plugin != NULL;
- Plugin = Plugin->Next) {
- if (Plugin->Factory(&p->xform, &p->UserData, &p->FreeUserData, &p->Lut, InputFormat, OutputFormat, dwFlags)) {
- // Last plugin in the declaration order takes control. We just keep
- // the original parameters as a logging.
- // Note that cmsFLAGS_CAN_CHANGE_FORMATTER is not set, so by default
- // an optimized transform is not reusable. The plug-in can, however, change
- // the flags and make it suitable.
- p->ContextID = ContextID;
- p->InputFormat = *InputFormat;
- p->OutputFormat = *OutputFormat;
- p->dwOriginalFlags = *dwFlags;
- // Fill the formatters just in case the optimized routine is interested.
- // No error is thrown if the formatter doesn't exist. It is up to the optimization
- // factory to decide what to do in those cases.
- p->FromInput = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
- p->ToOutput = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
- p->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
- p->ToOutputFloat = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
- // Save the day? (Ignore the warning)
- if (Plugin->OldXform) {
- p->OldXform = (_cmsTransformFn)(void*)p->xform;
- p->xform = _cmsTransform2toTransformAdaptor;
- }
- ParalellizeIfSuitable(p);
- return p;
- }
- }
- }
- // Not suitable for the transform plug-in, let's check the pipeline plug-in
- _cmsOptimizePipeline(ContextID, &p->Lut, Intent, InputFormat, OutputFormat, dwFlags);
- }
- // Check whatever this is a true floating point transform
- if (_cmsFormatterIsFloat(*InputFormat) || _cmsFormatterIsFloat(*OutputFormat)) {
- // Get formatter function always return a valid union, but the contents of this union may be NULL.
- p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
- p ->ToOutputFloat = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
- *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
- if (p ->FromInputFloat == NULL || p ->ToOutputFloat == NULL) {
- cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
- cmsDeleteTransform(p);
- return NULL;
- }
- if (*dwFlags & cmsFLAGS_NULLTRANSFORM) {
- p ->xform = NullFloatXFORM;
- }
- else {
- // Float transforms don't use cache, always are non-NULL
- p ->xform = FloatXFORM;
- }
- }
- else {
- // Formats are intended to be changed before use
- if (*InputFormat == 0 && *OutputFormat == 0) {
- p->FromInput = UnrollNothing;
- p->ToOutput = PackNothing;
- *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
- }
- else {
- cmsUInt32Number BytesPerPixelInput;
- p ->FromInput = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
- p ->ToOutput = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
- if (p ->FromInput == NULL || p ->ToOutput == NULL) {
- cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
- cmsDeleteTransform(p);
- return NULL;
- }
- BytesPerPixelInput = T_BYTES(*InputFormat);
- if (BytesPerPixelInput == 0 || BytesPerPixelInput >= 2)
- *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
- }
- if (*dwFlags & cmsFLAGS_NULLTRANSFORM) {
- p ->xform = NullXFORM;
- }
- else {
- if (*dwFlags & cmsFLAGS_NOCACHE) {
- if (*dwFlags & cmsFLAGS_GAMUTCHECK)
- p ->xform = PrecalculatedXFORMGamutCheck; // Gamut check, no cache
- else
- p ->xform = PrecalculatedXFORM; // No cache, no gamut check
- }
- else {
- if (*dwFlags & cmsFLAGS_GAMUTCHECK)
- p ->xform = CachedXFORMGamutCheck; // Gamut check, cache
- else
- p ->xform = CachedXFORM; // No gamut check, cache
- }
- }
- }
- /**
- * Check consistency for alpha channel copy
- */
- if (*dwFlags & cmsFLAGS_COPY_ALPHA)
- {
- if (T_EXTRA(*InputFormat) != T_EXTRA(*OutputFormat))
- {
- cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Mismatched alpha channels");
- cmsDeleteTransform(p);
- return NULL;
- }
- }
- p ->InputFormat = *InputFormat;
- p ->OutputFormat = *OutputFormat;
- p ->dwOriginalFlags = *dwFlags;
- p ->ContextID = ContextID;
- p ->UserData = NULL;
- ParalellizeIfSuitable(p);
- return p;
- }
- static
- cmsBool GetXFormColorSpaces(cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[], cmsColorSpaceSignature* Input, cmsColorSpaceSignature* Output)
- {
- cmsColorSpaceSignature ColorSpaceIn, ColorSpaceOut;
- cmsColorSpaceSignature PostColorSpace;
- cmsUInt32Number i;
- if (nProfiles == 0) return FALSE;
- if (hProfiles[0] == NULL) return FALSE;
- *Input = PostColorSpace = cmsGetColorSpace(hProfiles[0]);
- for (i=0; i < nProfiles; i++) {
- cmsProfileClassSignature cls;
- cmsHPROFILE hProfile = hProfiles[i];
- int lIsInput = (PostColorSpace != cmsSigXYZData) &&
- (PostColorSpace != cmsSigLabData);
- if (hProfile == NULL) return FALSE;
- cls = cmsGetDeviceClass(hProfile);
- if (cls == cmsSigNamedColorClass) {
- ColorSpaceIn = cmsSig1colorData;
- ColorSpaceOut = (nProfiles > 1) ? cmsGetPCS(hProfile) : cmsGetColorSpace(hProfile);
- }
- else
- if (lIsInput || (cls == cmsSigLinkClass)) {
- ColorSpaceIn = cmsGetColorSpace(hProfile);
- ColorSpaceOut = cmsGetPCS(hProfile);
- }
- else
- {
- ColorSpaceIn = cmsGetPCS(hProfile);
- ColorSpaceOut = cmsGetColorSpace(hProfile);
- }
- if (i==0)
- *Input = ColorSpaceIn;
- PostColorSpace = ColorSpaceOut;
- }
- *Output = PostColorSpace;
- return TRUE;
- }
- // Check colorspace
- static
- cmsBool IsProperColorSpace(cmsColorSpaceSignature Check, cmsUInt32Number dwFormat)
- {
- int Space1 = (int) T_COLORSPACE(dwFormat);
- int Space2 = _cmsLCMScolorSpace(Check);
- if (Space1 == PT_ANY) return TRUE;
- if (Space1 == Space2) return TRUE;
- if (Space1 == PT_LabV2 && Space2 == PT_Lab) return TRUE;
- if (Space1 == PT_Lab && Space2 == PT_LabV2) return TRUE;
- return FALSE;
- }
- // ----------------------------------------------------------------------------------------------------------------
- // Jun-21-2000: Some profiles (those that comes with W2K) comes
- // with the media white (media black?) x 100. Add a sanity check
- static
- void NormalizeXYZ(cmsCIEXYZ* Dest)
- {
- while (Dest -> X > 2. &&
- Dest -> Y > 2. &&
- Dest -> Z > 2.) {
- Dest -> X /= 10.;
- Dest -> Y /= 10.;
- Dest -> Z /= 10.;
- }
- }
- static
- void SetWhitePoint(cmsCIEXYZ* wtPt, const cmsCIEXYZ* src)
- {
- if (src == NULL) {
- wtPt ->X = cmsD50X;
- wtPt ->Y = cmsD50Y;
- wtPt ->Z = cmsD50Z;
- }
- else {
- wtPt ->X = src->X;
- wtPt ->Y = src->Y;
- wtPt ->Z = src->Z;
- NormalizeXYZ(wtPt);
- }
- }
- // New to lcms 2.0 -- have all parameters available.
- cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,
- cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[],
- cmsBool BPC[],
- cmsUInt32Number Intents[],
- cmsFloat64Number AdaptationStates[],
- cmsHPROFILE hGamutProfile,
- cmsUInt32Number nGamutPCSposition,
- cmsUInt32Number InputFormat,
- cmsUInt32Number OutputFormat,
- cmsUInt32Number dwFlags)
- {
- _cmsTRANSFORM* xform;
- cmsColorSpaceSignature EntryColorSpace;
- cmsColorSpaceSignature ExitColorSpace;
- cmsPipeline* Lut;
- cmsUInt32Number LastIntent = Intents[nProfiles-1];
- // If it is a fake transform
- if (dwFlags & cmsFLAGS_NULLTRANSFORM)
- {
- return AllocEmptyTransform(ContextID, NULL, INTENT_PERCEPTUAL, &InputFormat, &OutputFormat, &dwFlags);
- }
- // If gamut check is requested, make sure we have a gamut profile
- if (dwFlags & cmsFLAGS_GAMUTCHECK) {
- if (hGamutProfile == NULL) dwFlags &= ~cmsFLAGS_GAMUTCHECK;
- }
- // On floating point transforms, inhibit cache
- if (_cmsFormatterIsFloat(InputFormat) || _cmsFormatterIsFloat(OutputFormat))
- dwFlags |= cmsFLAGS_NOCACHE;
- // Mark entry/exit spaces
- if (!GetXFormColorSpaces(nProfiles, hProfiles, &EntryColorSpace, &ExitColorSpace)) {
- cmsSignalError(ContextID, cmsERROR_NULL, "NULL input profiles on transform");
- return NULL;
- }
- // Check if proper colorspaces
- if (!IsProperColorSpace(EntryColorSpace, InputFormat)) {
- cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong input color space on transform");
- return NULL;
- }
- if (!IsProperColorSpace(ExitColorSpace, OutputFormat)) {
- cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong output color space on transform");
- return NULL;
- }
- // Check whatever the transform is 16 bits and involves linear RGB in first profile. If so, disable optimizations
- if (EntryColorSpace == cmsSigRgbData && T_BYTES(InputFormat) == 2 && !(dwFlags & cmsFLAGS_NOOPTIMIZE))
- {
- cmsFloat64Number gamma = cmsDetectRGBProfileGamma(hProfiles[0], 0.1);
- if (gamma > 0 && gamma < 1.6)
- dwFlags |= cmsFLAGS_NOOPTIMIZE;
- }
- // Create a pipeline with all transformations
- Lut = _cmsLinkProfiles(ContextID, nProfiles, Intents, hProfiles, BPC, AdaptationStates, dwFlags);
- if (Lut == NULL) {
- cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Couldn't link the profiles");
- return NULL;
- }
- // Check channel count
- if ((cmsChannelsOfColorSpace(EntryColorSpace) != (cmsInt32Number) cmsPipelineInputChannels(Lut)) ||
- (cmsChannelsOfColorSpace(ExitColorSpace) != (cmsInt32Number) cmsPipelineOutputChannels(Lut))) {
- cmsPipelineFree(Lut);
- cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Channel count doesn't match. Profile is corrupted");
- return NULL;
- }
- // All seems ok
- xform = AllocEmptyTransform(ContextID, Lut, LastIntent, &InputFormat, &OutputFormat, &dwFlags);
- if (xform == NULL) {
- return NULL;
- }
- // Keep values
- xform ->EntryColorSpace = EntryColorSpace;
- xform ->ExitColorSpace = ExitColorSpace;
- xform ->RenderingIntent = Intents[nProfiles-1];
- // Take white points
- SetWhitePoint(&xform->EntryWhitePoint, (cmsCIEXYZ*) cmsReadTag(hProfiles[0], cmsSigMediaWhitePointTag));
- SetWhitePoint(&xform->ExitWhitePoint, (cmsCIEXYZ*) cmsReadTag(hProfiles[nProfiles-1], cmsSigMediaWhitePointTag));
-
- // Create a gamut check LUT if requested
- if (hGamutProfile != NULL && (dwFlags & cmsFLAGS_GAMUTCHECK))
- xform ->GamutCheck = _cmsCreateGamutCheckPipeline(ContextID, hProfiles,
- BPC, Intents,
- AdaptationStates,
- nGamutPCSposition,
- hGamutProfile);
- // Try to read input and output colorant table
- if (cmsIsTag(hProfiles[0], cmsSigColorantTableTag)) {
- // Input table can only come in this way.
- xform ->InputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[0], cmsSigColorantTableTag));
- }
- // Output is a little bit more complex.
- if (cmsGetDeviceClass(hProfiles[nProfiles-1]) == cmsSigLinkClass) {
- // This tag may exist only on devicelink profiles.
- if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag)) {
- // It may be NULL if error
- xform ->OutputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag));
- }
- } else {
- if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableTag)) {
- xform -> OutputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[nProfiles-1], cmsSigColorantTableTag));
- }
- }
- // Store the sequence of profiles
- if (dwFlags & cmsFLAGS_KEEP_SEQUENCE) {
- xform ->Sequence = _cmsCompileProfileSequence(ContextID, nProfiles, hProfiles);
- }
- else
- xform ->Sequence = NULL;
- // If this is a cached transform, init first value, which is zero (16 bits only)
- if (!(dwFlags & cmsFLAGS_NOCACHE)) {
- memset(&xform ->Cache.CacheIn, 0, sizeof(xform ->Cache.CacheIn));
- if (xform ->GamutCheck != NULL) {
- TransformOnePixelWithGamutCheck(xform, xform ->Cache.CacheIn, xform->Cache.CacheOut);
- }
- else {
- xform ->Lut ->Eval16Fn(xform ->Cache.CacheIn, xform->Cache.CacheOut, xform -> Lut->Data);
- }
- }
- return (cmsHTRANSFORM) xform;
- }
- // Multiprofile transforms: Gamut check is not available here, as it is unclear from which profile the gamut comes.
- cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransformTHR(cmsContext ContextID,
- cmsHPROFILE hProfiles[],
- cmsUInt32Number nProfiles,
- cmsUInt32Number InputFormat,
- cmsUInt32Number OutputFormat,
- cmsUInt32Number Intent,
- cmsUInt32Number dwFlags)
- {
- cmsUInt32Number i;
- cmsBool BPC[256];
- cmsUInt32Number Intents[256];
- cmsFloat64Number AdaptationStates[256];
- if (nProfiles <= 0 || nProfiles > 255) {
- cmsSignalError(ContextID, cmsERROR_RANGE, "Wrong number of profiles. 1..255 expected, %d found.", nProfiles);
- return NULL;
- }
- for (i=0; i < nProfiles; i++) {
- BPC[i] = dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION ? TRUE : FALSE;
- Intents[i] = Intent;
- AdaptationStates[i] = cmsSetAdaptationStateTHR(ContextID, -1);
- }
- return cmsCreateExtendedTransform(ContextID, nProfiles, hProfiles, BPC, Intents, AdaptationStates, NULL, 0, InputFormat, OutputFormat, dwFlags);
- }
- cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransform(cmsHPROFILE hProfiles[],
- cmsUInt32Number nProfiles,
- cmsUInt32Number InputFormat,
- cmsUInt32Number OutputFormat,
- cmsUInt32Number Intent,
- cmsUInt32Number dwFlags)
- {
- if (nProfiles <= 0 || nProfiles > 255) {
- cmsSignalError(NULL, cmsERROR_RANGE, "Wrong number of profiles. 1..255 expected, %d found.", nProfiles);
- return NULL;
- }
- return cmsCreateMultiprofileTransformTHR(cmsGetProfileContextID(hProfiles[0]),
- hProfiles,
- nProfiles,
- InputFormat,
- OutputFormat,
- Intent,
- dwFlags);
- }
- cmsHTRANSFORM CMSEXPORT cmsCreateTransformTHR(cmsContext ContextID,
- cmsHPROFILE Input,
- cmsUInt32Number InputFormat,
- cmsHPROFILE Output,
- cmsUInt32Number OutputFormat,
- cmsUInt32Number Intent,
- cmsUInt32Number dwFlags)
- {
- cmsHPROFILE hArray[2];
- hArray[0] = Input;
- hArray[1] = Output;
- return cmsCreateMultiprofileTransformTHR(ContextID, hArray, Output == NULL ? 1U : 2U, InputFormat, OutputFormat, Intent, dwFlags);
- }
- CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateTransform(cmsHPROFILE Input,
- cmsUInt32Number InputFormat,
- cmsHPROFILE Output,
- cmsUInt32Number OutputFormat,
- cmsUInt32Number Intent,
- cmsUInt32Number dwFlags)
- {
- return cmsCreateTransformTHR(cmsGetProfileContextID(Input), Input, InputFormat, Output, OutputFormat, Intent, dwFlags);
- }
- cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransformTHR(cmsContext ContextID,
- cmsHPROFILE InputProfile,
- cmsUInt32Number InputFormat,
- cmsHPROFILE OutputProfile,
- cmsUInt32Number OutputFormat,
- cmsHPROFILE ProofingProfile,
- cmsUInt32Number nIntent,
- cmsUInt32Number ProofingIntent,
- cmsUInt32Number dwFlags)
- {
- cmsHPROFILE hArray[4];
- cmsUInt32Number Intents[4];
- cmsBool BPC[4];
- cmsFloat64Number Adaptation[4];
- cmsBool DoBPC = (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION) ? TRUE : FALSE;
- hArray[0] = InputProfile; hArray[1] = ProofingProfile; hArray[2] = ProofingProfile; hArray[3] = OutputProfile;
- Intents[0] = nIntent; Intents[1] = nIntent; Intents[2] = INTENT_RELATIVE_COLORIMETRIC; Intents[3] = ProofingIntent;
- BPC[0] = DoBPC; BPC[1] = DoBPC; BPC[2] = 0; BPC[3] = 0;
- Adaptation[0] = Adaptation[1] = Adaptation[2] = Adaptation[3] = cmsSetAdaptationStateTHR(ContextID, -1);
- if (!(dwFlags & (cmsFLAGS_SOFTPROOFING|cmsFLAGS_GAMUTCHECK)))
- return cmsCreateTransformTHR(ContextID, InputProfile, InputFormat, OutputProfile, OutputFormat, nIntent, dwFlags);
- return cmsCreateExtendedTransform(ContextID, 4, hArray, BPC, Intents, Adaptation,
- ProofingProfile, 1, InputFormat, OutputFormat, dwFlags);
- }
- cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile,
- cmsUInt32Number InputFormat,
- cmsHPROFILE OutputProfile,
- cmsUInt32Number OutputFormat,
- cmsHPROFILE ProofingProfile,
- cmsUInt32Number nIntent,
- cmsUInt32Number ProofingIntent,
- cmsUInt32Number dwFlags)
- {
- return cmsCreateProofingTransformTHR(cmsGetProfileContextID(InputProfile),
- InputProfile,
- InputFormat,
- OutputProfile,
- OutputFormat,
- ProofingProfile,
- nIntent,
- ProofingIntent,
- dwFlags);
- }
- // Grab the ContextID from an open transform. Returns NULL if a NULL transform is passed
- cmsContext CMSEXPORT cmsGetTransformContextID(cmsHTRANSFORM hTransform)
- {
- _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
- if (xform == NULL) return NULL;
- return xform -> ContextID;
- }
- // Grab the input/output formats
- cmsUInt32Number CMSEXPORT cmsGetTransformInputFormat(cmsHTRANSFORM hTransform)
- {
- _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
- if (xform == NULL) return 0;
- return xform->InputFormat;
- }
- cmsUInt32Number CMSEXPORT cmsGetTransformOutputFormat(cmsHTRANSFORM hTransform)
- {
- _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
- if (xform == NULL) return 0;
- return xform->OutputFormat;
- }
- // For backwards compatibility
- cmsBool CMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform,
- cmsUInt32Number InputFormat,
- cmsUInt32Number OutputFormat)
- {
- _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
- cmsFormatter16 FromInput, ToOutput;
- // We only can afford to change formatters if previous transform is at least 16 bits
- if (!(xform ->dwOriginalFlags & cmsFLAGS_CAN_CHANGE_FORMATTER)) {
- cmsSignalError(xform ->ContextID, cmsERROR_NOT_SUITABLE, "cmsChangeBuffersFormat works only on transforms created originally with at least 16 bits of precision");
- return FALSE;
- }
- FromInput = _cmsGetFormatter(xform->ContextID, InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
- ToOutput = _cmsGetFormatter(xform->ContextID, OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
- if (FromInput == NULL || ToOutput == NULL) {
- cmsSignalError(xform -> ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
- return FALSE;
- }
- xform ->InputFormat = InputFormat;
- xform ->OutputFormat = OutputFormat;
- xform ->FromInput = FromInput;
- xform ->ToOutput = ToOutput;
- return TRUE;
- }
|