Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/share/native/liblcms/cmsxform.c
41152 views
1
/*
2
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3
*
4
* This code is free software; you can redistribute it and/or modify it
5
* under the terms of the GNU General Public License version 2 only, as
6
* published by the Free Software Foundation. Oracle designates this
7
* particular file as subject to the "Classpath" exception as provided
8
* by Oracle in the LICENSE file that accompanied this code.
9
*
10
* This code is distributed in the hope that it will be useful, but WITHOUT
11
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
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-2020 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
//---------------------------------------------------------------------------------
54
//
55
56
#include "lcms2_internal.h"
57
58
// Transformations stuff
59
// -----------------------------------------------------------------------
60
61
#define DEFAULT_OBSERVER_ADAPTATION_STATE 1.0
62
63
// The Context0 observer adaptation state.
64
_cmsAdaptationStateChunkType _cmsAdaptationStateChunk = { DEFAULT_OBSERVER_ADAPTATION_STATE };
65
66
// Init and duplicate observer adaptation state
67
void _cmsAllocAdaptationStateChunk(struct _cmsContext_struct* ctx,
68
const struct _cmsContext_struct* src)
69
{
70
static _cmsAdaptationStateChunkType AdaptationStateChunk = { DEFAULT_OBSERVER_ADAPTATION_STATE };
71
void* from;
72
73
if (src != NULL) {
74
from = src ->chunks[AdaptationStateContext];
75
}
76
else {
77
from = &AdaptationStateChunk;
78
}
79
80
ctx ->chunks[AdaptationStateContext] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsAdaptationStateChunkType));
81
}
82
83
84
// Sets adaptation state for absolute colorimetric intent in the given context. Adaptation state applies on all
85
// but cmsCreateExtendedTransformTHR(). Little CMS can handle incomplete adaptation states.
86
cmsFloat64Number CMSEXPORT cmsSetAdaptationStateTHR(cmsContext ContextID, cmsFloat64Number d)
87
{
88
cmsFloat64Number prev;
89
_cmsAdaptationStateChunkType* ptr = (_cmsAdaptationStateChunkType*) _cmsContextGetClientChunk(ContextID, AdaptationStateContext);
90
91
// Get previous value for return
92
prev = ptr ->AdaptationState;
93
94
// Set the value if d is positive or zero
95
if (d >= 0.0) {
96
97
ptr ->AdaptationState = d;
98
}
99
100
// Always return previous value
101
return prev;
102
}
103
104
105
// The adaptation state may be defaulted by this function. If you don't like it, use the extended transform routine
106
cmsFloat64Number CMSEXPORT cmsSetAdaptationState(cmsFloat64Number d)
107
{
108
return cmsSetAdaptationStateTHR(NULL, d);
109
}
110
111
// -----------------------------------------------------------------------
112
113
// Alarm codes for 16-bit transformations, because the fixed range of containers there are
114
// no values left to mark out of gamut.
115
116
#define DEFAULT_ALARM_CODES_VALUE {0x7F00, 0x7F00, 0x7F00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
117
118
_cmsAlarmCodesChunkType _cmsAlarmCodesChunk = { DEFAULT_ALARM_CODES_VALUE };
119
120
// Sets the codes used to mark out-out-gamut on Proofing transforms for a given context. Values are meant to be
121
// encoded in 16 bits.
122
void CMSEXPORT cmsSetAlarmCodesTHR(cmsContext ContextID, const cmsUInt16Number AlarmCodesP[cmsMAXCHANNELS])
123
{
124
_cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(ContextID, AlarmCodesContext);
125
126
_cmsAssert(ContextAlarmCodes != NULL); // Can't happen
127
128
memcpy(ContextAlarmCodes->AlarmCodes, AlarmCodesP, sizeof(ContextAlarmCodes->AlarmCodes));
129
}
130
131
// Gets the current codes used to mark out-out-gamut on Proofing transforms for the given context.
132
// Values are meant to be encoded in 16 bits.
133
void CMSEXPORT cmsGetAlarmCodesTHR(cmsContext ContextID, cmsUInt16Number AlarmCodesP[cmsMAXCHANNELS])
134
{
135
_cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(ContextID, AlarmCodesContext);
136
137
_cmsAssert(ContextAlarmCodes != NULL); // Can't happen
138
139
memcpy(AlarmCodesP, ContextAlarmCodes->AlarmCodes, sizeof(ContextAlarmCodes->AlarmCodes));
140
}
141
142
void CMSEXPORT cmsSetAlarmCodes(const cmsUInt16Number NewAlarm[cmsMAXCHANNELS])
143
{
144
_cmsAssert(NewAlarm != NULL);
145
146
cmsSetAlarmCodesTHR(NULL, NewAlarm);
147
}
148
149
void CMSEXPORT cmsGetAlarmCodes(cmsUInt16Number OldAlarm[cmsMAXCHANNELS])
150
{
151
_cmsAssert(OldAlarm != NULL);
152
cmsGetAlarmCodesTHR(NULL, OldAlarm);
153
}
154
155
156
// Init and duplicate alarm codes
157
void _cmsAllocAlarmCodesChunk(struct _cmsContext_struct* ctx,
158
const struct _cmsContext_struct* src)
159
{
160
static _cmsAlarmCodesChunkType AlarmCodesChunk = { DEFAULT_ALARM_CODES_VALUE };
161
void* from;
162
163
if (src != NULL) {
164
from = src ->chunks[AlarmCodesContext];
165
}
166
else {
167
from = &AlarmCodesChunk;
168
}
169
170
ctx ->chunks[AlarmCodesContext] = _cmsSubAllocDup(ctx ->MemPool, from, sizeof(_cmsAlarmCodesChunkType));
171
}
172
173
// -----------------------------------------------------------------------
174
175
// Get rid of transform resources
176
void CMSEXPORT cmsDeleteTransform(cmsHTRANSFORM hTransform)
177
{
178
_cmsTRANSFORM* p = (_cmsTRANSFORM*) hTransform;
179
180
_cmsAssert(p != NULL);
181
182
if (p -> GamutCheck)
183
cmsPipelineFree(p -> GamutCheck);
184
185
if (p -> Lut)
186
cmsPipelineFree(p -> Lut);
187
188
if (p ->InputColorant)
189
cmsFreeNamedColorList(p ->InputColorant);
190
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
204
static
205
cmsUInt32Number PixelSize(cmsUInt32Number Format)
206
{
207
cmsUInt32Number fmt_bytes = T_BYTES(Format);
208
209
// For double, the T_BYTES field is zero
210
if (fmt_bytes == 0)
211
return sizeof(cmsUInt64Number);
212
213
// Otherwise, it is already correct for all formats
214
return fmt_bytes;
215
}
216
217
218
219
220
// Apply transform.
221
void CMSEXPORT cmsDoTransform(cmsHTRANSFORM Transform,
222
const void* InputBuffer,
223
void* OutputBuffer,
224
cmsUInt32Number Size)
225
226
{
227
_cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform;
228
cmsStride stride;
229
230
stride.BytesPerLineIn = 0; // Not used
231
stride.BytesPerLineOut = 0;
232
stride.BytesPerPlaneIn = Size * PixelSize(p->InputFormat);
233
stride.BytesPerPlaneOut = Size * PixelSize(p->OutputFormat);
234
235
p -> xform(p, InputBuffer, OutputBuffer, Size, 1, &stride);
236
}
237
238
239
// This is a legacy stride for planar
240
void CMSEXPORT cmsDoTransformStride(cmsHTRANSFORM Transform,
241
const void* InputBuffer,
242
void* OutputBuffer,
243
cmsUInt32Number Size, cmsUInt32Number Stride)
244
245
{
246
_cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform;
247
cmsStride stride;
248
249
stride.BytesPerLineIn = 0;
250
stride.BytesPerLineOut = 0;
251
stride.BytesPerPlaneIn = Stride;
252
stride.BytesPerPlaneOut = Stride;
253
254
p -> xform(p, InputBuffer, OutputBuffer, Size, 1, &stride);
255
}
256
257
// This is the "fast" function for plugins
258
void CMSEXPORT cmsDoTransformLineStride(cmsHTRANSFORM Transform,
259
const void* InputBuffer,
260
void* OutputBuffer,
261
cmsUInt32Number PixelsPerLine,
262
cmsUInt32Number LineCount,
263
cmsUInt32Number BytesPerLineIn,
264
cmsUInt32Number BytesPerLineOut,
265
cmsUInt32Number BytesPerPlaneIn,
266
cmsUInt32Number BytesPerPlaneOut)
267
268
{
269
_cmsTRANSFORM* p = (_cmsTRANSFORM*) Transform;
270
cmsStride stride;
271
272
stride.BytesPerLineIn = BytesPerLineIn;
273
stride.BytesPerLineOut = BytesPerLineOut;
274
stride.BytesPerPlaneIn = BytesPerPlaneIn;
275
stride.BytesPerPlaneOut = BytesPerPlaneOut;
276
277
p->xform(p, InputBuffer, OutputBuffer, PixelsPerLine, LineCount, &stride);
278
}
279
280
281
282
// Transform routines ----------------------------------------------------------------------------------------------------------
283
284
// Float xform converts floats. Since there are no performance issues, one routine does all job, including gamut check.
285
// Note that because extended range, we can use a -1.0 value for out of gamut in this case.
286
static
287
void FloatXFORM(_cmsTRANSFORM* p,
288
const void* in,
289
void* out,
290
cmsUInt32Number PixelsPerLine,
291
cmsUInt32Number LineCount,
292
const cmsStride* Stride)
293
{
294
cmsUInt8Number* accum;
295
cmsUInt8Number* output;
296
cmsFloat32Number fIn[cmsMAXCHANNELS], fOut[cmsMAXCHANNELS];
297
cmsFloat32Number OutOfGamut;
298
cmsUInt32Number i, j, c, strideIn, strideOut;
299
300
_cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride);
301
302
strideIn = 0;
303
strideOut = 0;
304
memset(fIn, 0, sizeof(fIn));
305
memset(fOut, 0, sizeof(fOut));
306
307
for (i = 0; i < LineCount; i++) {
308
309
accum = (cmsUInt8Number*)in + strideIn;
310
output = (cmsUInt8Number*)out + strideOut;
311
312
for (j = 0; j < PixelsPerLine; j++) {
313
314
accum = p->FromInputFloat(p, fIn, accum, Stride->BytesPerPlaneIn);
315
316
// Any gamut chack to do?
317
if (p->GamutCheck != NULL) {
318
319
// Evaluate gamut marker.
320
cmsPipelineEvalFloat(fIn, &OutOfGamut, p->GamutCheck);
321
322
// Is current color out of gamut?
323
if (OutOfGamut > 0.0) {
324
325
// Certainly, out of gamut
326
for (c = 0; c < cmsMAXCHANNELS; c++)
327
fOut[c] = -1.0;
328
329
}
330
else {
331
// No, proceed normally
332
cmsPipelineEvalFloat(fIn, fOut, p->Lut);
333
}
334
}
335
else {
336
337
// No gamut check at all
338
cmsPipelineEvalFloat(fIn, fOut, p->Lut);
339
}
340
341
342
output = p->ToOutputFloat(p, fOut, output, Stride->BytesPerPlaneOut);
343
}
344
345
strideIn += Stride->BytesPerLineIn;
346
strideOut += Stride->BytesPerLineOut;
347
}
348
349
}
350
351
352
static
353
void NullFloatXFORM(_cmsTRANSFORM* p,
354
const void* in,
355
void* out,
356
cmsUInt32Number PixelsPerLine,
357
cmsUInt32Number LineCount,
358
const cmsStride* Stride)
359
360
{
361
cmsUInt8Number* accum;
362
cmsUInt8Number* output;
363
cmsFloat32Number fIn[cmsMAXCHANNELS];
364
cmsUInt32Number i, j, strideIn, strideOut;
365
366
_cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride);
367
368
strideIn = 0;
369
strideOut = 0;
370
memset(fIn, 0, sizeof(fIn));
371
372
for (i = 0; i < LineCount; i++) {
373
374
accum = (cmsUInt8Number*) in + strideIn;
375
output = (cmsUInt8Number*) out + strideOut;
376
377
for (j = 0; j < PixelsPerLine; j++) {
378
379
accum = p->FromInputFloat(p, fIn, accum, Stride ->BytesPerPlaneIn);
380
output = p->ToOutputFloat(p, fIn, output, Stride->BytesPerPlaneOut);
381
}
382
383
strideIn += Stride->BytesPerLineIn;
384
strideOut += Stride->BytesPerLineOut;
385
}
386
}
387
388
// 16 bit precision -----------------------------------------------------------------------------------------------------------
389
390
// Null transformation, only applies formatters. No cache
391
static
392
void NullXFORM(_cmsTRANSFORM* p,
393
const void* in,
394
void* out,
395
cmsUInt32Number PixelsPerLine,
396
cmsUInt32Number LineCount,
397
const cmsStride* Stride)
398
{
399
cmsUInt8Number* accum;
400
cmsUInt8Number* output;
401
cmsUInt16Number wIn[cmsMAXCHANNELS];
402
cmsUInt32Number i, j, strideIn, strideOut;
403
404
_cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride);
405
406
strideIn = 0;
407
strideOut = 0;
408
memset(wIn, 0, sizeof(wIn));
409
410
for (i = 0; i < LineCount; i++) {
411
412
accum = (cmsUInt8Number*)in + strideIn;
413
output = (cmsUInt8Number*)out + strideOut;
414
415
for (j = 0; j < PixelsPerLine; j++) {
416
417
accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn);
418
output = p->ToOutput(p, wIn, output, Stride->BytesPerPlaneOut);
419
}
420
421
strideIn += Stride->BytesPerLineIn;
422
strideOut += Stride->BytesPerLineOut;
423
}
424
425
}
426
427
428
// No gamut check, no cache, 16 bits
429
static
430
void PrecalculatedXFORM(_cmsTRANSFORM* p,
431
const void* in,
432
void* out,
433
cmsUInt32Number PixelsPerLine,
434
cmsUInt32Number LineCount,
435
const cmsStride* Stride)
436
{
437
CMSREGISTER cmsUInt8Number* accum;
438
CMSREGISTER cmsUInt8Number* output;
439
cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
440
cmsUInt32Number i, j, strideIn, strideOut;
441
442
_cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride);
443
444
strideIn = 0;
445
strideOut = 0;
446
memset(wIn, 0, sizeof(wIn));
447
memset(wOut, 0, sizeof(wOut));
448
449
for (i = 0; i < LineCount; i++) {
450
451
accum = (cmsUInt8Number*)in + strideIn;
452
output = (cmsUInt8Number*)out + strideOut;
453
454
for (j = 0; j < PixelsPerLine; j++) {
455
456
accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn);
457
p->Lut->Eval16Fn(wIn, wOut, p->Lut->Data);
458
output = p->ToOutput(p, wOut, output, Stride->BytesPerPlaneOut);
459
}
460
461
strideIn += Stride->BytesPerLineIn;
462
strideOut += Stride->BytesPerLineOut;
463
}
464
465
}
466
467
468
// Auxiliary: Handle precalculated gamut check. The retrieval of context may be alittle bit slow, but this function is not critical.
469
static
470
void TransformOnePixelWithGamutCheck(_cmsTRANSFORM* p,
471
const cmsUInt16Number wIn[],
472
cmsUInt16Number wOut[])
473
{
474
cmsUInt16Number wOutOfGamut;
475
476
p ->GamutCheck ->Eval16Fn(wIn, &wOutOfGamut, p ->GamutCheck ->Data);
477
if (wOutOfGamut >= 1) {
478
479
cmsUInt32Number i;
480
_cmsAlarmCodesChunkType* ContextAlarmCodes = (_cmsAlarmCodesChunkType*) _cmsContextGetClientChunk(p->ContextID, AlarmCodesContext);
481
482
for (i=0; i < p ->Lut->OutputChannels; i++) {
483
484
wOut[i] = ContextAlarmCodes ->AlarmCodes[i];
485
}
486
}
487
else
488
p ->Lut ->Eval16Fn(wIn, wOut, p -> Lut->Data);
489
}
490
491
// Gamut check, No cache, 16 bits.
492
static
493
void PrecalculatedXFORMGamutCheck(_cmsTRANSFORM* p,
494
const void* in,
495
void* out,
496
cmsUInt32Number PixelsPerLine,
497
cmsUInt32Number LineCount,
498
const cmsStride* Stride)
499
{
500
cmsUInt8Number* accum;
501
cmsUInt8Number* output;
502
cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
503
cmsUInt32Number i, j, strideIn, strideOut;
504
505
_cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride);
506
507
strideIn = 0;
508
strideOut = 0;
509
memset(wIn, 0, sizeof(wIn));
510
memset(wOut, 0, sizeof(wOut));
511
512
for (i = 0; i < LineCount; i++) {
513
514
accum = (cmsUInt8Number*)in + strideIn;
515
output = (cmsUInt8Number*)out + strideOut;
516
517
for (j = 0; j < PixelsPerLine; j++) {
518
519
accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn);
520
TransformOnePixelWithGamutCheck(p, wIn, wOut);
521
output = p->ToOutput(p, wOut, output, Stride->BytesPerPlaneOut);
522
}
523
524
strideIn += Stride->BytesPerLineIn;
525
strideOut += Stride->BytesPerLineOut;
526
}
527
}
528
529
530
// No gamut check, Cache, 16 bits,
531
static
532
void CachedXFORM(_cmsTRANSFORM* p,
533
const void* in,
534
void* out,
535
cmsUInt32Number PixelsPerLine,
536
cmsUInt32Number LineCount,
537
const cmsStride* Stride)
538
{
539
cmsUInt8Number* accum;
540
cmsUInt8Number* output;
541
cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
542
_cmsCACHE Cache;
543
cmsUInt32Number i, j, strideIn, strideOut;
544
545
_cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride);
546
547
// Empty buffers for quick memcmp
548
memset(wIn, 0, sizeof(wIn));
549
memset(wOut, 0, sizeof(wOut));
550
551
// Get copy of zero cache
552
memcpy(&Cache, &p->Cache, sizeof(Cache));
553
554
strideIn = 0;
555
strideOut = 0;
556
557
for (i = 0; i < LineCount; i++) {
558
559
accum = (cmsUInt8Number*)in + strideIn;
560
output = (cmsUInt8Number*)out + strideOut;
561
562
for (j = 0; j < PixelsPerLine; j++) {
563
564
accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn);
565
566
if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) {
567
568
memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut));
569
}
570
else {
571
p->Lut->Eval16Fn(wIn, wOut, p->Lut->Data);
572
573
memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn));
574
memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut));
575
}
576
577
output = p->ToOutput(p, wOut, output, Stride->BytesPerPlaneOut);
578
}
579
580
strideIn += Stride->BytesPerLineIn;
581
strideOut += Stride->BytesPerLineOut;
582
}
583
}
584
585
// All those nice features together
586
static
587
void CachedXFORMGamutCheck(_cmsTRANSFORM* p,
588
const void* in,
589
void* out,
590
cmsUInt32Number PixelsPerLine,
591
cmsUInt32Number LineCount,
592
const cmsStride* Stride)
593
{
594
cmsUInt8Number* accum;
595
cmsUInt8Number* output;
596
cmsUInt16Number wIn[cmsMAXCHANNELS], wOut[cmsMAXCHANNELS];
597
_cmsCACHE Cache;
598
cmsUInt32Number i, j, strideIn, strideOut;
599
600
_cmsHandleExtraChannels(p, in, out, PixelsPerLine, LineCount, Stride);
601
602
// Empty buffers for quick memcmp
603
memset(wIn, 0, sizeof(wIn));
604
memset(wOut, 0, sizeof(wOut));
605
606
// Get copy of zero cache
607
memcpy(&Cache, &p->Cache, sizeof(Cache));
608
609
strideIn = 0;
610
strideOut = 0;
611
612
for (i = 0; i < LineCount; i++) {
613
614
accum = (cmsUInt8Number*)in + strideIn;
615
output = (cmsUInt8Number*)out + strideOut;
616
617
for (j = 0; j < PixelsPerLine; j++) {
618
619
accum = p->FromInput(p, wIn, accum, Stride->BytesPerPlaneIn);
620
621
if (memcmp(wIn, Cache.CacheIn, sizeof(Cache.CacheIn)) == 0) {
622
623
memcpy(wOut, Cache.CacheOut, sizeof(Cache.CacheOut));
624
}
625
else {
626
TransformOnePixelWithGamutCheck(p, wIn, wOut);
627
628
memcpy(Cache.CacheIn, wIn, sizeof(Cache.CacheIn));
629
memcpy(Cache.CacheOut, wOut, sizeof(Cache.CacheOut));
630
}
631
632
output = p->ToOutput(p, wOut, output, Stride->BytesPerPlaneOut);
633
}
634
635
strideIn += Stride->BytesPerLineIn;
636
strideOut += Stride->BytesPerLineOut;
637
}
638
}
639
640
// Transform plug-ins ----------------------------------------------------------------------------------------------------
641
642
// List of used-defined transform factories
643
typedef struct _cmsTransformCollection_st {
644
645
_cmsTransform2Factory Factory;
646
cmsBool OldXform; // Factory returns xform function in the old style
647
648
struct _cmsTransformCollection_st *Next;
649
650
} _cmsTransformCollection;
651
652
// The linked list head
653
_cmsTransformPluginChunkType _cmsTransformPluginChunk = { NULL };
654
655
656
// Duplicates the zone of memory used by the plug-in in the new context
657
static
658
void DupPluginTransformList(struct _cmsContext_struct* ctx,
659
const struct _cmsContext_struct* src)
660
{
661
_cmsTransformPluginChunkType newHead = { NULL };
662
_cmsTransformCollection* entry;
663
_cmsTransformCollection* Anterior = NULL;
664
_cmsTransformPluginChunkType* head = (_cmsTransformPluginChunkType*) src->chunks[TransformPlugin];
665
666
// Walk the list copying all nodes
667
for (entry = head->TransformCollection;
668
entry != NULL;
669
entry = entry ->Next) {
670
671
_cmsTransformCollection *newEntry = ( _cmsTransformCollection *) _cmsSubAllocDup(ctx ->MemPool, entry, sizeof(_cmsTransformCollection));
672
673
if (newEntry == NULL)
674
return;
675
676
// We want to keep the linked list order, so this is a little bit tricky
677
newEntry -> Next = NULL;
678
if (Anterior)
679
Anterior -> Next = newEntry;
680
681
Anterior = newEntry;
682
683
if (newHead.TransformCollection == NULL)
684
newHead.TransformCollection = newEntry;
685
}
686
687
ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx->MemPool, &newHead, sizeof(_cmsTransformPluginChunkType));
688
}
689
690
// Allocates memory for transform plugin factory
691
void _cmsAllocTransformPluginChunk(struct _cmsContext_struct* ctx,
692
const struct _cmsContext_struct* src)
693
{
694
if (src != NULL) {
695
696
// Copy all linked list
697
DupPluginTransformList(ctx, src);
698
}
699
else {
700
static _cmsTransformPluginChunkType TransformPluginChunkType = { NULL };
701
ctx ->chunks[TransformPlugin] = _cmsSubAllocDup(ctx ->MemPool, &TransformPluginChunkType, sizeof(_cmsTransformPluginChunkType));
702
}
703
}
704
705
// Adaptor for old versions of plug-in
706
static
707
void _cmsTransform2toTransformAdaptor(struct _cmstransform_struct *CMMcargo,
708
const void* InputBuffer,
709
void* OutputBuffer,
710
cmsUInt32Number PixelsPerLine,
711
cmsUInt32Number LineCount,
712
const cmsStride* Stride)
713
{
714
715
cmsUInt32Number i, strideIn, strideOut;
716
717
_cmsHandleExtraChannels(CMMcargo, InputBuffer, OutputBuffer, PixelsPerLine, LineCount, Stride);
718
719
strideIn = 0;
720
strideOut = 0;
721
722
for (i = 0; i < LineCount; i++) {
723
724
void *accum = (cmsUInt8Number*)InputBuffer + strideIn;
725
void *output = (cmsUInt8Number*)OutputBuffer + strideOut;
726
727
CMMcargo->OldXform(CMMcargo, accum, output, PixelsPerLine, Stride->BytesPerPlaneIn);
728
729
strideIn += Stride->BytesPerLineIn;
730
strideOut += Stride->BytesPerLineOut;
731
}
732
}
733
734
735
736
// Register new ways to transform
737
cmsBool _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Data)
738
{
739
cmsPluginTransform* Plugin = (cmsPluginTransform*) Data;
740
_cmsTransformCollection* fl;
741
_cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID,TransformPlugin);
742
743
if (Data == NULL) {
744
745
// Free the chain. Memory is safely freed at exit
746
ctx->TransformCollection = NULL;
747
return TRUE;
748
}
749
750
// Factory callback is required
751
if (Plugin->factories.xform == NULL) return FALSE;
752
753
754
fl = (_cmsTransformCollection*) _cmsPluginMalloc(ContextID, sizeof(_cmsTransformCollection));
755
if (fl == NULL) return FALSE;
756
757
// Check for full xform plug-ins previous to 2.8, we would need an adapter in that case
758
if (Plugin->base.ExpectedVersion < 2080) {
759
760
fl->OldXform = TRUE;
761
}
762
else
763
fl->OldXform = FALSE;
764
765
// Copy the parameters
766
fl->Factory = Plugin->factories.xform;
767
768
// Keep linked list
769
fl ->Next = ctx->TransformCollection;
770
ctx->TransformCollection = fl;
771
772
// All is ok
773
return TRUE;
774
}
775
776
777
void CMSEXPORT _cmsSetTransformUserData(struct _cmstransform_struct *CMMcargo, void* ptr, _cmsFreeUserDataFn FreePrivateDataFn)
778
{
779
_cmsAssert(CMMcargo != NULL);
780
CMMcargo ->UserData = ptr;
781
CMMcargo ->FreeUserData = FreePrivateDataFn;
782
}
783
784
// returns the pointer defined by the plug-in to store private data
785
void * CMSEXPORT _cmsGetTransformUserData(struct _cmstransform_struct *CMMcargo)
786
{
787
_cmsAssert(CMMcargo != NULL);
788
return CMMcargo ->UserData;
789
}
790
791
// returns the current formatters
792
void CMSEXPORT _cmsGetTransformFormatters16(struct _cmstransform_struct *CMMcargo, cmsFormatter16* FromInput, cmsFormatter16* ToOutput)
793
{
794
_cmsAssert(CMMcargo != NULL);
795
if (FromInput) *FromInput = CMMcargo ->FromInput;
796
if (ToOutput) *ToOutput = CMMcargo ->ToOutput;
797
}
798
799
void CMSEXPORT _cmsGetTransformFormattersFloat(struct _cmstransform_struct *CMMcargo, cmsFormatterFloat* FromInput, cmsFormatterFloat* ToOutput)
800
{
801
_cmsAssert(CMMcargo != NULL);
802
if (FromInput) *FromInput = CMMcargo ->FromInputFloat;
803
if (ToOutput) *ToOutput = CMMcargo ->ToOutputFloat;
804
}
805
806
// returns original flags
807
cmsUInt32Number CMSEXPORT _cmsGetTransformFlags(struct _cmstransform_struct* CMMcargo)
808
{
809
_cmsAssert(CMMcargo != NULL);
810
return CMMcargo->dwOriginalFlags;
811
}
812
813
// Allocate transform struct and set it to defaults. Ask the optimization plug-in about if those formats are proper
814
// for separated transforms. If this is the case,
815
static
816
_cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
817
cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags)
818
{
819
_cmsTransformPluginChunkType* ctx = ( _cmsTransformPluginChunkType*) _cmsContextGetClientChunk(ContextID, TransformPlugin);
820
_cmsTransformCollection* Plugin;
821
822
// Allocate needed memory
823
_cmsTRANSFORM* p = (_cmsTRANSFORM*)_cmsMallocZero(ContextID, sizeof(_cmsTRANSFORM));
824
if (!p) {
825
cmsPipelineFree(lut);
826
return NULL;
827
}
828
829
// Store the proposed pipeline
830
p->Lut = lut;
831
832
// Let's see if any plug-in want to do the transform by itself
833
if (p->Lut != NULL) {
834
835
if (!(*dwFlags & cmsFLAGS_NOOPTIMIZE))
836
{
837
for (Plugin = ctx->TransformCollection;
838
Plugin != NULL;
839
Plugin = Plugin->Next) {
840
841
if (Plugin->Factory(&p->xform, &p->UserData, &p->FreeUserData, &p->Lut, InputFormat, OutputFormat, dwFlags)) {
842
843
// Last plugin in the declaration order takes control. We just keep
844
// the original parameters as a logging.
845
// Note that cmsFLAGS_CAN_CHANGE_FORMATTER is not set, so by default
846
// an optimized transform is not reusable. The plug-in can, however, change
847
// the flags and make it suitable.
848
849
p->ContextID = ContextID;
850
p->InputFormat = *InputFormat;
851
p->OutputFormat = *OutputFormat;
852
p->dwOriginalFlags = *dwFlags;
853
854
// Fill the formatters just in case the optimized routine is interested.
855
// No error is thrown if the formatter doesn't exist. It is up to the optimization
856
// factory to decide what to do in those cases.
857
p->FromInput = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
858
p->ToOutput = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
859
p->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
860
p->ToOutputFloat = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
861
862
// Save the day? (Ignore the warning)
863
if (Plugin->OldXform) {
864
p->OldXform = (_cmsTransformFn)(void*)p->xform;
865
p->xform = _cmsTransform2toTransformAdaptor;
866
}
867
868
return p;
869
}
870
}
871
}
872
873
// Not suitable for the transform plug-in, let's check the pipeline plug-in
874
_cmsOptimizePipeline(ContextID, &p->Lut, Intent, InputFormat, OutputFormat, dwFlags);
875
}
876
877
// Check whatever this is a true floating point transform
878
if (_cmsFormatterIsFloat(*InputFormat) && _cmsFormatterIsFloat(*OutputFormat)) {
879
880
// Get formatter function always return a valid union, but the contents of this union may be NULL.
881
p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
882
p ->ToOutputFloat = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
883
*dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
884
885
if (p ->FromInputFloat == NULL || p ->ToOutputFloat == NULL) {
886
887
cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
888
cmsDeleteTransform(p);
889
return NULL;
890
}
891
892
if (*dwFlags & cmsFLAGS_NULLTRANSFORM) {
893
894
p ->xform = NullFloatXFORM;
895
}
896
else {
897
// Float transforms don't use cache, always are non-NULL
898
p ->xform = FloatXFORM;
899
}
900
901
}
902
else {
903
904
if (*InputFormat == 0 && *OutputFormat == 0) {
905
p ->FromInput = p ->ToOutput = NULL;
906
*dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
907
}
908
else {
909
910
cmsUInt32Number BytesPerPixelInput;
911
912
p ->FromInput = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
913
p ->ToOutput = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
914
915
if (p ->FromInput == NULL || p ->ToOutput == NULL) {
916
917
cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
918
cmsDeleteTransform(p);
919
return NULL;
920
}
921
922
BytesPerPixelInput = T_BYTES(p ->InputFormat);
923
if (BytesPerPixelInput == 0 || BytesPerPixelInput >= 2)
924
*dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
925
926
}
927
928
if (*dwFlags & cmsFLAGS_NULLTRANSFORM) {
929
930
p ->xform = NullXFORM;
931
}
932
else {
933
if (*dwFlags & cmsFLAGS_NOCACHE) {
934
935
if (*dwFlags & cmsFLAGS_GAMUTCHECK)
936
p ->xform = PrecalculatedXFORMGamutCheck; // Gamut check, no cache
937
else
938
p ->xform = PrecalculatedXFORM; // No cache, no gamut check
939
}
940
else {
941
942
if (*dwFlags & cmsFLAGS_GAMUTCHECK)
943
p ->xform = CachedXFORMGamutCheck; // Gamut check, cache
944
else
945
p ->xform = CachedXFORM; // No gamut check, cache
946
947
}
948
}
949
}
950
951
p ->InputFormat = *InputFormat;
952
p ->OutputFormat = *OutputFormat;
953
p ->dwOriginalFlags = *dwFlags;
954
p ->ContextID = ContextID;
955
p ->UserData = NULL;
956
return p;
957
}
958
959
static
960
cmsBool GetXFormColorSpaces(cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[], cmsColorSpaceSignature* Input, cmsColorSpaceSignature* Output)
961
{
962
cmsColorSpaceSignature ColorSpaceIn, ColorSpaceOut;
963
cmsColorSpaceSignature PostColorSpace;
964
cmsUInt32Number i;
965
966
if (nProfiles == 0) return FALSE;
967
if (hProfiles[0] == NULL) return FALSE;
968
969
*Input = PostColorSpace = cmsGetColorSpace(hProfiles[0]);
970
971
for (i=0; i < nProfiles; i++) {
972
973
cmsProfileClassSignature cls;
974
cmsHPROFILE hProfile = hProfiles[i];
975
976
int lIsInput = (PostColorSpace != cmsSigXYZData) &&
977
(PostColorSpace != cmsSigLabData);
978
979
if (hProfile == NULL) return FALSE;
980
981
cls = cmsGetDeviceClass(hProfile);
982
983
if (cls == cmsSigNamedColorClass) {
984
985
ColorSpaceIn = cmsSig1colorData;
986
ColorSpaceOut = (nProfiles > 1) ? cmsGetPCS(hProfile) : cmsGetColorSpace(hProfile);
987
}
988
else
989
if (lIsInput || (cls == cmsSigLinkClass)) {
990
991
ColorSpaceIn = cmsGetColorSpace(hProfile);
992
ColorSpaceOut = cmsGetPCS(hProfile);
993
}
994
else
995
{
996
ColorSpaceIn = cmsGetPCS(hProfile);
997
ColorSpaceOut = cmsGetColorSpace(hProfile);
998
}
999
1000
if (i==0)
1001
*Input = ColorSpaceIn;
1002
1003
PostColorSpace = ColorSpaceOut;
1004
}
1005
1006
*Output = PostColorSpace;
1007
1008
return TRUE;
1009
}
1010
1011
// Check colorspace
1012
static
1013
cmsBool IsProperColorSpace(cmsColorSpaceSignature Check, cmsUInt32Number dwFormat)
1014
{
1015
int Space1 = (int) T_COLORSPACE(dwFormat);
1016
int Space2 = _cmsLCMScolorSpace(Check);
1017
1018
if (Space1 == PT_ANY) return TRUE;
1019
if (Space1 == Space2) return TRUE;
1020
1021
if (Space1 == PT_LabV2 && Space2 == PT_Lab) return TRUE;
1022
if (Space1 == PT_Lab && Space2 == PT_LabV2) return TRUE;
1023
1024
return FALSE;
1025
}
1026
1027
// ----------------------------------------------------------------------------------------------------------------
1028
1029
// Jun-21-2000: Some profiles (those that comes with W2K) comes
1030
// with the media white (media black?) x 100. Add a sanity check
1031
1032
static
1033
void NormalizeXYZ(cmsCIEXYZ* Dest)
1034
{
1035
while (Dest -> X > 2. &&
1036
Dest -> Y > 2. &&
1037
Dest -> Z > 2.) {
1038
1039
Dest -> X /= 10.;
1040
Dest -> Y /= 10.;
1041
Dest -> Z /= 10.;
1042
}
1043
}
1044
1045
static
1046
void SetWhitePoint(cmsCIEXYZ* wtPt, const cmsCIEXYZ* src)
1047
{
1048
if (src == NULL) {
1049
wtPt ->X = cmsD50X;
1050
wtPt ->Y = cmsD50Y;
1051
wtPt ->Z = cmsD50Z;
1052
}
1053
else {
1054
wtPt ->X = src->X;
1055
wtPt ->Y = src->Y;
1056
wtPt ->Z = src->Z;
1057
1058
NormalizeXYZ(wtPt);
1059
}
1060
1061
}
1062
1063
// New to lcms 2.0 -- have all parameters available.
1064
cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,
1065
cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[],
1066
cmsBool BPC[],
1067
cmsUInt32Number Intents[],
1068
cmsFloat64Number AdaptationStates[],
1069
cmsHPROFILE hGamutProfile,
1070
cmsUInt32Number nGamutPCSposition,
1071
cmsUInt32Number InputFormat,
1072
cmsUInt32Number OutputFormat,
1073
cmsUInt32Number dwFlags)
1074
{
1075
_cmsTRANSFORM* xform;
1076
cmsColorSpaceSignature EntryColorSpace;
1077
cmsColorSpaceSignature ExitColorSpace;
1078
cmsPipeline* Lut;
1079
cmsUInt32Number LastIntent = Intents[nProfiles-1];
1080
1081
// If it is a fake transform
1082
if (dwFlags & cmsFLAGS_NULLTRANSFORM)
1083
{
1084
return AllocEmptyTransform(ContextID, NULL, INTENT_PERCEPTUAL, &InputFormat, &OutputFormat, &dwFlags);
1085
}
1086
1087
// If gamut check is requested, make sure we have a gamut profile
1088
if (dwFlags & cmsFLAGS_GAMUTCHECK) {
1089
if (hGamutProfile == NULL) dwFlags &= ~cmsFLAGS_GAMUTCHECK;
1090
}
1091
1092
// On floating point transforms, inhibit cache
1093
if (_cmsFormatterIsFloat(InputFormat) || _cmsFormatterIsFloat(OutputFormat))
1094
dwFlags |= cmsFLAGS_NOCACHE;
1095
1096
// Mark entry/exit spaces
1097
if (!GetXFormColorSpaces(nProfiles, hProfiles, &EntryColorSpace, &ExitColorSpace)) {
1098
cmsSignalError(ContextID, cmsERROR_NULL, "NULL input profiles on transform");
1099
return NULL;
1100
}
1101
1102
// Check if proper colorspaces
1103
if (!IsProperColorSpace(EntryColorSpace, InputFormat)) {
1104
cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong input color space on transform");
1105
return NULL;
1106
}
1107
1108
if (!IsProperColorSpace(ExitColorSpace, OutputFormat)) {
1109
cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong output color space on transform");
1110
return NULL;
1111
}
1112
1113
// Create a pipeline with all transformations
1114
Lut = _cmsLinkProfiles(ContextID, nProfiles, Intents, hProfiles, BPC, AdaptationStates, dwFlags);
1115
if (Lut == NULL) {
1116
cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Couldn't link the profiles");
1117
return NULL;
1118
}
1119
1120
// Check channel count
1121
if ((cmsChannelsOf(EntryColorSpace) != cmsPipelineInputChannels(Lut)) ||
1122
(cmsChannelsOf(ExitColorSpace) != cmsPipelineOutputChannels(Lut))) {
1123
cmsPipelineFree(Lut);
1124
cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Channel count doesn't match. Profile is corrupted");
1125
return NULL;
1126
}
1127
1128
1129
// All seems ok
1130
xform = AllocEmptyTransform(ContextID, Lut, LastIntent, &InputFormat, &OutputFormat, &dwFlags);
1131
if (xform == NULL) {
1132
return NULL;
1133
}
1134
1135
// Keep values
1136
xform ->EntryColorSpace = EntryColorSpace;
1137
xform ->ExitColorSpace = ExitColorSpace;
1138
xform ->RenderingIntent = Intents[nProfiles-1];
1139
1140
// Take white points
1141
SetWhitePoint(&xform->EntryWhitePoint, (cmsCIEXYZ*) cmsReadTag(hProfiles[0], cmsSigMediaWhitePointTag));
1142
SetWhitePoint(&xform->ExitWhitePoint, (cmsCIEXYZ*) cmsReadTag(hProfiles[nProfiles-1], cmsSigMediaWhitePointTag));
1143
1144
1145
// Create a gamut check LUT if requested
1146
if (hGamutProfile != NULL && (dwFlags & cmsFLAGS_GAMUTCHECK))
1147
xform ->GamutCheck = _cmsCreateGamutCheckPipeline(ContextID, hProfiles,
1148
BPC, Intents,
1149
AdaptationStates,
1150
nGamutPCSposition,
1151
hGamutProfile);
1152
1153
1154
// Try to read input and output colorant table
1155
if (cmsIsTag(hProfiles[0], cmsSigColorantTableTag)) {
1156
1157
// Input table can only come in this way.
1158
xform ->InputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[0], cmsSigColorantTableTag));
1159
}
1160
1161
// Output is a little bit more complex.
1162
if (cmsGetDeviceClass(hProfiles[nProfiles-1]) == cmsSigLinkClass) {
1163
1164
// This tag may exist only on devicelink profiles.
1165
if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag)) {
1166
1167
// It may be NULL if error
1168
xform ->OutputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag));
1169
}
1170
1171
} else {
1172
1173
if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableTag)) {
1174
1175
xform -> OutputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[nProfiles-1], cmsSigColorantTableTag));
1176
}
1177
}
1178
1179
// Store the sequence of profiles
1180
if (dwFlags & cmsFLAGS_KEEP_SEQUENCE) {
1181
xform ->Sequence = _cmsCompileProfileSequence(ContextID, nProfiles, hProfiles);
1182
}
1183
else
1184
xform ->Sequence = NULL;
1185
1186
// If this is a cached transform, init first value, which is zero (16 bits only)
1187
if (!(dwFlags & cmsFLAGS_NOCACHE)) {
1188
1189
memset(&xform ->Cache.CacheIn, 0, sizeof(xform ->Cache.CacheIn));
1190
1191
if (xform ->GamutCheck != NULL) {
1192
TransformOnePixelWithGamutCheck(xform, xform ->Cache.CacheIn, xform->Cache.CacheOut);
1193
}
1194
else {
1195
1196
xform ->Lut ->Eval16Fn(xform ->Cache.CacheIn, xform->Cache.CacheOut, xform -> Lut->Data);
1197
}
1198
1199
}
1200
1201
return (cmsHTRANSFORM) xform;
1202
}
1203
1204
// Multiprofile transforms: Gamut check is not available here, as it is unclear from which profile the gamut comes.
1205
cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransformTHR(cmsContext ContextID,
1206
cmsHPROFILE hProfiles[],
1207
cmsUInt32Number nProfiles,
1208
cmsUInt32Number InputFormat,
1209
cmsUInt32Number OutputFormat,
1210
cmsUInt32Number Intent,
1211
cmsUInt32Number dwFlags)
1212
{
1213
cmsUInt32Number i;
1214
cmsBool BPC[256];
1215
cmsUInt32Number Intents[256];
1216
cmsFloat64Number AdaptationStates[256];
1217
1218
if (nProfiles <= 0 || nProfiles > 255) {
1219
cmsSignalError(ContextID, cmsERROR_RANGE, "Wrong number of profiles. 1..255 expected, %d found.", nProfiles);
1220
return NULL;
1221
}
1222
1223
for (i=0; i < nProfiles; i++) {
1224
BPC[i] = dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION ? TRUE : FALSE;
1225
Intents[i] = Intent;
1226
AdaptationStates[i] = cmsSetAdaptationStateTHR(ContextID, -1);
1227
}
1228
1229
1230
return cmsCreateExtendedTransform(ContextID, nProfiles, hProfiles, BPC, Intents, AdaptationStates, NULL, 0, InputFormat, OutputFormat, dwFlags);
1231
}
1232
1233
1234
1235
cmsHTRANSFORM CMSEXPORT cmsCreateMultiprofileTransform(cmsHPROFILE hProfiles[],
1236
cmsUInt32Number nProfiles,
1237
cmsUInt32Number InputFormat,
1238
cmsUInt32Number OutputFormat,
1239
cmsUInt32Number Intent,
1240
cmsUInt32Number dwFlags)
1241
{
1242
1243
if (nProfiles <= 0 || nProfiles > 255) {
1244
cmsSignalError(NULL, cmsERROR_RANGE, "Wrong number of profiles. 1..255 expected, %d found.", nProfiles);
1245
return NULL;
1246
}
1247
1248
return cmsCreateMultiprofileTransformTHR(cmsGetProfileContextID(hProfiles[0]),
1249
hProfiles,
1250
nProfiles,
1251
InputFormat,
1252
OutputFormat,
1253
Intent,
1254
dwFlags);
1255
}
1256
1257
cmsHTRANSFORM CMSEXPORT cmsCreateTransformTHR(cmsContext ContextID,
1258
cmsHPROFILE Input,
1259
cmsUInt32Number InputFormat,
1260
cmsHPROFILE Output,
1261
cmsUInt32Number OutputFormat,
1262
cmsUInt32Number Intent,
1263
cmsUInt32Number dwFlags)
1264
{
1265
1266
cmsHPROFILE hArray[2];
1267
1268
hArray[0] = Input;
1269
hArray[1] = Output;
1270
1271
return cmsCreateMultiprofileTransformTHR(ContextID, hArray, Output == NULL ? 1U : 2U, InputFormat, OutputFormat, Intent, dwFlags);
1272
}
1273
1274
CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateTransform(cmsHPROFILE Input,
1275
cmsUInt32Number InputFormat,
1276
cmsHPROFILE Output,
1277
cmsUInt32Number OutputFormat,
1278
cmsUInt32Number Intent,
1279
cmsUInt32Number dwFlags)
1280
{
1281
return cmsCreateTransformTHR(cmsGetProfileContextID(Input), Input, InputFormat, Output, OutputFormat, Intent, dwFlags);
1282
}
1283
1284
1285
cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransformTHR(cmsContext ContextID,
1286
cmsHPROFILE InputProfile,
1287
cmsUInt32Number InputFormat,
1288
cmsHPROFILE OutputProfile,
1289
cmsUInt32Number OutputFormat,
1290
cmsHPROFILE ProofingProfile,
1291
cmsUInt32Number nIntent,
1292
cmsUInt32Number ProofingIntent,
1293
cmsUInt32Number dwFlags)
1294
{
1295
cmsHPROFILE hArray[4];
1296
cmsUInt32Number Intents[4];
1297
cmsBool BPC[4];
1298
cmsFloat64Number Adaptation[4];
1299
cmsBool DoBPC = (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION) ? TRUE : FALSE;
1300
1301
1302
hArray[0] = InputProfile; hArray[1] = ProofingProfile; hArray[2] = ProofingProfile; hArray[3] = OutputProfile;
1303
Intents[0] = nIntent; Intents[1] = nIntent; Intents[2] = INTENT_RELATIVE_COLORIMETRIC; Intents[3] = ProofingIntent;
1304
BPC[0] = DoBPC; BPC[1] = DoBPC; BPC[2] = 0; BPC[3] = 0;
1305
1306
Adaptation[0] = Adaptation[1] = Adaptation[2] = Adaptation[3] = cmsSetAdaptationStateTHR(ContextID, -1);
1307
1308
if (!(dwFlags & (cmsFLAGS_SOFTPROOFING|cmsFLAGS_GAMUTCHECK)))
1309
return cmsCreateTransformTHR(ContextID, InputProfile, InputFormat, OutputProfile, OutputFormat, nIntent, dwFlags);
1310
1311
return cmsCreateExtendedTransform(ContextID, 4, hArray, BPC, Intents, Adaptation,
1312
ProofingProfile, 1, InputFormat, OutputFormat, dwFlags);
1313
1314
}
1315
1316
1317
cmsHTRANSFORM CMSEXPORT cmsCreateProofingTransform(cmsHPROFILE InputProfile,
1318
cmsUInt32Number InputFormat,
1319
cmsHPROFILE OutputProfile,
1320
cmsUInt32Number OutputFormat,
1321
cmsHPROFILE ProofingProfile,
1322
cmsUInt32Number nIntent,
1323
cmsUInt32Number ProofingIntent,
1324
cmsUInt32Number dwFlags)
1325
{
1326
return cmsCreateProofingTransformTHR(cmsGetProfileContextID(InputProfile),
1327
InputProfile,
1328
InputFormat,
1329
OutputProfile,
1330
OutputFormat,
1331
ProofingProfile,
1332
nIntent,
1333
ProofingIntent,
1334
dwFlags);
1335
}
1336
1337
1338
// Grab the ContextID from an open transform. Returns NULL if a NULL transform is passed
1339
cmsContext CMSEXPORT cmsGetTransformContextID(cmsHTRANSFORM hTransform)
1340
{
1341
_cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
1342
1343
if (xform == NULL) return NULL;
1344
return xform -> ContextID;
1345
}
1346
1347
// Grab the input/output formats
1348
cmsUInt32Number CMSEXPORT cmsGetTransformInputFormat(cmsHTRANSFORM hTransform)
1349
{
1350
_cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
1351
1352
if (xform == NULL) return 0;
1353
return xform->InputFormat;
1354
}
1355
1356
cmsUInt32Number CMSEXPORT cmsGetTransformOutputFormat(cmsHTRANSFORM hTransform)
1357
{
1358
_cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
1359
1360
if (xform == NULL) return 0;
1361
return xform->OutputFormat;
1362
}
1363
1364
// For backwards compatibility
1365
cmsBool CMSEXPORT cmsChangeBuffersFormat(cmsHTRANSFORM hTransform,
1366
cmsUInt32Number InputFormat,
1367
cmsUInt32Number OutputFormat)
1368
{
1369
_cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
1370
cmsFormatter16 FromInput, ToOutput;
1371
1372
1373
// We only can afford to change formatters if previous transform is at least 16 bits
1374
if (!(xform ->dwOriginalFlags & cmsFLAGS_CAN_CHANGE_FORMATTER)) {
1375
1376
cmsSignalError(xform ->ContextID, cmsERROR_NOT_SUITABLE, "cmsChangeBuffersFormat works only on transforms created originally with at least 16 bits of precision");
1377
return FALSE;
1378
}
1379
1380
FromInput = _cmsGetFormatter(xform->ContextID, InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
1381
ToOutput = _cmsGetFormatter(xform->ContextID, OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
1382
1383
if (FromInput == NULL || ToOutput == NULL) {
1384
1385
cmsSignalError(xform -> ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
1386
return FALSE;
1387
}
1388
1389
xform ->InputFormat = InputFormat;
1390
xform ->OutputFormat = OutputFormat;
1391
xform ->FromInput = FromInput;
1392
xform ->ToOutput = ToOutput;
1393
return TRUE;
1394
}
1395
1396