From 6b842fd4088d43e89fabaa4a013101ccd1edebc4 Mon Sep 17 00:00:00 2001 From: michael Date: Mon, 9 Jul 2012 06:28:15 -0400 Subject: [PATCH] Merge with 4e0f46f25a716ac65a4016bac6284685147b5ec9 (note: color.cc is still in the source tree and CMakeLists.txt) --- rtdata/images/Dark/.gtk-undo-ltr-small.png | Bin 508 -> 0 bytes rtdata/images/Dark/.gtk-undo-ltr.png | Bin 632 -> 0 bytes rtdata/images/Dark/.gtk-undo-rtl-small.png | Bin 501 -> 0 bytes rtdata/images/Dark/.gtk-undo-rtl.png | Bin 623 -> 0 bytes rtdata/images/Light/.gtk-undo-ltr-small.png | Bin 489 -> 0 bytes rtdata/images/Light/.gtk-undo-ltr.png | Bin 610 -> 0 bytes rtdata/images/Light/.gtk-undo-rtl-small.png | Bin 495 -> 0 bytes rtdata/images/Light/.gtk-undo-rtl.png | Bin 613 -> 0 bytes rtdata/languages/default | 2 + rtengine/dcp.cc | 24 ++-- rtengine/dcp.h | 2 +- rtengine/dcrop.cc | 2 +- rtengine/imagesource.h | 3 +- rtengine/improccoordinator.cc | 6 +- rtengine/rawimagesource.cc | 45 ++++---- rtengine/rawimagesource.h | 8 +- rtengine/rtthumbnail.cc | 5 +- rtengine/simpleprocess.cc | 2 +- rtengine/stdimagesource.cc | 2 +- rtengine/stdimagesource.h | 3 +- rtgui/curveeditorgroup.cc | 42 +++---- rtgui/curveeditorgroup.h | 1 + rtgui/editorpanel.cc | 67 ++++++----- rtgui/editorpanel.h | 5 +- rtgui/guiutils.cc | 19 ++- rtgui/guiutils.h | 1 + rtgui/icmpanel.cc | 31 ++++- rtgui/icmpanel.h | 1 + rtgui/options.cc | 5 + rtgui/options.h | 1 + rtgui/profilepanel.cc | 36 ++---- rtgui/profilepanel.h | 6 +- rtgui/saveasdlg.cc | 121 +++++++++++++------- rtgui/saveasdlg.h | 10 +- tools/osx/start | 5 +- 35 files changed, 270 insertions(+), 185 deletions(-) delete mode 100644 rtdata/images/Dark/.gtk-undo-ltr-small.png delete mode 100644 rtdata/images/Dark/.gtk-undo-ltr.png delete mode 100644 rtdata/images/Dark/.gtk-undo-rtl-small.png delete mode 100644 rtdata/images/Dark/.gtk-undo-rtl.png delete mode 100644 rtdata/images/Light/.gtk-undo-ltr-small.png delete mode 100644 rtdata/images/Light/.gtk-undo-ltr.png delete mode 100644 rtdata/images/Light/.gtk-undo-rtl-small.png delete mode 100644 rtdata/images/Light/.gtk-undo-rtl.png diff --git a/rtdata/images/Dark/.gtk-undo-ltr-small.png b/rtdata/images/Dark/.gtk-undo-ltr-small.png deleted file mode 100644 index cf90a87132f8462402eb1bb1d49b643b80f7bbdf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 508 zcmVW?07PUlm&+YlmZkb`!xs<{R7ybp01y#BZ~QQdqPD8~s>(z}&N-%IIOo{&JkGh*YIVu?{heyHdNGdUpU%1c z4MA1iE0@cc0pLXO@*WaVzK6ybGRE+7xlGeE-5U%BA2tL50GJs807N7|hP(w?mH_}L z0BDjVa(H-npsFu>z23WZjo*SI@+6L9|8Kdes)~p-8jUaAZuk3XI~zUxU;F~^Smb_t Sx-kg=0000lnGv9dFj#70RG2$;Lw85=(mlYro5%G2j@7rLZi``7Lh$>UO~jEL8FK)5z&l@bOGSl7;`fO zsMTuAM0ACSb3bnv5kN#prBcYu;+(tB<#PMQVzH|}lOW=WQmSCBePrfK5orxYMLZ;; z4QuU1r_(tz#y9`~1pp95(PAc(Srw62MBMg$|LtdrD2g7ewdcO?-wn>y2Yo?nP5pkq zRW6rD4g&yGDwWf*`t75=Js2fVKTn+G1K00000NkvXXu0mjfBk9PP diff --git a/rtdata/images/Dark/.gtk-undo-rtl.png b/rtdata/images/Dark/.gtk-undo-rtl.png deleted file mode 100644 index db16b9a082aecbcec0cb635befd0535790467362..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 623 zcmV-#0+9WQP)wz>)Rhp*y+<;*i22m8f&$8@#osRoj9*su+WHQ;h)LMJd7;}t>?3{Z! zo6TM)Nn&>bvn;y?0FM#zmWUkGx-5bx43ttNBD@O*0I+ma3j^55AtIgvfEZ)$4u`|b`=I-3 zJ(PaGe>)7rx5gMxjrQ^N-bFwsM$d z+4CR>9vWjjYprAEKeO{!mP7=~viu&$@tv)f0RUR9)=^behk2f#RaNC=SxZn|FcA^A zOzr%7E}^@B07%>$UlOUc_;HvKRQj^&3n0_|zYvFh~FZ002ov JPDHLkV1mCh4XpqG diff --git a/rtdata/images/Light/.gtk-undo-ltr-small.png b/rtdata/images/Light/.gtk-undo-ltr-small.png deleted file mode 100644 index 867095e574a1cc3e4b7a7d43eb58576ce5d0cdbe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 489 zcmV zh~)eJ=Dz@yN@YcBeM3b1e+A$ug4TM6nNJaM$r#f?#Mjj9r?vJaNs{X*iaHYjt+l6= zx@6`JA_8N~_+b!nf?|yM0Dyyfy&gxL`2qFCL$6M1prPqo89$1Z#jQ|mnOH1YO00000NkvXXu0mjf%lOM_ diff --git a/rtdata/images/Light/.gtk-undo-ltr.png b/rtdata/images/Light/.gtk-undo-ltr.png deleted file mode 100644 index 4121f7e7c9a44633c7be874eeacbc987d7f5de1d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 610 zcmV-o0-gPdP)nm{^XW0MRK6D$O6w($puf}KA= zEM#k2ZN+VDw-f6v^bgorC@F-6g~@}U1Z>jesrm4I+_BJvtVvvi92hvvz4y$VJD0%_ z0_+mBEzs?DEh6$x1f6r&(lkA8wOSYcR}fb%BO*KJ9sW#LOrnWUa*wi;OXQ zQ54-FqBqXDds{6#=Q_-MXsvB!S*Ar%9IEOJ5d#1OMAQ%hBH~pMxo@p4&1SP7S(e=$ z37{imv|Z9MtReOG%QXs(QR8C?ZGIYV|Sz{5kYD zHgGh?P!vTx9*=)cr_-Z;zyD!P5CDLPmeq^b|7*Ad0E9G6bu=0cLI^Ls_itAdmV$Yn wKTeV)`d8l&F(9H^Yd@c!o{l!=?E3rq1&?^ncJnS|A^-pY07*qoM6N<$f_+{8ng9R* diff --git a/rtdata/images/Light/.gtk-undo-rtl-small.png b/rtdata/images/Light/.gtk-undo-rtl-small.png deleted file mode 100644 index d6c019ba307a6b267e30661485d1f9dc46323ce2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 495 zcmV#?q>|KPX=7<4 zh^@VqtytLzVkP(w#L9nQV`Xu-h7=MTZIU9%=JsZ6jK-Ki&{sZYzL|Lpi3t89HEUs^ zP^b~nulkt*N~yhKv3OG|m6k_+8a*MG%Pn}Gw@*YB0CQuEHKkNWL^{^m6Rq{_4?wwG z4gg#$rIw~`;W!Q@Ng~$TM`k|IT6bIkAR-Ea;MDj1Y#hhW%zWiIPGhv$T6;u9o7URP zD2mQSBmn>y0P^|#s_*;j0N#7O-cGaG?2k_mg5U|jMHq$;qrUqY&`K(mQiH*uF{v2< zq9{6>1`fw_2@kG4qCq l%uidJnT3d6ew^@EeE?5Au@7C!I9UJy002ovPDHLkV1lg>#p?h7 diff --git a/rtdata/images/Light/.gtk-undo-rtl.png b/rtdata/images/Light/.gtk-undo-rtl.png deleted file mode 100644 index fc948ed731596ee9c50893fad7a5bf1ad3fb3fa1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 613 zcmV-r0-F7aP)Rv}|DNwWd%BttS}oVjz3&1B8QNkG}Jx_^J?`|dp` zB5;wSf4zW+s@Ll|7Y1y#T3(u_?~O6nD+?Zq-0$~mQ52Pm5>bPhzYviXk(Xf@z7~;u zFR;_;G!gMJBHj{_qe>TufQTp}!px`E+Gn%b>yNyS(fG2+6R-#-Fb- zFaUrgNix@UAC1T3PgVQdZ|G^QiJ9#_7yv-ws1gQH?!zGfi063&W6YI9&_g=^lyHbOYsj(;3x}&P3{MXN|5v{OaGC_IU6*TF00000NkvXXu0mjfRjUJN diff --git a/rtdata/languages/default b/rtdata/languages/default index f1dca7c8c..6c841c790 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -203,6 +203,7 @@ GENERAL_PORTRAIT;Portrait GENERAL_SAVE;Save GENERAL_UNCHANGED;(Unchanged) GENERAL_YES;Yes +GENERAL_WARNING;Warning HISTOGRAM_BUTTON_BAR;RGB HISTOGRAM_BUTTON_B;B HISTOGRAM_BUTTON_G;G @@ -805,6 +806,7 @@ SAVEDLG_SAVEIMMEDIATELY;Save immediately SAVEDLG_SAVESPP;Save processing parameters with image SAVEDLG_TIFFFILTER;TIFF files SAVEDLG_TIFFUNCOMPRESSED;Uncompressed TIFF +SAVEDLG_WARNFILENAME;File will be named THRESHOLDSELECTOR_B;Bottom THRESHOLDSELECTOR_BL;Bottom-left THRESHOLDSELECTOR_BR;Bottom-right diff --git a/rtengine/dcp.cc b/rtengine/dcp.cc index a6ffa4e63..60acca23f 100644 --- a/rtengine/dcp.cc +++ b/rtengine/dcp.cc @@ -205,7 +205,7 @@ DCPLightType DCPProfile::GetLightType(short iLightSource) const { return Daylight; } -void DCPProfile::Apply(Imagefloat *pImg, DCPLightType preferredProfile, Glib::ustring workingSpace) const { +void DCPProfile::Apply(Imagefloat *pImg, DCPLightType preferredProfile, Glib::ustring workingSpace, float rawWhiteFac) const { TMatrix mWork = iccStore->workingSpaceInverseMatrix (workingSpace); double mXYZCAM[3][3]; @@ -258,10 +258,12 @@ void DCPProfile::Apply(Imagefloat *pImg, DCPLightType preferredProfile, Glib::us int hueStep = iSatDivisions; int valStep = iHueDivisions * hueStep; + bool useRawWhite=fabs(rawWhiteFac)>0.001; + // Convert to prophoto and apply LUT #pragma omp parallel for for (int y=0; yheight; y++) { - float newr, newg, newb, h,s,v; + float newr, newg, newb, h,s,v,hs,ss,vs; for (int x=0; xwidth; x++) { newr = m2ProPhoto[0][0]*pImg->r[y][x] + m2ProPhoto[0][1]*pImg->g[y][x] + m2ProPhoto[0][2]*pImg->b[y][x]; newg = m2ProPhoto[1][0]*pImg->r[y][x] + m2ProPhoto[1][1]*pImg->g[y][x] + m2ProPhoto[1][2]*pImg->b[y][x]; @@ -272,13 +274,21 @@ void DCPProfile::Apply(Imagefloat *pImg, DCPLightType preferredProfile, Glib::us ImProcFunctions::rgb2hsv(newr, newg, newb, h , s, v); h*=6.f; // RT calculates in [0,1] + if (useRawWhite) { + // Retro-calculate what the point was like before RAW white came in + ImProcFunctions::rgb2hsv(newr/rawWhiteFac, newg/rawWhiteFac, newb/rawWhiteFac, hs, ss, vs); + hs*=6.f; // RT calculates in [0,1] + } else { + hs=h; ss=s; vs=v; + } + // Apply the HueSatMap. Ported from Adobes reference implementation float hueShift, satScale, valScale; if (iValDivisions < 2) // Optimize most common case of "2.5D" table. { - float hScaled = h * hScale; - float sScaled = s * sScale; + float hScaled = hs * hScale; + float sScaled = ss * sScale; int hIndex0 = max((int)hScaled, 0); int sIndex0 = max(min((int)sScaled,maxSatIndex0),0); @@ -329,9 +339,9 @@ void DCPProfile::Apply(Imagefloat *pImg, DCPLightType preferredProfile, Glib::us } else { - float hScaled = h * hScale; - float sScaled = s * sScale; - float vScaled = v * vScale; + float hScaled = hs * hScale; + float sScaled = ss * sScale; + float vScaled = vs * vScale; int hIndex0 = (int) hScaled; int sIndex0 = max(min((int)sScaled,maxSatIndex0),0); diff --git a/rtengine/dcp.h b/rtengine/dcp.h index ea90e4344..bb3ed2c88 100644 --- a/rtengine/dcp.h +++ b/rtengine/dcp.h @@ -57,7 +57,7 @@ namespace rtengine { DCPProfile(Glib::ustring fname); ~DCPProfile(); - void Apply(Imagefloat *pImg, DCPLightType preferredProfile, Glib::ustring workingSpace) const; + void Apply(Imagefloat *pImg, DCPLightType preferredProfile, Glib::ustring workingSpace, float rawWhiteFac=1) const; void Apply(Image16 *pImg, DCPLightType preferredProfile, Glib::ustring workingSpace) const; }; diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 01330dff6..409358184 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -109,7 +109,7 @@ void Crop::update (int todo) { parent->ipf.RGB_denoise(origCrop, origCrop, /*Roffset,*/ params.dirpyrDenoise, params.defringe); } } - parent->imgsrc->convertColorSpace(origCrop, params.icm); + parent->imgsrc->convertColorSpace(origCrop, params.icm, params.raw); } // transform diff --git a/rtengine/imagesource.h b/rtengine/imagesource.h index 7d4374c8f..83c9f2eff 100644 --- a/rtengine/imagesource.h +++ b/rtengine/imagesource.h @@ -91,7 +91,8 @@ class ImageSource : public InitialImage { virtual void getImage (ColorTemp ctemp, int tran, Imagefloat* image, PreviewProps pp, HRecParams hlp, ColorManagementParams cmp, RAWParams raw) {} // true is ready to provide the AutoWB, i.e. when the image has been demosaiced for RawImageSource virtual bool isWBProviderReady () =0; - virtual void convertColorSpace(Imagefloat* image, ColorManagementParams cmp) =0; + + virtual void convertColorSpace(Imagefloat* image, ColorManagementParams cmp, RAWParams raw) =0;// DIRTY HACK: this method is derived in rawimagesource and strimagesource, but (...,RAWParams raw) will be used ONLY for raw images virtual ColorTemp getWB () =0; virtual ColorTemp getAutoWB () =0; virtual ColorTemp getSpotWB (std::vector red, std::vector green, std::vector& blue, int tran) =0; diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 70f394eca..e1be00fcd 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -212,7 +212,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { setScale (scale); imgsrc->getImage (currWB, tr, orig_prev, pp, params.hlrecovery, params.icm, params.raw); - //imgsrc->convertColorSpace(orig_prev, params.icm); + //imgsrc->convertColorSpace(orig_prev, params.icm, params.raw); if (todo & M_LINDENOISE) { //printf("denoising!\n"); @@ -221,7 +221,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) { } ImageMatrices* imatrices = imgsrc->getImageMatrices (); } - imgsrc->convertColorSpace(orig_prev, params.icm); + imgsrc->convertColorSpace(orig_prev, params.icm, params.raw); ipf.firstAnalysis (orig_prev, ¶ms, vhist16, imgsrc->getGamma()); } @@ -644,7 +644,7 @@ void ImProcCoordinator::saveInputICCReference (const Glib::ustring& fname) { params.wb.temperature = currWB.getTemp (); params.wb.green = currWB.getGreen (); imgsrc->getImage (currWB, 0, im, pp, ppar.hlrecovery, ppar.icm, ppar.raw); - imgsrc->convertColorSpace(im, ppar.icm); + imgsrc->convertColorSpace(im, ppar.icm, params.raw); im16 = im->to16(); im16->saveTIFF (fname,16,true); //im->saveJPEG (fname, 85); diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index a73f32b72..0a74a662f 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -423,13 +423,13 @@ void RawImageSource::getImage (ColorTemp ctemp, int tran, Imagefloat* image, Pre if (ri->isBayer() && pp.skip==1) processFalseColorCorrection (image, raw.ccSteps); // *** colorSpaceConversion was here *** - //colorSpaceConversion (image, cmp, embProfile, camProfile, xyz_cam, (static_cast(getMetaData()))->getCamera(), defGain); + //colorSpaceConversion (image, cmp, raw, embProfile, camProfile, xyz_cam, (static_cast(getMetaData()))->getCamera()); } -void RawImageSource::convertColorSpace(Imagefloat* image, ColorManagementParams cmp) { - colorSpaceConversion (image, cmp, embProfile, camProfile, imatrices.xyz_cam, ((const ImageData*)getMetaData())->getCamera(), defGain); +void RawImageSource::convertColorSpace(Imagefloat* image, ColorManagementParams cmp, RAWParams raw) { + colorSpaceConversion (image, cmp, raw, embProfile, camProfile, imatrices.xyz_cam, (static_cast(getMetaData()))->getCamera()); } - + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /* cfaCleanFromMap: correct raw pixels looking at the bitmap @@ -1686,7 +1686,7 @@ void RawImageSource::getProfilePreprocParams(cmsHPROFILE in, float& gammaFac, fl //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // Converts raw image including ICC input profile to working space - floating point version -void RawImageSource::colorSpaceConversion (Imagefloat* im, ColorManagementParams cmp, cmsHPROFILE embedded, cmsHPROFILE camprofile, double camMatrix[3][3], std::string camName, double& defgain) { +void RawImageSource::colorSpaceConversion (Imagefloat* im, ColorManagementParams cmp, RAWParams raw, cmsHPROFILE embedded, cmsHPROFILE camprofile, double camMatrix[3][3], std::string camName) { //MyTime t1, t2, t3; //t1.set (); @@ -1696,7 +1696,7 @@ void RawImageSource::colorSpaceConversion (Imagefloat* im, ColorManagementParams if (!findInputProfile(cmp.input, embedded, camName, &dcpProf, in)) return; if (dcpProf!=NULL) { - dcpProf->Apply(im, (DCPLightType)cmp.preferredProfile, cmp.working); + dcpProf->Apply(im, (DCPLightType)cmp.preferredProfile, cmp.working, (float)raw.expos); } else { // Calculate matrix for direct conversion raw>working space TMatrix work = iccStore->workingSpaceInverseMatrix (cmp.working); @@ -1786,8 +1786,8 @@ void RawImageSource::colorSpaceConversion (Imagefloat* im, ColorManagementParams lcmsMutex->unlock (); if (hTransform) { im->ExecCMSTransform(hTransform); - } - else { + } + else { // create the profile from camera lcmsMutex->lock (); hTransform = cmsCreateTransform (camprofile, TYPE_RGB_FLT, out, TYPE_RGB_FLT, settings->colorimetricIntent, @@ -1795,21 +1795,22 @@ void RawImageSource::colorSpaceConversion (Imagefloat* im, ColorManagementParams lcmsMutex->unlock (); im->ExecCMSTransform(hTransform); - } - float x, y,z; + } Glib::ustring choiceprofile; choiceprofile=cmp.working; if(choiceprofile!="ProPhoto") { - for ( int h = 0; h < im->height; ++h ) - for ( int w = 0; w < im->width; ++w ) {//convert from Prophoto to XYZ - x = (toxyz[0][0] * im->r[h][w] + toxyz[0][1] * im->g[h][w] + toxyz[0][2] * im->b[h][w] ) ; - y = (toxyz[1][0] * im->r[h][w] + toxyz[1][1] * im->g[h][w] + toxyz[1][2] * im->b[h][w] ) ; - z = (toxyz[2][0] * im->r[h][w] + toxyz[2][1] * im->g[h][w] + toxyz[2][2] * im->b[h][w] ) ; - //convert from XYZ to cmp.working (sRGB...Adobe...Wide..) - im->r[h][w] = ((wiprof[0][0]*x + wiprof[0][1]*y + wiprof[0][2]*z)) ; - im->g[h][w] = ((wiprof[1][0]*x + wiprof[1][1]*y + wiprof[1][2]*z)) ; - im->b[h][w] = ((wiprof[2][0]*x + wiprof[2][1]*y + wiprof[2][2]*z)) ; - } + #pragma omp parallel for + for ( int h = 0; h < im->height; ++h ) + for ( int w = 0; w < im->width; ++w ) {//convert from Prophoto to XYZ + float x, y,z; + x = (toxyz[0][0] * im->r[h][w] + toxyz[0][1] * im->g[h][w] + toxyz[0][2] * im->b[h][w] ) ; + y = (toxyz[1][0] * im->r[h][w] + toxyz[1][1] * im->g[h][w] + toxyz[1][2] * im->b[h][w] ) ; + z = (toxyz[2][0] * im->r[h][w] + toxyz[2][1] * im->g[h][w] + toxyz[2][2] * im->b[h][w] ) ; + //convert from XYZ to cmp.working (sRGB...Adobe...Wide..) + im->r[h][w] = ((wiprof[0][0]*x + wiprof[0][1]*y + wiprof[0][2]*z)) ; + im->g[h][w] = ((wiprof[1][0]*x + wiprof[1][1]*y + wiprof[1][2]*z)) ; + im->b[h][w] = ((wiprof[2][0]*x + wiprof[2][1]*y + wiprof[2][2]*z)) ; + } } cmsDeleteTransform(hTransform); @@ -1912,7 +1913,7 @@ void RawImageSource::colorSpaceConversion (Imagefloat* im, ColorManagementParams //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% // Converts raw image including ICC input profile to working space - 16bit int version -void RawImageSource::colorSpaceConversion16 (Image16* im, ColorManagementParams cmp, cmsHPROFILE embedded, cmsHPROFILE camprofile, double camMatrix[3][3], std::string camName, double& defgain) { +void RawImageSource::colorSpaceConversion16 (Image16* im, ColorManagementParams cmp, cmsHPROFILE embedded, cmsHPROFILE camprofile, double camMatrix[3][3], std::string camName) { cmsHPROFILE in; DCPProfile *dcpProf; @@ -2588,7 +2589,7 @@ void RawImageSource::transformPosition (int x, int y, int tran, int& ttx, int& t tty = ty; } } - + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% void RawImageSource::inverse33 (const double (*rgb_cam)[3], double (*cam_rgb)[3]) { diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 299d66a3d..9cf9b4f22 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -154,7 +154,7 @@ class RawImageSource : public ImageSource { ColorTemp getWB () { return wb; } ColorTemp getAutoWB (); ColorTemp getSpotWB (std::vector red, std::vector green, std::vector& blue, int tran); - bool isWBProviderReady () { return rawData != NULL; }; + bool isWBProviderReady () { return rawData != NULL; };//TODO this generates compiler warning: converting to non-pointer type 'long long int' from NULL [-Wconversion-null] double getDefGain () { return defGain; } @@ -170,9 +170,9 @@ class RawImageSource : public ImageSource { void getAutoExpHistogram (LUTu & histogram, int& histcompr); void getRAWHistogram (LUTu & histRedRaw, LUTu & histGreenRaw, LUTu & histBlueRaw); - void convertColorSpace(Imagefloat* image, ColorManagementParams cmp); - static void colorSpaceConversion16 (Image16* im, ColorManagementParams cmp, cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], std::string camName, double& defgain); - static void colorSpaceConversion (Imagefloat* im, ColorManagementParams cmp, cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], std::string camName, double& defgain); + void convertColorSpace(Imagefloat* image, ColorManagementParams cmp, RAWParams raw); + static void colorSpaceConversion16 (Image16* im, ColorManagementParams cmp, cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], std::string camName); + static void colorSpaceConversion (Imagefloat* im, ColorManagementParams cmp, RAWParams raw, cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], std::string camName); static void inverse33 (const double (*coeff)[3], double (*icoeff)[3]); void boxblur2(float** src, float** dst, int H, int W, int box ); diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 01eff2cd9..5715ea737 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -38,9 +38,6 @@ #include "jpeg.h" #include "../rtgui/ppversion.h" -#define MAXVAL 0xffff -#define CLIP(a) ((a)>0?((a)convertColorSpace(baseImg, params.icm); + imgsrc->convertColorSpace(baseImg, params.icm, params.raw); // perform first analysis LUTu hist16 (65536); diff --git a/rtengine/stdimagesource.cc b/rtengine/stdimagesource.cc index 6bbc9d0cd..6ce81ba22 100644 --- a/rtengine/stdimagesource.cc +++ b/rtengine/stdimagesource.cc @@ -310,7 +310,7 @@ void StdImageSource::getImage (ColorTemp ctemp, int tran, Imagefloat* image, Pre t2.set (); } -void StdImageSource::convertColorSpace(Imagefloat* image, ColorManagementParams cmp) { +void StdImageSource::convertColorSpace(Imagefloat* image, ColorManagementParams cmp, RAWParams raw) { colorSpaceConversion (image, cmp, embProfile); } diff --git a/rtengine/stdimagesource.h b/rtengine/stdimagesource.h index 9d80260ea..220fa8ff1 100644 --- a/rtengine/stdimagesource.h +++ b/rtengine/stdimagesource.h @@ -59,7 +59,8 @@ class StdImageSource : public ImageSource { ImageData* getImageData () { return idata; } ImageMatrices* getImageMatrices () { return (ImageMatrices*)NULL; } void setProgressListener (ProgressListener* pl) { plistener = pl; } - void convertColorSpace(Imagefloat* image, ColorManagementParams cmp); + + void convertColorSpace(Imagefloat* image, ColorManagementParams cmp, RAWParams raw);// RAWParams raw will not be used for non-raw files (see imagesource.h) static void colorSpaceConversion (Imagefloat* im, ColorManagementParams cmp, cmsHPROFILE embedded); static void colorSpaceConversion16 (Image16* im, ColorManagementParams cmp, cmsHPROFILE embedded); diff --git a/rtgui/curveeditorgroup.cc b/rtgui/curveeditorgroup.cc index 8ffc6441d..aae30196a 100644 --- a/rtgui/curveeditorgroup.cc +++ b/rtgui/curveeditorgroup.cc @@ -295,13 +295,14 @@ void CurveEditorGroup::setUnChanged (bool uc, CurveEditor* ce) { } CurveEditorSubGroup::CurveEditorSubGroup(Glib::ustring& curveDir) : - curveDir(curveDir) { + curveDir(curveDir), lastFilename("") { } Glib::ustring CurveEditorSubGroup::outputFile () { Gtk::FileChooserDialog dialog(M("CURVEEDITOR_SAVEDLGLABEL"), Gtk::FILE_CHOOSER_ACTION_SAVE); FileChooserLastFolderPersister persister(&dialog, curveDir); + dialog.set_current_name (lastFilename); dialog.add_button(Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL); dialog.add_button(Gtk::StockID("gtk-save"), Gtk::RESPONSE_APPLY); @@ -316,33 +317,22 @@ Glib::ustring CurveEditorSubGroup::outputFile () { filter_any.add_pattern("*"); dialog.add_filter(filter_any); - dialog.set_do_overwrite_confirmation (true); + //dialog.set_do_overwrite_confirmation (true); - Glib::ustring fname; + Glib::ustring fname; do { - int result = dialog.run(); - - fname = dialog.get_filename(); - - if (result==Gtk::RESPONSE_APPLY) { - - if (getExtension (fname)!="rtc") - fname = fname + ".rtc"; - - if (safe_file_test (fname, Glib::FILE_TEST_EXISTS)) { - Glib::ustring msg_ = Glib::ustring("") + fname + ": " + M("MAIN_MSG_ALREADYEXISTS") + "\n" + M("MAIN_MSG_QOVERWRITE") + ""; - Gtk::MessageDialog msgd (msg_, true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true); - int response = msgd.run (); - if (response==Gtk::RESPONSE_YES) - break; - } - else - break; - } - else { - fname = ""; - break; - } + if (dialog.run() == Gtk::RESPONSE_APPLY) { + fname = dialog.get_filename(); + if (getExtension (fname) != "rtc") + fname += ".rtc"; + if (confirmOverwrite (dialog, fname)) { + lastFilename = Glib::path_get_basename (fname); + break; + } + } else { + fname = ""; + break; + } } while (1); return fname; diff --git a/rtgui/curveeditorgroup.h b/rtgui/curveeditorgroup.h index 27c5268df..6cec43e0c 100644 --- a/rtgui/curveeditorgroup.h +++ b/rtgui/curveeditorgroup.h @@ -98,6 +98,7 @@ class CurveEditorSubGroup { private: Glib::ustring& curveDir; + Glib::ustring lastFilename; protected: int valLinear; diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 0f45bd275..01141df55 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -258,7 +258,7 @@ EditorPanel::EditorPanel (FilePanel* filePanel) updateHistogramPosition (0, options.histogramPosition); show_all (); - +/* // save as dialog if (safe_file_test (options.lastSaveAsPath, Glib::FILE_TEST_IS_DIR)) saveAsDialog = new SaveAsDialog (options.lastSaveAsPath); @@ -266,7 +266,7 @@ EditorPanel::EditorPanel (FilePanel* filePanel) saveAsDialog = new SaveAsDialog (safe_get_user_picture_dir()); saveAsDialog->set_default_size (options.saveAsDialogWidth, options.saveAsDialogHeight); - +*/ // connect listeners profilep->setProfileChangeListener (tpc); history->setProfileChangeListener (tpc); @@ -329,7 +329,7 @@ EditorPanel::~EditorPanel () { delete ppframe; delete leftbox; delete vboxright; - delete saveAsDialog; + //delete saveAsDialog; if(catalogPane) delete catalogPane; } @@ -382,6 +382,8 @@ void EditorPanel::open (Thumbnail* tmb, rtengine::InitialImage* isrc) { openThm->increaseRef (); fname=openThm->getFileName(); + //saveAsDialog->setInitialFileName (removeExtension (Glib::path_get_basename (fname))); + lastSaveAsFileName = removeExtension (Glib::path_get_basename (fname)); previewHandler = new PreviewHandler (); @@ -407,7 +409,8 @@ void EditorPanel::open (Thumbnail* tmb, rtengine::InitialImage* isrc) { // initialize profile Glib::ustring defProf = openThm->getType()==FT_Raw ? options.defProfRaw : options.defProfImg; - profilep->initProfile (defProf, ldprof); + profilep->initProfile (defProf, ldprof); + profilep->setInitialFileName (Glib::path_get_basename (fname) + paramFileExtension); openThm->addThumbnailListener (this); info_toggled (); @@ -1016,42 +1019,52 @@ BatchQueueEntry* EditorPanel::createBatchQueueEntry () { void EditorPanel::saveAsPressed () { if (!ipc || !openThm) return; bool fnameOK = false; - Glib::ustring fname; + Glib::ustring fnameOut; + + SaveAsDialog* saveAsDialog; + if (safe_file_test (options.lastSaveAsPath, Glib::FILE_TEST_IS_DIR)) + saveAsDialog = new SaveAsDialog (options.lastSaveAsPath); + else + saveAsDialog = new SaveAsDialog (safe_get_user_picture_dir()); + + saveAsDialog->set_default_size (options.saveAsDialogWidth, options.saveAsDialogHeight); + saveAsDialog->setInitialFileName (lastSaveAsFileName); - saveAsDialog->setInitialFileName (removeExtension (Glib::path_get_basename (openThm->getFileName()))); do { - saveAsDialog->run (); - if (saveAsDialog->getResponse()!=Gtk::RESPONSE_OK) - return; + int result = saveAsDialog->run (); // The SaveAsDialog ensure that a filename has been specified - fname = saveAsDialog->getFileName (); + fnameOut = saveAsDialog->getFileName (); options.lastSaveAsPath = saveAsDialog->getDirectory (); - options.saveAsDialogWidth = saveAsDialog->get_width(); - options.saveAsDialogHeight = saveAsDialog->get_height(); - + options.saveAsDialogWidth = saveAsDialog->get_width (); + options.saveAsDialogHeight = saveAsDialog->get_height (); + options.autoSuffix = saveAsDialog->getAutoSuffix (); + options.saveMethodNum = saveAsDialog->getSaveMethodNum (); + lastSaveAsFileName = Glib::path_get_basename (removeExtension (fnameOut)); SaveFormat sf = saveAsDialog->getFormat (); - options.saveFormat = sf; - options.autoSuffix = saveAsDialog->getAutoSuffix(); + + if (result != Gtk::RESPONSE_OK) + break; if (saveAsDialog->getImmediately ()) { // separate filename and the path to the destination directory - Glib::ustring dstdir = Glib::path_get_dirname (fname); - Glib::ustring dstfname = Glib::path_get_basename (removeExtension(fname)); + Glib::ustring dstdir = Glib::path_get_dirname (fnameOut); + Glib::ustring dstfname = Glib::path_get_basename (removeExtension(fnameOut)); + Glib::ustring dstext = getExtension (fnameOut); if (saveAsDialog->getAutoSuffix()) { Glib::ustring fnameTemp; for (int tries=0; tries<100; tries++) { if (tries==0) - fnameTemp = Glib::ustring::compose ("%1.%2", Glib::build_filename (dstdir, dstfname), sf.format); + fnameTemp = Glib::ustring::compose ("%1.%2", Glib::build_filename (dstdir, dstfname), dstext); else - fnameTemp = Glib::ustring::compose ("%1-%2.%3", Glib::build_filename (dstdir, dstfname), tries, sf.format); + fnameTemp = Glib::ustring::compose ("%1-%2.%3", Glib::build_filename (dstdir, dstfname), tries, dstext); if (!safe_file_test (fnameTemp, Glib::FILE_TEST_EXISTS)) { - fname = fnameTemp; + fnameOut = fnameTemp; fnameOK = true; break; } @@ -1059,13 +1072,7 @@ void EditorPanel::saveAsPressed () { } // check if it exists if (!fnameOK) { - if (safe_file_test (fname, Glib::FILE_TEST_EXISTS)) { - Glib::ustring msg_ = Glib::ustring("") + fname + ": " + M("MAIN_MSG_ALREADYEXISTS") + "\n" + M("MAIN_MSG_QOVERWRITE") + ""; - Gtk::MessageDialog msgd (*parent, msg_, true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true); - int response = msgd.run (); - fnameOK = (response==Gtk::RESPONSE_YES); - } - else fnameOK = true; + fnameOK = confirmOverwrite (*saveAsDialog, fnameOut); } if (fnameOK) { @@ -1076,14 +1083,14 @@ void EditorPanel::saveAsPressed () { ProgressConnector *ld = new ProgressConnector(); ld->startFunc(sigc::bind(sigc::ptr_fun(&rtengine::processImage), job, err, parent->getProgressListener(), options.tunnelMetaData ), - sigc::bind(sigc::mem_fun( *this,&EditorPanel::idle_saveImage ),ld,fname,sf )); + sigc::bind(sigc::mem_fun( *this,&EditorPanel::idle_saveImage ),ld,fnameOut,sf )); saveimgas->set_sensitive(false); sendtogimp->set_sensitive(false); } } else { BatchQueueEntry* bqe = createBatchQueueEntry (); - bqe->outFileName = fname; + bqe->outFileName = fnameOut; bqe->saveFormat = saveAsDialog->getFormat (); parent->addBatchQueueJob (bqe, saveAsDialog->getToHeadOfQueue ()); fnameOK = true; @@ -1091,6 +1098,8 @@ void EditorPanel::saveAsPressed () { // ask parent to redraw file browser // ... or does it automatically when the tab is switched to it } while (!fnameOK); + + saveAsDialog->hide(); } void EditorPanel::queueImgPressed () { diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h index e0e12e999..2d5316aac 100644 --- a/rtgui/editorpanel.h +++ b/rtgui/editorpanel.h @@ -49,6 +49,9 @@ class EditorPanel : public Gtk::VBox, public ThumbnailListener, public HistoryBeforeLineListener, public rtengine::HistogramListener { + private: + + Glib::ustring lastSaveAsFileName; protected: Gtk::ProgressBar *progressLabel; @@ -97,7 +100,7 @@ class EditorPanel : public Gtk::VBox, HistogramPanel* histogramPanel; ToolPanelCoordinator* tpc; RTWindow* parent; - SaveAsDialog* saveAsDialog; + //SaveAsDialog* saveAsDialog; BatchToolPanelCoordinator* btpCoordinator; FilePanel* fPanel; diff --git a/rtgui/guiutils.cc b/rtgui/guiutils.cc index e8b00cee7..1c4fb9683 100644 --- a/rtgui/guiutils.cc +++ b/rtgui/guiutils.cc @@ -20,7 +20,9 @@ #include "guiutils.h" #include "options.h" #include "../rtengine/utils.h" +#include "../rtengine/safegtk.h" #include "rtimage.h" +#include "multilangmgr.h" #include @@ -53,7 +55,8 @@ Glib::ustring removeExtension (const Glib::ustring& filename) { Glib::ustring bname = Glib::path_get_basename(filename); size_t lastdot = bname.find_last_of ('.'); - if (lastdot!=bname.npos) + size_t lastwhitespace = bname.find_last_of (" \t\f\v\n\r"); + if (lastdot!=bname.npos && (lastwhitespace==bname.npos || lastdot > lastwhitespace)) return filename.substr (0, filename.size()-(bname.size()-lastdot)); else return filename; @@ -63,12 +66,24 @@ Glib::ustring getExtension (const Glib::ustring& filename) { Glib::ustring bname = Glib::path_get_basename(filename); size_t lastdot = bname.find_last_of ('.'); - if (lastdot!=bname.npos) + size_t lastwhitespace = bname.find_last_of (" \t\f\v\n\r"); + if (lastdot!=bname.npos && (lastwhitespace==bname.npos || lastdot > lastwhitespace)) return filename.substr (filename.size()-(bname.size()-lastdot)+1, filename.npos); else return ""; } +bool confirmOverwrite (Gtk::Window& parent, const std::string& filename) { + bool safe = true; + if (safe_file_test (filename, Glib::FILE_TEST_EXISTS)) { + Glib::ustring msg_ = Glib::ustring ("\"") + Glib::path_get_basename (filename) + "\": " + + M("MAIN_MSG_ALREADYEXISTS") + "\n" + M("MAIN_MSG_QOVERWRITE"); + Gtk::MessageDialog msgd (parent, msg_, true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true); + safe = (msgd.run () == Gtk::RESPONSE_YES); + } + return safe; +} + void drawCrop (Cairo::RefPtr cr, int imx, int imy, int imw, int imh, int startx, int starty, double scale, const rtengine::procparams::CropParams& cparams) { cr->set_line_width (0.); diff --git a/rtgui/guiutils.h b/rtgui/guiutils.h index 9bbeef28c..1f48502b5 100644 --- a/rtgui/guiutils.h +++ b/rtgui/guiutils.h @@ -26,6 +26,7 @@ bool removeIfThere (Gtk::Container* cont, Gtk::Widget* w, bool increference=true void thumbInterp (const unsigned char* src, int sw, int sh, unsigned char* dst, int dw, int dh); Glib::ustring removeExtension (const Glib::ustring& filename); Glib::ustring getExtension (const Glib::ustring& filename); +bool confirmOverwrite (Gtk::Window& parent, const std::string& filename); void drawCrop (Cairo::RefPtr cr, int imx, int imy, int imw, int imh, int startx, int starty, double scale, const rtengine::procparams::CropParams& cparams); /** diff --git a/rtgui/icmpanel.cc b/rtgui/icmpanel.cc index dc77bc980..14f87baec 100644 --- a/rtgui/icmpanel.cc +++ b/rtgui/icmpanel.cc @@ -30,7 +30,7 @@ using namespace rtengine::procparams; extern Options options; -ICMPanel::ICMPanel () : Gtk::VBox(), FoldableToolPanel(this), iunchanged(NULL), icmplistener(NULL) { +ICMPanel::ICMPanel () : Gtk::VBox(), FoldableToolPanel(this), iunchanged(NULL), icmplistener(NULL), lastRefFilename("") { // set_border_width (4); @@ -484,6 +484,7 @@ void ICMPanel::saveReferencePressed () { return; Gtk::FileChooserDialog dialog(M("TP_ICM_SAVEREFERENCEDLGLABEL"), Gtk::FILE_CHOOSER_ACTION_SAVE); FileChooserLastFolderPersister persister(&dialog, options.lastProfilingReferenceDir); + dialog.set_current_name (lastRefFilename); dialog.add_button(Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL); dialog.add_button(Gtk::StockID("gtk-save"), Gtk::RESPONSE_OK); @@ -491,12 +492,34 @@ void ICMPanel::saveReferencePressed () { Gtk::FileFilter filter_tif; filter_tif.set_name(M("SAVEDLG_TIFFFILTER")); filter_tif.add_pattern("*.tif"); + filter_tif.add_pattern("*.tiff"); dialog.add_filter(filter_tif); - dialog.set_do_overwrite_confirmation (true); + Gtk::FileFilter filter_any; + filter_any.set_name(M("TP_ICM_FILEDLGFILTERANY")); + filter_any.add_pattern("*"); + dialog.add_filter(filter_any); - if (dialog.run()==Gtk::RESPONSE_OK) - icmplistener->saveInputICCReference (dialog.get_filename()); + //dialog.set_do_overwrite_confirmation (true); + + bool done = false; + do { + int result = dialog.run(); + if (result != Gtk::RESPONSE_OK) { + done = true; + } else { + std::string fname = dialog.get_filename(); + Glib::ustring ext = getExtension(fname); + if (ext != "tif" && ext != "tiff") + fname += ".tif"; + if (confirmOverwrite(dialog, fname)) { + icmplistener->saveInputICCReference (fname); + lastRefFilename = Glib::path_get_basename (fname); + done = true; + } + } + } while (!done); + return; } void ICMPanel::setBatchMode (bool batchMode) { diff --git a/rtgui/icmpanel.h b/rtgui/icmpanel.h index 4b3fc33a8..63fef53d5 100644 --- a/rtgui/icmpanel.h +++ b/rtgui/icmpanel.h @@ -68,6 +68,7 @@ class ICMPanel : public Gtk::VBox, public AdjusterListener, public FoldableToolP ICMPanelListener* icmplistener; bool enableLastICCWorkDirChange; + Glib::ustring lastRefFilename; public: ICMPanel (); diff --git a/rtgui/options.cc b/rtgui/options.cc index 30a433851..7135f7f3c 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -190,6 +190,8 @@ void Options::setDefaults () { windowWidth = 900; windowHeight = 560; windowMaximized = false; + saveAsDialogWidth = 600; + saveAsDialogHeight = 600; savesParamsAtExit = true; saveFormat.format = "jpg"; saveFormat.jpegQuality = 100; @@ -262,6 +264,7 @@ void Options::setDefaults () { thumbnailFormat = FT_Custom; // was FT_Custom16 thumbInterp = 1; autoSuffix = false; + saveMethodNum = 0; // 0->immediate, 1->putToQueuHead, 2->putToQueueTail saveParamsFile = true; // was false, but saving the procparams files next to the file make more sense when reorganizing file tree than in a cache saveParamsCache = false; // there's no need to save the procparams files in a cache if saveParamsFile is true paramsLoadLocation = PLL_Input; // was PLL_Cache @@ -517,6 +520,7 @@ if (keyFile.has_group ("Output")) { if (keyFile.has_key ("Output", "PathTemplate")) savePathTemplate = keyFile.get_string ("Output", "PathTemplate"); if (keyFile.has_key ("Output", "PathFolder")) savePathFolder = keyFile.get_string ("Output", "PathFolder"); if (keyFile.has_key ("Output", "AutoSuffix")) autoSuffix = keyFile.get_boolean("Output", "AutoSuffix"); + if (keyFile.has_key ("Output", "SaveMethodNum")) saveMethodNum = keyFile.get_integer("Output", "SaveMethodNum"); if (keyFile.has_key ("Output", "UsePathTemplate")) saveUsePathTemplate = keyFile.get_boolean("Output", "UsePathTemplate"); if (keyFile.has_key ("Output", "LastSaveAsPath")) lastSaveAsPath = keyFile.get_string ("Output", "LastSaveAsPath"); if (keyFile.has_key ("Output", "OverwriteOutputFile")) overwriteOutputFile = keyFile.get_boolean("Output", "OverwriteOutputFile"); @@ -796,6 +800,7 @@ int Options::saveToFile (Glib::ustring fname) { keyFile.set_string ("Output", "PathTemplate", savePathTemplate); keyFile.set_string ("Output", "PathFolder", savePathFolder); keyFile.set_boolean ("Output", "AutoSuffix", autoSuffix); + keyFile.set_integer ("Output", "SaveMethodNum", saveMethodNum); keyFile.set_boolean ("Output", "UsePathTemplate", saveUsePathTemplate); keyFile.set_string ("Output", "LastSaveAsPath", lastSaveAsPath); keyFile.set_boolean ("Output", "OverwriteOutputFile", overwriteOutputFile); diff --git a/rtgui/options.h b/rtgui/options.h index 3eba1a8f1..2f586c34a 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -140,6 +140,7 @@ class Options { bool useSystemTheme; static Glib::ustring cacheBaseDir; bool autoSuffix; + int saveMethodNum; bool saveParamsFile; bool saveParamsCache; PPLoadLocation paramsLoadLocation; diff --git a/rtgui/profilepanel.cc b/rtgui/profilepanel.cc index 8885ad742..de02e9ae2 100644 --- a/rtgui/profilepanel.cc +++ b/rtgui/profilepanel.cc @@ -40,7 +40,7 @@ void ProfilePanel::cleanup () { delete partialProfileDlg; } -ProfilePanel::ProfilePanel (bool readOnly) { +ProfilePanel::ProfilePanel (bool readOnly) : lastFilename("") { tpc = NULL; @@ -126,6 +126,7 @@ void ProfilePanel::save_clicked (GdkEventButton* event) { Gtk::FileChooserDialog dialog(M("PROFILEPANEL_SAVEDLGLABEL"), Gtk::FILE_CHOOSER_ACTION_SAVE); FileChooserLastFolderPersister persister( &dialog, options.loadSaveProfilePath ); + dialog.set_current_name (lastFilename); //Add response buttons the the dialog: dialog.add_button(Gtk::StockID("gtk-cancel"), Gtk::RESPONSE_CANCEL); @@ -145,39 +146,20 @@ void ProfilePanel::save_clicked (GdkEventButton* event) { // dialog.set_do_overwrite_confirmation (true); - savedialog = &dialog; - bool done = false; do { - int result = dialog.run(); - dialog.hide(); - - if (result==Gtk::RESPONSE_OK) { + if (dialog.run()==Gtk::RESPONSE_OK) { std::string fname = dialog.get_filename(); + Glib::ustring ext = getExtension (fname); - bool hasext = true; - size_t dotpos = fname.find_last_of ('.'); - if (dotpos==Glib::ustring::npos) - hasext = false; - size_t dirpos1 = fname.find_last_of ('/'); - if (dirpos1!=Glib::ustring::npos && dirpos1>dotpos) - hasext = false; - size_t dirpos2 = fname.find_last_of ('\\'); - if (dirpos2!=Glib::ustring::npos && dirpos2>dotpos) - hasext = false; + if (("." + ext) != paramFileExtension) + fname += paramFileExtension; - if (!hasext) - fname = fname + paramFileExtension; + if (!confirmOverwrite (dialog, fname)) + continue; - if (safe_file_test (fname, Glib::FILE_TEST_EXISTS)) { - Glib::ustring msg_ = Glib::ustring("") + fname + ": " + M("MAIN_MSG_ALREADYEXISTS") + "\n" + M("MAIN_MSG_QOVERWRITE") + ""; - Gtk::MessageDialog msgd (msg_, true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_YES_NO, true); - int response = msgd.run (); - if (response==Gtk::RESPONSE_NO) - // make another try - continue; - } + lastFilename = Glib::path_get_basename (fname); PartialProfile* toSave = NULL; if (profiles->get_active_text() == Glib::ustring("(") + M("PROFILEPANEL_PCUSTOM") + ")") diff --git a/rtgui/profilepanel.h b/rtgui/profilepanel.h index b9677e8e1..e2bf6cd9c 100644 --- a/rtgui/profilepanel.h +++ b/rtgui/profilepanel.h @@ -29,6 +29,10 @@ class ProfilePanel : public Gtk::VBox, public PParamsChangeListener { + private: + + Glib::ustring lastFilename; + protected: static PartialPasteDlg* partialProfileDlg; @@ -44,7 +48,6 @@ class ProfilePanel : public Gtk::VBox, public PParamsChangeListener { ProfileChangeListener* tpc; bool dontupdate; sigc::connection changeconn; - Gtk::FileChooserDialog* savedialog; void changeTo (rtengine::procparams::PartialProfile* newpp, Glib::ustring profname); void refreshProfileList (); @@ -60,6 +63,7 @@ class ProfilePanel : public Gtk::VBox, public PParamsChangeListener { static void cleanup (); void initProfile (const Glib::ustring& profname, rtengine::procparams::ProcParams* lastSaved); + void setInitialFileName (const Glib::ustring& filename) {lastFilename = filename;} // PParamsChangeListener interface void procParamsChanged (rtengine::procparams::ProcParams* params, rtengine::ProcEvent ev, Glib::ustring descr, ParamsEdited* paramsEdited=NULL); diff --git a/rtgui/saveasdlg.cc b/rtgui/saveasdlg.cc index df3bdaa89..e5eccb67a 100644 --- a/rtgui/saveasdlg.cc +++ b/rtgui/saveasdlg.cc @@ -31,60 +31,52 @@ SaveAsDialog::SaveAsDialog (Glib::ustring initialDir) { fchooser = Gtk::manage( new Gtk::FileChooserWidget (Gtk::FILE_CHOOSER_ACTION_SAVE) ); fchooser->set_current_folder (initialDir); + fchooser->signal_file_activated().connect(sigc::mem_fun(*this,&SaveAsDialog::okPressed)); filter_jpg.set_name(M("SAVEDLG_JPGFILTER")); filter_jpg.add_pattern("*.jpg"); + filter_jpg.add_pattern("*.JPG"); + filter_jpg.add_pattern("*.jpeg"); + filter_jpg.add_pattern("*.JPEG"); + filter_jpg.add_pattern("*.jpe"); + filter_jpg.add_pattern("*.JPE"); filter_tif.set_name(M("SAVEDLG_JPGFILTER")); filter_tif.add_pattern("*.tif"); + filter_tif.add_pattern("*.TIF"); + filter_tif.add_pattern("*.tiff"); + filter_tif.add_pattern("*.TIFF"); filter_png.set_name(M("SAVEDLG_JPGFILTER")); filter_png.add_pattern("*.png"); + filter_png.add_pattern("*.PNG"); - vbox->pack_start (*fchooser); - - Gtk::HSeparator* hsep1 = Gtk::manage( new Gtk::HSeparator () ); - vbox->pack_start (*hsep1, Gtk::PACK_SHRINK, 2); + formatChanged (options.saveFormat.format); // Unique filename option // ~~~~~~~~~~~~~~~~~~~~~~ autoSuffix = Gtk::manage( new Gtk::CheckButton (M("SAVEDLG_AUTOSUFFIX")) ); autoSuffix->set_active(options.autoSuffix); - vbox->pack_start (*autoSuffix, Gtk::PACK_SHRINK, 4); - - Gtk::HSeparator* hsep2 = Gtk::manage( new Gtk::HSeparator () ); - vbox->pack_start (*hsep2, Gtk::PACK_SHRINK, 2); - // Output Options // ~~~~~~~~~~~~~~ formatOpts = Gtk::manage( new SaveFormatPanel () ); formatOpts->init (options.saveFormat); formatOpts->setListener (this); - vbox->pack_start (*formatOpts, Gtk::PACK_SHRINK, 4); - - Gtk::HSeparator* hsep3 = Gtk::manage( new Gtk::HSeparator () ); - vbox->pack_start (*hsep3, Gtk::PACK_SHRINK, 2); - // queue/immediate // ~~~~~~~~~~~~~ - immediately = Gtk::manage( new Gtk::RadioButton (M("SAVEDLG_SAVEIMMEDIATELY")) ); - putToQueueHead = Gtk::manage( new Gtk::RadioButton (M("SAVEDLG_PUTTOQUEUEHEAD")) ); - putToQueueTail = Gtk::manage( new Gtk::RadioButton (M("SAVEDLG_PUTTOQUEUETAIL")) ); + saveMethod[0] = Gtk::manage( new Gtk::RadioButton (M("SAVEDLG_SAVEIMMEDIATELY")) ); + saveMethod[1] = Gtk::manage( new Gtk::RadioButton (M("SAVEDLG_PUTTOQUEUEHEAD")) ); + saveMethod[2] = Gtk::manage( new Gtk::RadioButton (M("SAVEDLG_PUTTOQUEUETAIL")) ); - // There is no queue in simple mode, so no need to choose - if (!simpleEditor) { - vbox->pack_start (*immediately, Gtk::PACK_SHRINK, 4); - vbox->pack_start (*putToQueueHead, Gtk::PACK_SHRINK, 4); - vbox->pack_start (*putToQueueTail, Gtk::PACK_SHRINK, 4); - } + Gtk::RadioButton::Group g = saveMethod[0]->get_group(); + saveMethod[1]->set_group (g); + saveMethod[2]->set_group (g); + + if (options.saveMethodNum >= 0 && options.saveMethodNum < 3) + saveMethod[options.saveMethodNum]->set_active (true); - immediately->set_active (true); - Gtk::RadioButton::Group g = immediately->get_group(); - putToQueueHead->set_group (g); - putToQueueTail->set_group (g); - // buttons // ~~~~~~ Gtk::Button* ok = Gtk::manage( new Gtk::Button (M("GENERAL_OK")) ); @@ -96,11 +88,32 @@ SaveAsDialog::SaveAsDialog (Glib::ustring initialDir) { ok->signal_clicked().connect( sigc::mem_fun(*this, &SaveAsDialog::okPressed) ); cancel->signal_clicked().connect( sigc::mem_fun(*this, &SaveAsDialog::cancelPressed) ); +// pack everything +// ~~~~~~~~~~~~~~~ + Gtk::VBox* vbox_bottomRight = Gtk::manage(new Gtk::VBox ()); + // There is no queue in simple mode, so no need to choose + if (!simpleEditor) { + vbox_bottomRight->pack_start (*saveMethod[0], Gtk::PACK_SHRINK, 2); + vbox_bottomRight->pack_start (*saveMethod[1], Gtk::PACK_SHRINK, 2); + vbox_bottomRight->pack_start (*saveMethod[2], Gtk::PACK_SHRINK, 2); + vbox_bottomRight->pack_start (*Gtk::manage(new Gtk::HSeparator ()), Gtk::PACK_SHRINK, 5); + } + vbox_bottomRight->pack_start (*autoSuffix, Gtk::PACK_SHRINK, 4); + + Gtk::HBox* hbox_bottom = Gtk::manage( new Gtk::HBox() ); + hbox_bottom->pack_start (*formatOpts, Gtk::PACK_SHRINK, 2); + hbox_bottom->pack_start (*Gtk::manage(new Gtk::VSeparator ()), Gtk::PACK_SHRINK, 2); + hbox_bottom->pack_start (*vbox_bottomRight, Gtk::PACK_SHRINK, 2); + + vbox->pack_start (*fchooser); + vbox->pack_start (*hbox_bottom, Gtk::PACK_SHRINK, 2); + get_action_area()->pack_end (*ok, Gtk::PACK_SHRINK, 4); get_action_area()->pack_end (*cancel, Gtk::PACK_SHRINK, 4); set_border_width (4); show_all_children (); + } bool SaveAsDialog::getAutoSuffix () { @@ -110,26 +123,29 @@ bool SaveAsDialog::getAutoSuffix () { bool SaveAsDialog::getImmediately () { - return immediately->get_active (); + return saveMethod[0]->get_active (); } bool SaveAsDialog::getToHeadOfQueue () { - return putToQueueHead->get_active (); + return saveMethod[1]->get_active (); } bool SaveAsDialog::getToTailOfQueue () { - return putToQueueTail->get_active (); + return saveMethod[2]->get_active (); +} + +int SaveAsDialog::getSaveMethodNum () { + for (int i = 0; i < 3; i++) + if (saveMethod[i]->get_active()) + return i; + return -1; } Glib::ustring SaveAsDialog::getFileName () { - // fname is empty if the dialog has been cancelled - if (fname.length()) - return removeExtension(fname) + Glib::ustring(".") + formatOpts->getFormat().format; - else - return ""; + return fname; } Glib::ustring SaveAsDialog::getDirectory () { @@ -155,15 +171,38 @@ void SaveAsDialog::okPressed () { msgd.run (); return; } - response = Gtk::RESPONSE_OK; - hide (); + + // resolve extension ambiguities + SaveFormat sf = formatOpts->getFormat (); + Glib::ustring extLower = getExtension (fname).lowercase (); + bool extIsEmpty = (extLower == ""); + bool extIsJpeg = (extLower == "jpg" || extLower == "jpeg" || extLower == "jpe"); + bool extIsTiff = (extLower == "tif" || extLower == "tiff"); + bool extIsPng = (extLower == "png"); + if (extIsEmpty || !(extIsJpeg || extIsTiff || extIsPng)) { + // extension is either empty or unfamiliar. + fname += Glib::ustring (".") + sf.format; + } else if ( !(sf.format == "jpg" && extIsJpeg) + && !(sf.format == "tif" && extIsTiff) + && !(sf.format == "png" && extIsPng ) ) { + // create dialog to warn user that the filename may have two extensions on the end. + Glib::ustring msg_ = Glib::ustring ("") + M("GENERAL_WARNING") + ": " + + M("SAVEDLG_WARNFILENAME") + " \"" + Glib::path_get_basename (fname) + + "." + sf.format + "\""; + Gtk::MessageDialog msgd (*this, msg_, true, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK_CANCEL, true); + if (msgd.run () == Gtk::RESPONSE_OK) + fname += Glib::ustring (".") + sf.format; + else + return; + } + + response (Gtk::RESPONSE_OK); } void SaveAsDialog::cancelPressed () { - fname = ""; - response = Gtk::RESPONSE_CANCEL; - hide (); + fname = fchooser->get_filename(); + response (Gtk::RESPONSE_CANCEL); } void SaveAsDialog::formatChanged (Glib::ustring f) { diff --git a/rtgui/saveasdlg.h b/rtgui/saveasdlg.h index 38508d5ba..1570a95ab 100644 --- a/rtgui/saveasdlg.h +++ b/rtgui/saveasdlg.h @@ -34,10 +34,10 @@ class SaveAsDialog : public Gtk::Dialog, public FormatChangeListener { Gtk::FileFilter filter_jpg; Gtk::FileFilter filter_tif; Gtk::FileFilter filter_png; - Gtk::RadioButton* immediately; - Gtk::RadioButton* putToQueueHead; - Gtk::RadioButton* putToQueueTail; - Gtk::ResponseType response; + Gtk::RadioButton* saveMethod[3]; /* 0 -> immediately + * 1 -> putToQueueHead + * 2 -> putToQueueTail + */ public: SaveAsDialog (Glib::ustring initialDir); @@ -49,9 +49,9 @@ class SaveAsDialog : public Gtk::Dialog, public FormatChangeListener { bool getImmediately (); bool getToHeadOfQueue (); bool getToTailOfQueue (); + int getSaveMethodNum (); void setInitialFileName (Glib::ustring iname); - Gtk::ResponseType getResponse () { return response; }; void okPressed (); void cancelPressed (); diff --git a/tools/osx/start b/tools/osx/start index fe0024178..b6f40ca65 100755 --- a/tools/osx/start +++ b/tools/osx/start @@ -14,7 +14,6 @@ export GTK_IM_MODULE_FILE="${CWD}/gtk-2.0/gtk.immodules" export GDK_PIXBUF_MODULE_FILE="${CWD}/etc/gtk-2.0/gdk-pixbuf.loaders" export PANGO_RC_FILE="${CWD}/etc/pango/pangorc" -cp "${CWD}/etc/pango/pango.modules" /tmp/rt_pango.modules - -"${CWD}/rt" +cp "${CWD}/etc/pango/pango.modules" /tmp/rawtherapee_pango.modules +"${CWD}/rawtherapee"