cmsvirt.c 37.2 KB
Newer Older
D
duke 已提交
1 2 3 4 5
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
6
 * published by the Free Software Foundation.  Oracle designates this
D
duke 已提交
7
 * particular file as subject to the "Classpath" exception as provided
8
 * by Oracle in the LICENSE file that accompanied this code.
D
duke 已提交
9 10 11 12 13 14 15 16 17 18 19
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
20 21 22
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
D
duke 已提交
23 24 25 26 27 28 29
 */

// This file is available under and governed by the GNU General Public
// License version 2 only, as published by the Free Software Foundation.
// However, the following notice accompanied the original version of this
// file:
//
30
//---------------------------------------------------------------------------------
D
duke 已提交
31
//
32
//  Little Color Management System
P
prr 已提交
33
//  Copyright (c) 1998-2014 Marti Maria Saguer
D
duke 已提交
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
52 53 54
//
//---------------------------------------------------------------------------------
//
D
duke 已提交
55

56
#include "lcms2_internal.h"
D
duke 已提交
57 58 59 60

// Virtual (built-in) profiles
// -----------------------------------------------------------------------------------

61 62
static
cmsBool SetTextTags(cmsHPROFILE hProfile, const wchar_t* Description)
D
duke 已提交
63
{
64 65 66
    cmsMLU *DescriptionMLU, *CopyrightMLU;
    cmsBool  rc = FALSE;
    cmsContext ContextID = cmsGetProfileContextID(hProfile);
D
duke 已提交
67

68 69
    DescriptionMLU  = cmsMLUalloc(ContextID, 1);
    CopyrightMLU    = cmsMLUalloc(ContextID, 1);
D
duke 已提交
70

71
    if (DescriptionMLU == NULL || CopyrightMLU == NULL) goto Error;
D
duke 已提交
72

73 74
    if (!cmsMLUsetWide(DescriptionMLU,  "en", "US", Description)) goto Error;
    if (!cmsMLUsetWide(CopyrightMLU,    "en", "US", L"No copyright, use freely")) goto Error;
D
duke 已提交
75

76 77
    if (!cmsWriteTag(hProfile, cmsSigProfileDescriptionTag,  DescriptionMLU)) goto Error;
    if (!cmsWriteTag(hProfile, cmsSigCopyrightTag,           CopyrightMLU)) goto Error;
D
duke 已提交
78

79
    rc = TRUE;
D
duke 已提交
80

81
Error:
D
duke 已提交
82

83 84 85 86 87 88
    if (DescriptionMLU)
        cmsMLUfree(DescriptionMLU);
    if (CopyrightMLU)
        cmsMLUfree(CopyrightMLU);
    return rc;
}
D
duke 已提交
89 90


91 92 93 94 95 96
static
cmsBool  SetSeqDescTag(cmsHPROFILE hProfile, const char* Model)
{
    cmsBool  rc = FALSE;
    cmsContext ContextID = cmsGetProfileContextID(hProfile);
    cmsSEQ* Seq = cmsAllocProfileSequenceDescription(ContextID, 1);
D
duke 已提交
97

98
    if (Seq == NULL) return FALSE;
D
duke 已提交
99

100 101
    Seq->seq[0].deviceMfg = (cmsSignature) 0;
    Seq->seq[0].deviceModel = (cmsSignature) 0;
D
duke 已提交
102

103 104 105 106 107 108
#ifdef CMS_DONT_USE_INT64
    Seq->seq[0].attributes[0] = 0;
    Seq->seq[0].attributes[1] = 0;
#else
    Seq->seq[0].attributes = 0;
#endif
D
duke 已提交
109

110
    Seq->seq[0].technology = (cmsTechnologySignature) 0;
D
duke 已提交
111

112 113
    cmsMLUsetASCII( Seq->seq[0].Manufacturer, cmsNoLanguage, cmsNoCountry, "Little CMS");
    cmsMLUsetASCII( Seq->seq[0].Model,        cmsNoLanguage, cmsNoCountry, Model);
D
duke 已提交
114

115
    if (!_cmsWriteProfileSequence(hProfile, Seq)) goto Error;
D
duke 已提交
116

117
    rc = TRUE;
D
duke 已提交
118

119 120 121
Error:
    if (Seq)
        cmsFreeProfileSequenceDescription(Seq);
D
duke 已提交
122

123
    return rc;
D
duke 已提交
124 125 126 127
}



128 129 130 131 132 133
// This function creates a profile based on White point, primaries and
// transfer functions.
cmsHPROFILE CMSEXPORT cmsCreateRGBProfileTHR(cmsContext ContextID,
                                          const cmsCIExyY* WhitePoint,
                                          const cmsCIExyYTRIPLE* Primaries,
                                          cmsToneCurve* const TransferFunction[3])
D
duke 已提交
134
{
135 136 137 138 139 140 141 142 143 144
    cmsHPROFILE hICC;
    cmsMAT3 MColorants;
    cmsCIEXYZTRIPLE Colorants;
    cmsCIExyY MaxWhite;
    cmsMAT3 CHAD;
    cmsCIEXYZ WhitePointXYZ;

    hICC = cmsCreateProfilePlaceholder(ContextID);
    if (!hICC)                          // can't allocate
        return NULL;
D
duke 已提交
145

B
bae 已提交
146
    cmsSetProfileVersion(hICC, 4.3);
D
duke 已提交
147

148 149 150
    cmsSetDeviceClass(hICC,      cmsSigDisplayClass);
    cmsSetColorSpace(hICC,       cmsSigRgbData);
    cmsSetPCS(hICC,              cmsSigXYZData);
D
duke 已提交
151

152
    cmsSetHeaderRenderingIntent(hICC,  INTENT_PERCEPTUAL);
D
duke 已提交
153 154


155 156 157 158 159 160 161 162 163 164 165 166 167
    // Implement profile using following tags:
    //
    //  1 cmsSigProfileDescriptionTag
    //  2 cmsSigMediaWhitePointTag
    //  3 cmsSigRedColorantTag
    //  4 cmsSigGreenColorantTag
    //  5 cmsSigBlueColorantTag
    //  6 cmsSigRedTRCTag
    //  7 cmsSigGreenTRCTag
    //  8 cmsSigBlueTRCTag
    //  9 Chromatic adaptation Tag
    // This conforms a standard RGB DisplayProfile as says ICC, and then I add (As per addendum II)
    // 10 cmsSigChromaticityTag
D
duke 已提交
168 169


170
    if (!SetTextTags(hICC, L"RGB built-in")) goto Error;
D
duke 已提交
171

172
    if (WhitePoint) {
D
duke 已提交
173

174
        if (!cmsWriteTag(hICC, cmsSigMediaWhitePointTag, cmsD50_XYZ())) goto Error;
D
duke 已提交
175

176 177
        cmsxyY2XYZ(&WhitePointXYZ, WhitePoint);
        _cmsAdaptationMatrix(&CHAD, NULL, &WhitePointXYZ, cmsD50_XYZ());
D
duke 已提交
178

179 180 181
        // This is a V4 tag, but many CMM does read and understand it no matter which version
        if (!cmsWriteTag(hICC, cmsSigChromaticAdaptationTag, (void*) &CHAD)) goto Error;
    }
D
duke 已提交
182

183
    if (WhitePoint && Primaries) {
D
duke 已提交
184

185 186 187
        MaxWhite.x =  WhitePoint -> x;
        MaxWhite.y =  WhitePoint -> y;
        MaxWhite.Y =  1.0;
D
duke 已提交
188

189
        if (!_cmsBuildRGB2XYZtransferMatrix(&MColorants, &MaxWhite, Primaries)) goto Error;
D
duke 已提交
190

191 192 193
        Colorants.Red.X   = MColorants.v[0].n[0];
        Colorants.Red.Y   = MColorants.v[1].n[0];
        Colorants.Red.Z   = MColorants.v[2].n[0];
D
duke 已提交
194

195 196 197
        Colorants.Green.X = MColorants.v[0].n[1];
        Colorants.Green.Y = MColorants.v[1].n[1];
        Colorants.Green.Z = MColorants.v[2].n[1];
D
duke 已提交
198

199 200 201
        Colorants.Blue.X  = MColorants.v[0].n[2];
        Colorants.Blue.Y  = MColorants.v[1].n[2];
        Colorants.Blue.Z  = MColorants.v[2].n[2];
D
duke 已提交
202

203 204 205 206
        if (!cmsWriteTag(hICC, cmsSigRedColorantTag,   (void*) &Colorants.Red)) goto Error;
        if (!cmsWriteTag(hICC, cmsSigBlueColorantTag,  (void*) &Colorants.Blue)) goto Error;
        if (!cmsWriteTag(hICC, cmsSigGreenColorantTag, (void*) &Colorants.Green)) goto Error;
    }
D
duke 已提交
207 208


209
    if (TransferFunction) {
D
duke 已提交
210

P
prr 已提交
211
        // Tries to minimize space. Thanks to Richard Hughes for this nice idea
212
        if (!cmsWriteTag(hICC, cmsSigRedTRCTag,   (void*) TransferFunction[0])) goto Error;
P
prr 已提交
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230

        if (TransferFunction[1] == TransferFunction[0]) {

            if (!cmsLinkTag (hICC, cmsSigGreenTRCTag, cmsSigRedTRCTag)) goto Error;

        } else {

            if (!cmsWriteTag(hICC, cmsSigGreenTRCTag, (void*) TransferFunction[1])) goto Error;
        }

        if (TransferFunction[2] == TransferFunction[0]) {

            if (!cmsLinkTag (hICC, cmsSigBlueTRCTag, cmsSigRedTRCTag)) goto Error;

        } else {

            if (!cmsWriteTag(hICC, cmsSigBlueTRCTag, (void*) TransferFunction[2])) goto Error;
        }
231
    }
D
duke 已提交
232

233 234
    if (Primaries) {
        if (!cmsWriteTag(hICC, cmsSigChromaticityTag, (void*) Primaries)) goto Error;
D
duke 已提交
235 236 237
    }


238
    return hICC;
D
duke 已提交
239

240 241 242 243 244
Error:
    if (hICC)
        cmsCloseProfile(hICC);
    return NULL;
}
D
duke 已提交
245

246 247 248
cmsHPROFILE CMSEXPORT cmsCreateRGBProfile(const cmsCIExyY* WhitePoint,
                                          const cmsCIExyYTRIPLE* Primaries,
                                          cmsToneCurve* const TransferFunction[3])
D
duke 已提交
249
{
250
    return cmsCreateRGBProfileTHR(NULL, WhitePoint, Primaries, TransferFunction);
D
duke 已提交
251 252 253 254
}



255 256 257 258
// This function creates a profile based on White point and transfer function.
cmsHPROFILE CMSEXPORT cmsCreateGrayProfileTHR(cmsContext ContextID,
                                           const cmsCIExyY* WhitePoint,
                                           const cmsToneCurve* TransferFunction)
D
duke 已提交
259 260
{
    cmsHPROFILE hICC;
261
    cmsCIEXYZ tmp;
D
duke 已提交
262

263 264
    hICC = cmsCreateProfilePlaceholder(ContextID);
    if (!hICC)                          // can't allocate
D
duke 已提交
265 266
        return NULL;

B
bae 已提交
267
    cmsSetProfileVersion(hICC, 4.3);
D
duke 已提交
268

269 270 271 272
    cmsSetDeviceClass(hICC,      cmsSigDisplayClass);
    cmsSetColorSpace(hICC,       cmsSigGrayData);
    cmsSetPCS(hICC,              cmsSigXYZData);
    cmsSetHeaderRenderingIntent(hICC,  INTENT_PERCEPTUAL);
D
duke 已提交
273 274


275
    // Implement profile using following tags:
D
duke 已提交
276
    //
277 278 279
    //  1 cmsSigProfileDescriptionTag
    //  2 cmsSigMediaWhitePointTag
    //  3 cmsSigGrayTRCTag
D
duke 已提交
280

281
    // This conforms a standard Gray DisplayProfile
D
duke 已提交
282

283
    // Fill-in the tags
D
duke 已提交
284

285
    if (!SetTextTags(hICC, L"gray built-in")) goto Error;
D
duke 已提交
286 287


288
    if (WhitePoint) {
D
duke 已提交
289

290 291
        cmsxyY2XYZ(&tmp, WhitePoint);
        if (!cmsWriteTag(hICC, cmsSigMediaWhitePointTag, (void*) &tmp)) goto Error;
D
duke 已提交
292 293
    }

294
    if (TransferFunction) {
D
duke 已提交
295

296
        if (!cmsWriteTag(hICC, cmsSigGrayTRCTag, (void*) TransferFunction)) goto Error;
D
duke 已提交
297 298
    }

299
    return hICC;
D
duke 已提交
300

301 302 303 304 305
Error:
    if (hICC)
        cmsCloseProfile(hICC);
    return NULL;
}
D
duke 已提交
306 307 308



309 310 311 312 313
cmsHPROFILE CMSEXPORT cmsCreateGrayProfile(const cmsCIExyY* WhitePoint,
                                                    const cmsToneCurve* TransferFunction)
{
    return cmsCreateGrayProfileTHR(NULL, WhitePoint, TransferFunction);
}
D
duke 已提交
314

315
// This is a devicelink operating in the target colorspace with as many transfer functions as components
D
duke 已提交
316

317 318 319 320 321 322 323
cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLinkTHR(cmsContext ContextID,
                                                          cmsColorSpaceSignature ColorSpace,
                                                          cmsToneCurve* const TransferFunctions[])
{
    cmsHPROFILE hICC;
    cmsPipeline* Pipeline;
    int nChannels;
D
duke 已提交
324

325 326 327
    hICC = cmsCreateProfilePlaceholder(ContextID);
    if (!hICC)
        return NULL;
D
duke 已提交
328

B
bae 已提交
329
    cmsSetProfileVersion(hICC, 4.3);
D
duke 已提交
330

331 332 333
    cmsSetDeviceClass(hICC,      cmsSigLinkClass);
    cmsSetColorSpace(hICC,       ColorSpace);
    cmsSetPCS(hICC,              ColorSpace);
D
duke 已提交
334

335
    cmsSetHeaderRenderingIntent(hICC,  INTENT_PERCEPTUAL);
D
duke 已提交
336

337 338
    // Set up channels
    nChannels = cmsChannelsOf(ColorSpace);
D
duke 已提交
339

340 341 342
    // Creates a Pipeline with prelinearization step only
    Pipeline = cmsPipelineAlloc(ContextID, nChannels, nChannels);
    if (Pipeline == NULL) goto Error;
D
duke 已提交
343 344


345
    // Copy tables to Pipeline
P
prr 已提交
346 347
    if (!cmsPipelineInsertStage(Pipeline, cmsAT_BEGIN, cmsStageAllocToneCurves(ContextID, nChannels, TransferFunctions)))
        goto Error;
D
duke 已提交
348

349 350 351 352
    // Create tags
    if (!SetTextTags(hICC, L"Linearization built-in")) goto Error;
    if (!cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) Pipeline)) goto Error;
    if (!SetSeqDescTag(hICC, "Linearization built-in")) goto Error;
D
duke 已提交
353

354 355
    // Pipeline is already on virtual profile
    cmsPipelineFree(Pipeline);
D
duke 已提交
356

357 358
    // Ok, done
    return hICC;
D
duke 已提交
359

360
Error:
P
prr 已提交
361
    cmsPipelineFree(Pipeline);
362 363
    if (hICC)
        cmsCloseProfile(hICC);
D
duke 已提交
364 365


366
    return NULL;
D
duke 已提交
367 368
}

369 370 371 372 373
cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLink(cmsColorSpaceSignature ColorSpace,
                                                                 cmsToneCurve* const TransferFunctions[])
{
    return cmsCreateLinearizationDeviceLinkTHR(NULL, ColorSpace, TransferFunctions);
}
D
duke 已提交
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392

// Ink-limiting algorithm
//
//  Sum = C + M + Y + K
//  If Sum > InkLimit
//        Ratio= 1 - (Sum - InkLimit) / (C + M + Y)
//        if Ratio <0
//              Ratio=0
//        endif
//     Else
//         Ratio=1
//     endif
//
//     C = Ratio * C
//     M = Ratio * M
//     Y = Ratio * Y
//     K: Does not change

static
393
int InkLimitingSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo)
D
duke 已提交
394
{
395 396
    cmsFloat64Number InkLimit = *(cmsFloat64Number *) Cargo;
    cmsFloat64Number SumCMY, SumCMYK, Ratio;
D
duke 已提交
397

398
    InkLimit = (InkLimit * 655.35);
D
duke 已提交
399

400 401
    SumCMY   = In[0]  + In[1] + In[2];
    SumCMYK  = SumCMY + In[3];
D
duke 已提交
402

403
    if (SumCMYK > InkLimit) {
D
duke 已提交
404

405 406 407 408 409
        Ratio = 1 - ((SumCMYK - InkLimit) / SumCMY);
        if (Ratio < 0)
            Ratio = 0;
    }
    else Ratio = 1;
D
duke 已提交
410

411 412 413
    Out[0] = _cmsQuickSaturateWord(In[0] * Ratio);     // C
    Out[1] = _cmsQuickSaturateWord(In[1] * Ratio);     // M
    Out[2] = _cmsQuickSaturateWord(In[2] * Ratio);     // Y
D
duke 已提交
414

415
    Out[3] = In[3];                                 // K (untouched)
D
duke 已提交
416

417
    return TRUE;
D
duke 已提交
418 419 420 421
}

// This is a devicelink operating in CMYK for ink-limiting

422 423 424
cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext ContextID,
                                                     cmsColorSpaceSignature ColorSpace,
                                                     cmsFloat64Number Limit)
D
duke 已提交
425
{
426 427 428 429
    cmsHPROFILE hICC;
    cmsPipeline* LUT;
    cmsStage* CLUT;
    int nChannels;
D
duke 已提交
430

431 432 433 434
    if (ColorSpace != cmsSigCmykData) {
        cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "InkLimiting: Only CMYK currently supported");
        return NULL;
    }
D
duke 已提交
435

436
    if (Limit < 0.0 || Limit > 400) {
D
duke 已提交
437

438 439 440
        cmsSignalError(ContextID, cmsERROR_RANGE, "InkLimiting: Limit should be between 0..400");
        if (Limit < 0) Limit = 0;
        if (Limit > 400) Limit = 400;
D
duke 已提交
441

442
    }
D
duke 已提交
443

444 445 446
    hICC = cmsCreateProfilePlaceholder(ContextID);
    if (!hICC)                          // can't allocate
        return NULL;
D
duke 已提交
447

B
bae 已提交
448
    cmsSetProfileVersion(hICC, 4.3);
D
duke 已提交
449

450 451 452
    cmsSetDeviceClass(hICC,      cmsSigLinkClass);
    cmsSetColorSpace(hICC,       ColorSpace);
    cmsSetPCS(hICC,              ColorSpace);
D
duke 已提交
453

454
    cmsSetHeaderRenderingIntent(hICC,  INTENT_PERCEPTUAL);
D
duke 已提交
455 456


457 458 459
    // Creates a Pipeline with 3D grid only
    LUT = cmsPipelineAlloc(ContextID, 4, 4);
    if (LUT == NULL) goto Error;
D
duke 已提交
460 461


462
    nChannels = cmsChannelsOf(ColorSpace);
D
duke 已提交
463

464 465
    CLUT = cmsStageAllocCLut16bit(ContextID, 17, nChannels, nChannels, NULL);
    if (CLUT == NULL) goto Error;
D
duke 已提交
466

467
    if (!cmsStageSampleCLut16bit(CLUT, InkLimitingSampler, (void*) &Limit, 0)) goto Error;
D
duke 已提交
468

P
prr 已提交
469 470 471 472
    if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, nChannels)) ||
        !cmsPipelineInsertStage(LUT, cmsAT_END, CLUT) ||
        !cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocIdentityCurves(ContextID, nChannels)))
        goto Error;
D
duke 已提交
473

474 475
    // Create tags
    if (!SetTextTags(hICC, L"ink-limiting built-in")) goto Error;
D
duke 已提交
476

477 478
    if (!cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) LUT))  goto Error;
    if (!SetSeqDescTag(hICC, "ink-limiting built-in")) goto Error;
D
duke 已提交
479

480 481
    // cmsPipeline is already on virtual profile
    cmsPipelineFree(LUT);
D
duke 已提交
482

483 484
    // Ok, done
    return hICC;
D
duke 已提交
485

486 487 488
Error:
    if (LUT != NULL)
        cmsPipelineFree(LUT);
D
duke 已提交
489

490 491
    if (hICC != NULL)
        cmsCloseProfile(hICC);
D
duke 已提交
492

493
    return NULL;
D
duke 已提交
494 495
}

496 497 498 499
cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLink(cmsColorSpaceSignature ColorSpace, cmsFloat64Number Limit)
{
    return cmsCreateInkLimitingDeviceLinkTHR(NULL, ColorSpace, Limit);
}
D
duke 已提交
500 501 502


// Creates a fake Lab identity.
503
cmsHPROFILE CMSEXPORT cmsCreateLab2ProfileTHR(cmsContext ContextID, const cmsCIExyY* WhitePoint)
D
duke 已提交
504
{
505 506
    cmsHPROFILE hProfile;
    cmsPipeline* LUT = NULL;
D
duke 已提交
507

508 509
    hProfile = cmsCreateRGBProfileTHR(ContextID, WhitePoint == NULL ? cmsD50_xyY() : WhitePoint, NULL, NULL);
    if (hProfile == NULL) return NULL;
D
duke 已提交
510

511
    cmsSetProfileVersion(hProfile, 2.1);
D
duke 已提交
512

513 514 515
    cmsSetDeviceClass(hProfile, cmsSigAbstractClass);
    cmsSetColorSpace(hProfile,  cmsSigLabData);
    cmsSetPCS(hProfile,         cmsSigLabData);
D
duke 已提交
516

517
    if (!SetTextTags(hProfile, L"Lab identity built-in")) return NULL;
D
duke 已提交
518

519 520 521
    // An identity LUT is all we need
    LUT = cmsPipelineAlloc(ContextID, 3, 3);
    if (LUT == NULL) goto Error;
D
duke 已提交
522

P
prr 已提交
523 524
    if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCLut(ContextID, 3)))
        goto Error;
D
duke 已提交
525

526 527
    if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error;
    cmsPipelineFree(LUT);
D
duke 已提交
528

529 530 531 532 533 534 535 536 537 538 539
    return hProfile;

Error:

    if (LUT != NULL)
        cmsPipelineFree(LUT);

    if (hProfile != NULL)
        cmsCloseProfile(hProfile);

    return NULL;
D
duke 已提交
540 541 542
}


543 544 545 546 547 548 549 550
cmsHPROFILE CMSEXPORT cmsCreateLab2Profile(const cmsCIExyY* WhitePoint)
{
    return cmsCreateLab2ProfileTHR(NULL, WhitePoint);
}


// Creates a fake Lab V4 identity.
cmsHPROFILE CMSEXPORT cmsCreateLab4ProfileTHR(cmsContext ContextID, const cmsCIExyY* WhitePoint)
D
duke 已提交
551
{
552 553
    cmsHPROFILE hProfile;
    cmsPipeline* LUT = NULL;
D
duke 已提交
554

555 556
    hProfile = cmsCreateRGBProfileTHR(ContextID, WhitePoint == NULL ? cmsD50_xyY() : WhitePoint, NULL, NULL);
    if (hProfile == NULL) return NULL;
D
duke 已提交
557

B
bae 已提交
558
    cmsSetProfileVersion(hProfile, 4.3);
D
duke 已提交
559

560 561 562
    cmsSetDeviceClass(hProfile, cmsSigAbstractClass);
    cmsSetColorSpace(hProfile,  cmsSigLabData);
    cmsSetPCS(hProfile,         cmsSigLabData);
D
duke 已提交
563

564
    if (!SetTextTags(hProfile, L"Lab identity built-in")) goto Error;
D
duke 已提交
565

566 567 568
    // An empty LUTs is all we need
    LUT = cmsPipelineAlloc(ContextID, 3, 3);
    if (LUT == NULL) goto Error;
D
duke 已提交
569

P
prr 已提交
570 571
    if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3)))
        goto Error;
572 573 574

    if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error;
    cmsPipelineFree(LUT);
D
duke 已提交
575

576
    return hProfile;
D
duke 已提交
577

578
Error:
D
duke 已提交
579

580 581
    if (LUT != NULL)
        cmsPipelineFree(LUT);
D
duke 已提交
582

583 584 585 586
    if (hProfile != NULL)
        cmsCloseProfile(hProfile);

    return NULL;
D
duke 已提交
587 588
}

589 590 591 592
cmsHPROFILE CMSEXPORT cmsCreateLab4Profile(const cmsCIExyY* WhitePoint)
{
    return cmsCreateLab4ProfileTHR(NULL, WhitePoint);
}
D
duke 已提交
593 594 595


// Creates a fake XYZ identity
596
cmsHPROFILE CMSEXPORT cmsCreateXYZProfileTHR(cmsContext ContextID)
D
duke 已提交
597
{
598 599
    cmsHPROFILE hProfile;
    cmsPipeline* LUT = NULL;
D
duke 已提交
600

601 602
    hProfile = cmsCreateRGBProfileTHR(ContextID, cmsD50_xyY(), NULL, NULL);
    if (hProfile == NULL) return NULL;
D
duke 已提交
603

B
bae 已提交
604
    cmsSetProfileVersion(hProfile, 4.3);
D
duke 已提交
605

606 607 608
    cmsSetDeviceClass(hProfile, cmsSigAbstractClass);
    cmsSetColorSpace(hProfile,  cmsSigXYZData);
    cmsSetPCS(hProfile,         cmsSigXYZData);
D
duke 已提交
609

610
    if (!SetTextTags(hProfile, L"XYZ identity built-in")) goto Error;
D
duke 已提交
611

612 613 614
    // An identity LUT is all we need
    LUT = cmsPipelineAlloc(ContextID, 3, 3);
    if (LUT == NULL) goto Error;
D
duke 已提交
615

P
prr 已提交
616 617
    if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, 3)))
        goto Error;
D
duke 已提交
618

619 620
    if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, LUT)) goto Error;
    cmsPipelineFree(LUT);
D
duke 已提交
621

622
    return hProfile;
D
duke 已提交
623

624
Error:
D
duke 已提交
625

626 627
    if (LUT != NULL)
        cmsPipelineFree(LUT);
D
duke 已提交
628

629 630
    if (hProfile != NULL)
        cmsCloseProfile(hProfile);
D
duke 已提交
631

632 633
    return NULL;
}
D
duke 已提交
634 635


636 637 638 639
cmsHPROFILE CMSEXPORT cmsCreateXYZProfile(void)
{
    return cmsCreateXYZProfileTHR(NULL);
}
D
duke 已提交
640 641


642 643 644 645 646 647 648 649 650 651 652 653 654 655
//sRGB Curves are defined by:
//
//If  RsRGB,GsRGB, BsRGB < 0.04045
//
//    R =  RsRGB / 12.92
//    G =  GsRGB / 12.92
//    B =  BsRGB / 12.92
//
//
//else if  RsRGB,GsRGB, BsRGB >= 0.04045
//
//    R = ((RsRGB + 0.055) / 1.055)^2.4
//    G = ((GsRGB + 0.055) / 1.055)^2.4
//    B = ((BsRGB + 0.055) / 1.055)^2.4
D
duke 已提交
656 657

static
658
cmsToneCurve* Build_sRGBGamma(cmsContext ContextID)
D
duke 已提交
659
{
660
    cmsFloat64Number Parameters[5];
D
duke 已提交
661 662 663 664 665

    Parameters[0] = 2.4;
    Parameters[1] = 1. / 1.055;
    Parameters[2] = 0.055 / 1.055;
    Parameters[3] = 1. / 12.92;
666
    Parameters[4] = 0.04045;
D
duke 已提交
667

668
    return cmsBuildParametricToneCurve(ContextID, 4, Parameters);
D
duke 已提交
669 670
}

671
// Create the ICC virtual profile for sRGB space
672
cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfileTHR(cmsContext ContextID)
D
duke 已提交
673
{
P
prr 已提交
674
       cmsCIExyY       D65 = { 0.3127, 0.3290, 1.0 };
D
duke 已提交
675 676 677 678 679
       cmsCIExyYTRIPLE Rec709Primaries = {
                                   {0.6400, 0.3300, 1.0},
                                   {0.3000, 0.6000, 1.0},
                                   {0.1500, 0.0600, 1.0}
                                   };
680
       cmsToneCurve* Gamma22[3];
D
duke 已提交
681 682
       cmsHPROFILE  hsRGB;

P
prr 已提交
683
      // cmsWhitePointFromTemp(&D65, 6504);
684 685
       Gamma22[0] = Gamma22[1] = Gamma22[2] = Build_sRGBGamma(ContextID);
       if (Gamma22[0] == NULL) return NULL;
D
duke 已提交
686

687 688
       hsRGB = cmsCreateRGBProfileTHR(ContextID, &D65, &Rec709Primaries, Gamma22);
       cmsFreeToneCurve(Gamma22[0]);
689
       if (hsRGB == NULL) return NULL;
D
duke 已提交
690

691 692 693 694
       if (!SetTextTags(hsRGB, L"sRGB built-in")) {
           cmsCloseProfile(hsRGB);
           return NULL;
       }
D
duke 已提交
695 696 697 698

       return hsRGB;
}

699 700 701 702 703
cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfile(void)
{
    return cmsCreate_sRGBProfileTHR(NULL);
}

D
duke 已提交
704 705 706


typedef struct {
707 708 709 710
                cmsFloat64Number Brightness;
                cmsFloat64Number Contrast;
                cmsFloat64Number Hue;
                cmsFloat64Number Saturation;
P
prr 已提交
711
                cmsBool          lAdjustWP;
D
duke 已提交
712 713 714 715 716 717
                cmsCIEXYZ WPsrc, WPdest;

} BCHSWADJUSTS, *LPBCHSWADJUSTS;


static
718
int bchswSampler(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo)
D
duke 已提交
719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740
{
    cmsCIELab LabIn, LabOut;
    cmsCIELCh LChIn, LChOut;
    cmsCIEXYZ XYZ;
    LPBCHSWADJUSTS bchsw = (LPBCHSWADJUSTS) Cargo;


    cmsLabEncoded2Float(&LabIn, In);


    cmsLab2LCh(&LChIn, &LabIn);

    // Do some adjusts on LCh

    LChOut.L = LChIn.L * bchsw ->Contrast + bchsw ->Brightness;
    LChOut.C = LChIn.C + bchsw -> Saturation;
    LChOut.h = LChIn.h + bchsw -> Hue;


    cmsLCh2Lab(&LabOut, &LChOut);

    // Move white point in Lab
P
prr 已提交
741 742 743 744
    if (bchsw->lAdjustWP) {
           cmsLab2XYZ(&bchsw->WPsrc, &XYZ, &LabOut);
           cmsXYZ2Lab(&bchsw->WPdest, &LabOut, &XYZ);
    }
D
duke 已提交
745 746 747 748 749 750 751 752 753 754 755 756

    // Back to encoded

    cmsFloat2LabEncoded(Out, &LabOut);

    return TRUE;
}


// Creates an abstract profile operating in Lab space for Brightness,
// contrast, Saturation and white point displacement

757
cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID,
P
prr 已提交
758 759 760 761 762 763 764
    int nLUTPoints,
    cmsFloat64Number Bright,
    cmsFloat64Number Contrast,
    cmsFloat64Number Hue,
    cmsFloat64Number Saturation,
    int TempSrc,
    int TempDest)
D
duke 已提交
765
{
P
prr 已提交
766 767 768 769 770 771 772
    cmsHPROFILE hICC;
    cmsPipeline* Pipeline;
    BCHSWADJUSTS bchsw;
    cmsCIExyY WhitePnt;
    cmsStage* CLUT;
    cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS];
    int i;
D
duke 已提交
773

P
prr 已提交
774 775 776 777
    bchsw.Brightness = Bright;
    bchsw.Contrast   = Contrast;
    bchsw.Hue        = Hue;
    bchsw.Saturation = Saturation;
P
prr 已提交
778
    if (TempSrc == TempDest) {
D
duke 已提交
779

P
prr 已提交
780 781 782 783 784 785 786 787
           bchsw.lAdjustWP = FALSE;
    }
    else {
           bchsw.lAdjustWP = TRUE;
           cmsWhitePointFromTemp(&WhitePnt, TempSrc);
           cmsxyY2XYZ(&bchsw.WPsrc, &WhitePnt);
           cmsWhitePointFromTemp(&WhitePnt, TempDest);
           cmsxyY2XYZ(&bchsw.WPdest, &WhitePnt);
D
duke 已提交
788

P
prr 已提交
789
    }
D
duke 已提交
790

P
prr 已提交
791 792 793
    hICC = cmsCreateProfilePlaceholder(ContextID);
    if (!hICC)                          // can't allocate
        return NULL;
D
duke 已提交
794

P
prr 已提交
795 796 797
    cmsSetDeviceClass(hICC,      cmsSigAbstractClass);
    cmsSetColorSpace(hICC,       cmsSigLabData);
    cmsSetPCS(hICC,              cmsSigLabData);
D
duke 已提交
798

P
prr 已提交
799
    cmsSetHeaderRenderingIntent(hICC,  INTENT_PERCEPTUAL);
D
duke 已提交
800

P
prr 已提交
801 802 803 804 805 806
    // Creates a Pipeline with 3D grid only
    Pipeline = cmsPipelineAlloc(ContextID, 3, 3);
    if (Pipeline == NULL) {
        cmsCloseProfile(hICC);
        return NULL;
    }
D
duke 已提交
807

P
prr 已提交
808 809 810
    for (i=0; i < MAX_INPUT_DIMENSIONS; i++) Dimensions[i] = nLUTPoints;
    CLUT = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 3, 3, NULL);
    if (CLUT == NULL) return NULL;
811

D
duke 已提交
812

P
prr 已提交
813
    if (!cmsStageSampleCLut16bit(CLUT, bchswSampler, (void*) &bchsw, 0)) {
D
duke 已提交
814

P
prr 已提交
815 816 817
        // Shouldn't reach here
        goto Error;
    }
D
duke 已提交
818

P
prr 已提交
819 820 821
    if (!cmsPipelineInsertStage(Pipeline, cmsAT_END, CLUT)) {
        goto Error;
    }
822

P
prr 已提交
823 824
    // Create tags
    if (!SetTextTags(hICC, L"BCHS built-in")) return NULL;
D
duke 已提交
825

P
prr 已提交
826
    cmsWriteTag(hICC, cmsSigMediaWhitePointTag, (void*) cmsD50_XYZ());
D
duke 已提交
827

P
prr 已提交
828
    cmsWriteTag(hICC, cmsSigAToB0Tag, (void*) Pipeline);
D
duke 已提交
829

P
prr 已提交
830 831
    // Pipeline is already on virtual profile
    cmsPipelineFree(Pipeline);
D
duke 已提交
832

P
prr 已提交
833 834
    // Ok, done
    return hICC;
D
duke 已提交
835

P
prr 已提交
836 837 838 839
Error:
    cmsPipelineFree(Pipeline);
    cmsCloseProfile(hICC);
    return NULL;
840 841
}

D
duke 已提交
842

843 844 845 846 847 848 849 850 851
CMSAPI cmsHPROFILE   CMSEXPORT cmsCreateBCHSWabstractProfile(int nLUTPoints,
                                                             cmsFloat64Number Bright,
                                                             cmsFloat64Number Contrast,
                                                             cmsFloat64Number Hue,
                                                             cmsFloat64Number Saturation,
                                                             int TempSrc,
                                                             int TempDest)
{
    return cmsCreateBCHSWabstractProfileTHR(NULL, nLUTPoints, Bright, Contrast, Hue, Saturation, TempSrc, TempDest);
D
duke 已提交
852 853 854 855 856
}


// Creates a fake NULL profile. This profile return 1 channel as always 0.
// Is useful only for gamut checking tricks
857 858 859 860 861 862 863 864 865 866 867 868
cmsHPROFILE CMSEXPORT cmsCreateNULLProfileTHR(cmsContext ContextID)
{
    cmsHPROFILE hProfile;
    cmsPipeline* LUT = NULL;
    cmsStage* PostLin;
    cmsToneCurve* EmptyTab;
    cmsUInt16Number Zero[2] = { 0, 0 };

    hProfile = cmsCreateProfilePlaceholder(ContextID);
    if (!hProfile)                          // can't allocate
        return NULL;

B
bae 已提交
869
    cmsSetProfileVersion(hProfile, 4.3);
870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885

    if (!SetTextTags(hProfile, L"NULL profile built-in")) goto Error;



    cmsSetDeviceClass(hProfile, cmsSigOutputClass);
    cmsSetColorSpace(hProfile,  cmsSigGrayData);
    cmsSetPCS(hProfile,         cmsSigLabData);

    // An empty LUTs is all we need
    LUT = cmsPipelineAlloc(ContextID, 1, 1);
    if (LUT == NULL) goto Error;

    EmptyTab = cmsBuildTabulatedToneCurve16(ContextID, 2, Zero);
    PostLin = cmsStageAllocToneCurves(ContextID, 1, &EmptyTab);
    cmsFreeToneCurve(EmptyTab);
D
duke 已提交
886

P
prr 已提交
887 888
    if (!cmsPipelineInsertStage(LUT, cmsAT_END, PostLin))
        goto Error;
889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907

    if (!cmsWriteTag(hProfile, cmsSigBToA0Tag, (void*) LUT)) goto Error;
    if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, cmsD50_XYZ())) goto Error;

    cmsPipelineFree(LUT);
    return hProfile;

Error:

    if (LUT != NULL)
        cmsPipelineFree(LUT);

    if (hProfile != NULL)
        cmsCloseProfile(hProfile);

    return NULL;
}

cmsHPROFILE CMSEXPORT cmsCreateNULLProfile(void)
D
duke 已提交
908
{
909 910
    return cmsCreateNULLProfileTHR(NULL);
}
D
duke 已提交
911 912


913 914 915 916 917 918
static
int IsPCS(cmsColorSpaceSignature ColorSpace)
{
    return (ColorSpace == cmsSigXYZData ||
            ColorSpace == cmsSigLabData);
}
D
duke 已提交
919 920


921 922 923 924 925 926 927
static
void FixColorSpaces(cmsHPROFILE hProfile,
                              cmsColorSpaceSignature ColorSpace,
                              cmsColorSpaceSignature PCS,
                              cmsUInt32Number dwFlags)
{
    if (dwFlags & cmsFLAGS_GUESSDEVICECLASS) {
D
duke 已提交
928

929
            if (IsPCS(ColorSpace) && IsPCS(PCS)) {
D
duke 已提交
930

931 932 933 934 935
                    cmsSetDeviceClass(hProfile,      cmsSigAbstractClass);
                    cmsSetColorSpace(hProfile,       ColorSpace);
                    cmsSetPCS(hProfile,              PCS);
                    return;
            }
D
duke 已提交
936

937 938 939 940 941 942 943
            if (IsPCS(ColorSpace) && !IsPCS(PCS)) {

                    cmsSetDeviceClass(hProfile, cmsSigOutputClass);
                    cmsSetPCS(hProfile,         ColorSpace);
                    cmsSetColorSpace(hProfile,  PCS);
                    return;
            }
D
duke 已提交
944

945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994
            if (IsPCS(PCS) && !IsPCS(ColorSpace)) {

                   cmsSetDeviceClass(hProfile,  cmsSigInputClass);
                   cmsSetColorSpace(hProfile,   ColorSpace);
                   cmsSetPCS(hProfile,          PCS);
                   return;
            }
    }

    cmsSetDeviceClass(hProfile,      cmsSigLinkClass);
    cmsSetColorSpace(hProfile,       ColorSpace);
    cmsSetPCS(hProfile,              PCS);
}



// This function creates a named color profile dumping all the contents of transform to a single profile
// In this way, LittleCMS may be used to "group" several named color databases into a single profile.
// It has, however, several minor limitations. PCS is always Lab, which is not very critic since this
// is the normal PCS for named color profiles.
static
cmsHPROFILE CreateNamedColorDevicelink(cmsHTRANSFORM xform)
{
    _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform;
    cmsHPROFILE hICC = NULL;
    int i, nColors;
    cmsNAMEDCOLORLIST *nc2 = NULL, *Original = NULL;

    // Create an empty placeholder
    hICC = cmsCreateProfilePlaceholder(v->ContextID);
    if (hICC == NULL) return NULL;

    // Critical information
    cmsSetDeviceClass(hICC, cmsSigNamedColorClass);
    cmsSetColorSpace(hICC, v ->ExitColorSpace);
    cmsSetPCS(hICC, cmsSigLabData);

    // Tag profile with information
    if (!SetTextTags(hICC, L"Named color devicelink")) goto Error;

    Original = cmsGetNamedColorList(xform);
    if (Original == NULL) goto Error;

    nColors = cmsNamedColorCount(Original);
    nc2     = cmsDupNamedColorList(Original);
    if (nc2 == NULL) goto Error;

    // Colorant count now depends on the output space
    nc2 ->ColorantCount = cmsPipelineOutputChannels(v ->Lut);

B
bae 已提交
995 996 997 998 999
    // Make sure we have proper formatters
    cmsChangeBuffersFormat(xform, TYPE_NAMED_COLOR_INDEX,
        FLOAT_SH(0) | COLORSPACE_SH(_cmsLCMScolorSpace(v ->ExitColorSpace))
        | BYTES_SH(2) | CHANNELS_SH(cmsChannelsOf(v ->ExitColorSpace)));

1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019
    // Apply the transfor to colorants.
    for (i=0; i < nColors; i++) {
        cmsDoTransform(xform, &i, nc2 ->List[i].DeviceColorant, 1);
    }

    if (!cmsWriteTag(hICC, cmsSigNamedColor2Tag, (void*) nc2)) goto Error;
    cmsFreeNamedColorList(nc2);

    return hICC;

Error:
    if (hICC != NULL) cmsCloseProfile(hICC);
    return NULL;
}


// This structure holds information about which MPU can be stored on a profile based on the version

typedef struct {
    cmsBool              IsV4;             // Is a V4 tag?
B
bae 已提交
1020
    cmsTagSignature      RequiredTag;      // Set to 0 for both types
1021 1022 1023 1024 1025 1026
    cmsTagTypeSignature  LutType;          // The LUT type
    int                  nTypes;           // Number of types (up to 5)
    cmsStageSignature    MpeTypes[5];      // 5 is the maximum number

} cmsAllowedLUT;

P
prr 已提交
1027 1028
#define cmsSig0 ((cmsTagSignature) 0)

1029 1030
static const cmsAllowedLUT AllowedLUTTypes[] = {

P
prr 已提交
1031 1032 1033 1034
    { FALSE, cmsSig0,        cmsSigLut16Type, 4, { cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType } },
    { FALSE, cmsSig0,        cmsSigLut16Type, 3, { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType } },
    { FALSE, cmsSig0,        cmsSigLut16Type, 2, { cmsSigCurveSetElemType, cmsSigCLutElemType } },
    { TRUE,  cmsSig0,        cmsSigLutAtoBType, 1, { cmsSigCurveSetElemType } },
B
bae 已提交
1035 1036 1037 1038 1039 1040 1041
    { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType,  3,  { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType } },
    { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType,  3,  { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType   } },
    { TRUE , cmsSigAToB0Tag, cmsSigLutAtoBType,  5,  { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType }},
    { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType,  1,  { cmsSigCurveSetElemType }},
    { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType,  3,  { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType }},
    { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType,  3,  { cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType }},
    { TRUE , cmsSigBToA0Tag, cmsSigLutBtoAType,  5,  { cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType, cmsSigCLutElemType, cmsSigCurveSetElemType }}
1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063
};

#define SIZE_OF_ALLOWED_LUT (sizeof(AllowedLUTTypes)/sizeof(cmsAllowedLUT))

// Check a single entry
static
cmsBool CheckOne(const cmsAllowedLUT* Tab, const cmsPipeline* Lut)
{
    cmsStage* mpe;
    int n;

    for (n=0, mpe = Lut ->Elements; mpe != NULL; mpe = mpe ->Next, n++) {

        if (n > Tab ->nTypes) return FALSE;
        if (cmsStageType(mpe) != Tab ->MpeTypes[n]) return FALSE;
    }

    return (n == Tab ->nTypes);
}


static
B
bae 已提交
1064
const cmsAllowedLUT* FindCombination(const cmsPipeline* Lut, cmsBool IsV4, cmsTagSignature DestinationTag)
1065
{
B
bae 已提交
1066
    cmsUInt32Number n;
1067 1068 1069 1070 1071 1072

    for (n=0; n < SIZE_OF_ALLOWED_LUT; n++) {

        const cmsAllowedLUT* Tab = AllowedLUTTypes + n;

        if (IsV4 ^ Tab -> IsV4) continue;
B
bae 已提交
1073 1074
        if ((Tab ->RequiredTag != 0) && (Tab ->RequiredTag != DestinationTag)) continue;

1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092
        if (CheckOne(Tab, Lut)) return Tab;
    }

    return NULL;
}


// Does convert a transform into a device link profile
cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat64Number Version, cmsUInt32Number dwFlags)
{
    cmsHPROFILE hProfile = NULL;
    cmsUInt32Number FrmIn, FrmOut, ChansIn, ChansOut;
    cmsUInt32Number ColorSpaceBitsIn, ColorSpaceBitsOut;
    _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
    cmsPipeline* LUT = NULL;
    cmsStage* mpe;
    cmsContext ContextID = cmsGetTransformContextID(hTransform);
    const cmsAllowedLUT* AllowedLUT;
B
bae 已提交
1093
    cmsTagSignature DestinationTag;
P
prr 已提交
1094
    cmsProfileClassSignature deviceClass;
1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115

    _cmsAssert(hTransform != NULL);

    // Get the first mpe to check for named color
    mpe = cmsPipelineGetPtrToFirstStage(xform ->Lut);

    // Check if is a named color transform
    if (mpe != NULL) {

        if (cmsStageType(mpe) == cmsSigNamedColorElemType) {
            return CreateNamedColorDevicelink(hTransform);
        }
    }

    // First thing to do is to get a copy of the transformation
    LUT = cmsPipelineDup(xform ->Lut);
    if (LUT == NULL) return NULL;

    // Time to fix the Lab2/Lab4 issue.
    if ((xform ->EntryColorSpace == cmsSigLabData) && (Version < 4.0)) {

P
prr 已提交
1116 1117
        if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocLabV2ToV4curves(ContextID)))
            goto Error;
1118 1119 1120 1121 1122
    }

    // On the output side too
    if ((xform ->ExitColorSpace) == cmsSigLabData && (Version < 4.0)) {

P
prr 已提交
1123 1124
        if (!cmsPipelineInsertStage(LUT, cmsAT_END, _cmsStageAllocLabV4ToV2(ContextID)))
            goto Error;
1125 1126
    }

B
bae 已提交
1127 1128 1129 1130 1131 1132 1133 1134

    hProfile = cmsCreateProfilePlaceholder(ContextID);
    if (!hProfile) goto Error;                    // can't allocate

    cmsSetProfileVersion(hProfile, Version);

    FixColorSpaces(hProfile, xform -> EntryColorSpace, xform -> ExitColorSpace, dwFlags);

1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145
    // Optimize the LUT and precalculate a devicelink

    ChansIn  = cmsChannelsOf(xform -> EntryColorSpace);
    ChansOut = cmsChannelsOf(xform -> ExitColorSpace);

    ColorSpaceBitsIn  = _cmsLCMScolorSpace(xform -> EntryColorSpace);
    ColorSpaceBitsOut = _cmsLCMScolorSpace(xform -> ExitColorSpace);

    FrmIn  = COLORSPACE_SH(ColorSpaceBitsIn) | CHANNELS_SH(ChansIn)|BYTES_SH(2);
    FrmOut = COLORSPACE_SH(ColorSpaceBitsOut) | CHANNELS_SH(ChansOut)|BYTES_SH(2);

P
prr 已提交
1146
    deviceClass = cmsGetDeviceClass(hProfile);
1147

P
prr 已提交
1148
     if (deviceClass == cmsSigOutputClass)
B
bae 已提交
1149 1150 1151 1152
         DestinationTag = cmsSigBToA0Tag;
     else
         DestinationTag = cmsSigAToB0Tag;

1153 1154 1155 1156
    // Check if the profile/version can store the result
    if (dwFlags & cmsFLAGS_FORCE_CLUT)
        AllowedLUT = NULL;
    else
B
bae 已提交
1157
        AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag);
1158 1159 1160 1161

    if (AllowedLUT == NULL) {

        // Try to optimize
P
prr 已提交
1162
        _cmsOptimizePipeline(ContextID, &LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags);
B
bae 已提交
1163
        AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag);
1164 1165 1166 1167 1168 1169 1170

    }

    // If no way, then force CLUT that for sure can be written
    if (AllowedLUT == NULL) {

        dwFlags |= cmsFLAGS_FORCE_CLUT;
P
prr 已提交
1171
        _cmsOptimizePipeline(ContextID, &LUT, xform ->RenderingIntent, &FrmIn, &FrmOut, &dwFlags);
1172 1173

        // Put identity curves if needed
B
bae 已提交
1174
        if (cmsPipelineGetPtrToFirstStage(LUT) ->Type != cmsSigCurveSetElemType)
P
prr 已提交
1175 1176
             if (!cmsPipelineInsertStage(LUT, cmsAT_BEGIN, _cmsStageAllocIdentityCurves(ContextID, ChansIn)))
                 goto Error;
1177

B
bae 已提交
1178
        if (cmsPipelineGetPtrToLastStage(LUT) ->Type != cmsSigCurveSetElemType)
P
prr 已提交
1179 1180
             if (!cmsPipelineInsertStage(LUT, cmsAT_END,   _cmsStageAllocIdentityCurves(ContextID, ChansOut)))
                 goto Error;
1181

B
bae 已提交
1182
        AllowedLUT = FindCombination(LUT, Version >= 4.0, DestinationTag);
1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194
    }

    // Somethings is wrong...
    if (AllowedLUT == NULL) {
        goto Error;
    }


    if (dwFlags & cmsFLAGS_8BITS_DEVICELINK)
                     cmsPipelineSetSaveAs8bitsFlag(LUT, TRUE);

    // Tag profile with information
B
bae 已提交
1195
    if (!SetTextTags(hProfile, L"devicelink")) goto Error;
1196

B
bae 已提交
1197 1198
    // Store result
    if (!cmsWriteTag(hProfile, DestinationTag, LUT)) goto Error;
1199 1200 1201 1202 1203 1204 1205 1206 1207 1208


    if (xform -> InputColorant != NULL) {
           if (!cmsWriteTag(hProfile, cmsSigColorantTableTag, xform->InputColorant)) goto Error;
    }

    if (xform -> OutputColorant != NULL) {
           if (!cmsWriteTag(hProfile, cmsSigColorantTableOutTag, xform->OutputColorant)) goto Error;
    }

P
prr 已提交
1209
    if ((deviceClass == cmsSigLinkClass) && (xform ->Sequence != NULL)) {
1210 1211
        if (!_cmsWriteProfileSequence(hProfile, xform ->Sequence)) goto Error;
    }
D
duke 已提交
1212

P
prr 已提交
1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224
    // Set the white point
    if (deviceClass == cmsSigInputClass) {
        if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, &xform ->EntryWhitePoint)) goto Error;
    }
    else {
         if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, &xform ->ExitWhitePoint)) goto Error;
    }


    // Per 7.2.15 in spec 4.3
    cmsSetHeaderRenderingIntent(hProfile, xform ->RenderingIntent);

1225 1226
    cmsPipelineFree(LUT);
    return hProfile;
D
duke 已提交
1227

1228 1229 1230 1231
Error:
    if (LUT != NULL) cmsPipelineFree(LUT);
    cmsCloseProfile(hProfile);
    return NULL;
D
duke 已提交
1232
}