icStatusCMM CIccEvalCompare::EvaluateProfile(CIccProfile *pProfile, icUInt8Number nGran/* =0 */, icRenderingIntent nIntent/* =icUnknownIntent */, icXformInterp nInterp/* =icInterpLinear */, bool buseMpeTags/* =true */) { if (!pProfile) { return icCmmStatCantOpenProfile; } if (pProfile->m_Header.deviceClass!=icSigInputClass && pProfile->m_Header.deviceClass!=icSigDisplayClass && pProfile->m_Header.deviceClass!=icSigOutputClass && pProfile->m_Header.deviceClass!=icSigColorSpaceClass) { return icCmmStatInvalidProfile; } CIccCmm dev2Lab(icSigUnknownData, icSigLabData); CIccCmm Lab2Dev2Lab(icSigLabData, icSigLabData, false); icStatusCMM result; result = dev2Lab.AddXform(*pProfile, nIntent, nInterp, icXformLutColor, buseMpeTags); if (result!=icCmmStatOk) { return result; } result = dev2Lab.Begin(); if (result != icCmmStatOk) { return result; } result = Lab2Dev2Lab.AddXform(*pProfile, nIntent, nInterp, icXformLutColor, buseMpeTags); if (result != icCmmStatOk) { return result; } result = Lab2Dev2Lab.AddXform(*pProfile, nIntent, nInterp, icXformLutColor, buseMpeTags); if (result != icCmmStatOk) { return result; } result = Lab2Dev2Lab.Begin(); if (result != icCmmStatOk) { return result; } icFloatNumber sPixel[15]; icFloatNumber devPcs[15], roundPcs1[15], roundPcs2[15]; int ndim = icGetSpaceSamples(pProfile->m_Header.colorSpace); int ndim1 = ndim+1; // determine granularity if (!nGran) { CIccTagLutAtoB* pTag = (CIccTagLutAtoB*)pProfile->FindTag(icSigAToB0Tag+(nIntent==icAbsoluteColorimetric ? icRelativeColorimetric : nIntent)); if (!pTag || ndim==3) { nGran = 33; } else { CIccCLUT* pClut = pTag->GetCLUT(); if (pClut) nGran = pClut->GridPoints()+2; else nGran = 33; } } int i, j; icFloatNumber stepsize = (icFloatNumber)(1.0/(icFloatNumber)(nGran-1)); icFloatNumber* steps = new icFloatNumber[ndim1]; icFloatNumber nstart = 0.0; icFloatNumber nEnd = (icFloatNumber)(1.0+stepsize/2.0); for(j=0; j<ndim1; j++) { steps[j] = nstart; } while(steps[0]==nstart) { for(j=0; j<ndim; j++) { sPixel[j] = icMin(steps[j+1],1.0); } steps[ndim] = (steps[ndim]+stepsize); for(i=ndim; i>=0; i--) { if(steps[i]>nEnd) { steps[i] = nstart; steps[i-1] = (steps[i-1]+stepsize); } else break; } dev2Lab.Apply(devPcs, sPixel); //Convert device value to pcs from input table Lab2Dev2Lab.Apply(roundPcs1, devPcs); //First round trip gets color into output gamut Lab2Dev2Lab.Apply(roundPcs2, roundPcs1); //Second round trip find reproducibility error icLabFromPcs(devPcs); icLabFromPcs(roundPcs1); icLabFromPcs(roundPcs2); Compare(sPixel, devPcs, roundPcs1, roundPcs2); } delete[] steps; return icCmmStatOk; }
int main(int argc, char* argv[]) { int nArg = 1; if (argc<=1) { printf("Usage: iccGamutMapGirdle profile num_hue {rendering_intent=3 {use_mpe=0}}\n"); printf(" where\n"); printf(" num_hue is number of equal spaced hue steps\n"); printf(" rendering_intent is (0=perceptual, 1=relative, 2=saturation, 3=absolute)\n"); return -1; } icRenderingIntent nIntent = icAbsoluteColorimetric; int nUseMPE = 0; int nHueSteps = atoi(argv[2]); if (argc>3) { nIntent = (icRenderingIntent)atoi(argv[3]); if (argc>4) { nUseMPE = atoi(argv[4]); } } CIccCmm cmm(icSigLabData, icSigLabData, false); if (cmm.AddXform(argv[1], nIntent, icInterpTetrahedral, icXformLutColor, nUseMPE==1)!=icCmmStatOk) { printf("Unable to add '%s' to cmm\n", argv[1]); return -2; } if (cmm.AddXform(argv[1], nIntent, icInterpTetrahedral, icXformLutColor, nUseMPE==1)!=icCmmStatOk) { printf("Unable to append '%s' to cmm\n", argv[1]); return -2; } if (cmm.Begin()!=icCmmStatOk) { printf("Unable to begin profile apply\n"); return -3; } icFloatNumber pixel[16], bestLCH[3]; icFloatNumber hue, hueStep; icFloatNumber Lval, Cval; icFloatNumber maxC; hueStep = 360.0f /(icFloatNumber)nHueSteps; printf("L*\tC*\tH*\n"); for (hue=0.0; hue<360.0; hue += hueStep) { maxC=-10; memset(bestLCH, 0, sizeof(bestLCH)); for (Lval = 100.0; Lval>=0.0; Lval-=.5) { pixel[0] = Lval; pixel[1] = 128; pixel[2] = hue; icLch2Lab(pixel); icLabToPcs(pixel); cmm.Apply(pixel,pixel); icLabFromPcs(pixel); icLab2Lch(pixel); if (pixel[1]>maxC) { maxC = pixel[1]; memcpy(bestLCH, pixel, 3*sizeof(icFloatNumber)); } } for (Cval=25; Cval<128; Cval+=.5) { pixel[0] = 100; pixel[1] = Cval; pixel[2] = hue; icLch2Lab(pixel); icLabToPcs(pixel); cmm.Apply(pixel,pixel); icLabFromPcs(pixel); icLab2Lch(pixel); if (pixel[1]>maxC) { maxC = pixel[1]; memcpy(bestLCH, pixel, 3*sizeof(icFloatNumber)); } pixel[0] = 0; pixel[1] = Cval; pixel[2] = hue; icLch2Lab(pixel); icLabToPcs(pixel); cmm.Apply(pixel,pixel); icLabFromPcs(pixel); icLab2Lch(pixel); if (pixel[1]>maxC) { maxC = pixel[1]; memcpy(bestLCH, pixel, 3*sizeof(icFloatNumber)); } } printf("%.2f\t%.2f\t%.2f\n", bestLCH[0], bestLCH[1], bestLCH[2]); } return 0; }
bool Apply(const char *szSrcImage, const char *szSrcProfile, const char *szDstProfile, const char *szDstImage, int nIntent) { unsigned long i, j, k, sn, sphoto, dn, photo, space; CTiffImg SrcImg, DstImg; CIccCmm cmm; unsigned char *sptr, *dptr; bool bSuccess = true; bool bConvert = false; if (cmm.AddXform(szSrcProfile, nIntent<0 ? icUnknownIntent : (icRenderingIntent)nIntent/*, icInterpTetrahedral*/)) { printf("Invalid Profile: %s\n", szSrcProfile); return false; } if (szDstProfile && *szDstProfile && cmm.AddXform(szDstProfile/*, icUnknownIntent, icInterpTetrahedral*/)) { printf("Invalid Profile: %s\n", szDstProfile); return false; } if (cmm.Begin() != icCmmStatOk) { printf("Invalid Profile:\n %s\n %s'\n", szSrcProfile, szDstProfile); return false; } if (!SrcImg.Open(szSrcImage)) { printf("Invalid Tiff file - '%s'\n", szSrcImage); return false; } sn = SrcImg.GetSamples(); sphoto = SrcImg.GetPhoto(); space = cmm.GetSourceSpace(); if (SrcImg.GetBitsPerSample()!=8 || !((space==icSigRgbData && sn==3 && sphoto==PHOTO_MINISBLACK) || (space==icSigLabData && sn==3 && sphoto==PHOTO_CIELAB) || (space==icSigXYZData && sn==3 && sphoto==PHOTO_CIELAB) || (space==icSigCmykData && sn==4 && sphoto==PHOTO_MINISWHITE) || (space==icSigMCH4Data && sn==4 && sphoto==PHOTO_MINISWHITE) || (space==icSigMCH5Data && sn==5 && sphoto==PHOTO_MINISWHITE) || (space==icSigMCH6Data && sn==6 && sphoto==PHOTO_MINISWHITE))) { printf("Invalid source profile/image pixel format\n"); return false; } switch (cmm.GetDestSpace()) { case icSigRgbData: photo = PHOTO_MINISBLACK; dn = 3; break; case icSigCmyData: photo = PHOTO_MINISWHITE; dn = 3; break; case icSigXYZData: bConvert = true; //Fall through - No break here case icSigLabData: photo = PHOTO_CIELAB; dn = 3; break; case icSigCmykData: case icSig4colorData: photo = PHOTO_MINISWHITE; dn = 4; break; case icSig5colorData: photo = PHOTO_MINISWHITE; dn = 5; break; case icSig6colorData: photo = PHOTO_MINISWHITE; dn = 6; break; case icSig7colorData: photo = PHOTO_MINISWHITE; dn = 7; break; case icSig8colorData: photo = PHOTO_MINISWHITE; dn = 8; break; default: printf("Invalid destination profile/image pixel format\n"); return false; } if (!DstImg.Create(szDstImage, SrcImg.GetWidth(), SrcImg.GetHeight(), 8, photo, dn, SrcImg.GetXRes(), SrcImg.GetYRes(), false)) { printf("Unable to create Tiff file - '%s'\n", szDstImage); return false; } unsigned char *pSBuf = (unsigned char *)malloc(SrcImg.GetBytesPerLine()); unsigned char *pDBuf = (unsigned char *)malloc(DstImg.GetBytesPerLine()); icFloatNumber Pixel[16]; if (!pSBuf) { printf("Out of Memory!\n"); return false; } if (!pDBuf) { printf("Out of Memory!\n"); free(pSBuf); return false; } for (i=0; i<SrcImg.GetHeight(); i++) { if (!SrcImg.ReadLine(pSBuf)) { bSuccess = false; break; } for (sptr=pSBuf, dptr=pDBuf, j=0; j<SrcImg.GetWidth(); j++, sptr+=sn, dptr+=dn) { if (sphoto==PHOTO_CIELAB) { Pixel[0] = (icFloatNumber)sptr[0] / 255.0f; Pixel[1] = ((icFloatNumber)((signed char)sptr[1]) + 128.0f) / 255.0f; Pixel[2] = ((icFloatNumber)((signed char)sptr[2]) + 128.0f) / 255.0f; if (space==icSigXYZData) { icLabFromPcs(Pixel); icLabtoXYZ(Pixel); icXyzToPcs(Pixel); } } else { for (k=0; k<sn; k++) { Pixel[k] = (icFloatNumber)sptr[k] / 255.0f; } } cmm.Apply(Pixel, Pixel); if (photo==PHOTO_CIELAB) { if (bConvert) { icXyzFromPcs(Pixel); icXYZtoLab(Pixel); icLabToPcs(Pixel); } dptr[0] = (unsigned char)(UnitClip(Pixel[0]) * 255.0 + 0.5); dptr[1] = (unsigned char)(UnitClip(Pixel[1]) * 255.0 - 128.0); dptr[2] = (unsigned char)(UnitClip(Pixel[2]) * 255.0 - 128.0); } else { for (k=0; k<dn; k++) { dptr[k] = (unsigned char)(UnitClip(Pixel[k]) * 255.0 + 0.5); } } } if (!DstImg.WriteLine(pDBuf)) { bSuccess = false; break; } } SrcImg.Close(); free(pSBuf); free(pDBuf); return bSuccess; }