Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.desktop/share/native/liblcms/cmsvirt.c
41149 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
// Virtual (built-in) profiles
59
// -----------------------------------------------------------------------------------
60
61
static
62
cmsBool SetTextTags(cmsHPROFILE hProfile, const wchar_t* Description)
63
{
64
cmsMLU *DescriptionMLU, *CopyrightMLU;
65
cmsBool rc = FALSE;
66
cmsContext ContextID = cmsGetProfileContextID(hProfile);
67
68
DescriptionMLU = cmsMLUalloc(ContextID, 1);
69
CopyrightMLU = cmsMLUalloc(ContextID, 1);
70
71
if (DescriptionMLU == NULL || CopyrightMLU == NULL) goto Error;
72
73
if (!cmsMLUsetWide(DescriptionMLU, "en", "US", Description)) goto Error;
74
if (!cmsMLUsetWide(CopyrightMLU, "en", "US", L"No copyright, use freely")) goto Error;
75
76
if (!cmsWriteTag(hProfile, cmsSigProfileDescriptionTag, DescriptionMLU)) goto Error;
77
if (!cmsWriteTag(hProfile, cmsSigCopyrightTag, CopyrightMLU)) goto Error;
78
79
rc = TRUE;
80
81
Error:
82
83
if (DescriptionMLU)
84
cmsMLUfree(DescriptionMLU);
85
if (CopyrightMLU)
86
cmsMLUfree(CopyrightMLU);
87
return rc;
88
}
89
90
91
static
92
cmsBool SetSeqDescTag(cmsHPROFILE hProfile, const char* Model)
93
{
94
cmsBool rc = FALSE;
95
cmsContext ContextID = cmsGetProfileContextID(hProfile);
96
cmsSEQ* Seq = cmsAllocProfileSequenceDescription(ContextID, 1);
97
98
if (Seq == NULL) return FALSE;
99
100
Seq->seq[0].deviceMfg = (cmsSignature) 0;
101
Seq->seq[0].deviceModel = (cmsSignature) 0;
102
103
#ifdef CMS_DONT_USE_INT64
104
Seq->seq[0].attributes[0] = 0;
105
Seq->seq[0].attributes[1] = 0;
106
#else
107
Seq->seq[0].attributes = 0;
108
#endif
109
110
Seq->seq[0].technology = (cmsTechnologySignature) 0;
111
112
cmsMLUsetASCII( Seq->seq[0].Manufacturer, cmsNoLanguage, cmsNoCountry, "Little CMS");
113
cmsMLUsetASCII( Seq->seq[0].Model, cmsNoLanguage, cmsNoCountry, Model);
114
115
if (!_cmsWriteProfileSequence(hProfile, Seq)) goto Error;
116
117
rc = TRUE;
118
119
Error:
120
if (Seq)
121
cmsFreeProfileSequenceDescription(Seq);
122
123
return rc;
124
}
125
126
127
128
// This function creates a profile based on White point, primaries and
129
// transfer functions.
130
cmsHPROFILE CMSEXPORT cmsCreateRGBProfileTHR(cmsContext ContextID,
131
const cmsCIExyY* WhitePoint,
132
const cmsCIExyYTRIPLE* Primaries,
133
cmsToneCurve* const TransferFunction[3])
134
{
135
cmsHPROFILE hICC;
136
cmsMAT3 MColorants;
137
cmsCIEXYZTRIPLE Colorants;
138
cmsCIExyY MaxWhite;
139
cmsMAT3 CHAD;
140
cmsCIEXYZ WhitePointXYZ;
141
142
hICC = cmsCreateProfilePlaceholder(ContextID);
143
if (!hICC) // can't allocate
144
return NULL;
145
146
cmsSetProfileVersion(hICC, 4.3);
147
148
cmsSetDeviceClass(hICC, cmsSigDisplayClass);
149
cmsSetColorSpace(hICC, cmsSigRgbData);
150
cmsSetPCS(hICC, cmsSigXYZData);
151
152
cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL);
153
154
155
// Implement profile using following tags:
156
//
157
// 1 cmsSigProfileDescriptionTag
158
// 2 cmsSigMediaWhitePointTag
159
// 3 cmsSigRedColorantTag
160
// 4 cmsSigGreenColorantTag
161
// 5 cmsSigBlueColorantTag
162
// 6 cmsSigRedTRCTag
163
// 7 cmsSigGreenTRCTag
164
// 8 cmsSigBlueTRCTag
165
// 9 Chromatic adaptation Tag
166
// This conforms a standard RGB DisplayProfile as says ICC, and then I add (As per addendum II)
167
// 10 cmsSigChromaticityTag
168
169
170
if (!SetTextTags(hICC, L"RGB built-in")) goto Error;
171
172
if (WhitePoint) {
173
174
if (!cmsWriteTag(hICC, cmsSigMediaWhitePointTag, cmsD50_XYZ())) goto Error;
175
176
cmsxyY2XYZ(&WhitePointXYZ, WhitePoint);
177
_cmsAdaptationMatrix(&CHAD, NULL, &WhitePointXYZ, cmsD50_XYZ());
178
179
// This is a V4 tag, but many CMM does read and understand it no matter which version
180
if (!cmsWriteTag(hICC, cmsSigChromaticAdaptationTag, (void*) &CHAD)) goto Error;
181
}
182
183
if (WhitePoint && Primaries) {
184
185
MaxWhite.x = WhitePoint -> x;
186
MaxWhite.y = WhitePoint -> y;
187
MaxWhite.Y = 1.0;
188
189
if (!_cmsBuildRGB2XYZtransferMatrix(&MColorants, &MaxWhite, Primaries)) goto Error;
190
191
Colorants.Red.X = MColorants.v[0].n[0];
192
Colorants.Red.Y = MColorants.v[1].n[0];
193
Colorants.Red.Z = MColorants.v[2].n[0];
194
195
Colorants.Green.X = MColorants.v[0].n[1];
196
Colorants.Green.Y = MColorants.v[1].n[1];
197
Colorants.Green.Z = MColorants.v[2].n[1];
198
199
Colorants.Blue.X = MColorants.v[0].n[2];
200
Colorants.Blue.Y = MColorants.v[1].n[2];
201
Colorants.Blue.Z = MColorants.v[2].n[2];
202
203
if (!cmsWriteTag(hICC, cmsSigRedColorantTag, (void*) &Colorants.Red)) goto Error;
204
if (!cmsWriteTag(hICC, cmsSigBlueColorantTag, (void*) &Colorants.Blue)) goto Error;
205
if (!cmsWriteTag(hICC, cmsSigGreenColorantTag, (void*) &Colorants.Green)) goto Error;
206
}
207
208
209
if (TransferFunction) {
210
211
// Tries to minimize space. Thanks to Richard Hughes for this nice idea
212
if (!cmsWriteTag(hICC, cmsSigRedTRCTag, (void*) TransferFunction[0])) goto Error;
213
214
if (TransferFunction[1] == TransferFunction[0]) {
215
216
if (!cmsLinkTag (hICC, cmsSigGreenTRCTag, cmsSigRedTRCTag)) goto Error;
217
218
} else {
219
220
if (!cmsWriteTag(hICC, cmsSigGreenTRCTag, (void*) TransferFunction[1])) goto Error;
221
}
222
223
if (TransferFunction[2] == TransferFunction[0]) {
224
225
if (!cmsLinkTag (hICC, cmsSigBlueTRCTag, cmsSigRedTRCTag)) goto Error;
226
227
} else {
228
229
if (!cmsWriteTag(hICC, cmsSigBlueTRCTag, (void*) TransferFunction[2])) goto Error;
230
}
231
}
232
233
if (Primaries) {
234
if (!cmsWriteTag(hICC, cmsSigChromaticityTag, (void*) Primaries)) goto Error;
235
}
236
237
238
return hICC;
239
240
Error:
241
if (hICC)
242
cmsCloseProfile(hICC);
243
return NULL;
244
}
245
246
cmsHPROFILE CMSEXPORT cmsCreateRGBProfile(const cmsCIExyY* WhitePoint,
247
const cmsCIExyYTRIPLE* Primaries,
248
cmsToneCurve* const TransferFunction[3])
249
{
250
return cmsCreateRGBProfileTHR(NULL, WhitePoint, Primaries, TransferFunction);
251
}
252
253
254
255
// This function creates a profile based on White point and transfer function.
256
cmsHPROFILE CMSEXPORT cmsCreateGrayProfileTHR(cmsContext ContextID,
257
const cmsCIExyY* WhitePoint,
258
const cmsToneCurve* TransferFunction)
259
{
260
cmsHPROFILE hICC;
261
cmsCIEXYZ tmp;
262
263
hICC = cmsCreateProfilePlaceholder(ContextID);
264
if (!hICC) // can't allocate
265
return NULL;
266
267
cmsSetProfileVersion(hICC, 4.3);
268
269
cmsSetDeviceClass(hICC, cmsSigDisplayClass);
270
cmsSetColorSpace(hICC, cmsSigGrayData);
271
cmsSetPCS(hICC, cmsSigXYZData);
272
cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL);
273
274
275
// Implement profile using following tags:
276
//
277
// 1 cmsSigProfileDescriptionTag
278
// 2 cmsSigMediaWhitePointTag
279
// 3 cmsSigGrayTRCTag
280
281
// This conforms a standard Gray DisplayProfile
282
283
// Fill-in the tags
284
285
if (!SetTextTags(hICC, L"gray built-in")) goto Error;
286
287
288
if (WhitePoint) {
289
290
cmsxyY2XYZ(&tmp, WhitePoint);
291
if (!cmsWriteTag(hICC, cmsSigMediaWhitePointTag, (void*) &tmp)) goto Error;
292
}
293
294
if (TransferFunction) {
295
296
if (!cmsWriteTag(hICC, cmsSigGrayTRCTag, (void*) TransferFunction)) goto Error;
297
}
298
299
return hICC;
300
301
Error:
302
if (hICC)
303
cmsCloseProfile(hICC);
304
return NULL;
305
}
306
307
308
309
cmsHPROFILE CMSEXPORT cmsCreateGrayProfile(const cmsCIExyY* WhitePoint,
310
const cmsToneCurve* TransferFunction)
311
{
312
return cmsCreateGrayProfileTHR(NULL, WhitePoint, TransferFunction);
313
}
314
315
// This is a devicelink operating in the target colorspace with as many transfer functions as components
316
317
cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLinkTHR(cmsContext ContextID,
318
cmsColorSpaceSignature ColorSpace,
319
cmsToneCurve* const TransferFunctions[])
320
{
321
cmsHPROFILE hICC;
322
cmsPipeline* Pipeline;
323
cmsUInt32Number nChannels;
324
325
hICC = cmsCreateProfilePlaceholder(ContextID);
326
if (!hICC)
327
return NULL;
328
329
cmsSetProfileVersion(hICC, 4.3);
330
331
cmsSetDeviceClass(hICC, cmsSigLinkClass);
332
cmsSetColorSpace(hICC, ColorSpace);
333
cmsSetPCS(hICC, ColorSpace);
334
335
cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL);
336
337
// Set up channels
338
nChannels = cmsChannelsOf(ColorSpace);
339
340
// Creates a Pipeline with prelinearization step only
341
Pipeline = cmsPipelineAlloc(ContextID, nChannels, nChannels);
342
if (Pipeline == NULL) goto Error;
343
344
345
// Copy tables to Pipeline
346
if (!cmsPipelineInsertStage(Pipeline, cmsAT_BEGIN, cmsStageAllocToneCurves(ContextID, nChannels, TransferFunctions)))
347
goto Error;
348
349
// Create tags
350
if (!SetTextTags(hICC, L"Linearization built-in")) goto Error;
351
if (!cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) Pipeline)) goto Error;
352
if (!SetSeqDescTag(hICC, "Linearization built-in")) goto Error;
353
354
// Pipeline is already on virtual profile
355
cmsPipelineFree(Pipeline);
356
357
// Ok, done
358
return hICC;
359
360
Error:
361
cmsPipelineFree(Pipeline);
362
if (hICC)
363
cmsCloseProfile(hICC);
364
365
366
return NULL;
367
}
368
369
cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLink(cmsColorSpaceSignature ColorSpace,
370
cmsToneCurve* const TransferFunctions[])
371
{
372
return cmsCreateLinearizationDeviceLinkTHR(NULL, ColorSpace, TransferFunctions);
373
}
374
375
// Ink-limiting algorithm
376
//
377
// Sum = C + M + Y + K
378
// If Sum > InkLimit
379
// Ratio= 1 - (Sum - InkLimit) / (C + M + Y)
380
// if Ratio <0
381
// Ratio=0
382
// endif
383
// Else
384
// Ratio=1
385
// endif
386
//
387
// C = Ratio * C
388
// M = Ratio * M
389
// Y = Ratio * Y
390
// K: Does not change
391
392
static
393
int InkLimitingSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Number Out[], CMSREGISTER void* Cargo)
394
{
395
cmsFloat64Number InkLimit = *(cmsFloat64Number *) Cargo;
396
cmsFloat64Number SumCMY, SumCMYK, Ratio;
397
398
InkLimit = (InkLimit * 655.35);
399
400
SumCMY = In[0] + In[1] + In[2];
401
SumCMYK = SumCMY + In[3];
402
403
if (SumCMYK > InkLimit) {
404
405
Ratio = 1 - ((SumCMYK - InkLimit) / SumCMY);
406
if (Ratio < 0)
407
Ratio = 0;
408
}
409
else Ratio = 1;
410
411
Out[0] = _cmsQuickSaturateWord(In[0] * Ratio); // C
412
Out[1] = _cmsQuickSaturateWord(In[1] * Ratio); // M
413
Out[2] = _cmsQuickSaturateWord(In[2] * Ratio); // Y
414
415
Out[3] = In[3]; // K (untouched)
416
417
return TRUE;
418
}
419
420
// This is a devicelink operating in CMYK for ink-limiting
421
422
cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext ContextID,
423
cmsColorSpaceSignature ColorSpace,
424
cmsFloat64Number Limit)
425
{
426
cmsHPROFILE hICC;
427
cmsPipeline* LUT;
428
cmsStage* CLUT;
429
cmsUInt32Number nChannels;
430
431
if (ColorSpace != cmsSigCmykData) {
432
cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "InkLimiting: Only CMYK currently supported");
433
return NULL;
434
}
435
436
if (Limit < 0.0 || Limit > 400) {
437
438
cmsSignalError(ContextID, cmsERROR_RANGE, "InkLimiting: Limit should be between 0..400");
439
if (Limit < 0) Limit = 0;
440
if (Limit > 400) Limit = 400;
441
442
}
443
444
hICC = cmsCreateProfilePlaceholder(ContextID);
445
if (!hICC) // can't allocate
446
return NULL;
447
448
cmsSetProfileVersion(hICC, 4.3);
449
450
cmsSetDeviceClass(hICC, cmsSigLinkClass);
451
cmsSetColorSpace(hICC, ColorSpace);
452
cmsSetPCS(hICC, ColorSpace);
453
454
cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL);
455
456
457
// Creates a Pipeline with 3D grid only
458
LUT = cmsPipelineAlloc(ContextID, 4, 4);
459
if (LUT == NULL) goto Error;
460
461
462
nChannels = cmsChannelsOf(ColorSpace);
463
464
CLUT = cmsStageAllocCLut16bit(ContextID, 17, nChannels, nChannels, NULL);
465
if (CLUT == NULL) goto Error;
466
467
if (!cmsStageSampleCLut16bit(CLUT, InkLimitingSampler, (void*) &Limit, 0)) goto Error;
468
469
if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, nChannels)) ||
470
!cmsPipelineInsertStage(LUT, cmsAT_END, CLUT) ||
471
!cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, nChannels)))
472
goto Error;
473
474
// Create tags
475
if (!SetTextTags(hICC, L"ink-limiting built-in")) goto Error;
476
477
if (!cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) LUT)) goto Error;
478
if (!SetSeqDescTag(hICC, "ink-limiting built-in")) goto Error;
479
480
// cmsPipeline is already on virtual profile
481
cmsPipelineFree(LUT);
482
483
// Ok, done
484
return hICC;
485
486
Error:
487
if (LUT != NULL)
488
cmsPipelineFree(LUT);
489
490
if (hICC != NULL)
491
cmsCloseProfile(hICC);
492
493
return NULL;
494
}
495
496
cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLink(cmsColorSpaceSignature ColorSpace, cmsFloat64Number Limit)
497
{
498
return cmsCreateInkLimitingDeviceLinkTHR(NULL, ColorSpace, Limit);
499
}
500
501
502
// Creates a fake Lab identity.
503
cmsHPROFILE CMSEXPORT cmsCreateLab2ProfileTHR(cmsContext ContextID, const cmsCIExyY* WhitePoint)
504
{
505
cmsHPROFILE hProfile;
506
cmsPipeline* LUT = NULL;
507
508
hProfile = cmsCreateRGBProfileTHR(ContextID, WhitePoint == NULL ? cmsD50_xyY() : WhitePoint, NULL, NULL);
509
if (hProfile == NULL) return NULL;
510
511
cmsSetProfileVersion(hProfile, 2.1);
512
513
cmsSetDeviceClass(hProfile, cmsSigAbstractClass);
514
cmsSetColorSpace(hProfile, cmsSigLabData);
515
cmsSetPCS(hProfile, cmsSigLabData);
516
517
if (!SetTextTags(hProfile, L"Lab identity built-in")) return NULL;
518
519
// An identity LUT is all we need
520
LUT = cmsPipelineAlloc(ContextID, 3, 3);
521
if (LUT == NULL) goto Error;
522
523
if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCLut(ContextID, 3)))
524
goto Error;
525
526
if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error;
527
cmsPipelineFree(LUT);
528
529
return hProfile;
530
531
Error:
532
533
if (LUT != NULL)
534
cmsPipelineFree(LUT);
535
536
if (hProfile != NULL)
537
cmsCloseProfile(hProfile);
538
539
return NULL;
540
}
541
542
543
cmsHPROFILE CMSEXPORT cmsCreateLab2Profile(const cmsCIExyY* WhitePoint)
544
{
545
return cmsCreateLab2ProfileTHR(NULL, WhitePoint);
546
}
547
548
549
// Creates a fake Lab V4 identity.
550
cmsHPROFILE CMSEXPORT cmsCreateLab4ProfileTHR(cmsContext ContextID, const cmsCIExyY* WhitePoint)
551
{
552
cmsHPROFILE hProfile;
553
cmsPipeline* LUT = NULL;
554
555
hProfile = cmsCreateRGBProfileTHR(ContextID, WhitePoint == NULL ? cmsD50_xyY() : WhitePoint, NULL, NULL);
556
if (hProfile == NULL) return NULL;
557
558
cmsSetProfileVersion(hProfile, 4.3);
559
560
cmsSetDeviceClass(hProfile, cmsSigAbstractClass);
561
cmsSetColorSpace(hProfile, cmsSigLabData);
562
cmsSetPCS(hProfile, cmsSigLabData);
563
564
if (!SetTextTags(hProfile, L"Lab identity built-in")) goto Error;
565
566
// An empty LUTs is all we need
567
LUT = cmsPipelineAlloc(ContextID, 3, 3);
568
if (LUT == NULL) goto Error;
569
570
if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3)))
571
goto Error;
572
573
if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error;
574
cmsPipelineFree(LUT);
575
576
return hProfile;
577
578
Error:
579
580
if (LUT != NULL)
581
cmsPipelineFree(LUT);
582
583
if (hProfile != NULL)
584
cmsCloseProfile(hProfile);
585
586
return NULL;
587
}
588
589
cmsHPROFILE CMSEXPORT cmsCreateLab4Profile(const cmsCIExyY* WhitePoint)
590
{
591
return cmsCreateLab4ProfileTHR(NULL, WhitePoint);
592
}
593
594
595
// Creates a fake XYZ identity
596
cmsHPROFILE CMSEXPORT cmsCreateXYZProfileTHR(cmsContext ContextID)
597
{
598
cmsHPROFILE hProfile;
599
cmsPipeline* LUT = NULL;
600
601
hProfile = cmsCreateRGBProfileTHR(ContextID, cmsD50_xyY(), NULL, NULL);
602
if (hProfile == NULL) return NULL;
603
604
cmsSetProfileVersion(hProfile, 4.3);
605
606
cmsSetDeviceClass(hProfile, cmsSigAbstractClass);
607
cmsSetColorSpace(hProfile, cmsSigXYZData);
608
cmsSetPCS(hProfile, cmsSigXYZData);
609
610
if (!SetTextTags(hProfile, L"XYZ identity built-in")) goto Error;
611
612
// An identity LUT is all we need
613
LUT = cmsPipelineAlloc(ContextID, 3, 3);
614
if (LUT == NULL) goto Error;
615
616
if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3)))
617
goto Error;
618
619
if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error;
620
cmsPipelineFree(LUT);
621
622
return hProfile;
623
624
Error:
625
626
if (LUT != NULL)
627
cmsPipelineFree(LUT);
628
629
if (hProfile != NULL)
630
cmsCloseProfile(hProfile);
631
632
return NULL;
633
}
634
635
636
cmsHPROFILE CMSEXPORT cmsCreateXYZProfile(void)
637
{
638
return cmsCreateXYZProfileTHR(NULL);
639
}
640
641
642
//sRGB Curves are defined by:
643
//
644
//If R'sRGB,G'sRGB, B'sRGB < 0.04045
645
//
646
// R = R'sRGB / 12.92
647
// G = G'sRGB / 12.92
648
// B = B'sRGB / 12.92
649
//
650
//
651
//else if R'sRGB,G'sRGB, B'sRGB >= 0.04045
652
//
653
// R = ((R'sRGB + 0.055) / 1.055)^2.4
654
// G = ((G'sRGB + 0.055) / 1.055)^2.4
655
// B = ((B'sRGB + 0.055) / 1.055)^2.4
656
657
static
658
cmsToneCurve* Build_sRGBGamma(cmsContext ContextID)
659
{
660
cmsFloat64Number Parameters[5];
661
662
Parameters[0] = 2.4;
663
Parameters[1] = 1. / 1.055;
664
Parameters[2] = 0.055 / 1.055;
665
Parameters[3] = 1. / 12.92;
666
Parameters[4] = 0.04045;
667
668
return cmsBuildParametricToneCurve(ContextID, 4, Parameters);
669
}
670
671
// Create the ICC virtual profile for sRGB space
672
cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfileTHR(cmsContext ContextID)
673
{
674
cmsCIExyY D65 = { 0.3127, 0.3290, 1.0 };
675
cmsCIExyYTRIPLE Rec709Primaries = {
676
{0.6400, 0.3300, 1.0},
677
{0.3000, 0.6000, 1.0},
678
{0.1500, 0.0600, 1.0}
679
};
680
cmsToneCurve* Gamma22[3];
681
cmsHPROFILE hsRGB;
682
683
// cmsWhitePointFromTemp(&D65, 6504);
684
Gamma22[0] = Gamma22[1] = Gamma22[2] = Build_sRGBGamma(ContextID);
685
if (Gamma22[0] == NULL) return NULL;
686
687
hsRGB = cmsCreateRGBProfileTHR(ContextID, &D65, &Rec709Primaries, Gamma22);
688
cmsFreeToneCurve(Gamma22[0]);
689
if (hsRGB == NULL) return NULL;
690
691
if (!SetTextTags(hsRGB, L"sRGB built-in")) {
692
cmsCloseProfile(hsRGB);
693
return NULL;
694
}
695
696
return hsRGB;
697
}
698
699
cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfile(void)
700
{
701
return cmsCreate_sRGBProfileTHR(NULL);
702
}
703
704
705
706
typedef struct {
707
cmsFloat64Number Brightness;
708
cmsFloat64Number Contrast;
709
cmsFloat64Number Hue;
710
cmsFloat64Number Saturation;
711
cmsBool lAdjustWP;
712
cmsCIEXYZ WPsrc, WPdest;
713
714
} BCHSWADJUSTS, *LPBCHSWADJUSTS;
715
716
717
static
718
int bchswSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Number Out[], CMSREGISTER void* Cargo)
719
{
720
cmsCIELab LabIn, LabOut;
721
cmsCIELCh LChIn, LChOut;
722
cmsCIEXYZ XYZ;
723
LPBCHSWADJUSTS bchsw = (LPBCHSWADJUSTS) Cargo;
724
725
726
cmsLabEncoded2Float(&LabIn, In);
727
728
729
cmsLab2LCh(&LChIn, &LabIn);
730
731
// Do some adjusts on LCh
732
733
LChOut.L = LChIn.L * bchsw ->Contrast + bchsw ->Brightness;
734
LChOut.C = LChIn.C + bchsw -> Saturation;
735
LChOut.h = LChIn.h + bchsw -> Hue;
736
737
738
cmsLCh2Lab(&LabOut, &LChOut);
739
740
// Move white point in Lab
741
if (bchsw->lAdjustWP) {
742
cmsLab2XYZ(&bchsw->WPsrc, &XYZ, &LabOut);
743
cmsXYZ2Lab(&bchsw->WPdest, &LabOut, &XYZ);
744
}
745
746
// Back to encoded
747
748
cmsFloat2LabEncoded(Out, &LabOut);
749
750
return TRUE;
751
}
752
753
754
// Creates an abstract profile operating in Lab space for Brightness,
755
// contrast, Saturation and white point displacement
756
757
cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID,
758
cmsUInt32Number nLUTPoints,
759
cmsFloat64Number Bright,
760
cmsFloat64Number Contrast,
761
cmsFloat64Number Hue,
762
cmsFloat64Number Saturation,
763
cmsUInt32Number TempSrc,
764
cmsUInt32Number TempDest)
765
{
766
cmsHPROFILE hICC;
767
cmsPipeline* Pipeline;
768
BCHSWADJUSTS bchsw;
769
cmsCIExyY WhitePnt;
770
cmsStage* CLUT;
771
cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS];
772
cmsUInt32Number i;
773
774
bchsw.Brightness = Bright;
775
bchsw.Contrast = Contrast;
776
bchsw.Hue = Hue;
777
bchsw.Saturation = Saturation;
778
if (TempSrc == TempDest) {
779
780
bchsw.lAdjustWP = FALSE;
781
}
782
else {
783
bchsw.lAdjustWP = TRUE;
784
cmsWhitePointFromTemp(&WhitePnt, TempSrc);
785
cmsxyY2XYZ(&bchsw.WPsrc, &WhitePnt);
786
cmsWhitePointFromTemp(&WhitePnt, TempDest);
787
cmsxyY2XYZ(&bchsw.WPdest, &WhitePnt);
788
789
}
790
791
hICC = cmsCreateProfilePlaceholder(ContextID);
792
if (!hICC) // can't allocate
793
return NULL;
794
795
cmsSetDeviceClass(hICC, cmsSigAbstractClass);
796
cmsSetColorSpace(hICC, cmsSigLabData);
797
cmsSetPCS(hICC, cmsSigLabData);
798
799
cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL);
800
801
// Creates a Pipeline with 3D grid only
802
Pipeline = cmsPipelineAlloc(ContextID, 3, 3);
803
if (Pipeline == NULL) {
804
cmsCloseProfile(hICC);
805
return NULL;
806
}
807
808
for (i=0; i < MAX_INPUT_DIMENSIONS; i++) Dimensions[i] = nLUTPoints;
809
CLUT = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 3, 3, NULL);
810
if (CLUT == NULL) goto Error;
811
812
813
if (!cmsStageSampleCLut16bit(CLUT, bchswSampler, (void*) &bchsw, 0)) {
814
815
// Shouldn't reach here
816
goto Error;
817
}
818
819
if (!cmsPipelineInsertStage(Pipeline, cmsAT_END, CLUT)) {
820
goto Error;
821
}
822
823
// Create tags
824
if (!SetTextTags(hICC, L"BCHS built-in")) return NULL;
825
826
cmsWriteTag(hICC, cmsSigMediaWhitePointTag, (void*) cmsD50_XYZ());
827
828
cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) Pipeline);
829
830
// Pipeline is already on virtual profile
831
cmsPipelineFree(Pipeline);
832
833
// Ok, done
834
return hICC;
835
836
Error:
837
cmsPipelineFree(Pipeline);
838
cmsCloseProfile(hICC);
839
return NULL;
840
}
841
842
843
CMSAPI cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfile(cmsUInt32Number nLUTPoints,
844
cmsFloat64Number Bright,
845
cmsFloat64Number Contrast,
846
cmsFloat64Number Hue,
847
cmsFloat64Number Saturation,
848
cmsUInt32Number TempSrc,
849
cmsUInt32Number TempDest)
850
{
851
return cmsCreateBCHSWabstractProfileTHR(NULL, nLUTPoints, Bright, Contrast, Hue, Saturation, TempSrc, TempDest);
852
}
853
854
855
// Creates a fake NULL profile. This profile return 1 channel as always 0.
856
// Is useful only for gamut checking tricks
857
cmsHPROFILE CMSEXPORT cmsCreateNULLProfileTHR(cmsContext ContextID)
858
{
859
cmsHPROFILE hProfile;
860
cmsPipeline* LUT = NULL;
861
cmsStage* PostLin;
862
cmsStage* OutLin;
863
cmsToneCurve* EmptyTab[3];
864
cmsUInt16Number Zero[2] = { 0, 0 };
865
const cmsFloat64Number PickLstarMatrix[] = { 1, 0, 0 };
866
867
hProfile = cmsCreateProfilePlaceholder(ContextID);
868
if (!hProfile) // can't allocate
869
return NULL;
870
871
cmsSetProfileVersion(hProfile, 4.3);
872
873
if (!SetTextTags(hProfile, L"NULL profile built-in")) goto Error;
874
875
876
cmsSetDeviceClass(hProfile, cmsSigOutputClass);
877
cmsSetColorSpace(hProfile, cmsSigGrayData);
878
cmsSetPCS(hProfile, cmsSigLabData);
879
880
// Create a valid ICC 4 structure
881
LUT = cmsPipelineAlloc(ContextID, 3, 1);
882
if (LUT == NULL) goto Error;
883
884
EmptyTab[0] = EmptyTab[1] = EmptyTab[2] = cmsBuildTabulatedToneCurve16(ContextID, 2, Zero);
885
PostLin = cmsStageAllocToneCurves(ContextID, 3, EmptyTab);
886
OutLin = cmsStageAllocToneCurves(ContextID, 1, EmptyTab);
887
cmsFreeToneCurve(EmptyTab[0]);
888
889
if (!cmsPipelineInsertStage(LUT, cmsAT_END, PostLin))
890
goto Error;
891
892
if (!cmsPipelineInsertStage(LUT, cmsAT_END, cmsStageAllocMatrix(ContextID, 1, 3, PickLstarMatrix, NULL)))
893
goto Error;
894
895
if (!cmsPipelineInsertStage(LUT, cmsAT_END, OutLin))
896
goto Error;
897
898
if (!cmsWriteTag(hProfile, cmsSigBToA0Tag, (void*) LUT)) goto Error;
899
if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, cmsD50_XYZ())) goto Error;
900
901
cmsPipelineFree(LUT);
902
return hProfile;
903
904
Error:
905
906
if (LUT != NULL)
907
cmsPipelineFree(LUT);
908
909
if (hProfile != NULL)
910
cmsCloseProfile(hProfile);
911
912
return NULL;
913
}
914
915
cmsHPROFILE CMSEXPORT cmsCreateNULLProfile(void)
916
{
917
return cmsCreateNULLProfileTHR(NULL);
918
}
919
920
921
static
922
int IsPCS(cmsColorSpaceSignature ColorSpace)
923
{
924
return (ColorSpace == cmsSigXYZData ||
925
ColorSpace == cmsSigLabData);
926
}
927
928
929
static
930
void FixColorSpaces(cmsHPROFILE hProfile,
931
cmsColorSpaceSignature ColorSpace,
932
cmsColorSpaceSignature PCS,
933
cmsUInt32Number dwFlags)
934
{
935
if (dwFlags & cmsFLAGS_GUESSDEVICECLASS) {
936
937
if (IsPCS(ColorSpace) && IsPCS(PCS)) {
938
939
cmsSetDeviceClass(hProfile, cmsSigAbstractClass);
940
cmsSetColorSpace(hProfile, ColorSpace);
941
cmsSetPCS(hProfile, PCS);
942
return;
943
}
944
945
if (IsPCS(ColorSpace) && !IsPCS(PCS)) {
946
947
cmsSetDeviceClass(hProfile, cmsSigOutputClass);
948
cmsSetPCS(hProfile, ColorSpace);
949
cmsSetColorSpace(hProfile, PCS);
950
return;
951
}
952
953
if (IsPCS(PCS) && !IsPCS(ColorSpace)) {
954
955
cmsSetDeviceClass(hProfile, cmsSigInputClass);
956
cmsSetColorSpace(hProfile, ColorSpace);
957
cmsSetPCS(hProfile, PCS);
958
return;
959
}
960
}
961
962
cmsSetDeviceClass(hProfile, cmsSigLinkClass);
963
cmsSetColorSpace(hProfile, ColorSpace);
964
cmsSetPCS(hProfile, PCS);
965
}
966
967
968
969
// This function creates a named color profile dumping all the contents of transform to a single profile
970
// In this way, LittleCMS may be used to "group" several named color databases into a single profile.
971
// It has, however, several minor limitations. PCS is always Lab, which is not very critic since this
972
// is the normal PCS for named color profiles.
973
static
974
cmsHPROFILE CreateNamedColorDevicelink(cmsHTRANSFORM xform)
975
{
976
_cmsTRANSFORM* v = (_cmsTRANSFORM*) xform;
977
cmsHPROFILE hICC = NULL;
978
cmsUInt32Number i, nColors;
979
cmsNAMEDCOLORLIST *nc2 = NULL, *Original = NULL;
980
981
// Create an empty placeholder
982
hICC = cmsCreateProfilePlaceholder(v->ContextID);
983
if (hICC == NULL) return NULL;
984
985
// Critical information
986
cmsSetDeviceClass(hICC, cmsSigNamedColorClass);
987
cmsSetColorSpace(hICC, v ->ExitColorSpace);
988
cmsSetPCS(hICC, cmsSigLabData);
989
990
// Tag profile with information
991
if (!SetTextTags(hICC, L"Named color devicelink")) goto Error;
992
993
Original = cmsGetNamedColorList(xform);
994
if (Original == NULL) goto Error;
995
996
nColors = cmsNamedColorCount(Original);
997
nc2 = cmsDupNamedColorList(Original);
998
if (nc2 == NULL) goto Error;
999
1000
// Colorant count now depends on the output space
1001
nc2 ->ColorantCount = cmsPipelineOutputChannels(v ->Lut);
1002
1003
// Make sure we have proper formatters
1004
cmsChangeBuffersFormat(xform, TYPE_NAMED_COLOR_INDEX,
1005
FLOAT_SH(0) | COLORSPACE_SH(_cmsLCMScolorSpace(v ->ExitColorSpace))
1006
| BYTES_SH(2) | CHANNELS_SH(cmsChannelsOf(v ->ExitColorSpace)));
1007
1008
// Apply the transfor to colorants.
1009
for (i=0; i < nColors; i++) {
1010
cmsDoTransform(xform, &i, nc2 ->List[i].DeviceColorant, 1);
1011
}
1012
1013
if (!cmsWriteTag(hICC, cmsSigNamedColor2Tag, (void*) nc2)) goto Error;
1014
cmsFreeNamedColorList(nc2);
1015
1016
return hICC;
1017
1018
Error:
1019
if (hICC != NULL) cmsCloseProfile(hICC);
1020
return NULL;
1021
}
1022
1023
1024
// This structure holds information about which MPU can be stored on a profile based on the version
1025
1026
typedef struct {
1027
cmsBool IsV4; // Is a V4 tag?
1028
cmsTagSignature RequiredTag; // Set to 0 for both types
1029
cmsTagTypeSignature LutType; // The LUT type
1030
int nTypes; // Number of types (up to 5)
1031
cmsStageSignature MpeTypes[5]; // 5 is the maximum number
1032
1033
} cmsAllowedLUT;
1034
1035
#define cmsSig0 ((cmsTagSignature) 0)
1036
1037
static const cmsAllowedLUT AllowedLUTTypes[] = {
1038
1039
{ FALSE, cmsSig0, cmsSigLut16Type, 4, { cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType } },
1040
{ FALSE, cmsSig0, cmsSigLut16Type, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType } },
1041
{ FALSE, cmsSig0, cmsSigLut16Type, 2, { cmsSigCurveSetElemType, cmsSigCLutElemType } },
1042
{ TRUE, cmsSig0, cmsSigLutAtoBType, 1, { cmsSigCurveSetElemType } },
1043
{ TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 3, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType } },
1044
{ TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType } },
1045
{ TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType, 5, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType }},
1046
{ TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType, 1, { cmsSigCurveSetElemType }},
1047
{ TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType, 3, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType }},
1048
{ TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType }},
1049
{ TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType, 5, { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType }}
1050
};
1051
1052
#define SIZE_OF_ALLOWED_LUT (sizeof(AllowedLUTTypes)/sizeof(cmsAllowedLUT))
1053
1054
// Check a single entry
1055
static
1056
cmsBool CheckOne(const cmsAllowedLUT* Tab, const cmsPipeline* Lut)
1057
{
1058
cmsStage* mpe;
1059
int n;
1060
1061
for (n=0, mpe = Lut ->Elements; mpe != NULL; mpe = mpe ->Next, n++) {
1062
1063
if (n > Tab ->nTypes) return FALSE;
1064
if (cmsStageType(mpe) != Tab ->MpeTypes[n]) return FALSE;
1065
}
1066
1067
return (n == Tab ->nTypes);
1068
}
1069
1070
1071
static
1072
const cmsAllowedLUT* FindCombination(const cmsPipeline* Lut, cmsBool IsV4, cmsTagSignature DestinationTag)
1073
{
1074
cmsUInt32Number n;
1075
1076
for (n=0; n < SIZE_OF_ALLOWED_LUT; n++) {
1077
1078
const cmsAllowedLUT* Tab = AllowedLUTTypes + n;
1079
1080
if (IsV4 ^ Tab -> IsV4) continue;
1081
if ((Tab ->RequiredTag != 0) && (Tab ->RequiredTag != DestinationTag)) continue;
1082
1083
if (CheckOne(Tab, Lut)) return Tab;
1084
}
1085
1086
return NULL;
1087
}
1088
1089
1090
// Does convert a transform into a device link profile
1091
cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat64Number Version, cmsUInt32Number dwFlags)
1092
{
1093
cmsHPROFILE hProfile = NULL;
1094
cmsUInt32Number FrmIn, FrmOut, ChansIn, ChansOut;
1095
int ColorSpaceBitsIn, ColorSpaceBitsOut;
1096
_cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
1097
cmsPipeline* LUT = NULL;
1098
cmsStage* mpe;
1099
cmsContext ContextID = cmsGetTransformContextID(hTransform);
1100
const cmsAllowedLUT* AllowedLUT;
1101
cmsTagSignature DestinationTag;
1102
cmsProfileClassSignature deviceClass;
1103
1104
_cmsAssert(hTransform != NULL);
1105
1106
// Get the first mpe to check for named color
1107
mpe = cmsPipelineGetPtrToFirstStage(xform ->Lut);
1108
1109
// Check if is a named color transform
1110
if (mpe != NULL) {
1111
1112
if (cmsStageType(mpe) == cmsSigNamedColorElemType) {
1113
return CreateNamedColorDevicelink(hTransform);
1114
}
1115
}
1116
1117
// First thing to do is to get a copy of the transformation
1118
LUT = cmsPipelineDup(xform ->Lut);
1119
if (LUT == NULL) return NULL;
1120
1121
// Time to fix the Lab2/Lab4 issue.
1122
if ((xform ->EntryColorSpace == cmsSigLabData) && (Version < 4.0)) {
1123
1124
if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocLabV2ToV4curves(ContextID)))
1125
goto Error;
1126
}
1127
1128
// On the output side too. Note that due to V2/V4 PCS encoding on lab we cannot fix white misalignments
1129
if ((xform ->ExitColorSpace) == cmsSigLabData && (Version < 4.0)) {
1130
1131
dwFlags |= cmsFLAGS_NOWHITEONWHITEFIXUP;
1132
if (!cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocLabV4ToV2(ContextID)))
1133
goto Error;
1134
}
1135
1136
1137
hProfile = cmsCreateProfilePlaceholder(ContextID);
1138
if (!hProfile) goto Error; // can't allocate
1139
1140
cmsSetProfileVersion(hProfile, Version);
1141
1142
FixColorSpaces(hProfile, xform -> EntryColorSpace, xform -> ExitColorSpace, dwFlags);
1143
1144
// Optimize the LUT and precalculate a devicelink
1145
1146
ChansIn = cmsChannelsOf(xform -> EntryColorSpace);
1147
ChansOut = cmsChannelsOf(xform -> ExitColorSpace);
1148
1149
ColorSpaceBitsIn = _cmsLCMScolorSpace(xform -> EntryColorSpace);
1150
ColorSpaceBitsOut = _cmsLCMScolorSpace(xform -> ExitColorSpace);
1151
1152
FrmIn = COLORSPACE_SH(ColorSpaceBitsIn) | CHANNELS_SH(ChansIn)|BYTES_SH(2);
1153
FrmOut = COLORSPACE_SH(ColorSpaceBitsOut) | CHANNELS_SH(ChansOut)|BYTES_SH(2);
1154
1155
deviceClass = cmsGetDeviceClass(hProfile);
1156
1157
if (deviceClass == cmsSigOutputClass)
1158
DestinationTag = cmsSigBToA0Tag;
1159
else
1160
DestinationTag = cmsSigAToB0Tag;
1161
1162
// Check if the profile/version can store the result
1163
if (dwFlags & cmsFLAGS_FORCE_CLUT)
1164
AllowedLUT = NULL;
1165
else
1166
AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag);
1167
1168
if (AllowedLUT == NULL) {
1169
1170
// Try to optimize
1171
_cmsOptimizePipeline(ContextID, &LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags);
1172
AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag);
1173
1174
}
1175
1176
// If no way, then force CLUT that for sure can be written
1177
if (AllowedLUT == NULL) {
1178
1179
cmsStage* FirstStage;
1180
cmsStage* LastStage;
1181
1182
dwFlags |= cmsFLAGS_FORCE_CLUT;
1183
_cmsOptimizePipeline(ContextID, &LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags);
1184
1185
// Put identity curves if needed
1186
FirstStage = cmsPipelineGetPtrToFirstStage(LUT);
1187
if (FirstStage != NULL && FirstStage ->Type != cmsSigCurveSetElemType)
1188
if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, ChansIn)))
1189
goto Error;
1190
1191
LastStage = cmsPipelineGetPtrToLastStage(LUT);
1192
if (LastStage != NULL && LastStage ->Type != cmsSigCurveSetElemType)
1193
if (!cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, ChansOut)))
1194
goto Error;
1195
1196
AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag);
1197
}
1198
1199
// Somethings is wrong...
1200
if (AllowedLUT == NULL) {
1201
goto Error;
1202
}
1203
1204
1205
if (dwFlags & cmsFLAGS_8BITS_DEVICELINK)
1206
cmsPipelineSetSaveAs8bitsFlag(LUT, TRUE);
1207
1208
// Tag profile with information
1209
if (!SetTextTags(hProfile, L"devicelink")) goto Error;
1210
1211
// Store result
1212
if (!cmsWriteTag(hProfile, DestinationTag, LUT)) goto Error;
1213
1214
1215
if (xform -> InputColorant != NULL) {
1216
if (!cmsWriteTag(hProfile, cmsSigColorantTableTag, xform->InputColorant)) goto Error;
1217
}
1218
1219
if (xform -> OutputColorant != NULL) {
1220
if (!cmsWriteTag(hProfile, cmsSigColorantTableOutTag, xform->OutputColorant)) goto Error;
1221
}
1222
1223
if ((deviceClass == cmsSigLinkClass) && (xform ->Sequence != NULL)) {
1224
if (!_cmsWriteProfileSequence(hProfile, xform ->Sequence)) goto Error;
1225
}
1226
1227
// Set the white point
1228
if (deviceClass == cmsSigInputClass) {
1229
if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, &xform ->EntryWhitePoint)) goto Error;
1230
}
1231
else {
1232
if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, &xform ->ExitWhitePoint)) goto Error;
1233
}
1234
1235
1236
// Per 7.2.15 in spec 4.3
1237
cmsSetHeaderRenderingIntent(hProfile, xform ->RenderingIntent);
1238
1239
cmsPipelineFree(LUT);
1240
return hProfile;
1241
1242
Error:
1243
if (LUT != NULL) cmsPipelineFree(LUT);
1244
cmsCloseProfile(hProfile);
1245
return NULL;
1246
}
1247
1248