Ejemplo n.º 1
0
// Create an output MPE LUT from agiven profile. Version mismatches are handled here
cmsPipeline* _cmsReadOutputLUT(cmsHPROFILE hProfile, int Intent)
{
    cmsTagTypeSignature OriginalType;
    cmsTagSignature tag16    = PCS2Device16[Intent];
    cmsTagSignature tagFloat = PCS2DeviceFloat[Intent];
    cmsContext ContextID     = cmsGetProfileContextID(hProfile);

    if (cmsIsTag(hProfile, tagFloat)) {  // Float tag takes precedence

        // Floating point LUT are always V4, so no adjustment is required
        return cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat));
    }

    // Revert to perceptual if no tag is found
    if (!cmsIsTag(hProfile, tag16)) {
        tag16 = PCS2Device16[0];
    }

    if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table?

        // Check profile version and LUT type. Do the necessary adjustments if needed

        // First read the tag
        cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16);
        if (Lut == NULL) return NULL;

        // After reading it, we have info about the original type
        OriginalType =  _cmsGetTagTrueType(hProfile, tag16);

        // The profile owns the Lut, so we need to copy it
        Lut = cmsPipelineDup(Lut);
        if (Lut == NULL) return NULL;

        // Now it is time for a controversial stuff. I found that for 3D LUTS using 
        // Lab used as indexer space,  trilinear interpolation should be used         
        if (cmsGetPCS(hProfile) == cmsSigLabData)
                             ChangeInterpolationToTrilinear(Lut);       

        // We need to adjust data only for Lab and Lut16 type
        if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData) 
            return Lut;

        // Add a matrix for conversion V4 to V2 Lab PCS
        cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID));
        return Lut;
    }   

    // Lut not found, try to create a matrix-shaper

    // Check if this is a grayscale profile.
     if (cmsGetColorSpace(hProfile) == cmsSigGrayData) {

              // if so, build appropiate conversion tables. 
              // The tables are the PCS iluminant, scaled across GrayTRC
              return BuildGrayOutputPipeline(hProfile);              
    }

    // Not gray, create a normal matrix-shaper 
    return BuildRGBOutputMatrixShaper(hProfile);
}
Ejemplo n.º 2
0
void LcmsColorProfileContainer::DelinearizeFloatValue(QVector <double> & Value) const
{
    QVector <double> TRCtriplet(3);
    TRCtriplet[0] = Value[0];
    TRCtriplet[1] = Value[1];
    TRCtriplet[2] = Value[2];
    if (cmsIsTag(d->profile, cmsSigRedTRCTag)) {
        if (cmsIsToneCurveLinear(d->redTRC)) {
            TRCtriplet[0] = Value[0];
        } else {
            TRCtriplet[0] = cmsEvalToneCurveFloat(d->redTRCReverse, Value[0]);
        }
        if (cmsIsToneCurveLinear(d->greenTRC)) {
            TRCtriplet[1] = Value[1];
        } else {
            TRCtriplet[1] = cmsEvalToneCurveFloat(d->greenTRCReverse, Value[1]);
        }
        if (cmsIsToneCurveLinear(d->blueTRC)) {
            TRCtriplet[2] = Value[2];
        } else {
            TRCtriplet[2] = cmsEvalToneCurveFloat(d->blueTRCReverse, Value[2]);
        }
            
    } else {
        if (cmsIsTag(d->profile, cmsSigGrayTRCTag)) {
            TRCtriplet.fill(cmsEvalToneCurveFloat(d->grayTRCReverse, Value[0]));
        }
    }

    Value = TRCtriplet;
}
Ejemplo n.º 3
0
// Read and create a BRAND NEW MPE LUT from a given profile. All stuff dependent of version, etc
// is adjusted here in order to create a LUT that takes care of all those details
cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent)
{
    cmsTagTypeSignature OriginalType;
    cmsTagSignature tag16    = Device2PCS16[Intent];
    cmsTagSignature tagFloat = Device2PCSFloat[Intent];
    cmsContext ContextID = cmsGetProfileContextID(hProfile);

    if (cmsIsTag(hProfile, tagFloat)) {  // Float tag takes precedence

        // Floating point LUT are always V4, so no adjustment is required
        return cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat));
    }

    // Revert to perceptual if no tag is found
    if (!cmsIsTag(hProfile, tag16)) {
        tag16 = Device2PCS16[0];
    }

    if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table?

        // Check profile version and LUT type. Do the necessary adjustments if needed

        // First read the tag
        cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16);
        if (Lut == NULL) return NULL;

        // After reading it, we have now info about the original type
        OriginalType =  _cmsGetTagTrueType(hProfile, tag16);

        // The profile owns the Lut, so we need to copy it
        Lut = cmsPipelineDup(Lut);

        // We need to adjust data only for Lab16 on output
        if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData) 
            return Lut;

        // If the input is Lab, add also a conversion at the begin
        if (cmsGetColorSpace(hProfile) == cmsSigLabData)
            cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID));

        // Add a matrix for conversion V2 to V4 Lab PCS
        cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID));
        return Lut;
    }   

    // Lut was not found, try to create a matrix-shaper

    // Check if this is a grayscale profile.
    if (cmsGetColorSpace(hProfile) == cmsSigGrayData) {

        // if so, build appropiate conversion tables. 
        // The tables are the PCS iluminant, scaled across GrayTRC
        return BuildGrayInputMatrixPipeline(hProfile);              
    }

    // Not gray, create a normal matrix-shaper 
    return BuildRGBInputMatrixShaper(hProfile);
}
Ejemplo n.º 4
0
QString dkCmsTakeProductInfo(cmsHPROFILE hProfile)
{
    static char Info[4096];
    cmsMLU*     mlu = 0;
    Info[0]         = '\0';

    if (cmsIsTag(hProfile, cmsSigProfileDescriptionTag))
    {
        char Desc[1024];

        mlu = static_cast<cmsMLU*>( cmsReadTag(hProfile, cmsSigProfileDescriptionTag) );
        cmsMLUgetASCII(mlu, "en", "US", Desc, 1024);
        strcat(Info, Desc);
    }

    if (cmsIsTag(hProfile, cmsSigCopyrightTag))
    {
        char Copyright[1024];

        mlu = static_cast<cmsMLU*>( cmsReadTag(hProfile, cmsSigCopyrightTag) );
        cmsMLUgetASCII(mlu, "en", "US", Copyright, 1024);
        strcat(Info, " - ");
        strcat(Info, Copyright);
    }

#define K007 static_cast<cmsTagSignature>( 0x4B303037 )

    if (cmsIsTag(hProfile, K007))
    {
        char MonCal[1024];

        mlu = static_cast<cmsMLU*>( cmsReadTag(hProfile, K007) );
        cmsMLUgetASCII(mlu, "en", "US", MonCal, 1024);
        strcat(Info, " - ");
        strcat(Info, MonCal);
    }
    else
    {
        /*
         *  _cmsIdentifyWhitePoint is complex and partly redundant
         *  with cietonguewidget, leave this part off
         *  untill the full lcms2 implementation
         *
        cmsCIEXYZ WhitePt;
        char WhiteStr[1024];

        dkCmsTakeMediaWhitePoint(&WhitePt, hProfile);
        _cmsIdentifyWhitePoint(WhiteStr, &WhitePt);
        strcat(Info, " - ");
        strcat(Info, WhiteStr);
        */
    }

#undef K007

    return QString::fromLatin1(Info);
}
Ejemplo n.º 5
0
// This one includes abstract profiles as well. Matrix-shaper cannot be obtained on that device class. The
// tag name here may default to AToB0
cmsPipeline* _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, int Intent)
{
    cmsPipeline* Lut;
    cmsTagTypeSignature OriginalType;
    cmsTagSignature tag16    = Device2PCS16[Intent];
    cmsTagSignature tagFloat = Device2PCSFloat[Intent];
    cmsContext ContextID = cmsGetProfileContextID(hProfile);

    if (cmsIsTag(hProfile, tagFloat)) {  // Float tag takes precedence

        // Floating point LUT are always V4, no adjustment is required
        return cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat));
    }

    tagFloat = Device2PCSFloat[0];
    if (cmsIsTag(hProfile, tagFloat)) {

        return cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat));
    }

    if (!cmsIsTag(hProfile, tag16)) {  // Is there any LUT-Based table?

        tag16    = Device2PCS16[0];
        if (!cmsIsTag(hProfile, tag16)) return NULL;
    }

    // Check profile version and LUT type. Do the necessary adjustments if needed

    // Read the tag
    Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16);
    if (Lut == NULL) return NULL;

    // The profile owns the Lut, so we need to copy it
    Lut = cmsPipelineDup(Lut);

    // After reading it, we have info about the original type
    OriginalType =  _cmsGetTagTrueType(hProfile, tag16);

    // We need to adjust data for Lab16 on output
    if (OriginalType != cmsSigLut16Type) return Lut;

    // Here it is possible to get Lab on both sides

    if (cmsGetPCS(hProfile) == cmsSigLabData) {
            cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID));
    }

    if (cmsGetColorSpace(hProfile) == cmsSigLabData) {
            cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID));
    }

    return Lut;


}
Ejemplo n.º 6
0
QVector <double> LcmsColorProfileContainer::getEstimatedTRC() const
{
    QVector <double> TRCtriplet(3);
    if (d->hasColorants) {
        if (cmsIsToneCurveLinear(d->redTRC)) {
            TRCtriplet[0] = 1.0;
        } else {
            TRCtriplet[0] = cmsEstimateGamma(d->redTRC, 0.01);
        }
        if (cmsIsToneCurveLinear(d->greenTRC)) {
            TRCtriplet[1] = 1.0;
        } else {
            TRCtriplet[1] = cmsEstimateGamma(d->greenTRC, 0.01);
        }
        if (cmsIsToneCurveLinear(d->blueTRC)) {
            TRCtriplet[2] = 1.0;
        } else {
            TRCtriplet[2] = cmsEstimateGamma(d->blueTRC, 0.01);
        }

    } else {
        if (cmsIsTag(d->profile, cmsSigGrayTRCTag)) {
            if (cmsIsToneCurveLinear(d->grayTRC)) {
                TRCtriplet.fill(1.0);
            } else {
                TRCtriplet.fill(cmsEstimateGamma(d->grayTRC,  0.01));
            }
        } else {
            TRCtriplet.fill(1.0);
        }
    }
    return TRCtriplet;
}
Ejemplo n.º 7
0
// Displays the colorant table
static
void PrintColorantTable(cmsHPROFILE hInput, cmsTagSignature Sig, const char* Title)
{
    cmsNAMEDCOLORLIST* list;
    int i, n;

    if (cmsIsTag(hInput, Sig)) {
        
        printf("%s:\n", Title);
        
        list = cmsReadTag(hInput, Sig);
        if (list == NULL) {
            printf("(Unavailable)\n");
            return;
        }

        n = cmsNamedColorCount(list);
        for (i=0; i < n; i++) {

            char Name[cmsMAX_PATH];

            cmsNamedColorInfo(list, i, Name, NULL, NULL, NULL, NULL);
            printf("\t%s\n", Name);
        }
            
        printf("\n");
    }
    
}
Ejemplo n.º 8
0
void LcmsColorProfileContainer::DelinearizeFloatValueFast(QVector <double> & Value) const
{
    const qreal scale = 65535.0;
    const qreal invScale = 1.0 / scale;

    if (d->hasColorants) {
        //we can only reliably delinearise in the 0-1.0 range, outside of that leave the value alone.
        QVector <quint16> TRCtriplet(3);
        TRCtriplet[0] = Value[0] * scale;
        TRCtriplet[1] = Value[1] * scale;
        TRCtriplet[2] = Value[2] * scale;

        if (!cmsIsToneCurveLinear(d->redTRC) && Value[0]<1.0) {
            TRCtriplet[0] = cmsEvalToneCurve16(d->redTRCReverse, TRCtriplet[0]);
            Value[0] = TRCtriplet[0] * invScale;
        }
        if (!cmsIsToneCurveLinear(d->greenTRC) && Value[1]<1.0) {
            TRCtriplet[1] = cmsEvalToneCurve16(d->greenTRCReverse, TRCtriplet[1]);
            Value[1] = TRCtriplet[1] * invScale;
        }
        if (!cmsIsToneCurveLinear(d->blueTRC) && Value[2]<1.0) {
            TRCtriplet[2] = cmsEvalToneCurve16(d->blueTRCReverse, TRCtriplet[2]);
            Value[2] = TRCtriplet[2] * invScale;
        }
    } else {
        if (cmsIsTag(d->profile, cmsSigGrayTRCTag) && Value[0]<1.0) {
            quint16 newValue = cmsEvalToneCurve16(d->grayTRCReverse, Value[0] * scale);
            Value[0] = newValue * invScale;
        }
    }
}
Ejemplo n.º 9
0
// Returns TRUE if the intent is implemented as CLUT
cmsBool  CMSEXPORT cmsIsCLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number UsedDirection)
{
    const cmsTagSignature* TagTable;

    // For devicelinks, the supported intent is that one stated in the header
    if (cmsGetDeviceClass(hProfile) == cmsSigLinkClass) {
            return (cmsGetHeaderRenderingIntent(hProfile) == Intent);
    }

    switch (UsedDirection) {

       case LCMS_USED_AS_INPUT: TagTable = Device2PCS16; break;
       case LCMS_USED_AS_OUTPUT:TagTable = PCS2Device16; break;

       // For proofing, we need rel. colorimetric in output. Let's do some recursion
       case LCMS_USED_AS_PROOF:
           return cmsIsIntentSupported(hProfile, Intent, LCMS_USED_AS_INPUT) &&
                  cmsIsIntentSupported(hProfile, INTENT_RELATIVE_COLORIMETRIC, LCMS_USED_AS_OUTPUT);

       default:
           cmsSignalError(cmsGetProfileContextID(hProfile), cmsERROR_RANGE, "Unexpected direction (%d)", UsedDirection);
           return FALSE;
    }

    return cmsIsTag(hProfile, TagTable[Intent]);

}
Ejemplo n.º 10
0
void LcmsColorProfileContainer::LinearizeFloatValueFast(QVector <double> & Value) const
{
    //we can only reliably delinearise in the 0-1.0 range, outside of that leave the value alone.
    QVector <quint16> TRCtriplet(3);
    TRCtriplet[0] = Value[0]*65535;
    TRCtriplet[1] = Value[1]*65535;
    TRCtriplet[2] = Value[2]*65535;
    

    if (d->hasColorants) {
        if (!cmsIsToneCurveLinear(d->redTRC) && Value[0]<1.0) {
            TRCtriplet[0] = cmsEvalToneCurve16(d->redTRC, TRCtriplet[0]);
            Value[0] = TRCtriplet[0]/65535.0;
        }
        if (!cmsIsToneCurveLinear(d->greenTRC) && Value[1]<1.0) {
            TRCtriplet[1] = cmsEvalToneCurve16(d->greenTRC, TRCtriplet[1]);
            Value[1] = TRCtriplet[1]/65535.0;
        }
        if (!cmsIsToneCurveLinear(d->blueTRC) && Value[2]<1.0) {
            TRCtriplet[2] = cmsEvalToneCurve16(d->blueTRC, TRCtriplet[2]);
            Value[2] = TRCtriplet[2]/65535.0;
        }
            
    } else {
        if (cmsIsTag(d->profile, cmsSigGrayTRCTag) && Value[0]<1.0) {
            TRCtriplet[0] = (cmsEvalToneCurve16(d->grayTRC, Value[0]*65535));
            Value.fill(TRCtriplet[0]/65535.0);
        }
    }
}
Ejemplo n.º 11
0
int cmsDetectBlackPoint(LPcmsCIEXYZ BlackPoint, cmsHPROFILE hProfile, int Intent, DWORD dwFlags)
{    

    // v4 + perceptual & saturation intents does have its own black point

    if ((cmsGetProfileICCversion(hProfile) >= 0x4000000) &&
        (Intent == INTENT_PERCEPTUAL || Intent == INTENT_SATURATION)) {

       return GetV4PerceptualBlack(BlackPoint, hProfile, dwFlags);
    }


#ifdef HONOR_BLACK_POINT_TAG

    // v2, v4 rel/abs colorimetric
    if (cmsIsTag(hProfile, icSigMediaBlackPointTag) && 
                    Intent == INTENT_RELATIVE_COLORIMETRIC) {

        cmsCIEXYZ BlackXYZ, UntrustedBlackPoint, TrustedBlackPoint, MediaWhite;
        cmsCIELab Lab;

             // If black point is specified, then use it, 
        
             cmsTakeMediaBlackPoint(&BlackXYZ, hProfile);
             cmsTakeMediaWhitePoint(&MediaWhite, hProfile);

             // Black point is absolute XYZ, so adapt to D50 to get PCS value

             cmsAdaptToIlluminant(&UntrustedBlackPoint, &MediaWhite, cmsD50_XYZ(), &BlackXYZ);

             // Force a=b=0 to get rid of any chroma

             cmsXYZ2Lab(NULL, &Lab, &UntrustedBlackPoint);
             Lab.a = Lab.b = 0;
             if (Lab.L > 50) Lab.L = 50; // Clip to L* <= 50

             cmsLab2XYZ(NULL, &TrustedBlackPoint, &Lab);

             // Return BP as D50 relative or absolute XYZ (depends on flags)

             if (!(dwFlags & LCMS_BPFLAGS_D50_ADAPTED))
                    cmsAdaptToIlluminant(BlackPoint, cmsD50_XYZ(), &MediaWhite, &TrustedBlackPoint);
             else
                    *BlackPoint = TrustedBlackPoint;
    }

#endif
    
    // If output profile, discount ink-limiting

    if (Intent == INTENT_RELATIVE_COLORIMETRIC && 
            (cmsGetDeviceClass(hProfile) == icSigOutputClass) &&
            (cmsGetColorSpace(hProfile) == icSigCmykData))
                return BlackPointUsingPerceptualBlack(BlackPoint, hProfile, dwFlags);

    // Nope, compute BP using current intent.

    return BlackPointAsDarkerColorant(hProfile, Intent, BlackPoint, dwFlags);

}
Ejemplo n.º 12
0
QString dkCmsTakeProductName(cmsHPROFILE hProfile)
{
    static char Name[1024*2+4];
    char Manufacturer[1024], Model[1024];

    Name[0]         = '\0';
    Manufacturer[0] = Model[0] = '\0';
    cmsMLU* mlu     = 0;

    if (cmsIsTag(hProfile, cmsSigDeviceMfgDescTag))
    {
        mlu = static_cast<cmsMLU*>( cmsReadTag(hProfile, cmsSigDeviceMfgDescTag) );
        cmsMLUgetASCII(mlu, "en", "US", Manufacturer, 1024);
    }

    if (cmsIsTag(hProfile, cmsSigDeviceModelDescTag))
    {
        mlu = static_cast<cmsMLU*>( cmsReadTag(hProfile, cmsSigDeviceModelDescTag) );
        cmsMLUgetASCII(mlu, "en", "US", Model, 1024);
    }

    if (!Manufacturer[0] && !Model[0])
    {

        if (cmsIsTag(hProfile, cmsSigProfileDescriptionTag))
        {
            mlu = static_cast<cmsMLU*>( cmsReadTag(hProfile, cmsSigProfileDescriptionTag) );
            cmsMLUgetASCII(mlu, "en", "US", Name, 1024);
            return QString::fromLatin1(Name);
        }
        else
        {
            return QString::fromLatin1("{no name}");
        }
    }

    if (!Manufacturer[0] || strncmp(Model, Manufacturer, 8) == 0 || strlen(Model) > 30)
    {
        strcpy(Name, Model);
    }
    else
    {
        sprintf(Name, "%s - %s", Model, Manufacturer);
    }

    return QString::fromLatin1(Name);
}
Ejemplo n.º 13
0
void LcmsColorProfileContainer::DelinearizeFloatValue(QVector <double> & Value) const
{
    if (d->hasColorants) {
        if (!cmsIsToneCurveLinear(d->redTRC)) {
            Value[0] = cmsEvalToneCurveFloat(d->redTRCReverse, Value[0]);
        }
        if (!cmsIsToneCurveLinear(d->greenTRC)) {
            Value[1] = cmsEvalToneCurveFloat(d->greenTRCReverse, Value[1]);
        }
        if (!cmsIsToneCurveLinear(d->blueTRC)) {
            Value[2] = cmsEvalToneCurveFloat(d->blueTRCReverse, Value[2]);
        }

    } else {
        if (cmsIsTag(d->profile, cmsSigGrayTRCTag)) {
            Value[0] = cmsEvalToneCurveFloat(d->grayTRCReverse, Value[0]);
        }
    }
}
Ejemplo n.º 14
0
QString dkCmsTakeProductDesc(cmsHPROFILE hProfile)
{
    static char Name[2048];

    if (cmsIsTag(hProfile, cmsSigProfileDescriptionTag))
    {
        cmsMLU* const mlu = static_cast<cmsMLU*>( cmsReadTag(hProfile, cmsSigProfileDescriptionTag) );
        cmsMLUgetASCII(mlu, "en", "US", Name, 1024);
    }
    else
    {
        return dkCmsTakeProductName(hProfile);
    }

    if (strncmp(Name, "Copyrig", 7) == 0)
    {
        return dkCmsTakeProductName(hProfile);
    }

    return QString::fromLatin1(Name);
}
Ejemplo n.º 15
0
/*
 * Class:     sun_java2d_cmm_lcms_LCMS
 * Method:    getTagSize
 * Signature: (JI)I
 */
JNIEXPORT jint JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagSize
  (JNIEnv *env, jobject obj, jlong id, jint tagSig)
{
    storeID_t sProf;
    TagSignature_t sig;
    jint result = -1;

    sProf.j = id;
    sig.j = tagSig;

    if (tagSig == SigHead) {
        result = sizeof(cmsICCHeader);
    } else {
      if (cmsIsTag(sProf.pf, sig.cms)) {
            result = cmsReadRawTag(sProf.pf, sig.cms, NULL, 0);
        } else {
            JNU_ThrowByName(env, "java/awt/color/CMMException",
                            "ICC profile tag not found");
        }
    }

    return result;
}
Ejemplo n.º 16
0
// Returns TRUE if the profile is implemented as matrix-shaper
cmsBool  CMSEXPORT cmsIsMatrixShaper(cmsHPROFILE hProfile)
{
    switch (cmsGetColorSpace(hProfile)) {

    case cmsSigGrayData:

        return cmsIsTag(hProfile, cmsSigGrayTRCTag);

    case cmsSigRgbData:

        return (cmsIsTag(hProfile, cmsSigRedColorantTag) &&
                cmsIsTag(hProfile, cmsSigGreenColorantTag) &&
                cmsIsTag(hProfile, cmsSigBlueColorantTag) &&
                cmsIsTag(hProfile, cmsSigRedTRCTag) &&
                cmsIsTag(hProfile, cmsSigGreenTRCTag) &&
                cmsIsTag(hProfile, cmsSigBlueTRCTag));

    default:

        return FALSE;
    }
}
Ejemplo n.º 17
0
// This one includes abstract profiles as well. Matrix-shaper cannot be obtained on that device class. The
// tag name here may default to AToB0
cmsPipeline* _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, int Intent)
{
    cmsPipeline* Lut;
    cmsTagTypeSignature OriginalType;
    cmsTagSignature tag16;
    cmsTagSignature tagFloat;
    cmsContext ContextID = cmsGetProfileContextID(hProfile);


    if (Intent < INTENT_PERCEPTUAL || Intent > INTENT_ABSOLUTE_COLORIMETRIC)
        return NULL;

    tag16 = Device2PCS16[Intent];
    tagFloat = Device2PCSFloat[Intent];

    // On named color, take the appropriate tag
    if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) {

        cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*)cmsReadTag(hProfile, cmsSigNamedColor2Tag);

        if (nc == NULL) return NULL;

        Lut = cmsPipelineAlloc(ContextID, 0, 0);
        if (Lut == NULL)
            goto Error;

        if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocNamedColor(nc, FALSE)))
            goto Error;

        if (cmsGetColorSpace(hProfile) == cmsSigLabData)
            if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)))
                goto Error;

        return Lut;
    Error:
        cmsPipelineFree(Lut);
        cmsFreeNamedColorList(nc);
        return NULL;
    }


    if (cmsIsTag(hProfile, tagFloat)) {  // Float tag takes precedence

        // Floating point LUT are always V
        return _cmsReadFloatDevicelinkTag(hProfile, tagFloat);
    }

    tagFloat = Device2PCSFloat[0];
    if (cmsIsTag(hProfile, tagFloat)) {

        return cmsPipelineDup((cmsPipeline*)cmsReadTag(hProfile, tagFloat));
    }

    if (!cmsIsTag(hProfile, tag16)) {  // Is there any LUT-Based table?

        tag16 = Device2PCS16[0];
        if (!cmsIsTag(hProfile, tag16)) return NULL;
    }

    // Check profile version and LUT type. Do the necessary adjustments if needed

    // Read the tag
    Lut = (cmsPipeline*)cmsReadTag(hProfile, tag16);
    if (Lut == NULL) return NULL;

    // The profile owns the Lut, so we need to copy it
    Lut = cmsPipelineDup(Lut);
    if (Lut == NULL) return NULL;

    // Now it is time for a controversial stuff. I found that for 3D LUTS using
    // Lab used as indexer space,  trilinear interpolation should be used
    if (cmsGetPCS(hProfile) == cmsSigLabData)
        ChangeInterpolationToTrilinear(Lut);

    // After reading it, we have info about the original type
    OriginalType = _cmsGetTagTrueType(hProfile, tag16);

    // We need to adjust data for Lab16 on output
    if (OriginalType != cmsSigLut16Type) return Lut;

    // Here it is possible to get Lab on both sides

    if (cmsGetColorSpace(hProfile) == cmsSigLabData) {
        if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID)))
            goto Error2;
    }

    if (cmsGetPCS(hProfile) == cmsSigLabData) {
        if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)))
            goto Error2;
    }

    return Lut;

Error2:
    cmsPipelineFree(Lut);
    return NULL;
}
Ejemplo n.º 18
0
// Read and create a BRAND NEW MPE LUT from a given profile. All stuff dependent of version, etc
// is adjusted here in order to create a LUT that takes care of all those details.
// We add intent = -1 as a way to read matrix shaper always, no matter of other LUT
cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent)
{
    cmsTagTypeSignature OriginalType;
    cmsTagSignature tag16;
    cmsTagSignature tagFloat;
    cmsContext ContextID = cmsGetProfileContextID(hProfile);

    // On named color, take the appropriate tag
    if (cmsGetDeviceClass(hProfile) == cmsSigNamedColorClass) {

        cmsPipeline* Lut;
        cmsNAMEDCOLORLIST* nc = (cmsNAMEDCOLORLIST*) cmsReadTag(hProfile, cmsSigNamedColor2Tag);

        if (nc == NULL) return NULL;

        Lut = cmsPipelineAlloc(ContextID, 0, 0);
        if (Lut == NULL) {
            cmsFreeNamedColorList(nc);
            return NULL;
        }

        if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocNamedColor(nc, TRUE)) ||
            !cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) {
            cmsPipelineFree(Lut);
            return NULL;
        }
        return Lut;
    }

    // This is an attempt to reuse this function to retrieve the matrix-shaper as pipeline no
    // matter other LUT are present and have precedence. Intent = -1 means just this.
    if (Intent >= INTENT_PERCEPTUAL && Intent <= INTENT_ABSOLUTE_COLORIMETRIC) {

        tag16 = Device2PCS16[Intent];
        tagFloat = Device2PCSFloat[Intent];

        if (cmsIsTag(hProfile, tagFloat)) {  // Float tag takes precedence

            // Floating point LUT are always V4, but the encoding range is no
            // longer 0..1.0, so we need to add an stage depending on the color space
            return _cmsReadFloatInputTag(hProfile, tagFloat);
        }

        // Revert to perceptual if no tag is found
        if (!cmsIsTag(hProfile, tag16)) {
            tag16 = Device2PCS16[0];
        }

        if (cmsIsTag(hProfile, tag16)) { // Is there any LUT-Based table?

            // Check profile version and LUT type. Do the necessary adjustments if needed

            // First read the tag
            cmsPipeline* Lut = (cmsPipeline*) cmsReadTag(hProfile, tag16);
            if (Lut == NULL) return NULL;

            // After reading it, we have now info about the original type
            OriginalType =  _cmsGetTagTrueType(hProfile, tag16);

            // The profile owns the Lut, so we need to copy it
            Lut = cmsPipelineDup(Lut);

            // We need to adjust data only for Lab16 on output
            if (OriginalType != cmsSigLut16Type || cmsGetPCS(hProfile) != cmsSigLabData)
                return Lut;

            // If the input is Lab, add also a conversion at the begin
            if (cmsGetColorSpace(hProfile) == cmsSigLabData &&
                !cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocLabV4ToV2(ContextID)))
                goto Error;

            // Add a matrix for conversion V2 to V4 Lab PCS
            if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID)))
                goto Error;

            return Lut;
Error:
            cmsPipelineFree(Lut);
            return NULL;
        }
    }

    // Lut was not found, try to create a matrix-shaper

    // Check if this is a grayscale profile.
    if (cmsGetColorSpace(hProfile) == cmsSigGrayData) {

        // if so, build appropriate conversion tables.
        // The tables are the PCS iluminant, scaled across GrayTRC
        return BuildGrayInputMatrixPipeline(hProfile);
    }

    // Not gray, create a normal matrix-shaper
    return BuildRGBInputMatrixShaper(hProfile);
}
Ejemplo n.º 19
0
LCMSBOOL dkCmsIsTag(cmsHPROFILE hProfile, icTagSignature sig)
{
    return static_cast<LCMSBOOL>( cmsIsTag(hProfile, static_cast<cmsTagSignature>( sig )) );
}
Ejemplo n.º 20
0
// Creates all needed color transforms
static
cmsBool OpenTransforms(void)
{
    cmsHPROFILE hInput, hOutput, hProof;
    cmsUInt32Number dwIn, dwOut, dwFlags;
    cmsNAMEDCOLORLIST* List;
    int i;

    // We don't need cache
    dwFlags = cmsFLAGS_NOCACHE;

    if (lIsDeviceLink) {

        hInput  = OpenStockProfile(0, cInProf);
        if (hInput == NULL) return FALSE; 
        hOutput = NULL;
        hProof  = NULL;

        if (cmsGetDeviceClass(hInput) == cmsSigNamedColorClass) {
            OutputColorSpace  = cmsGetColorSpace(hInput);
            InputColorSpace = cmsGetPCS(hInput);
        }
        else {
            InputColorSpace  = cmsGetColorSpace(hInput);
            OutputColorSpace = cmsGetPCS(hInput);
        }

        // Read colorant tables if present
        if (cmsIsTag(hInput, cmsSigColorantTableTag)) {
            List = cmsReadTag(hInput, cmsSigColorantTableTag);
            InputColorant = cmsDupNamedColorList(List);
            InputRange = 1;
        }
        else InputColorant = ComponentNames(InputColorSpace, TRUE);

        if (cmsIsTag(hInput, cmsSigColorantTableOutTag)){

            List = cmsReadTag(hInput, cmsSigColorantTableOutTag);
            OutputColorant = cmsDupNamedColorList(List);
            OutputRange = 1;
        }
        else OutputColorant = ComponentNames(OutputColorSpace, FALSE);

    }
    else {

        hInput  = OpenStockProfile(0, cInProf);
        if (hInput == NULL) return FALSE;

        hOutput = OpenStockProfile(0, cOutProf);    
        if (hOutput == NULL) return FALSE;
        hProof  = NULL;


        if (cmsGetDeviceClass(hInput) == cmsSigLinkClass ||
            cmsGetDeviceClass(hOutput) == cmsSigLinkClass)   
            FatalError("Use %cl flag for devicelink profiles!\n", SW);


        InputColorSpace   = cmsGetColorSpace(hInput);
        OutputColorSpace  = cmsGetColorSpace(hOutput);

        // Read colorant tables if present
        if (cmsIsTag(hInput, cmsSigColorantTableTag)) {
            List = cmsReadTag(hInput, cmsSigColorantTableTag);
            InputColorant = cmsDupNamedColorList(List);
            if (cmsNamedColorCount(InputColorant) <= 3) 
                SetRange(255, TRUE);
            else
                SetRange(1, TRUE);  // Inks are already divided by 100 in the formatter

        }
        else InputColorant = ComponentNames(InputColorSpace, TRUE);

        if (cmsIsTag(hOutput, cmsSigColorantTableTag)){

            List = cmsReadTag(hOutput, cmsSigColorantTableTag);
            OutputColorant = cmsDupNamedColorList(List);
            if (cmsNamedColorCount(OutputColorant) <= 3) 
                SetRange(255, FALSE);
            else
                SetRange(1, FALSE);  // Inks are already divided by 100 in the formatter
        }
        else OutputColorant = ComponentNames(OutputColorSpace, FALSE);


        if (cProofing != NULL) {

            hProof = OpenStockProfile(0, cProofing);
            if (hProof == NULL) return FALSE;
            dwFlags |= cmsFLAGS_SOFTPROOFING;
        }
    }

    // Print information on profiles
    if (Verbose > 2) {

        printf("Profile:\n");
        PrintProfileInformation(hInput);

        if (hOutput) {

            printf("Output profile:\n");
            PrintProfileInformation(hOutput);
        }  

        if (hProof != NULL) {
            printf("Proofing profile:\n");
            PrintProfileInformation(hProof);
        }
    }


    // Input is always in floating point
    dwIn  = cmsFormatterForColorspaceOfProfile(hInput, 0, TRUE);

    if (lIsDeviceLink) {

        dwOut = cmsFormatterForPCSOfProfile(hInput, lIsFloat ? 0 : 2, lIsFloat);
    }
    else {

        // 16 bits or floating point (only on output)   
        dwOut = cmsFormatterForColorspaceOfProfile(hOutput, lIsFloat ? 0 : 2, lIsFloat);
    }

    // For named color, there is a specialized formatter
    if (cmsGetDeviceClass(hInput) == cmsSigNamedColorClass) {
        
        dwIn = TYPE_NAMED_COLOR_INDEX;
        InputNamedColor = TRUE;
    }

    // Precision mode
    switch (PrecalcMode) {

       case 0: dwFlags |= cmsFLAGS_NOOPTIMIZE; break;
       case 2: dwFlags |= cmsFLAGS_HIGHRESPRECALC; break;
       case 3: dwFlags |= cmsFLAGS_LOWRESPRECALC; break;
       case 1: break;

       default: 
           FatalError("Unknown precalculation mode '%d'", PrecalcMode);
    }


    if (BlackPointCompensation) 
        dwFlags |= cmsFLAGS_BLACKPOINTCOMPENSATION;


    if (GamutCheck) {

        cmsUInt16Number Alarm[cmsMAXCHANNELS];

        if (hProof == NULL)
            FatalError("I need proofing profile -p for gamut checking!");

        for (i=0; i < cmsMAXCHANNELS; i++)
            Alarm[i] = 0xFFFF;

        cmsSetAlarmCodes(Alarm);
        dwFlags |= cmsFLAGS_GAMUTCHECK;            
    }


    // The main transform
    hTrans = cmsCreateProofingTransform(hInput,  dwIn, hOutput, dwOut, hProof, Intent, ProofingIntent, dwFlags);

    if (hProof) cmsCloseProfile(hProof);

    if (hTrans == NULL) return FALSE;


    // PCS Dump if requested
    hTransXYZ = NULL; hTransLab = NULL;

    if (hOutput && Verbose > 1) {

        cmsHPROFILE hXYZ = cmsCreateXYZProfile();
        cmsHPROFILE hLab = cmsCreateLab4Profile(NULL);

        hTransXYZ = cmsCreateTransform(hInput, dwIn, hXYZ,  lIsFloat ? TYPE_XYZ_DBL : TYPE_XYZ_16, Intent, cmsFLAGS_NOCACHE);        
        if (hTransXYZ == NULL) return FALSE;

        hTransLab = cmsCreateTransform(hInput, dwIn, hLab,  lIsFloat? TYPE_Lab_DBL : TYPE_Lab_16, Intent, cmsFLAGS_NOCACHE);    
        if (hTransLab == NULL) return FALSE;

        cmsCloseProfile(hXYZ);
        cmsCloseProfile(hLab);
    } 

    if (hInput) cmsCloseProfile(hInput);
    if (hOutput) cmsCloseProfile(hOutput); 

    return TRUE;
}
Ejemplo n.º 21
0
/*
 * Class:     sun_java2d_cmm_lcms_LCMS
 * Method:    getTagData
 * Signature: (JI[B)V
 */
JNIEXPORT void JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagData
  (JNIEnv *env, jobject obj, jlong id, jint tagSig, jbyteArray data)
{
    storeID_t sProf;
    TagSignature_t sig;
    cmsInt32Number tagSize;

    jbyte* dataArray;
    jint bufSize;

    sProf.j = id;
    sig.j = tagSig;

    if (tagSig == SigHead) {
        cmsBool status;

        bufSize =(*env)->GetArrayLength(env, data);

        if (bufSize < sizeof(cmsICCHeader)) {
           JNU_ThrowByName(env, "java/awt/color/CMMException",
                            "Insufficient buffer capacity");
           return;
        }

        dataArray = (*env)->GetByteArrayElements (env, data, 0);

        if (dataArray == NULL) {
           JNU_ThrowByName(env, "java/awt/color/CMMException",
                            "Unable to get buffer");
           return;
        }

        status = _getHeaderInfo(sProf.pf, dataArray, bufSize);

        (*env)->ReleaseByteArrayElements (env, data, dataArray, 0);

        if (!status) {
            JNU_ThrowByName(env, "java/awt/color/CMMException",
                            "ICC Profile header not found");
        }

        return;
    }

    if (cmsIsTag(sProf.pf, sig.cms)) {
        tagSize = cmsReadRawTag(sProf.pf, sig.cms, NULL, 0);
    } else {
        JNU_ThrowByName(env, "java/awt/color/CMMException",
                        "ICC profile tag not found");
        return;
    }

    // verify data buffer capacity
    bufSize = (*env)->GetArrayLength(env, data);

    if (tagSize < 0 || 0 > bufSize || tagSize > bufSize) {
        JNU_ThrowByName(env, "java/awt/color/CMMException",
                        "Insufficient buffer capacity.");
        return;
    }

    dataArray = (*env)->GetByteArrayElements (env, data, 0);

    if (dataArray == NULL) {
        JNU_ThrowByName(env, "java/awt/color/CMMException",
                        "Unable to get buffer");
        return;
    }

    bufSize = cmsReadRawTag(sProf.pf, sig.cms, dataArray, tagSize);

    (*env)->ReleaseByteArrayElements (env, data, dataArray, 0);

    if (bufSize != tagSize) {
        JNU_ThrowByName(env, "java/awt/color/CMMException",
                        "Can not get tag data.");
    }
    return;
}
Ejemplo n.º 22
0
bool LcmsColorProfileContainer::init()
{
    if (d->profile) {
        cmsCloseProfile(d->profile);
    }

    d->profile = cmsOpenProfileFromMem((void *)d->data->rawData().constData(), d->data->rawData().size());

#ifndef NDEBUG
    if (d->data->rawData().size() == 4096) {
        qWarning() << "Profile has a size of 4096, which is suspicious and indicates a possible misuse of QIODevice::read(int), check your code.";
    }
#endif

    if (d->profile) {
        wchar_t buffer[_BUFFER_SIZE_];
        d->colorSpaceSignature = cmsGetColorSpace(d->profile);
        d->deviceClass = cmsGetDeviceClass(d->profile);
        cmsGetProfileInfo(d->profile, cmsInfoDescription, cmsNoLanguage, cmsNoCountry, buffer, _BUFFER_SIZE_);
        d->name = QString::fromWCharArray(buffer);

        //apparantly this should give us a localised string??? Not sure about this.
        cmsGetProfileInfo(d->profile, cmsInfoModel, cmsNoLanguage, cmsNoCountry, buffer, _BUFFER_SIZE_);
        d->productDescription = QString::fromWCharArray(buffer);

        cmsGetProfileInfo(d->profile, cmsInfoManufacturer, cmsNoLanguage, cmsNoCountry, buffer, _BUFFER_SIZE_);
        d->manufacturer = QString::fromWCharArray(buffer);

        cmsGetProfileInfo(d->profile, cmsInfoCopyright, cmsNoLanguage, cmsNoCountry, buffer, _BUFFER_SIZE_);
        d->copyright = QString::fromWCharArray(buffer);

        cmsProfileClassSignature profile_class;
        profile_class = cmsGetDeviceClass(d->profile);
        d->valid = (profile_class != cmsSigNamedColorClass);

        //This is where obtain the whitepoint, and convert it to the actual white point of the profile in the case a Chromatic adaption tag is
        //present. This is necessary for profiles following the v4 spec.
        cmsCIEXYZ baseMediaWhitePoint;//dummy to hold copy of mediawhitepoint if this is modified by chromatic adaption.
        if (cmsIsTag(d->profile, cmsSigMediaWhitePointTag)) {
            d->mediaWhitePoint = *((cmsCIEXYZ *)cmsReadTag(d->profile, cmsSigMediaWhitePointTag));
            baseMediaWhitePoint = d->mediaWhitePoint;
            cmsXYZ2xyY(&d->whitePoint, &d->mediaWhitePoint);

            if (cmsIsTag(d->profile, cmsSigChromaticAdaptationTag)) {
                //the chromatic adaption tag represent a matrix from the actual white point of the profile to D50.
                cmsCIEXYZ *CAM1 = (cmsCIEXYZ *)cmsReadTag(d->profile, cmsSigChromaticAdaptationTag);
                //We first put all our data into structures we can manipulate.
                double d3dummy [3] = {d->mediaWhitePoint.X, d->mediaWhitePoint.Y, d->mediaWhitePoint.Z};
                QGenericMatrix<1, 3, double> whitePointMatrix(d3dummy);
                QTransform invertDummy(CAM1[0].X, CAM1[0].Y, CAM1[0].Z, CAM1[1].X, CAM1[1].Y, CAM1[1].Z, CAM1[2].X, CAM1[2].Y, CAM1[2].Z);
                //we then abuse QTransform's invert function because it probably does matrix invertion 20 times better than I can program.
                //if the matrix is uninvertable, invertedDummy will be an identity matrix, which for us means that it won't give any noticeble
                //effect when we start multiplying.
                QTransform invertedDummy = invertDummy.inverted();
                //we then put the QTransform into a generic 3x3 matrix.
                double d9dummy [9] = {invertedDummy.m11(), invertedDummy.m12(), invertedDummy.m13(),
                                      invertedDummy.m21(), invertedDummy.m22(), invertedDummy.m23(),
                                      invertedDummy.m31(), invertedDummy.m32(), invertedDummy.m33()
                                     };
                QGenericMatrix<3, 3, double> chromaticAdaptionMatrix(d9dummy);
                //multiplying our inverted adaption matrix with the whitepoint gives us the right whitepoint.
                QGenericMatrix<1, 3, double> result = chromaticAdaptionMatrix * whitePointMatrix;
                //and then we pour the matrix into the whitepoint variable. Generic matrix does row/column for indices even though it
                //uses column/row for initialising.
                d->mediaWhitePoint.X = result(0, 0);
                d->mediaWhitePoint.Y = result(1, 0);
                d->mediaWhitePoint.Z = result(2, 0);
                cmsXYZ2xyY(&d->whitePoint, &d->mediaWhitePoint);
            }
        }
        //This is for RGB profiles, but it only works for matrix profiles. Need to design it to work with non-matrix profiles.
        if (cmsIsTag(d->profile, cmsSigRedColorantTag)) {
            cmsCIEXYZTRIPLE tempColorants;
            tempColorants.Red = *((cmsCIEXYZ *)cmsReadTag(d->profile, cmsSigRedColorantTag));
            tempColorants.Green = *((cmsCIEXYZ *)cmsReadTag(d->profile, cmsSigGreenColorantTag));
            tempColorants.Blue = *((cmsCIEXYZ *)cmsReadTag(d->profile, cmsSigBlueColorantTag));
            //convert to d65, this is useless.
            cmsAdaptToIlluminant(&d->colorants.Red, &baseMediaWhitePoint, &d->mediaWhitePoint, &tempColorants.Red);
            cmsAdaptToIlluminant(&d->colorants.Green, &baseMediaWhitePoint, &d->mediaWhitePoint, &tempColorants.Green);
            cmsAdaptToIlluminant(&d->colorants.Blue, &baseMediaWhitePoint, &d->mediaWhitePoint, &tempColorants.Blue);
            //d->colorants = tempColorants;
            d->hasColorants = true;
        } else {
            //qDebug()<<d->name<<": has no colorants";
            d->hasColorants = false;
        }
        //retrieve TRC.
        if (cmsIsTag(d->profile, cmsSigRedTRCTag) && cmsIsTag(d->profile, cmsSigBlueTRCTag) && cmsIsTag(d->profile, cmsSigGreenTRCTag)) {

            d->redTRC = ((cmsToneCurve *)cmsReadTag (d->profile, cmsSigRedTRCTag));
            d->greenTRC = ((cmsToneCurve *)cmsReadTag (d->profile, cmsSigGreenTRCTag));
            d->blueTRC = ((cmsToneCurve *)cmsReadTag (d->profile, cmsSigBlueTRCTag));
            d->redTRCReverse = cmsReverseToneCurve(d->redTRC);
            d->greenTRCReverse = cmsReverseToneCurve(d->greenTRC);
            d->blueTRCReverse = cmsReverseToneCurve(d->blueTRC);
            d->hasTRC = true;

        } else if (cmsIsTag(d->profile, cmsSigGrayTRCTag)) {
            d->grayTRC = ((cmsToneCurve *)cmsReadTag (d->profile, cmsSigGrayTRCTag));
            d->grayTRCReverse = cmsReverseToneCurve(d->grayTRC);
            d->hasTRC = true;
        } else {
            d->hasTRC = false;
        }

        // Check if the profile can convert (something->this)
        d->suitableForOutput = cmsIsMatrixShaper(d->profile)
                               || (cmsIsCLUT(d->profile, INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT) &&
                                   cmsIsCLUT(d->profile, INTENT_PERCEPTUAL, LCMS_USED_AS_OUTPUT));

        d->version = cmsGetProfileVersion(d->profile);
        d->defaultIntent = cmsGetHeaderRenderingIntent(d->profile);
        d->isMatrixShaper = cmsIsMatrixShaper(d->profile);
        d->isPerceptualCLUT = cmsIsCLUT(d->profile, INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT);
        d->isSaturationCLUT = cmsIsCLUT(d->profile, INTENT_SATURATION, LCMS_USED_AS_INPUT);
        d->isAbsoluteCLUT = cmsIsCLUT(d->profile, INTENT_SATURATION, LCMS_USED_AS_INPUT);
        d->isRelativeCLUT = cmsIsCLUT(d->profile, INTENT_RELATIVE_COLORIMETRIC, LCMS_USED_AS_INPUT);

        return true;
    }

    return false;
}
Ejemplo n.º 23
0
cmsHPROFILE LCMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, DWORD dwFlags)
{
    cmsHPROFILE hICC;
    _LPcmsTRANSFORM v = (_LPcmsTRANSFORM) hTransform;
    LPLUT Lut;
    LCMSBOOL MustFreeLUT;
    LPcmsNAMEDCOLORLIST InputColorant = NULL;
    LPcmsNAMEDCOLORLIST OutputColorant = NULL;
    
    
    // Check if is a named color transform
    
    if (cmsGetDeviceClass(v ->InputProfile) == icSigNamedColorClass) {
        
        return CreateNamedColorDevicelink(hTransform);
        
    }
    
    if (v ->DeviceLink) {
        
        Lut = v -> DeviceLink;
        MustFreeLUT = FALSE;
    }
    else {
        
        Lut = _cmsPrecalculateDeviceLink(hTransform, dwFlags);
        if (!Lut) return NULL;
        MustFreeLUT = TRUE;
    }
    
    hICC = _cmsCreateProfilePlaceholder();
    if (!hICC) {                          // can't allocate
        
        if (MustFreeLUT) cmsFreeLUT(Lut);
        return NULL;
    }
    
    
    FixColorSpaces(hICC, v -> EntryColorSpace, v -> ExitColorSpace, dwFlags);             
    
    cmsSetRenderingIntent(hICC,  v -> Intent); 
    
    // Implement devicelink profile using following tags:
    //
    //  1 icSigProfileDescriptionTag
    //  2 icSigMediaWhitePointTag
    //  3 icSigAToB0Tag
    
    
    cmsAddTag(hICC, icSigDeviceMfgDescTag,       (LPVOID) "LittleCMS");       
    cmsAddTag(hICC, icSigProfileDescriptionTag,  (LPVOID) "Device link");
    cmsAddTag(hICC, icSigDeviceModelDescTag,     (LPVOID) "Device link");      
    
    
    cmsAddTag(hICC, icSigMediaWhitePointTag,  (LPVOID) cmsD50_XYZ());
    
    if (cmsGetDeviceClass(hICC) == icSigOutputClass) {
                
        cmsAddTag(hICC, icSigBToA0Tag, (LPVOID) Lut);
    }
    else
        cmsAddTag(hICC, icSigAToB0Tag, (LPVOID) Lut);
    
    
    
    // Try to read input and output colorant table
    if (cmsIsTag(v ->InputProfile, icSigColorantTableTag)) {
        
        // Input table can only come in this way.
        InputColorant = cmsReadColorantTable(v ->InputProfile, icSigColorantTableTag);
    }
    
    // Output is a little bit more complex.    
    if (cmsGetDeviceClass(v ->OutputProfile) == icSigLinkClass) {
        
        // This tag may exist only on devicelink profiles.        
        if (cmsIsTag(v ->OutputProfile, icSigColorantTableOutTag)) {
            
            OutputColorant = cmsReadColorantTable(v ->OutputProfile, icSigColorantTableOutTag);
        }
        
    } else {
        
        if (cmsIsTag(v ->OutputProfile, icSigColorantTableTag)) {
            
            OutputColorant = cmsReadColorantTable(v ->OutputProfile, icSigColorantTableTag);
        }     
    }
    
    if (InputColorant) 
           cmsAddTag(hICC, icSigColorantTableTag, InputColorant);       
       
    if (OutputColorant) 
           cmsAddTag(hICC, icSigColorantTableOutTag, OutputColorant);       
       
       
       
    if (MustFreeLUT) cmsFreeLUT(Lut);
    if (InputColorant) cmsFreeNamedColorList(InputColorant);
    if (OutputColorant) cmsFreeNamedColorList(OutputColorant);
       
    return hICC;
       
}
Ejemplo n.º 24
0
// New to lcms 2.0 -- have all parameters available.
cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID,
                                                   cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[],
                                                   cmsBool  BPC[],
                                                   cmsUInt32Number Intents[],
                                                   cmsFloat64Number AdaptationStates[],
                                                   cmsHPROFILE hGamutProfile,
                                                   cmsUInt32Number nGamutPCSposition,
                                                   cmsUInt32Number InputFormat,
                                                   cmsUInt32Number OutputFormat,
                                                   cmsUInt32Number dwFlags)
{
    _cmsTRANSFORM* xform;    
    cmsColorSpaceSignature EntryColorSpace;
    cmsColorSpaceSignature ExitColorSpace;
    cmsPipeline* Lut;
    cmsUInt32Number LastIntent = Intents[nProfiles-1];

    // If it is a fake transform
    if (dwFlags & cmsFLAGS_NULLTRANSFORM)
    {
        return AllocEmptyTransform(ContextID, NULL, INTENT_PERCEPTUAL, &InputFormat, &OutputFormat, &dwFlags);
    }

    // If gamut check is requested, make sure we have a gamut profile
    if (dwFlags & cmsFLAGS_GAMUTCHECK) {
        if (hGamutProfile == NULL) dwFlags &= ~cmsFLAGS_GAMUTCHECK;
    }

    // On floating point transforms, inhibit cache
    if (_cmsFormatterIsFloat(InputFormat) || _cmsFormatterIsFloat(OutputFormat))
        dwFlags |= cmsFLAGS_NOCACHE;

    // Mark entry/exit spaces
    if (!GetXFormColorSpaces(nProfiles, hProfiles, &EntryColorSpace, &ExitColorSpace)) {
        cmsSignalError(ContextID, cmsERROR_NULL, "NULL input profiles on transform");
        return NULL;
    }

    // Check if proper colorspaces
    if (!IsProperColorSpace(EntryColorSpace, InputFormat)) {
        cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong input color space on transform");
        return NULL;
    }

    if (!IsProperColorSpace(ExitColorSpace, OutputFormat)) {
        cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "Wrong output color space on transform");
        return NULL;
    }

    // Create a pipeline with all transformations
    Lut = _cmsLinkProfiles(ContextID, nProfiles, Intents, hProfiles, BPC, AdaptationStates, dwFlags);
    if (Lut == NULL) {
        cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Couldn't link the profiles");
        return NULL;
    }

    // Check channel count
    if ((cmsChannelsOf(EntryColorSpace) != cmsPipelineInputChannels(Lut)) ||
        (cmsChannelsOf(ExitColorSpace)  != cmsPipelineOutputChannels(Lut))) {
        cmsPipelineFree(Lut);
        cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Channel count doesn't match. Profile is corrupted");
        return NULL;
    }


    // All seems ok
    xform = AllocEmptyTransform(ContextID, Lut, LastIntent, &InputFormat, &OutputFormat, &dwFlags);
    if (xform == NULL) {
        return NULL;
    }

    // Keep values
    xform ->EntryColorSpace = EntryColorSpace;
    xform ->ExitColorSpace  = ExitColorSpace;
    xform ->RenderingIntent = Intents[nProfiles-1];

    // Take white points
    SetWhitePoint(&xform->EntryWhitePoint, (cmsCIEXYZ*) cmsReadTag(hProfiles[0], cmsSigMediaWhitePointTag));
    SetWhitePoint(&xform->ExitWhitePoint,  (cmsCIEXYZ*) cmsReadTag(hProfiles[nProfiles-1], cmsSigMediaWhitePointTag));
   

    // Create a gamut check LUT if requested
    if (hGamutProfile != NULL && (dwFlags & cmsFLAGS_GAMUTCHECK))
        xform ->GamutCheck  = _cmsCreateGamutCheckPipeline(ContextID, hProfiles,
                                                        BPC, Intents,
                                                        AdaptationStates,
                                                        nGamutPCSposition,
                                                        hGamutProfile);


    // Try to read input and output colorant table
    if (cmsIsTag(hProfiles[0], cmsSigColorantTableTag)) {

        // Input table can only come in this way.
        xform ->InputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[0], cmsSigColorantTableTag));
    }

    // Output is a little bit more complex.
    if (cmsGetDeviceClass(hProfiles[nProfiles-1]) == cmsSigLinkClass) {

        // This tag may exist only on devicelink profiles.
        if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag)) {

            // It may be NULL if error
            xform ->OutputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[nProfiles-1], cmsSigColorantTableOutTag));
        }

    } else {

        if (cmsIsTag(hProfiles[nProfiles-1], cmsSigColorantTableTag)) {

            xform -> OutputColorant = cmsDupNamedColorList((cmsNAMEDCOLORLIST*) cmsReadTag(hProfiles[nProfiles-1], cmsSigColorantTableTag));
        }
    }

    // Store the sequence of profiles
    if (dwFlags & cmsFLAGS_KEEP_SEQUENCE) {
        xform ->Sequence = _cmsCompileProfileSequence(ContextID, nProfiles, hProfiles);
    }
    else
        xform ->Sequence = NULL;

    // If this is a cached transform, init first value, which is zero (16 bits only)
    if (!(dwFlags & cmsFLAGS_NOCACHE)) {

        memset(&xform ->Cache.CacheIn, 0, sizeof(xform ->Cache.CacheIn));

        if (xform ->GamutCheck != NULL) {
            TransformOnePixelWithGamutCheck(xform, xform ->Cache.CacheIn, xform->Cache.CacheOut);
        }
        else {

            xform ->Lut ->Eval16Fn(xform ->Cache.CacheIn, xform->Cache.CacheOut, xform -> Lut->Data);
        }

    }

    return (cmsHTRANSFORM) xform;
}
Ejemplo n.º 25
0
cmsBool CMSEXPORT cmsDetectBlackPoint(cmsCIEXYZ* BlackPoint, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags)
{    

    // Zero for black point
    if (cmsGetDeviceClass(hProfile) == cmsSigLinkClass) {

        BlackPoint -> X = BlackPoint ->Y = BlackPoint -> Z = 0.0;
        return FALSE;       
    }

    // v4 + perceptual & saturation intents does have its own black point, and it is 
    // well specified enough to use it. Black point tag is deprecated in V4.

    if ((cmsGetEncodedICCversion(hProfile) >= 0x4000000) &&     
        (Intent == INTENT_PERCEPTUAL || Intent == INTENT_SATURATION)) {

            // Matrix shaper share MRC & perceptual intents
            if (cmsIsMatrixShaper(hProfile)) 
                return BlackPointAsDarkerColorant(hProfile, INTENT_RELATIVE_COLORIMETRIC, BlackPoint, 0);

            // Get Perceptual black out of v4 profiles. That is fixed for perceptual & saturation intents
            BlackPoint -> X = cmsPERCEPTUAL_BLACK_X; 
            BlackPoint -> Y = cmsPERCEPTUAL_BLACK_Y;
            BlackPoint -> Z = cmsPERCEPTUAL_BLACK_Z;

            return TRUE;
    }


#ifdef CMS_USE_PROFILE_BLACK_POINT_TAG

    // v2, v4 rel/abs colorimetric
    if (cmsIsTag(hProfile, cmsSigMediaBlackPointTag) && 
        Intent == INTENT_RELATIVE_COLORIMETRIC) {

            cmsCIEXYZ *BlackPtr, BlackXYZ, UntrustedBlackPoint, TrustedBlackPoint, MediaWhite;
            cmsCIELab Lab;

            // If black point is specified, then use it, 

            BlackPtr = cmsReadTag(hProfile, cmsSigMediaBlackPointTag);
            if (BlackPtr != NULL) {

                BlackXYZ = *BlackPtr;
                _cmsReadMediaWhitePoint(&MediaWhite, hProfile);

                // Black point is absolute XYZ, so adapt to D50 to get PCS value
                cmsAdaptToIlluminant(&UntrustedBlackPoint, &MediaWhite, cmsD50_XYZ(), &BlackXYZ);

                // Force a=b=0 to get rid of any chroma
                cmsXYZ2Lab(NULL, &Lab, &UntrustedBlackPoint);
                Lab.a = Lab.b = 0;
                if (Lab.L > 50) Lab.L = 50; // Clip to L* <= 50
                cmsLab2XYZ(NULL, &TrustedBlackPoint, &Lab);

                if (BlackPoint != NULL)
                    *BlackPoint = TrustedBlackPoint;
                
                return TRUE;
            }
    }
#endif

    // That is about v2 profiles. 

    // If output profile, discount ink-limiting and that's all
    if (Intent == INTENT_RELATIVE_COLORIMETRIC && 
        (cmsGetDeviceClass(hProfile) == cmsSigOutputClass) &&
        (cmsGetColorSpace(hProfile)  == cmsSigCmykData))
        return BlackPointUsingPerceptualBlack(BlackPoint, hProfile);

    // Nope, compute BP using current intent.
    return BlackPointAsDarkerColorant(hProfile, Intent, BlackPoint, dwFlags);
}