13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 */
24
25 // This file is available under and governed by the GNU General Public
26 // License version 2 only, as published by the Free Software Foundation.
27 // However, the following notice accompanied the original version of this
28 // file:
29 //
30 //---------------------------------------------------------------------------------
31 //
32 // Little Color Management System
33 // Copyright (c) 1998-2014 Marti Maria Saguer
34 //
35 // Permission is hereby granted, free of charge, to any person obtaining
36 // a copy of this software and associated documentation files (the "Software"),
37 // to deal in the Software without restriction, including without limitation
38 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
39 // and/or sell copies of the Software, and to permit persons to whom the Software
40 // is furnished to do so, subject to the following conditions:
41 //
42 // The above copyright notice and this permission notice shall be included in
43 // all copies or substantial portions of the Software.
44 //
45 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
46 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
47 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
48 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
49 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
50 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
51 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
52 //
53 //---------------------------------------------------------------------------------
191 if (p -> OutputColorant)
192 cmsFreeNamedColorList(p ->OutputColorant);
193
194 if (p ->Sequence)
195 cmsFreeProfileSequenceDescription(p ->Sequence);
196
197 if (p ->UserData)
198 p ->FreeUserData(p ->ContextID, p ->UserData);
199
200 _cmsFree(p ->ContextID, (void *) p);
201 }
202
203 // Apply transform.
204 void CMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform,
205 const void* InputBuffer,
206 void* OutputBuffer,
207 cmsUInt32Number Size)
208
209 {
210 _cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform;
211
212 p -> xform(p, InputBuffer, OutputBuffer, Size, Size);
213 }
214
215
216 // Apply transform.
217 void CMSEXPORT cmsDoTransformStride(cmsHTRANSFORM Transform,
218 const void* InputBuffer,
219 void* OutputBuffer,
220 cmsUInt32Number Size, cmsUInt32Number Stride)
221
222 {
223 _cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform;
224
225 p -> xform(p, InputBuffer, OutputBuffer, Size, Stride);
226 }
227
228
229 // Transform routines ----------------------------------------------------------------------------------------------------------
230
231 // Float xform converts floats. Since there are no performance issues, one routine does all job, including gamut check.
232 // Note that because extended range, we can use a -1.0 value for out of gamut in this case.
233 static
234 void FloatXFORM(_cmsTRANSFORM* p,
235 const void* in,
236 void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
237 {
238 cmsUInt8Number* accum;
239 cmsUInt8Number* output;
240 cmsFloat32Number fIn[cmsMAXCHANNELS], fOut[cmsMAXCHANNELS];
241 cmsFloat32Number OutOfGamut;
242 cmsUInt32Number i, j;
243
244 accum = (cmsUInt8Number*) in;
245 output = (cmsUInt8Number*) out;
246
247 for (i=0; i < Size; i++) {
248
249 accum = p -> FromInputFloat(p, fIn, accum, Stride);
250
251 // Any gamut chack to do?
252 if (p ->GamutCheck != NULL) {
253
254 // Evaluate gamut marker.
255 cmsPipelineEvalFloat( fIn, &OutOfGamut, p ->GamutCheck);
256
257 // Is current color out of gamut?
258 if (OutOfGamut > 0.0) {
259
260 // Certainly, out of gamut
261 for (j=0; j < cmsMAXCHANNELS; j++)
262 fOut[j] = -1.0;
263
264 }
265 else {
266 // No, proceed normally
267 cmsPipelineEvalFloat(fIn, fOut, p -> Lut);
268 }
269 }
270 else {
271
272 // No gamut check at all
273 cmsPipelineEvalFloat(fIn, fOut, p -> Lut);
274 }
275
276 // Back to asked representation
277 output = p -> ToOutputFloat(p, fOut, output, Stride);
278 }
279 }
280
281
282 static
283 void NullFloatXFORM(_cmsTRANSFORM* p,
284 const void* in,
285 void* out,
286 cmsUInt32Number Size,
287 cmsUInt32Number Stride)
288 {
289 cmsUInt8Number* accum;
290 cmsUInt8Number* output;
291 cmsFloat32Number fIn[cmsMAXCHANNELS];
292 cmsUInt32Number i, n;
293
294 accum = (cmsUInt8Number*) in;
295 output = (cmsUInt8Number*) out;
296 n = Size;
297
298 for (i=0; i < n; i++) {
299
300 accum = p -> FromInputFloat(p, fIn, accum, Stride);
301 output = p -> ToOutputFloat(p, fIn, output, Stride);
302 }
303 }
304
305 // 16 bit precision -----------------------------------------------------------------------------------------------------------
306
307 // Null transformation, only applies formatters. No caché
308 static
309 void NullXFORM(_cmsTRANSFORM* p,
310 const void* in,
311 void* out, cmsUInt32Number Size,
312 cmsUInt32Number Stride)
313 {
314 cmsUInt8Number* accum;
315 cmsUInt8Number* output;
316 cmsUInt16Number wIn[cmsMAXCHANNELS];
317 cmsUInt32Number i, n;
318
319 accum = (cmsUInt8Number*) in;
320 output = (cmsUInt8Number*) out;
321 n = Size; // Buffer len
322
323 for (i=0; i < n; i++) {
324
325 accum = p -> FromInput(p, wIn, accum, Stride);
326 output = p -> ToOutput(p, wIn, output, Stride);
327 }
328 }
329
330
331 // No gamut check, no cache, 16 bits
332 static
333 void PrecalculatedXFORM(_cmsTRANSFORM* p,
334 const void* in,
335 void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
336 {
337 register cmsUInt8Number* accum;
338 register cmsUInt8Number* output;
339 cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
340 cmsUInt32Number i, n;
341
342 accum = (cmsUInt8Number*) in;
343 output = (cmsUInt8Number*) out;
344 n = Size;
345
346 for (i=0; i < n; i++) {
347
348 accum = p -> FromInput(p, wIn, accum, Stride);
349 p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
350 output = p -> ToOutput(p, wOut, output, Stride);
351 }
352 }
353
354
355 // Auxiliar: Handle precalculated gamut check. The retrieval of context may be alittle bit slow, but this function is not critical.
356 static
357 void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p,
358 const cmsUInt16Number wIn[],
359 cmsUInt16Number wOut[])
360 {
361 cmsUInt16Number wOutOfGamut;
362
363 p ->GamutCheck ->Eval16Fn(wIn, &wOutOfGamut, p ->GamutCheck ->Data);
364 if (wOutOfGamut >= 1) {
365
366 cmsUInt16Number i;
367 _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(p->ContextID, AlarmCodesContext);
368
369 for (i=0; i < p ->Lut->OutputChannels; i++) {
370
371 wOut[i] = ContextAlarmCodes ->AlarmCodes[i];
372 }
373 }
374 else
375 p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
376 }
377
378 // Gamut check, No caché, 16 bits.
379 static
380 void PrecalculatedXFORMGamutCheck(_cmsTRANSFORM* p,
381 const void* in,
382 void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
383 {
384 cmsUInt8Number* accum;
385 cmsUInt8Number* output;
386 cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
387 cmsUInt32Number i, n;
388
389 accum = (cmsUInt8Number*) in;
390 output = (cmsUInt8Number*) out;
391 n = Size; // Buffer len
392
393 for (i=0; i < n; i++) {
394
395 accum = p -> FromInput(p, wIn, accum, Stride);
396 TransformOnePixelWithGamutCheck(p, wIn, wOut);
397 output = p -> ToOutput(p, wOut, output, Stride);
398 }
399 }
400
401
402 // No gamut check, Caché, 16 bits,
403 static
404 void CachedXFORM(_cmsTRANSFORM* p,
405 const void* in,
406 void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
407 {
408 cmsUInt8Number* accum;
409 cmsUInt8Number* output;
410 cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
411 cmsUInt32Number i, n;
412 _cmsCACHE Cache;
413
414 accum = (cmsUInt8Number*) in;
415 output = (cmsUInt8Number*) out;
416 n = Size; // Buffer len
417
418 // Empty buffers for quick memcmp
419 memset(wIn, 0, sizeof(wIn));
420 memset(wOut, 0, sizeof(wOut));
421
422 // Get copy of zero cache
423 memcpy(&Cache, &p ->Cache, sizeof(Cache));
424
425 for (i=0; i < n; i++) {
426
427 accum = p -> FromInput(p, wIn, accum, Stride);
428
429 if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) {
430
431 memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut));
432 }
433 else {
434
435 p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
436
437 memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn));
438 memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut));
439 }
440
441 output = p -> ToOutput(p, wOut, output, Stride);
442 }
443
444 }
445
446
447 // All those nice features together
448 static
449 void CachedXFORMGamutCheck(_cmsTRANSFORM* p,
450 const void* in,
451 void* out, cmsUInt32Number Size, cmsUInt32Number Stride)
452 {
453 cmsUInt8Number* accum;
454 cmsUInt8Number* output;
455 cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
456 cmsUInt32Number i, n;
457 _cmsCACHE Cache;
458
459 accum = (cmsUInt8Number*) in;
460 output = (cmsUInt8Number*) out;
461 n = Size; // Buffer len
462
463 // Empty buffers for quick memcmp
464 memset(wIn, 0, sizeof(cmsUInt16Number) * cmsMAXCHANNELS);
465 memset(wOut, 0, sizeof(cmsUInt16Number) * cmsMAXCHANNELS);
466
467 // Get copy of zero cache
468 memcpy(&Cache, &p ->Cache, sizeof(Cache));
469
470 for (i=0; i < n; i++) {
471
472 accum = p -> FromInput(p, wIn, accum, Stride);
473
474 if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) {
475 memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut));
476 }
477 else {
478 TransformOnePixelWithGamutCheck(p, wIn, wOut);
479 memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn));
480 memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut));
481 }
482
483 output = p -> ToOutput(p, wOut, output, Stride);
484 }
485
486 }
487
488 // -------------------------------------------------------------------------------------------------------------
489
490 // List of used-defined transform factories
491 typedef struct _cmsTransformCollection_st {
492
493 _cmsTransformFactory Factory;
494 struct _cmsTransformCollection_st *Next;
495
496 } _cmsTransformCollection;
497
498 // The linked list head
499 _cmsTransformPluginChunkType _cmsTransformPluginChunk = { NULL };
500
501
502 // Duplicates the zone of memory used by the plug-in in the new context
503 static
504 void DupPluginTransformList(struct _cmsContext_struct* ctx,
505 const struct _cmsContext_struct* src)
506 {
507 _cmsTransformPluginChunkType newHead = { NULL };
508 _cmsTransformCollection* entry;
509 _cmsTransformCollection* Anterior = NULL;
510 _cmsTransformPluginChunkType* head = (_cmsTransformPluginChunkType*) src->chunks[TransformPlugin];
511
512 // Walk the list copying all nodes
513 for (entry = head->TransformCollection;
516
517 _cmsTransformCollection *newEntry = ( _cmsTransformCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTransformCollection));
518
519 if (newEntry == NULL)
520 return;
521
522 // We want to keep the linked list order, so this is a little bit tricky
523 newEntry -> Next = NULL;
524 if (Anterior)
525 Anterior -> Next = newEntry;
526
527 Anterior = newEntry;
528
529 if (newHead.TransformCollection == NULL)
530 newHead.TransformCollection = newEntry;
531 }
532
533 ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTransformPluginChunkType));
534 }
535
536 void _cmsAllocTransformPluginChunk(struct _cmsContext_struct* ctx,
537 const struct _cmsContext_struct* src)
538 {
539 if (src != NULL) {
540
541 // Copy all linked list
542 DupPluginTransformList(ctx, src);
543 }
544 else {
545 static _cmsTransformPluginChunkType TransformPluginChunkType = { NULL };
546 ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TransformPluginChunkType, sizeof(_cmsTransformPluginChunkType));
547 }
548 }
549
550
551
552 // Register new ways to transform
553 cmsBool _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Data)
554 {
555 cmsPluginTransform* Plugin = (cmsPluginTransform*) Data;
556 _cmsTransformCollection* fl;
557 _cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID,TransformPlugin);
558
559 if (Data == NULL) {
560
561 // Free the chain. Memory is safely freed at exit
562 ctx->TransformCollection = NULL;
563 return TRUE;
564 }
565
566 // Factory callback is required
567 if (Plugin ->Factory == NULL) return FALSE;
568
569
570 fl = (_cmsTransformCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsTransformCollection));
571 if (fl == NULL) return FALSE;
572
573 // Copy the parameters
574 fl ->Factory = Plugin ->Factory;
575
576 // Keep linked list
577 fl ->Next = ctx->TransformCollection;
578 ctx->TransformCollection = fl;
579
580 // All is ok
581 return TRUE;
582 }
583
584
585 void CMSEXPORT _cmsSetTransformUserData(struct _cmstransform_struct *CMMcargo, void* ptr, _cmsFreeUserDataFn FreePrivateDataFn)
586 {
587 _cmsAssert(CMMcargo != NULL);
588 CMMcargo ->UserData = ptr;
589 CMMcargo ->FreeUserData = FreePrivateDataFn;
590 }
591
592 // returns the pointer defined by the plug-in to store private data
593 void * CMSEXPORT _cmsGetTransformUserData(struct _cmstransform_struct *CMMcargo)
594 {
639
640 // Last plugin in the declaration order takes control. We just keep
641 // the original parameters as a logging.
642 // Note that cmsFLAGS_CAN_CHANGE_FORMATTER is not set, so by default
643 // an optimized transform is not reusable. The plug-in can, however, change
644 // the flags and make it suitable.
645
646 p->ContextID = ContextID;
647 p->InputFormat = *InputFormat;
648 p->OutputFormat = *OutputFormat;
649 p->dwOriginalFlags = *dwFlags;
650
651 // Fill the formatters just in case the optimized routine is interested.
652 // No error is thrown if the formatter doesn't exist. It is up to the optimization
653 // factory to decide what to do in those cases.
654 p->FromInput = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
655 p->ToOutput = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
656 p->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
657 p->ToOutputFloat = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
658
659 return p;
660 }
661 }
662
663 // Not suitable for the transform plug-in, let's check the pipeline plug-in
664 _cmsOptimizePipeline(ContextID, &p->Lut, Intent, InputFormat, OutputFormat, dwFlags);
665 }
666
667 // Check whatever this is a true floating point transform
668 if (_cmsFormatterIsFloat(*InputFormat) && _cmsFormatterIsFloat(*OutputFormat)) {
669
670 // Get formatter function always return a valid union, but the contents of this union may be NULL.
671 p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
672 p ->ToOutputFloat = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
673 *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
674
675 if (p ->FromInputFloat == NULL || p ->ToOutputFloat == NULL) {
676
677 cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
678 _cmsFree(ContextID, p);
799 }
800
801 // Check colorspace
802 static
803 cmsBool IsProperColorSpace(cmsColorSpaceSignature Check, cmsUInt32Number dwFormat)
804 {
805 int Space1 = T_COLORSPACE(dwFormat);
806 int Space2 = _cmsLCMScolorSpace(Check);
807
808 if (Space1 == PT_ANY) return TRUE;
809 if (Space1 == Space2) return TRUE;
810
811 if (Space1 == PT_LabV2 && Space2 == PT_Lab) return TRUE;
812 if (Space1 == PT_Lab && Space2 == PT_LabV2) return TRUE;
813
814 return FALSE;
815 }
816
817 // ----------------------------------------------------------------------------------------------------------------
818
819 static
820 void SetWhitePoint(cmsCIEXYZ* wtPt, const cmsCIEXYZ* src)
821 {
822 if (src == NULL) {
823 wtPt ->X = cmsD50X;
824 wtPt ->Y = cmsD50Y;
825 wtPt ->Z = cmsD50Z;
826 }
827 else {
828 wtPt ->X = src->X;
829 wtPt ->Y = src->Y;
830 wtPt ->Z = src->Z;
831 }
832
833 }
834
835 // New to lcms 2.0 -- have all parameters available.
836 cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,
837 cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[],
838 cmsBool BPC[],
839 cmsUInt32Number Intents[],
840 cmsFloat64Number AdaptationStates[],
841 cmsHPROFILE hGamutProfile,
842 cmsUInt32Number nGamutPCSposition,
843 cmsUInt32Number InputFormat,
844 cmsUInt32Number OutputFormat,
845 cmsUInt32Number dwFlags)
846 {
847 _cmsTRANSFORM* xform;
848 cmsColorSpaceSignature EntryColorSpace;
849 cmsColorSpaceSignature ExitColorSpace;
850 cmsPipeline* Lut;
1121 {
1122 _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
1123
1124 if (xform == NULL) return 0;
1125 return xform->InputFormat;
1126 }
1127
1128 cmsUInt32Number CMSEXPORT cmsGetTransformOutputFormat(cmsHTRANSFORM hTransform)
1129 {
1130 _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
1131
1132 if (xform == NULL) return 0;
1133 return xform->OutputFormat;
1134 }
1135
1136 // For backwards compatibility
1137 cmsBool CMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform,
1138 cmsUInt32Number InputFormat,
1139 cmsUInt32Number OutputFormat)
1140 {
1141
1142 _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
1143 cmsFormatter16 FromInput, ToOutput;
1144
1145
1146 // We only can afford to change formatters if previous transform is at least 16 bits
1147 if (!(xform ->dwOriginalFlags & cmsFLAGS_CAN_CHANGE_FORMATTER)) {
1148
1149 cmsSignalError(xform ->ContextID, cmsERROR_NOT_SUITABLE, "cmsChangeBuffersFormat works only on transforms created originally with at least 16 bits of precision");
1150 return FALSE;
1151 }
1152
1153 FromInput = _cmsGetFormatter(xform->ContextID, InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
1154 ToOutput = _cmsGetFormatter(xform->ContextID, OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
1155
1156 if (FromInput == NULL || ToOutput == NULL) {
1157
1158 cmsSignalError(xform -> ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
1159 return FALSE;
1160 }
1161
|
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 */
24
25 // This file is available under and governed by the GNU General Public
26 // License version 2 only, as published by the Free Software Foundation.
27 // However, the following notice accompanied the original version of this
28 // file:
29 //
30 //---------------------------------------------------------------------------------
31 //
32 // Little Color Management System
33 // Copyright (c) 1998-2016 Marti Maria Saguer
34 //
35 // Permission is hereby granted, free of charge, to any person obtaining
36 // a copy of this software and associated documentation files (the "Software"),
37 // to deal in the Software without restriction, including without limitation
38 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
39 // and/or sell copies of the Software, and to permit persons to whom the Software
40 // is furnished to do so, subject to the following conditions:
41 //
42 // The above copyright notice and this permission notice shall be included in
43 // all copies or substantial portions of the Software.
44 //
45 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
46 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
47 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
48 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
49 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
50 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
51 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
52 //
53 //---------------------------------------------------------------------------------
191 if (p -> OutputColorant)
192 cmsFreeNamedColorList(p ->OutputColorant);
193
194 if (p ->Sequence)
195 cmsFreeProfileSequenceDescription(p ->Sequence);
196
197 if (p ->UserData)
198 p ->FreeUserData(p ->ContextID, p ->UserData);
199
200 _cmsFree(p ->ContextID, (void *) p);
201 }
202
203 // Apply transform.
204 void CMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform,
205 const void* InputBuffer,
206 void* OutputBuffer,
207 cmsUInt32Number Size)
208
209 {
210 _cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform;
211 cmsStride stride;
212
213 stride.BytesPerLineIn = 0; // Not used
214 stride.BytesPerLineOut = 0;
215 stride.BytesPerPlaneIn = Size;
216 stride.BytesPerPlaneOut = Size;
217
218 p -> xform(p, InputBuffer, OutputBuffer, Size, 1, &stride);
219 }
220
221
222 // This is a legacy stride for planar
223 void CMSEXPORT cmsDoTransformStride(cmsHTRANSFORM Transform,
224 const void* InputBuffer,
225 void* OutputBuffer,
226 cmsUInt32Number Size, cmsUInt32Number Stride)
227
228 {
229 _cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform;
230 cmsStride stride;
231
232 stride.BytesPerLineIn = 0;
233 stride.BytesPerLineOut = 0;
234 stride.BytesPerPlaneIn = Stride;
235 stride.BytesPerPlaneOut = Stride;
236
237 p -> xform(p, InputBuffer, OutputBuffer, Size, 1, &stride);
238 }
239
240 // This is the "fast" function for plugins
241 void CMSEXPORT cmsDoTransformLineStride(cmsHTRANSFORM Transform,
242 const void* InputBuffer,
243 void* OutputBuffer,
244 cmsUInt32Number PixelsPerLine,
245 cmsUInt32Number LineCount,
246 cmsUInt32Number BytesPerLineIn,
247 cmsUInt32Number BytesPerLineOut,
248 cmsUInt32Number BytesPerPlaneIn,
249 cmsUInt32Number BytesPerPlaneOut)
250
251 {
252 _cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform;
253 cmsStride stride;
254
255 stride.BytesPerLineIn = BytesPerLineIn;
256 stride.BytesPerLineOut = BytesPerLineOut;
257 stride.BytesPerPlaneIn = BytesPerPlaneIn;
258 stride.BytesPerPlaneOut = BytesPerPlaneOut;
259
260 p->xform(p, InputBuffer, OutputBuffer, PixelsPerLine, LineCount, &stride);
261 }
262
263
264
265 // Transform routines ----------------------------------------------------------------------------------------------------------
266
267 // Float xform converts floats. Since there are no performance issues, one routine does all job, including gamut check.
268 // Note that because extended range, we can use a -1.0 value for out of gamut in this case.
269 static
270 void FloatXFORM(_cmsTRANSFORM* p,
271 const void* in,
272 void* out,
273 cmsUInt32Number PixelsPerLine,
274 cmsUInt32Number LineCount,
275 const cmsStride* Stride)
276 {
277 cmsUInt8Number* accum;
278 cmsUInt8Number* output;
279 cmsFloat32Number fIn[cmsMAXCHANNELS], fOut[cmsMAXCHANNELS];
280 cmsFloat32Number OutOfGamut;
281 cmsUInt32Number i, j, c, strideIn, strideOut;
282
283 _cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride);
284
285 strideIn = 0;
286 strideOut = 0;
287
288 for (i = 0; i < LineCount; i++) {
289
290 accum = (cmsUInt8Number*)in + strideIn;
291 output = (cmsUInt8Number*)out + strideOut;
292
293 for (j = 0; j < PixelsPerLine; j++) {
294
295 accum = p->FromInputFloat(p, fIn, accum, Stride->BytesPerPlaneIn);
296
297 // Any gamut chack to do?
298 if (p->GamutCheck != NULL) {
299
300 // Evaluate gamut marker.
301 cmsPipelineEvalFloat(fIn, &OutOfGamut, p->GamutCheck);
302
303 // Is current color out of gamut?
304 if (OutOfGamut > 0.0) {
305
306 // Certainly, out of gamut
307 for (c = 0; c < cmsMAXCHANNELS; c++)
308 fOut[c] = -1.0;
309
310 }
311 else {
312 // No, proceed normally
313 cmsPipelineEvalFloat(fIn, fOut, p->Lut);
314 }
315 }
316 else {
317
318 // No gamut check at all
319 cmsPipelineEvalFloat(fIn, fOut, p->Lut);
320 }
321
322
323 output = p->ToOutputFloat(p, fOut, output, Stride->BytesPerPlaneOut);
324 }
325
326 strideIn += Stride->BytesPerLineIn;
327 strideOut += Stride->BytesPerLineOut;
328 }
329
330 }
331
332
333 static
334 void NullFloatXFORM(_cmsTRANSFORM* p,
335 const void* in,
336 void* out,
337 cmsUInt32Number PixelsPerLine,
338 cmsUInt32Number LineCount,
339 const cmsStride* Stride)
340
341 {
342 cmsUInt8Number* accum;
343 cmsUInt8Number* output;
344 cmsFloat32Number fIn[cmsMAXCHANNELS];
345 cmsUInt32Number i, j, strideIn, strideOut;
346
347 _cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride);
348
349 strideIn = 0;
350 strideOut = 0;
351
352 for (i = 0; i < LineCount; i++) {
353
354 accum = (cmsUInt8Number*) in + strideIn;
355 output = (cmsUInt8Number*) out + strideOut;
356
357 for (j = 0; j < PixelsPerLine; j++) {
358
359 accum = p->FromInputFloat(p, fIn, accum, Stride ->BytesPerPlaneIn);
360 output = p->ToOutputFloat(p, fIn, output, Stride->BytesPerPlaneOut);
361 }
362
363 strideIn += Stride->BytesPerLineIn;
364 strideOut += Stride->BytesPerLineOut;
365 }
366 }
367
368 // 16 bit precision -----------------------------------------------------------------------------------------------------------
369
370 // Null transformation, only applies formatters. No caché
371 static
372 void NullXFORM(_cmsTRANSFORM* p,
373 const void* in,
374 void* out,
375 cmsUInt32Number PixelsPerLine,
376 cmsUInt32Number LineCount,
377 const cmsStride* Stride)
378 {
379 cmsUInt8Number* accum;
380 cmsUInt8Number* output;
381 cmsUInt16Number wIn[cmsMAXCHANNELS];
382 cmsUInt32Number i, j, strideIn, strideOut;
383
384 _cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride);
385
386 strideIn = 0;
387 strideOut = 0;
388
389 for (i = 0; i < LineCount; i++) {
390
391 accum = (cmsUInt8Number*)in + strideIn;
392 output = (cmsUInt8Number*)out + strideOut;
393
394 for (j = 0; j < PixelsPerLine; j++) {
395
396 accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn);
397 output = p->ToOutput(p, wIn, output, Stride->BytesPerPlaneOut);
398 }
399
400 strideIn += Stride->BytesPerLineIn;
401 strideOut += Stride->BytesPerLineOut;
402 }
403
404 }
405
406
407 // No gamut check, no cache, 16 bits
408 static
409 void PrecalculatedXFORM(_cmsTRANSFORM* p,
410 const void* in,
411 void* out,
412 cmsUInt32Number PixelsPerLine,
413 cmsUInt32Number LineCount,
414 const cmsStride* Stride)
415 {
416 register cmsUInt8Number* accum;
417 register cmsUInt8Number* output;
418 cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
419 cmsUInt32Number i, j, strideIn, strideOut;
420
421 _cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride);
422
423 strideIn = 0;
424 strideOut = 0;
425
426 for (i = 0; i < LineCount; i++) {
427
428 accum = (cmsUInt8Number*)in + strideIn;
429 output = (cmsUInt8Number*)out + strideOut;
430
431 for (j = 0; j < PixelsPerLine; j++) {
432
433 accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn);
434 p->Lut->Eval16Fn(wIn, wOut, p->Lut->Data);
435 output = p->ToOutput(p, wOut, output, Stride->BytesPerPlaneOut);
436 }
437
438 strideIn += Stride->BytesPerLineIn;
439 strideOut += Stride->BytesPerLineOut;
440 }
441
442 }
443
444
445 // Auxiliary: Handle precalculated gamut check. The retrieval of context may be alittle bit slow, but this function is not critical.
446 static
447 void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p,
448 const cmsUInt16Number wIn[],
449 cmsUInt16Number wOut[])
450 {
451 cmsUInt16Number wOutOfGamut;
452
453 p ->GamutCheck ->Eval16Fn(wIn, &wOutOfGamut, p ->GamutCheck ->Data);
454 if (wOutOfGamut >= 1) {
455
456 cmsUInt16Number i;
457 _cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(p->ContextID, AlarmCodesContext);
458
459 for (i=0; i < p ->Lut->OutputChannels; i++) {
460
461 wOut[i] = ContextAlarmCodes ->AlarmCodes[i];
462 }
463 }
464 else
465 p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
466 }
467
468 // Gamut check, No caché, 16 bits.
469 static
470 void PrecalculatedXFORMGamutCheck(_cmsTRANSFORM* p,
471 const void* in,
472 void* out,
473 cmsUInt32Number PixelsPerLine,
474 cmsUInt32Number LineCount,
475 const cmsStride* Stride)
476 {
477 cmsUInt8Number* accum;
478 cmsUInt8Number* output;
479 cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
480 cmsUInt32Number i, j, strideIn, strideOut;
481
482 _cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride);
483
484 strideIn = 0;
485 strideOut = 0;
486
487 for (i = 0; i < LineCount; i++) {
488
489 accum = (cmsUInt8Number*)in + strideIn;
490 output = (cmsUInt8Number*)out + strideOut;
491
492 for (j = 0; j < PixelsPerLine; j++) {
493
494 accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn);
495 TransformOnePixelWithGamutCheck(p, wIn, wOut);
496 output = p->ToOutput(p, wOut, output, Stride->BytesPerPlaneOut);
497 }
498
499 strideIn += Stride->BytesPerLineIn;
500 strideOut += Stride->BytesPerLineOut;
501 }
502 }
503
504
505 // No gamut check, Caché, 16 bits,
506 static
507 void CachedXFORM(_cmsTRANSFORM* p,
508 const void* in,
509 void* out,
510 cmsUInt32Number PixelsPerLine,
511 cmsUInt32Number LineCount,
512 const cmsStride* Stride)
513 {
514 cmsUInt8Number* accum;
515 cmsUInt8Number* output;
516 cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
517 _cmsCACHE Cache;
518 cmsUInt32Number i, j, strideIn, strideOut;
519
520 _cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride);
521
522 // Empty buffers for quick memcmp
523 memset(wIn, 0, sizeof(wIn));
524 memset(wOut, 0, sizeof(wOut));
525
526 // Get copy of zero cache
527 memcpy(&Cache, &p->Cache, sizeof(Cache));
528
529 strideIn = 0;
530 strideOut = 0;
531
532 for (i = 0; i < LineCount; i++) {
533
534 accum = (cmsUInt8Number*)in + strideIn;
535 output = (cmsUInt8Number*)out + strideOut;
536
537 for (j = 0; j < PixelsPerLine; j++) {
538
539 accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn);
540
541 if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) {
542
543 memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut));
544 }
545 else {
546 p->Lut->Eval16Fn(wIn, wOut, p->Lut->Data);
547
548 memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn));
549 memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut));
550 }
551
552 output = p->ToOutput(p, wOut, output, Stride->BytesPerPlaneOut);
553 }
554
555 strideIn += Stride->BytesPerLineIn;
556 strideOut += Stride->BytesPerLineOut;
557 }
558 }
559
560 // All those nice features together
561 static
562 void CachedXFORMGamutCheck(_cmsTRANSFORM* p,
563 const void* in,
564 void* out,
565 cmsUInt32Number PixelsPerLine,
566 cmsUInt32Number LineCount,
567 const cmsStride* Stride)
568 {
569 cmsUInt8Number* accum;
570 cmsUInt8Number* output;
571 cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
572 _cmsCACHE Cache;
573 cmsUInt32Number i, j, strideIn, strideOut;
574
575 _cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride);
576
577 // Empty buffers for quick memcmp
578 memset(wIn, 0, sizeof(wIn));
579 memset(wOut, 0, sizeof(wOut));
580
581 // Get copy of zero cache
582 memcpy(&Cache, &p->Cache, sizeof(Cache));
583
584 strideIn = 0;
585 strideOut = 0;
586
587 for (i = 0; i < LineCount; i++) {
588
589 accum = (cmsUInt8Number*)in + strideIn;
590 output = (cmsUInt8Number*)out + strideOut;
591
592 for (j = 0; j < PixelsPerLine; j++) {
593
594 accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn);
595
596 if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) {
597
598 memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut));
599 }
600 else {
601 TransformOnePixelWithGamutCheck(p, wIn, wOut);
602
603 memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn));
604 memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut));
605 }
606
607 output = p->ToOutput(p, wOut, output, Stride->BytesPerPlaneOut);
608 }
609
610 strideIn += Stride->BytesPerLineIn;
611 strideOut += Stride->BytesPerLineOut;
612 }
613 }
614
615 // Transform plug-ins ----------------------------------------------------------------------------------------------------
616
617 // List of used-defined transform factories
618 typedef struct _cmsTransformCollection_st {
619
620 _cmsTransform2Factory Factory;
621 cmsBool OldXform; // Factory returns xform function in the old style
622
623 struct _cmsTransformCollection_st *Next;
624
625 } _cmsTransformCollection;
626
627 // The linked list head
628 _cmsTransformPluginChunkType _cmsTransformPluginChunk = { NULL };
629
630
631 // Duplicates the zone of memory used by the plug-in in the new context
632 static
633 void DupPluginTransformList(struct _cmsContext_struct* ctx,
634 const struct _cmsContext_struct* src)
635 {
636 _cmsTransformPluginChunkType newHead = { NULL };
637 _cmsTransformCollection* entry;
638 _cmsTransformCollection* Anterior = NULL;
639 _cmsTransformPluginChunkType* head = (_cmsTransformPluginChunkType*) src->chunks[TransformPlugin];
640
641 // Walk the list copying all nodes
642 for (entry = head->TransformCollection;
645
646 _cmsTransformCollection *newEntry = ( _cmsTransformCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTransformCollection));
647
648 if (newEntry == NULL)
649 return;
650
651 // We want to keep the linked list order, so this is a little bit tricky
652 newEntry -> Next = NULL;
653 if (Anterior)
654 Anterior -> Next = newEntry;
655
656 Anterior = newEntry;
657
658 if (newHead.TransformCollection == NULL)
659 newHead.TransformCollection = newEntry;
660 }
661
662 ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTransformPluginChunkType));
663 }
664
665 // Allocates memory for transform plugin factory
666 void _cmsAllocTransformPluginChunk(struct _cmsContext_struct* ctx,
667 const struct _cmsContext_struct* src)
668 {
669 if (src != NULL) {
670
671 // Copy all linked list
672 DupPluginTransformList(ctx, src);
673 }
674 else {
675 static _cmsTransformPluginChunkType TransformPluginChunkType = { NULL };
676 ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TransformPluginChunkType, sizeof(_cmsTransformPluginChunkType));
677 }
678 }
679
680 // Adaptor for old versions of plug-in
681 static
682 void _cmsTransform2toTransformAdaptor(struct _cmstransform_struct *CMMcargo,
683 const void* InputBuffer,
684 void* OutputBuffer,
685 cmsUInt32Number PixelsPerLine,
686 cmsUInt32Number LineCount,
687 const cmsStride* Stride)
688 {
689
690 cmsUInt32Number i, strideIn, strideOut;
691
692 _cmsHandleExtraChannels(CMMcargo, InputBuffer, OutputBuffer, PixelsPerLine, LineCount, Stride);
693
694 strideIn = 0;
695 strideOut = 0;
696
697 for (i = 0; i < LineCount; i++) {
698
699 void *accum = (cmsUInt8Number*)InputBuffer + strideIn;
700 void *output = (cmsUInt8Number*)OutputBuffer + strideOut;
701
702 CMMcargo->OldXform(CMMcargo, accum, output, PixelsPerLine, Stride->BytesPerPlaneIn);
703
704 strideIn += Stride->BytesPerLineIn;
705 strideOut += Stride->BytesPerLineOut;
706 }
707 }
708
709
710
711 // Register new ways to transform
712 cmsBool _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Data)
713 {
714 cmsPluginTransform* Plugin = (cmsPluginTransform*) Data;
715 _cmsTransformCollection* fl;
716 _cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID,TransformPlugin);
717
718 if (Data == NULL) {
719
720 // Free the chain. Memory is safely freed at exit
721 ctx->TransformCollection = NULL;
722 return TRUE;
723 }
724
725 // Factory callback is required
726 if (Plugin->factories.xform == NULL) return FALSE;
727
728
729 fl = (_cmsTransformCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsTransformCollection));
730 if (fl == NULL) return FALSE;
731
732 // Check for full xform plug-ins previous to 2.8, we would need an adapter in that case
733 if (Plugin->base.ExpectedVersion < 2080) {
734
735 fl->OldXform = TRUE;
736 }
737 else
738 fl->OldXform = FALSE;
739
740 // Copy the parameters
741 fl->Factory = Plugin->factories.xform;
742
743 // Keep linked list
744 fl ->Next = ctx->TransformCollection;
745 ctx->TransformCollection = fl;
746
747 // All is ok
748 return TRUE;
749 }
750
751
752 void CMSEXPORT _cmsSetTransformUserData(struct _cmstransform_struct *CMMcargo, void* ptr, _cmsFreeUserDataFn FreePrivateDataFn)
753 {
754 _cmsAssert(CMMcargo != NULL);
755 CMMcargo ->UserData = ptr;
756 CMMcargo ->FreeUserData = FreePrivateDataFn;
757 }
758
759 // returns the pointer defined by the plug-in to store private data
760 void * CMSEXPORT _cmsGetTransformUserData(struct _cmstransform_struct *CMMcargo)
761 {
806
807 // Last plugin in the declaration order takes control. We just keep
808 // the original parameters as a logging.
809 // Note that cmsFLAGS_CAN_CHANGE_FORMATTER is not set, so by default
810 // an optimized transform is not reusable. The plug-in can, however, change
811 // the flags and make it suitable.
812
813 p->ContextID = ContextID;
814 p->InputFormat = *InputFormat;
815 p->OutputFormat = *OutputFormat;
816 p->dwOriginalFlags = *dwFlags;
817
818 // Fill the formatters just in case the optimized routine is interested.
819 // No error is thrown if the formatter doesn't exist. It is up to the optimization
820 // factory to decide what to do in those cases.
821 p->FromInput = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
822 p->ToOutput = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
823 p->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
824 p->ToOutputFloat = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
825
826 // Save the day?
827 if (Plugin->OldXform) {
828 p->OldXform = (_cmsTransformFn) p->xform;
829 p->xform = _cmsTransform2toTransformAdaptor;
830 }
831
832 return p;
833 }
834 }
835
836 // Not suitable for the transform plug-in, let's check the pipeline plug-in
837 _cmsOptimizePipeline(ContextID, &p->Lut, Intent, InputFormat, OutputFormat, dwFlags);
838 }
839
840 // Check whatever this is a true floating point transform
841 if (_cmsFormatterIsFloat(*InputFormat) && _cmsFormatterIsFloat(*OutputFormat)) {
842
843 // Get formatter function always return a valid union, but the contents of this union may be NULL.
844 p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
845 p ->ToOutputFloat = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
846 *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
847
848 if (p ->FromInputFloat == NULL || p ->ToOutputFloat == NULL) {
849
850 cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
851 _cmsFree(ContextID, p);
972 }
973
974 // Check colorspace
975 static
976 cmsBool IsProperColorSpace(cmsColorSpaceSignature Check, cmsUInt32Number dwFormat)
977 {
978 int Space1 = T_COLORSPACE(dwFormat);
979 int Space2 = _cmsLCMScolorSpace(Check);
980
981 if (Space1 == PT_ANY) return TRUE;
982 if (Space1 == Space2) return TRUE;
983
984 if (Space1 == PT_LabV2 && Space2 == PT_Lab) return TRUE;
985 if (Space1 == PT_Lab && Space2 == PT_LabV2) return TRUE;
986
987 return FALSE;
988 }
989
990 // ----------------------------------------------------------------------------------------------------------------
991
992 // Jun-21-2000: Some profiles (those that comes with W2K) comes
993 // with the media white (media black?) x 100. Add a sanity check
994
995 static
996 void NormalizeXYZ(cmsCIEXYZ* Dest)
997 {
998 while (Dest -> X > 2. &&
999 Dest -> Y > 2. &&
1000 Dest -> Z > 2.) {
1001
1002 Dest -> X /= 10.;
1003 Dest -> Y /= 10.;
1004 Dest -> Z /= 10.;
1005 }
1006 }
1007
1008 static
1009 void SetWhitePoint(cmsCIEXYZ* wtPt, const cmsCIEXYZ* src)
1010 {
1011 if (src == NULL) {
1012 wtPt ->X = cmsD50X;
1013 wtPt ->Y = cmsD50Y;
1014 wtPt ->Z = cmsD50Z;
1015 }
1016 else {
1017 wtPt ->X = src->X;
1018 wtPt ->Y = src->Y;
1019 wtPt ->Z = src->Z;
1020
1021 NormalizeXYZ(wtPt);
1022 }
1023
1024 }
1025
1026 // New to lcms 2.0 -- have all parameters available.
1027 cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,
1028 cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[],
1029 cmsBool BPC[],
1030 cmsUInt32Number Intents[],
1031 cmsFloat64Number AdaptationStates[],
1032 cmsHPROFILE hGamutProfile,
1033 cmsUInt32Number nGamutPCSposition,
1034 cmsUInt32Number InputFormat,
1035 cmsUInt32Number OutputFormat,
1036 cmsUInt32Number dwFlags)
1037 {
1038 _cmsTRANSFORM* xform;
1039 cmsColorSpaceSignature EntryColorSpace;
1040 cmsColorSpaceSignature ExitColorSpace;
1041 cmsPipeline* Lut;
1312 {
1313 _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
1314
1315 if (xform == NULL) return 0;
1316 return xform->InputFormat;
1317 }
1318
1319 cmsUInt32Number CMSEXPORT cmsGetTransformOutputFormat(cmsHTRANSFORM hTransform)
1320 {
1321 _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
1322
1323 if (xform == NULL) return 0;
1324 return xform->OutputFormat;
1325 }
1326
1327 // For backwards compatibility
1328 cmsBool CMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform,
1329 cmsUInt32Number InputFormat,
1330 cmsUInt32Number OutputFormat)
1331 {
1332 _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
1333 cmsFormatter16 FromInput, ToOutput;
1334
1335
1336 // We only can afford to change formatters if previous transform is at least 16 bits
1337 if (!(xform ->dwOriginalFlags & cmsFLAGS_CAN_CHANGE_FORMATTER)) {
1338
1339 cmsSignalError(xform ->ContextID, cmsERROR_NOT_SUITABLE, "cmsChangeBuffersFormat works only on transforms created originally with at least 16 bits of precision");
1340 return FALSE;
1341 }
1342
1343 FromInput = _cmsGetFormatter(xform->ContextID, InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
1344 ToOutput = _cmsGetFormatter(xform->ContextID, OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
1345
1346 if (FromInput == NULL || ToOutput == NULL) {
1347
1348 cmsSignalError(xform -> ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
1349 return FALSE;
1350 }
1351
|