DCP dual illuminant support

see issue 1336
This commit is contained in:
Oliver Duis
2012-04-23 17:45:27 +02:00
parent 29dc72e26c
commit c615e7b132
13 changed files with 187 additions and 44 deletions

View File

@@ -908,6 +908,11 @@ TP_ICM_LABEL;Farbmanagement
TP_ICM_NOICM;Kein ICM: sRGB-Ausgabe TP_ICM_NOICM;Kein ICM: sRGB-Ausgabe
TP_ICM_OUTPUTDLGLABEL;Wähle Ausgabe-ICC-Profil... TP_ICM_OUTPUTDLGLABEL;Wähle Ausgabe-ICC-Profil...
TP_ICM_OUTPUTPROFILE;Ausgabeprofil TP_ICM_OUTPUTPROFILE;Ausgabeprofil
TP_ICM_PREFERREDPROFILE;Bevorzugtes DCP-Profil
TP_ICM_PREFERREDPROFILE_1;Tageslight
TP_ICM_PREFERREDPROFILE_2;Glühlampe
TP_ICM_PREFERREDPROFILE_3;Neonröhre
TP_ICM_PREFERREDPROFILE_4;Blitz
TP_ICM_SAVEREFERENCE;Referenzbild für Profil speichern TP_ICM_SAVEREFERENCE;Referenzbild für Profil speichern
TP_ICM_WORKINGPROFILE;Arbeitsfarbraum TP_ICM_WORKINGPROFILE;Arbeitsfarbraum
TP_IMPULSEDENOISE_LABEL;Impulsrauschminderung TP_IMPULSEDENOISE_LABEL;Impulsrauschminderung

View File

@@ -478,7 +478,7 @@ MAIN_MSG_EMPTYFILENAME;Filename unspecified!
MAIN_MSG_ERRORDURINGIMAGESAVING;Error during image saving MAIN_MSG_ERRORDURINGIMAGESAVING;Error during image saving
MAIN_MSG_EXITJOBSINQUEUEINFO;Unprocessed images in the queue will be lost on exit. MAIN_MSG_EXITJOBSINQUEUEINFO;Unprocessed images in the queue will be lost on exit.
MAIN_MSG_EXITJOBSINQUEUEQUEST;Are you sure you want to exit? There are unprocessed images waiting in the queue. MAIN_MSG_EXITJOBSINQUEUEQUEST;Are you sure you want to exit? There are unprocessed images waiting in the queue.
MAIN_MSG_IMAGEUNPROCESSED;This command requires all selected images to be queue process first. MAIN_MSG_IMAGEUNPROCESSED;This command requires all selected images to be queue processed first.
MAIN_MSG_JOBSINQUEUE;job(s) in the queue MAIN_MSG_JOBSINQUEUE;job(s) in the queue
MAIN_MSG_NAVIGATOR;Navigator MAIN_MSG_NAVIGATOR;Navigator
MAIN_MSG_PLACES;Places MAIN_MSG_PLACES;Places
@@ -940,6 +940,11 @@ TP_ICM_LABEL;Color Management
TP_ICM_NOICM;No ICM: sRGB output TP_ICM_NOICM;No ICM: sRGB output
TP_ICM_OUTPUTDLGLABEL;Select Output ICC Profile... TP_ICM_OUTPUTDLGLABEL;Select Output ICC Profile...
TP_ICM_OUTPUTPROFILE;Output Profile TP_ICM_OUTPUTPROFILE;Output Profile
TP_ICM_PREFERREDPROFILE;Preferred DCP profile
TP_ICM_PREFERREDPROFILE_1;Daylight
TP_ICM_PREFERREDPROFILE_2;Tungsten
TP_ICM_PREFERREDPROFILE_3;Fluorescent
TP_ICM_PREFERREDPROFILE_4;Flash
TP_ICM_SAVEREFERENCE;Save reference image for profiling TP_ICM_SAVEREFERENCE;Save reference image for profiling
TP_ICM_WORKINGPROFILE;Working Profile TP_ICM_WORKINGPROFILE;Working Profile
TP_IMPULSEDENOISE_LABEL;Impulse Noise Reduction TP_IMPULSEDENOISE_LABEL;Impulse Noise Reduction

View File

@@ -31,32 +31,32 @@ using namespace rtengine;
using namespace rtexif; using namespace rtexif;
DCPProfile::DCPProfile(Glib::ustring fname) { DCPProfile::DCPProfile(Glib::ustring fname) {
const int TIFFFloatSize=4;
const int TagColorMatrix1=50721, TagColorMatrix2=50722, TagProfileHueSatMapDims=50937; const int TagColorMatrix1=50721, TagColorMatrix2=50722, TagProfileHueSatMapDims=50937;
const int TagProfileHueSatMapData1=50938, TagProfileHueSatMapData2=50939; const int TagProfileHueSatMapData1=50938, TagProfileHueSatMapData2=50939;
const int TagCalibrationIlluminant1=50778, TagCalibrationIlluminant2=50779; const int TagCalibrationIlluminant1=50778, TagCalibrationIlluminant2=50779;
const int TagProfileLookTableData=50982, TagProfileLookTableDims=50981; // ProfileLookup is the low quality variant const int TagProfileLookTableData=50982, TagProfileLookTableDims=50981; // ProfileLookup is the low quality variant
aDeltas=NULL; iHueDivisions=iSatDivisions=iValDivisions=iArrayCount=0; aDeltas1=aDeltas2=NULL; iHueDivisions=iSatDivisions=iValDivisions=iArrayCount=0;
FILE *pFile = safe_g_fopen(fname, "rb"); FILE *pFile = safe_g_fopen(fname, "rb");
TagDirectory *tagDir=ExifManager::parseTIFF(pFile, false); TagDirectory *tagDir=ExifManager::parseTIFF(pFile, false);
// If there are two profiles, check what is the best target to take Tag* tag = tagDir->getTag(TagCalibrationIlluminant1); iLightSource1 = (tag!=NULL ? tag->toInt(0,SHORT) : -1);
// We don't mix the profiles as adobe does, since with more and more non-tungsten light tag = tagDir->getTag(TagCalibrationIlluminant2); iLightSource2 = (tag!=NULL ? tag->toInt(0,SHORT) : -1);
// it makes no sense. Take the daylight reference light
Tag* tag = tagDir->getTag(TagCalibrationIlluminant2);
bool hasSecondHueSat = tagDir->getTag(TagProfileHueSatMapData2)!=NULL; // some profiles have two matrices but just one huesat
bool use2nd = (tag!=NULL && tag->toInt(0,SHORT)>=20 && tag->toInt(0,SHORT)<=23);
// Color Matrix bool hasSecondHueSat = tagDir->getTag(TagProfileHueSatMapData2)!=NULL; // some profiles have two matrices, but just one huesat
tag = tagDir->getTag( use2nd ? TagColorMatrix2 : TagColorMatrix1);
// Color Matrix (1 is always there)
tag = tagDir->getTag(TagColorMatrix1);
for (int row=0;row<3;row++) { for (int row=0;row<3;row++) {
for (int col=0;col<3;col++) { for (int col=0;col<3;col++) {
mColorMatrix[col][row]=(float)tag->toDouble((col+row*3)*8); mColorMatrix1[col][row]=(float)tag->toDouble((col+row*3)*8);
} }
} }
ConvertDNGMatrix2XYZCAM(mColorMatrix1,mXYZCAM1);
// LUT profile? Divisions counts // LUT profile? Divisions counts
bool useSimpleLookup=false; bool useSimpleLookup=false;
@@ -70,24 +70,61 @@ DCPProfile::DCPProfile(Glib::ustring fname) {
iHueDivisions=tag->toInt(0); iSatDivisions=tag->toInt(4); iValDivisions=tag->toInt(8); iHueDivisions=tag->toInt(0); iSatDivisions=tag->toInt(4); iValDivisions=tag->toInt(8);
// Saturation maps. Need to be unwinded. // Saturation maps. Need to be unwinded.
tag = tagDir->getTag(useSimpleLookup ? TagProfileLookTableData : ( use2nd && hasSecondHueSat ? TagProfileHueSatMapData2 : TagProfileHueSatMapData1)); tag = tagDir->getTag(useSimpleLookup ? TagProfileLookTableData : TagProfileHueSatMapData1);
iArrayCount = tag->getCount()/3; iArrayCount = tag->getCount()/3;
aDeltas=new HSBModify[iArrayCount]; aDeltas1=new HSBModify[iArrayCount];
const int TIFFFloatSize=4;
for (int i=0;i<iArrayCount;i++) { for (int i=0;i<iArrayCount;i++) {
aDeltas[i].fHueShift=tag->toDouble((i*3)*TIFFFloatSize); aDeltas1[i].fHueShift=tag->toDouble((i*3)*TIFFFloatSize);
aDeltas[i].fSatScale=tag->toDouble((i*3+1)*TIFFFloatSize); aDeltas1[i].fSatScale=tag->toDouble((i*3+1)*TIFFFloatSize);
aDeltas[i].fValScale=tag->toDouble((i*3+2)*TIFFFloatSize); aDeltas1[i].fValScale=tag->toDouble((i*3+2)*TIFFFloatSize);
}
}
// For second profile, copy everything from first profile is no better data is available
if (iLightSource2!=-1) {
// Second matrix
tag = tagDir->getTag(TagColorMatrix2);
for (int row=0;row<3;row++) {
for (int col=0;col<3;col++) {
mColorMatrix2[col][row]= (tag!=NULL ? (float)tag->toDouble((col+row*3)*8) : mColorMatrix1[col][row]);
}
}
ConvertDNGMatrix2XYZCAM(mColorMatrix2,mXYZCAM2);
// Second huesatmap, or copy of first
if (hasSecondHueSat) {
aDeltas2=new HSBModify[iArrayCount];
// Saturation maps. Need to be unwinded.
tag = tagDir->getTag(TagProfileHueSatMapData2);
for (int i=0;i<iArrayCount;i++) {
aDeltas2[i].fHueShift=tag->toDouble((i*3)*TIFFFloatSize);
aDeltas2[i].fSatScale=tag->toDouble((i*3+1)*TIFFFloatSize);
aDeltas2[i].fValScale=tag->toDouble((i*3+2)*TIFFFloatSize);
}
} else {
if (aDeltas1!=NULL) {
aDeltas2=new HSBModify[iArrayCount];
for (int i=0;i<iArrayCount;i++) aDeltas2[i]=aDeltas1[i];
}
} }
} }
if (pFile!=NULL) fclose(pFile); if (pFile!=NULL) fclose(pFile);
delete tagDir; delete tagDir;
}
DCPProfile::~DCPProfile() {
delete[] aDeltas1; delete[] aDeltas2;
}
if (iArrayCount>0) {
// Convert DNG color matrix to xyz_cam compatible matrix // Convert DNG color matrix to xyz_cam compatible matrix
void DCPProfile::ConvertDNGMatrix2XYZCAM(const double (*mColorMatrix)[3], double (*mXYZCAM)[3]) {
int i,j,k; int i,j,k;
double cam_xyz[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; double cam_xyz[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
@@ -114,21 +151,66 @@ DCPProfile::DCPProfile(Glib::ustring fname) {
double rgb_cam[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; double rgb_cam[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
RawImageSource::inverse33 (cam_rgb, rgb_cam); RawImageSource::inverse33 (cam_rgb, rgb_cam);
memset(mXYZCAM,0,sizeof(mXYZCAM)); for (i=0; i<3; i++)
for (j=0; j<3; j++) mXYZCAM[i][j]=0;
for (i=0; i<3; i++) for (i=0; i<3; i++)
for (j=0; j<3; j++) for (j=0; j<3; j++)
for (k=0; k<3; k++) for (k=0; k<3; k++)
mXYZCAM[i][j] += xyz_sRGB[i][k] * rgb_cam[k][j]; mXYZCAM[i][j] += xyz_sRGB[i][k] * rgb_cam[k][j];
} }
const DCPProfile::HSBModify* DCPProfile::GetBestProfile(DCPLightType preferredProfile, double (*mXYZCAM)[3]) const {
bool use2=false;
if (iLightSource2!=-1) {
DCPLightType t1=GetLightType(iLightSource1); DCPLightType t2=GetLightType(iLightSource2);
// usually second is the daylight (default if nothing else found)
if (t2==Daylight) use2=true;
switch (preferredProfile) {
case Tungsten:
if (t1==Tungsten) use2=false; else if (t2==Tungsten) use2=true;
break;
case Fluorescent:
if (t1==Fluorescent) use2=false; else if (t2==Fluorescent) use2=true;
break;
case Flash:
if (t1==Flash) use2=false; else if (t2==Flash) use2=true;
break;
default: break; // e.g. Daylight
}
} }
DCPProfile::~DCPProfile() { // printf("DCP using LightSource %i: %i for requested %i\n", use2?2:1, use2?iLightSource2:iLightSource1, (int)preferredProfile);
delete[] aDeltas;
for (int row=0;row<3;row++) {
for (int col=0;col<3;col++) {
mXYZCAM[col][row]= (use2 ? mXYZCAM2[col][row] : mXYZCAM1[col][row]);
}
} }
void DCPProfile::Apply(Imagefloat *pImg, Glib::ustring workingSpace) const { return use2?aDeltas2:aDeltas1;
}
DCPLightType DCPProfile::GetLightType(short iLightSource) const {
if (iLightSource==3 || iLightSource==17 || iLightSource==24) return Tungsten;
if (iLightSource==2 || (iLightSource>=12 && iLightSource<=15)) return Fluorescent;
if (iLightSource==4) return Flash;
return Daylight;
}
void DCPProfile::Apply(Imagefloat *pImg, DCPLightType preferredProfile, Glib::ustring workingSpace) const {
TMatrix mWork = iccStore->workingSpaceInverseMatrix (workingSpace); TMatrix mWork = iccStore->workingSpaceInverseMatrix (workingSpace);
double mXYZCAM[3][3];
const HSBModify* tableBase=GetBestProfile(preferredProfile,mXYZCAM);
if (iArrayCount==0) { if (iArrayCount==0) {
//===== No LUT- Calculate matrix for direct conversion raw>working space //===== No LUT- Calculate matrix for direct conversion raw>working space
double mat[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; double mat[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
@@ -173,8 +255,6 @@ void DCPProfile::Apply(Imagefloat *pImg, Glib::ustring workingSpace) const {
int maxSatIndex0 = iSatDivisions - 2; int maxSatIndex0 = iSatDivisions - 2;
int maxValIndex0 = iValDivisions - 2; int maxValIndex0 = iValDivisions - 2;
const HSBModify *tableBase = aDeltas;
int hueStep = iSatDivisions; int hueStep = iSatDivisions;
int valStep = iHueDivisions * hueStep; int valStep = iHueDivisions * hueStep;
@@ -342,9 +422,12 @@ void DCPProfile::Apply(Imagefloat *pImg, Glib::ustring workingSpace) const {
// Integer variant is legacy, only used for thumbs. Simply take the matrix here // Integer variant is legacy, only used for thumbs. Simply take the matrix here
void DCPProfile::Apply(Image16 *pImg, Glib::ustring workingSpace) const { void DCPProfile::Apply(Image16 *pImg, DCPLightType preferredProfile, Glib::ustring workingSpace) const {
TMatrix mWork = iccStore->workingSpaceInverseMatrix (workingSpace); TMatrix mWork = iccStore->workingSpaceInverseMatrix (workingSpace);
double mXYZCAM[3][3];
const HSBModify* tableBase=GetBestProfile(preferredProfile,mXYZCAM);
// Calculate matrix for direct conversion raw>working space // Calculate matrix for direct conversion raw>working space
double mat[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}; double mat[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
for (int i=0; i<3; i++) for (int i=0; i<3; i++)

View File

@@ -26,6 +26,9 @@
#include <string> #include <string>
namespace rtengine { namespace rtengine {
enum DCPLightType {
Daylight=1, Tungsten=2, Fluorescent=3, Flash=4
};
class DCPProfile { class DCPProfile {
struct HSBModify struct HSBModify
@@ -35,20 +38,27 @@ namespace rtengine {
float fValScale; float fValScale;
}; };
double mColorMatrix[3][3]; double mColorMatrix1[3][3],mColorMatrix2[3][3];
double mXYZCAM[3][3]; // compatible to RTs xyz_cam double mXYZCAM1[3][3],mXYZCAM2[3][3]; // compatible to RTs xyz_cam
HSBModify *aDeltas; HSBModify *aDeltas1,*aDeltas2;
short iLightSource1,iLightSource2;
int iHueDivisions, iSatDivisions, iValDivisions; int iHueDivisions, iSatDivisions, iValDivisions;
int iHueStep, iValStep, iArrayCount; int iHueStep, iValStep, iArrayCount;
void ConvertDNGMatrix2XYZCAM(const double (*mColorMatrix)[3], double (*mXYZCAM)[3]);
const HSBModify* GetBestProfile(DCPLightType preferredProfile, double (*mXYZCAM)[3]) const;
DCPLightType GetLightType(short iLightSource) const;
public: public:
DCPProfile(Glib::ustring fname); DCPProfile(Glib::ustring fname);
~DCPProfile(); ~DCPProfile();
void Apply(Imagefloat *pImg, Glib::ustring workingSpace) const; void Apply(Imagefloat *pImg, DCPLightType preferredProfile, Glib::ustring workingSpace) const;
void Apply(Image16 *pImg, Glib::ustring workingSpace) const; void Apply(Image16 *pImg, DCPLightType preferredProfile, Glib::ustring workingSpace) const;
}; };
class DCPStore { class DCPStore {

View File

@@ -70,7 +70,7 @@ enum ProcEvent {
EvCDNEnabled=45, // obsolete EvCDNEnabled=45, // obsolete
EvCDNRadius=46, // obsolete EvCDNRadius=46, // obsolete
EvCDNEdgeTolerance=47, // obsolete EvCDNEdgeTolerance=47, // obsolete
EvCDNEdgeSensitive=48, // obsolete EvPrefProfile=48,
EvSHEnabled=49, EvSHEnabled=49,
EvSHHighlights=50, EvSHHighlights=50,
EvSHShadows=51, EvSHShadows=51,

View File

@@ -33,6 +33,7 @@
#include "rawimage.h" #include "rawimage.h"
#include "../rtgui/ppversion.h" #include "../rtgui/ppversion.h"
#include "../rtgui/paramsedited.h" #include "../rtgui/paramsedited.h"
#include "dcp.h"
#define APPVERSION VERSION #define APPVERSION VERSION
@@ -295,6 +296,7 @@ void ProcParams::setDefaults () {
icm.input = ""; icm.input = "";
icm.blendCMSMatrix = false; icm.blendCMSMatrix = false;
icm.preferredProfile = (short)rtengine::Daylight;
icm.working = "sRGB"; icm.working = "sRGB";
icm.output = "sRGB"; icm.output = "sRGB";
icm.gamma = "default"; icm.gamma = "default";
@@ -570,6 +572,7 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, ParamsEdited* p
// save color management settings // save color management settings
if (!pedited || pedited->icm.input) keyFile.set_string ("Color Management", "InputProfile", icm.input); if (!pedited || pedited->icm.input) keyFile.set_string ("Color Management", "InputProfile", icm.input);
if (!pedited || pedited->icm.blendCMSMatrix) keyFile.set_boolean ("Color Management", "BlendCMSMatrix", icm.blendCMSMatrix); if (!pedited || pedited->icm.blendCMSMatrix) keyFile.set_boolean ("Color Management", "BlendCMSMatrix", icm.blendCMSMatrix);
if (!pedited || pedited->icm.preferredProfile) keyFile.set_boolean ("Color Management", "PreferredProfile", icm.preferredProfile);
if (!pedited || pedited->icm.working) keyFile.set_string ("Color Management", "WorkingProfile", icm.working); if (!pedited || pedited->icm.working) keyFile.set_string ("Color Management", "WorkingProfile", icm.working);
if (!pedited || pedited->icm.output) keyFile.set_string ("Color Management", "OutputProfile", icm.output); if (!pedited || pedited->icm.output) keyFile.set_string ("Color Management", "OutputProfile", icm.output);
if (!pedited || pedited->icm.gamma) keyFile.set_string ("Color Management", "Gammafree", icm.gamma); if (!pedited || pedited->icm.gamma) keyFile.set_string ("Color Management", "Gammafree", icm.gamma);
@@ -980,6 +983,7 @@ if (keyFile.has_group ("Resize")) {
if (keyFile.has_group ("Color Management")) { if (keyFile.has_group ("Color Management")) {
if (keyFile.has_key ("Color Management", "InputProfile")) { icm.input = keyFile.get_string ("Color Management", "InputProfile"); if (pedited) pedited->icm.input = true; } if (keyFile.has_key ("Color Management", "InputProfile")) { icm.input = keyFile.get_string ("Color Management", "InputProfile"); if (pedited) pedited->icm.input = true; }
if (keyFile.has_key ("Color Management", "BlendCMSMatrix")) { icm.blendCMSMatrix = keyFile.get_boolean ("Color Management", "BlendCMSMatrix"); if (pedited) pedited->icm.blendCMSMatrix = true; } if (keyFile.has_key ("Color Management", "BlendCMSMatrix")) { icm.blendCMSMatrix = keyFile.get_boolean ("Color Management", "BlendCMSMatrix"); if (pedited) pedited->icm.blendCMSMatrix = true; }
if (keyFile.has_key ("Color Management", "PreferredProfile")) { icm.preferredProfile = keyFile.get_boolean ("Color Management", "PreferredProfile"); if (pedited) pedited->icm.preferredProfile = true; }
if (keyFile.has_key ("Color Management", "WorkingProfile")) { icm.working = keyFile.get_string ("Color Management", "WorkingProfile"); if (pedited) pedited->icm.working = true; } if (keyFile.has_key ("Color Management", "WorkingProfile")) { icm.working = keyFile.get_string ("Color Management", "WorkingProfile"); if (pedited) pedited->icm.working = true; }
if (keyFile.has_key ("Color Management", "OutputProfile")) { icm.output = keyFile.get_string ("Color Management", "OutputProfile"); if (pedited) pedited->icm.output = true; } if (keyFile.has_key ("Color Management", "OutputProfile")) { icm.output = keyFile.get_string ("Color Management", "OutputProfile"); if (pedited) pedited->icm.output = true; }
if (keyFile.has_key ("Color Management", "Gammafree")) { icm.gamma = keyFile.get_string ("Color Management", "Gammafree"); if (pedited) pedited->icm.gamfree = true; } if (keyFile.has_key ("Color Management", "Gammafree")) { icm.gamma = keyFile.get_string ("Color Management", "Gammafree"); if (pedited) pedited->icm.gamfree = true; }
@@ -1271,6 +1275,7 @@ bool ProcParams::operator== (const ProcParams& other) {
&& raw.linenoise == other.raw.linenoise && raw.linenoise == other.raw.linenoise
&& icm.input == other.icm.input && icm.input == other.icm.input
&& icm.blendCMSMatrix == other.icm.blendCMSMatrix && icm.blendCMSMatrix == other.icm.blendCMSMatrix
&& icm.preferredProfile == other.icm.preferredProfile
&& icm.working == other.icm.working && icm.working == other.icm.working
&& icm.output == other.icm.output && icm.output == other.icm.output
&& icm.gamma == other.icm.gamma && icm.gamma == other.icm.gamma

View File

@@ -407,6 +407,7 @@ class ColorManagementParams {
public: public:
Glib::ustring input; Glib::ustring input;
bool blendCMSMatrix; bool blendCMSMatrix;
short preferredProfile;
Glib::ustring working; Glib::ustring working;
Glib::ustring output; Glib::ustring output;
static const Glib::ustring NoICMString; static const Glib::ustring NoICMString;

View File

@@ -1680,7 +1680,7 @@ void RawImageSource::colorSpaceConversion (Imagefloat* im, ColorManagementParams
if (!findInputProfile(cmp.input, embedded, camName, &dcpProf, in)) return; if (!findInputProfile(cmp.input, embedded, camName, &dcpProf, in)) return;
if (dcpProf!=NULL) { if (dcpProf!=NULL) {
dcpProf->Apply(im, cmp.working); dcpProf->Apply(im, (DCPLightType)cmp.preferredProfile, cmp.working);
} else { } else {
// Calculate matrix for direct conversion raw>working space // Calculate matrix for direct conversion raw>working space
TMatrix work = iccStore->workingSpaceInverseMatrix (cmp.working); TMatrix work = iccStore->workingSpaceInverseMatrix (cmp.working);
@@ -1903,7 +1903,7 @@ void RawImageSource::colorSpaceConversion16 (Image16* im, ColorManagementParams
if (!findInputProfile(cmp.input, embedded, camName, &dcpProf, in)) return; if (!findInputProfile(cmp.input, embedded, camName, &dcpProf, in)) return;
if (dcpProf!=NULL) { if (dcpProf!=NULL) {
dcpProf->Apply(im, cmp.working); dcpProf->Apply(im, (DCPLightType)cmp.preferredProfile, cmp.working);
} else { } else {
if (in==NULL) { if (in==NULL) {
// Take camprofile from DCRAW // Take camprofile from DCRAW

View File

@@ -68,7 +68,7 @@ WHITEBALANCE, // EvWBGreen,
0, // EvCDNEnabled:obsolete, 0, // EvCDNEnabled:obsolete,
0, // EvCDNRadius: obsolete, 0, // EvCDNRadius: obsolete,
0, // EvCDNEdgeTolerance: obsolete, 0, // EvCDNEdgeTolerance: obsolete,
0, // EvCDNEdgeSensitive: obsolete, ALL, // EvPrefProfile,
RETINEX, // EvSHEnabled, RETINEX, // EvSHEnabled,
RGBCURVE, // EvSHHighlights, RGBCURVE, // EvSHHighlights,
RGBCURVE, // EvSHShadows, RGBCURVE, // EvSHShadows,

View File

@@ -74,6 +74,20 @@ ICMPanel::ICMPanel () : Gtk::VBox(), FoldableToolPanel(this), iunchanged(NULL),
ifromfile->set_group (opts); ifromfile->set_group (opts);
inone->set_group (opts); inone->set_group (opts);
Gtk::HBox* hb = Gtk::manage (new Gtk::HBox ());
hb->show ();
Gtk::Label* ppl = Gtk::manage (new Gtk::Label (M("TP_ICM_PREFERREDPROFILE")+":"));
ppl->show ();
prefprof = Gtk::manage (new MyComboBoxText ());
prefprof->append_text (M("TP_ICM_PREFERREDPROFILE_1"));
prefprof->append_text (M("TP_ICM_PREFERREDPROFILE_2"));
prefprof->append_text (M("TP_ICM_PREFERREDPROFILE_3"));
prefprof->append_text (M("TP_ICM_PREFERREDPROFILE_4"));
prefprof->show ();
hb->pack_start(*ppl, Gtk::PACK_SHRINK, 4);
hb->pack_start(*prefprof);
pack_start (*hb, Gtk::PACK_SHRINK, 4);
ckbBlendCMSMatrix = Gtk::manage (new Gtk::CheckButton (M("TP_ICM_BLENDCMSMATRIX"))); ckbBlendCMSMatrix = Gtk::manage (new Gtk::CheckButton (M("TP_ICM_BLENDCMSMATRIX")));
ckbBlendCMSMatrix->set_sensitive (false); ckbBlendCMSMatrix->set_sensitive (false);
ckbBlendCMSMatrix->set_tooltip_text (M("TP_ICM_BLENDCMSMATRIX_TOOLTIP")); ckbBlendCMSMatrix->set_tooltip_text (M("TP_ICM_BLENDCMSMATRIX_TOOLTIP"));
@@ -181,6 +195,7 @@ ICMPanel::ICMPanel () : Gtk::VBox(), FoldableToolPanel(this), iunchanged(NULL),
wnames->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::wpChanged) ); wnames->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::wpChanged) );
onames->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::opChanged) ); onames->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::opChanged) );
wgamma->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::gpChanged) ); wgamma->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::gpChanged) );
prefprof->signal_changed().connect( sigc::mem_fun(*this, &ICMPanel::prefProfChanged) );
icamera->signal_toggled().connect( sigc::mem_fun(*this, &ICMPanel::ipChanged) ); icamera->signal_toggled().connect( sigc::mem_fun(*this, &ICMPanel::ipChanged) );
icameraICC->signal_toggled().connect( sigc::mem_fun(*this, &ICMPanel::ipChanged) ); icameraICC->signal_toggled().connect( sigc::mem_fun(*this, &ICMPanel::ipChanged) );
@@ -199,32 +214,33 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) {
ipc.block (true); ipc.block (true);
if (pp->icm.input == "(none)" && icamera->get_state()!=Gtk::STATE_INSENSITIVE) { if (pp->icm.input == "(none)" && icamera->get_state()!=Gtk::STATE_INSENSITIVE) {
inone->set_active (true); inone->set_active (true); prefprof->set_sensitive (false);
ckbBlendCMSMatrix->set_sensitive (false); ckbBlendCMSMatrix->set_sensitive (false);
} }
else if (pp->icm.input == "(embedded)" || ((pp->icm.input == "(camera)" || pp->icm.input=="") && icamera->get_state()==Gtk::STATE_INSENSITIVE)) { else if (pp->icm.input == "(embedded)" || ((pp->icm.input == "(camera)" || pp->icm.input=="") && icamera->get_state()==Gtk::STATE_INSENSITIVE)) {
iembedded->set_active (true); iembedded->set_active (true); prefprof->set_sensitive (false);
ckbBlendCMSMatrix->set_sensitive (false); ckbBlendCMSMatrix->set_sensitive (false);
} }
else if ((pp->icm.input == "(cameraICC)") && icameraICC->get_state()!=Gtk::STATE_INSENSITIVE) { else if ((pp->icm.input == "(cameraICC)") && icameraICC->get_state()!=Gtk::STATE_INSENSITIVE) {
icameraICC->set_active (true); icameraICC->set_active (true); prefprof->set_sensitive (true);
ckbBlendCMSMatrix->set_sensitive (true); ckbBlendCMSMatrix->set_sensitive (true);
} }
else if ((pp->icm.input == "(cameraICC)") && icameraICC->get_state()==Gtk::STATE_INSENSITIVE) { else if ((pp->icm.input == "(cameraICC)") && icameraICC->get_state()==Gtk::STATE_INSENSITIVE) {
// this is the case when (cameraICC) is instructed by packaged profiles, but ICC file is not found // this is the case when (cameraICC) is instructed by packaged profiles, but ICC file is not found
// therefore falling back UI to explicitly reflect the (camera) option // therefore falling back UI to explicitly reflect the (camera) option
icamera->set_active (true); icamera->set_active (true);
prefprof->set_sensitive (false); // RT's own are always single-illuminant
ckbBlendCMSMatrix->set_sensitive (false); ckbBlendCMSMatrix->set_sensitive (false);
} }
else if ((pp->icm.input == "(camera)" || pp->icm.input=="") && icamera->get_state()!=Gtk::STATE_INSENSITIVE) { else if ((pp->icm.input == "(camera)" || pp->icm.input=="") && icamera->get_state()!=Gtk::STATE_INSENSITIVE) {
icamera->set_active (true); icamera->set_active (true);
ckbBlendCMSMatrix->set_sensitive (false); ckbBlendCMSMatrix->set_sensitive (false); prefprof->set_sensitive (false);
} }
else { else {
ifromfile->set_active (true); ifromfile->set_active (true);
oldip = pp->icm.input.substr(5); // cut of "file:" oldip = pp->icm.input.substr(5); // cut of "file:"
ipDialog->set_filename (pp->icm.input.substr(5)); ipDialog->set_filename (pp->icm.input.substr(5));
ckbBlendCMSMatrix->set_sensitive (true); ckbBlendCMSMatrix->set_sensitive (true); prefprof->set_sensitive (true);
} }
wnames->set_active_text (pp->icm.working); wnames->set_active_text (pp->icm.working);
@@ -238,6 +254,8 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) {
if (onames->get_active_row_number()==-1) if (onames->get_active_row_number()==-1)
onames->set_active_text (M("TP_ICM_NOICM")); onames->set_active_text (M("TP_ICM_NOICM"));
prefprof->set_active(pp->icm.preferredProfile-1);
ckbBlendCMSMatrix->set_active (pp->icm.blendCMSMatrix); ckbBlendCMSMatrix->set_active (pp->icm.blendCMSMatrix);
onames->set_sensitive(wgamma->get_active_row_number()==0 || freegamma->get_active()); //"default" onames->set_sensitive(wgamma->get_active_row_number()==0 || freegamma->get_active()); //"default"
wgamma->set_sensitive(!freegamma->get_active()); wgamma->set_sensitive(!freegamma->get_active());
@@ -249,6 +267,8 @@ void ICMPanel::read (const ProcParams* pp, const ParamsEdited* pedited) {
wnames->set_active_text(M("GENERAL_UNCHANGED")); wnames->set_active_text(M("GENERAL_UNCHANGED"));
if (!pedited->icm.output) if (!pedited->icm.output)
onames->set_active_text(M("GENERAL_UNCHANGED")); onames->set_active_text(M("GENERAL_UNCHANGED"));
if (!pedited->icm.preferredProfile)
prefprof->set_active_text(M("GENERAL_UNCHANGED"));
if (!pedited->icm.gamma){ if (!pedited->icm.gamma){
wgamma->set_active_text(M("GENERAL_UNCHANGED")); wgamma->set_active_text(M("GENERAL_UNCHANGED"));
wgamma->set_active_text(M("GENERAL_UNCHANGED")); wgamma->set_active_text(M("GENERAL_UNCHANGED"));
@@ -296,6 +316,7 @@ void ICMPanel::write (ProcParams* pp, ParamsEdited* pedited) {
pp->icm.working = wnames->get_active_text (); pp->icm.working = wnames->get_active_text ();
pp->icm.gamma = wgamma->get_active_text (); pp->icm.gamma = wgamma->get_active_text ();
pp->icm.preferredProfile = prefprof->get_active_row_number()+1;
if (onames->get_active_text()==M("TP_ICM_NOICM")) if (onames->get_active_text()==M("TP_ICM_NOICM"))
pp->icm.output = ColorManagementParams::NoICMString; pp->icm.output = ColorManagementParams::NoICMString;
@@ -310,6 +331,7 @@ void ICMPanel::write (ProcParams* pp, ParamsEdited* pedited) {
pedited->icm.input = !iunchanged->get_active (); pedited->icm.input = !iunchanged->get_active ();
pedited->icm.working = wnames->get_active_text()!=M("GENERAL_UNCHANGED"); pedited->icm.working = wnames->get_active_text()!=M("GENERAL_UNCHANGED");
pedited->icm.output = onames->get_active_text()!=M("GENERAL_UNCHANGED"); pedited->icm.output = onames->get_active_text()!=M("GENERAL_UNCHANGED");
pedited->icm.preferredProfile = prefprof->get_active_text()!=M("GENERAL_UNCHANGED");
pedited->icm.blendCMSMatrix = !ckbBlendCMSMatrix->get_inconsistent (); pedited->icm.blendCMSMatrix = !ckbBlendCMSMatrix->get_inconsistent ();
pedited->icm.gamma = wgamma->get_active_text()!=M("GENERAL_UNCHANGED"); pedited->icm.gamma = wgamma->get_active_text()!=M("GENERAL_UNCHANGED");
pedited->icm.freegamma =!freegamma->get_inconsistent(); pedited->icm.freegamma =!freegamma->get_inconsistent();
@@ -368,28 +390,33 @@ void ICMPanel::gpChanged () {
} }
} }
void ICMPanel::prefProfChanged() {
if (listener)
listener->panelChanged (EvPrefProfile, prefprof->get_active_text ());
}
void ICMPanel::ipChanged () { void ICMPanel::ipChanged () {
std::string profname; std::string profname;
if (inone->get_active()) { if (inone->get_active()) {
profname = "(none)"; profname = "(none)";
ckbBlendCMSMatrix->set_sensitive(false); ckbBlendCMSMatrix->set_sensitive(false); prefprof->set_sensitive (false);
} }
else if (iembedded->get_active ()) { else if (iembedded->get_active ()) {
profname = "(embedded)"; profname = "(embedded)";
ckbBlendCMSMatrix->set_sensitive(false); ckbBlendCMSMatrix->set_sensitive(false); prefprof->set_sensitive (false);
} }
else if (icamera->get_active ()) { else if (icamera->get_active ()) {
profname = "(camera)"; profname = "(camera)";
ckbBlendCMSMatrix->set_sensitive(false); ckbBlendCMSMatrix->set_sensitive(false); prefprof->set_sensitive (false);
} }
else if (icameraICC->get_active ()) { else if (icameraICC->get_active ()) {
profname = "(cameraICC)"; profname = "(cameraICC)";
ckbBlendCMSMatrix->set_sensitive(true); ckbBlendCMSMatrix->set_sensitive(true); prefprof->set_sensitive (false);
} }
else { else {
profname = ipDialog->get_filename (); profname = ipDialog->get_filename ();
ckbBlendCMSMatrix->set_sensitive(true); ckbBlendCMSMatrix->set_sensitive(true); prefprof->set_sensitive (true);
} }
if (listener && profname!=oldip) if (listener && profname!=oldip)
@@ -488,6 +515,7 @@ void ICMPanel::setBatchMode (bool batchMode) {
onames->append_text (M("GENERAL_UNCHANGED")); onames->append_text (M("GENERAL_UNCHANGED"));
wnames->append_text (M("GENERAL_UNCHANGED")); wnames->append_text (M("GENERAL_UNCHANGED"));
wgamma->append_text (M("GENERAL_UNCHANGED")); wgamma->append_text (M("GENERAL_UNCHANGED"));
prefprof->append_text (M("GENERAL_UNCHANGED"));
gampos->showEditedCB (); gampos->showEditedCB ();
slpos->showEditedCB (); slpos->showEditedCB ();

View File

@@ -48,6 +48,7 @@ class ICMPanel : public Gtk::VBox, public AdjusterListener, public FoldableToolP
Gtk::RadioButton* icamera; Gtk::RadioButton* icamera;
Gtk::RadioButton* icameraICC; Gtk::RadioButton* icameraICC;
Gtk::RadioButton* ifromfile; Gtk::RadioButton* ifromfile;
MyComboBoxText* prefprof;
Gtk::CheckButton* ckbBlendCMSMatrix; Gtk::CheckButton* ckbBlendCMSMatrix;
MyComboBoxText* wnames; MyComboBoxText* wnames;
MyComboBoxText* wgamma; MyComboBoxText* wgamma;
@@ -83,6 +84,7 @@ class ICMPanel : public Gtk::VBox, public AdjusterListener, public FoldableToolP
void GamChanged (); void GamChanged ();
void ipSelectionChanged (); void ipSelectionChanged ();
void iccTogglesChanged(); void iccTogglesChanged();
void prefProfChanged();
void setRawMeta (bool raw, const rtengine::ImageData* pMeta); void setRawMeta (bool raw, const rtengine::ImageData* pMeta);
void saveReferencePressed (); void saveReferencePressed ();

View File

@@ -165,6 +165,7 @@ void ParamsEdited::set (bool v) {
resize.enabled = v; resize.enabled = v;
icm.input = v; icm.input = v;
icm.blendCMSMatrix = v; icm.blendCMSMatrix = v;
icm.preferredProfile = v;
icm.working = v; icm.working = v;
icm.output = v; icm.output = v;
icm.gamma = v; icm.gamma = v;
@@ -357,6 +358,7 @@ void ParamsEdited::initFrom (const std::vector<rtengine::procparams::ProcParams>
resize.enabled = resize.enabled && p.resize.enabled == other.resize.enabled; resize.enabled = resize.enabled && p.resize.enabled == other.resize.enabled;
icm.input = icm.input && p.icm.input == other.icm.input; icm.input = icm.input && p.icm.input == other.icm.input;
icm.blendCMSMatrix = icm.blendCMSMatrix && p.icm.blendCMSMatrix == other.icm.blendCMSMatrix; icm.blendCMSMatrix = icm.blendCMSMatrix && p.icm.blendCMSMatrix == other.icm.blendCMSMatrix;
icm.preferredProfile = icm.preferredProfile && p.icm.preferredProfile == other.icm.preferredProfile;
icm.working = icm.working && p.icm.working == other.icm.working; icm.working = icm.working && p.icm.working == other.icm.working;
icm.output = icm.output && p.icm.output == other.icm.output; icm.output = icm.output && p.icm.output == other.icm.output;
icm.gamma = icm.gamma && p.icm.gamma == other.icm.gamma; icm.gamma = icm.gamma && p.icm.gamma == other.icm.gamma;
@@ -544,6 +546,7 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten
if (resize.enabled) toEdit.resize.enabled = mods.resize.enabled; if (resize.enabled) toEdit.resize.enabled = mods.resize.enabled;
if (icm.input) toEdit.icm.input = mods.icm.input; if (icm.input) toEdit.icm.input = mods.icm.input;
if (icm.blendCMSMatrix) toEdit.icm.blendCMSMatrix = mods.icm.blendCMSMatrix; if (icm.blendCMSMatrix) toEdit.icm.blendCMSMatrix = mods.icm.blendCMSMatrix;
if (icm.preferredProfile) toEdit.icm.preferredProfile = mods.icm.preferredProfile;
if (icm.working) toEdit.icm.working = mods.icm.working; if (icm.working) toEdit.icm.working = mods.icm.working;
if (icm.output) toEdit.icm.output = mods.icm.output; if (icm.output) toEdit.icm.output = mods.icm.output;
//if (icm.gampos) toEdit.icm.gampos = mods.icm.gampos; //if (icm.gampos) toEdit.icm.gampos = mods.icm.gampos;

View File

@@ -303,6 +303,7 @@ class ColorManagementParamsEdited {
public: public:
bool input; bool input;
bool blendCMSMatrix; bool blendCMSMatrix;
bool preferredProfile;
bool working; bool working;
bool output; bool output;
bool gamma; bool gamma;