diff --git a/rtdata/languages/default b/rtdata/languages/default index 0bc981b8d..a556c1ebd 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1296,6 +1296,10 @@ PREFERENCES_TAB_IMPROC;Image Processing PREFERENCES_TAB_PERFORMANCE;Performance & Quality PREFERENCES_TAB_SOUND;Sounds PREFERENCES_THEME;Theme +PREFERENCES_THUMBNAIL_INSPECTOR_JPEG;Embedded JPEG preview +PREFERENCES_THUMBNAIL_INSPECTOR_MODE;Image to show +PREFERENCES_THUMBNAIL_INSPECTOR_RAW;Neutral raw rendering +PREFERENCES_THUMBNAIL_INSPECTOR_RAW_IF_NO_JPEG_FULLSIZE;Embedded JPEG if fullsize, neutral raw otherwise PREFERENCES_TIMAX;High PREFERENCES_TINB;Number of tiles PREFERENCES_TISTD;Standard diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc index 7d82b68a1..afe54200a 100644 --- a/rtengine/dcraw.cc +++ b/rtengine/dcraw.cc @@ -6386,6 +6386,26 @@ guess_cfa_pc: ((int *)mask)[i] = getint(type); black = 0; break; + case 51008: /* OpcodeList1 */ + { + unsigned oldOrder = order; + order = 0x4d4d; // always big endian per definition in https://www.adobe.com/content/dam/acom/en/products/photoshop/pdfs/dng_spec_1.4.0.0.pdf chapter 7 + unsigned ntags = get4(); // read the number of opcodes + while (ntags--) { + unsigned opcode = get4(); + fseek (ifp, 8, SEEK_CUR); // skip 8 bytes as they don't interest us currently + if (opcode == 4) { // FixBadPixelsConstant + fseek (ifp, 4, SEEK_CUR); // skip 4 bytes as we know that the opcode 4 takes 4 byte + if(get4() == 0) { // if raw 0 values should be treated as bad pixels, set zero_is_bad to true (1). That's the only value currently supported by rt + zero_is_bad = 1; + } + } else { + fseek (ifp, get4(), SEEK_CUR); + } + } + order = oldOrder; + break; + } case 51009: /* OpcodeList2 */ meta_offset = ftell(ifp); break; diff --git a/rtengine/hilite_recon.cc b/rtengine/hilite_recon.cc index b8ad23e70..636ffdc80 100644 --- a/rtengine/hilite_recon.cc +++ b/rtengine/hilite_recon.cc @@ -28,6 +28,8 @@ #include "rawimagesource.h" #include "rt_math.h" #include "opthelper.h" +#include "gauss.h" + namespace rtengine { @@ -412,6 +414,9 @@ void RawImageSource :: HLRecovery_inpaint (float** red, float** green, float** b constexpr float itrans[ColorCount][ColorCount] = { { 1.f, 0.8660254f, -0.5f }, { 1.f, -0.8660254f, -0.5f }, { 1.f, 0.f, 1.f } }; + std::unique_ptr recovered_partial; + std::unique_ptr recovered_full; + if(settings->verbose) for(int c = 0; c < 3; c++) { printf("chmax[%d] : %f\tclmax[%d] : %f\tratio[%d] : %f\n", c, chmax[c], c, clmax[c], c, chmax[c] / clmax[c]); @@ -566,7 +571,7 @@ void RawImageSource :: HLRecovery_inpaint (float** red, float** green, float** b //blur highlight data boxblur2(hilite_full[3], hilite_full4, temp, height, width, 1); - temp.free(); // free temporary buffer + //temp.free(); // free temporary buffer if(plistener) { progress += 0.05; @@ -1104,30 +1109,40 @@ void RawImageSource :: HLRecovery_inpaint (float** red, float** green, float** b //now correct clipped channels if (pixel[0] > max_f[0] && pixel[1] > max_f[1] && pixel[2] > max_f[2]) { //all channels clipped - float Y = (0.299 * clipfix[0] + 0.587 * clipfix[1] + 0.114 * clipfix[2]); - - float factor = whitept / Y; - red[i][j] = clipfix[0] * factor; - green[i][j] = clipfix[1] * factor; - blue[i][j] = clipfix[2] * factor; + // float Y = (0.299 * clipfix[0] + 0.587 * clipfix[1] + 0.114 * clipfix[2]); + // float factor = whitept / Y; + // red[i][j] = CLIP(clipfix[0] * factor); + // green[i][j] = CLIP(clipfix[1] * factor); + // blue[i][j] = CLIP(clipfix[2] * factor); + red[i][j] = green[i][j] = blue[i][j] = whitept; + if (!recovered_full) { + recovered_full.reset(new PixelsMap(width, height)); + } + recovered_full->set(j, i); + } else {//some channels clipped float notclipped[3] = {pixel[0] <= max_f[0] ? 1.f : 0.f, pixel[1] <= max_f[1] ? 1.f : 0.f, pixel[2] <= max_f[2] ? 1.f : 0.f}; if (notclipped[0] == 0.f) { //red clipped - red[i][j] = max(red[i][j], (clipfix[0] * ((notclipped[1] * pixel[1] + notclipped[2] * pixel[2]) / + red[i][j] = CLIP((clipfix[0] * ((notclipped[1] * pixel[1] + notclipped[2] * pixel[2]) / (notclipped[1] * clipfix[1] + notclipped[2] * clipfix[2] + epsilon)))); } if (notclipped[1] == 0.f) { //green clipped - green[i][j] = max(green[i][j], (clipfix[1] * ((notclipped[2] * pixel[2] + notclipped[0] * pixel[0]) / + green[i][j] = CLIP((clipfix[1] * ((notclipped[2] * pixel[2] + notclipped[0] * pixel[0]) / (notclipped[2] * clipfix[2] + notclipped[0] * clipfix[0] + epsilon)))); } if (notclipped[2] == 0.f) { //blue clipped - blue[i][j] = max(blue[i][j], (clipfix[2] * ((notclipped[0] * pixel[0] + notclipped[1] * pixel[1]) / + blue[i][j] = CLIP((clipfix[2] * ((notclipped[0] * pixel[0] + notclipped[1] * pixel[1]) / (notclipped[0] * clipfix[0] + notclipped[1] * clipfix[1] + epsilon)))); } - } + + if (!recovered_partial) { + recovered_partial.reset(new PixelsMap(width, height)); + } + recovered_partial->set(j, i); + } Y = (0.299 * red[i][j] + 0.587 * green[i][j] + 0.114 * blue[i][j]); @@ -1141,6 +1156,54 @@ void RawImageSource :: HLRecovery_inpaint (float** red, float** green, float** b } } + { + for (int c = 0; c < 3; ++c) { + float **color = c == 0 ? red : c == 1 ? green : blue; + + if (recovered_partial) { +#ifdef _OPENMP + #pragma omp parallel +#endif + gaussianBlur(color, temp, width, height, 1.5f); + +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int i = 0; i < height; ++i) { + for (int j = 0; j < width; ++j) { + int skip = recovered_partial->skipIfZero(j, i); + if (skip) { + j += skip-1; + } else if (recovered_partial->get(j, i)) { + color[i][j] = temp[i][j]; + } + } + } + } + + if (recovered_full) { +#ifdef _OPENMP + #pragma omp parallel +#endif + gaussianBlur(color, temp, width, height, 3.f); + +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int i = 0; i < height; ++i) { + for (int j = 0; j < width; ++j) { + int skip = recovered_full->skipIfZero(j, i); + if (skip) { + j += skip-1; + } else if (recovered_full->get(j, i)) { + color[i][j] = temp[i][j]; + } + } + } + } + } + } + if(plistener) { plistener->setProgress(1.00); } diff --git a/rtengine/histmatching.cc b/rtengine/histmatching.cc index d63428738..0faa8c357 100644 --- a/rtengine/histmatching.cc +++ b/rtengine/histmatching.cc @@ -219,7 +219,7 @@ void RawImageSource::getAutoMatchedToneCurve(const ColorManagementParams &cp, st RawMetaDataLocation rml; eSensorType sensor_type; int w, h; - std::unique_ptr thumb(Thumbnail::loadQuickFromRaw(getFileName(), rml, sensor_type, w, h, 1, false, true)); + std::unique_ptr thumb(Thumbnail::loadQuickFromRaw(getFileName(), rml, sensor_type, w, h, 1, false, true, true)); if (!thumb) { if (settings->verbose) { std::cout << "histogram matching: no thumbnail found, generating a neutral curve" << std::endl; @@ -227,6 +227,13 @@ void RawImageSource::getAutoMatchedToneCurve(const ColorManagementParams &cp, st histMatchingCache = outCurve; histMatchingParams = cp; return; + } else if (w * 10 < fw) { + if (settings->verbose) { + std::cout << "histogram matching: the embedded thumbnail is too small: " << w << "x" << h << std::endl; + } + histMatchingCache = outCurve; + histMatchingParams = cp; + return; } skip = LIM(skip * fh / h, 6, 10); // adjust the skip factor -- the larger the thumbnail, the less we should skip to get a good match source.reset(thumb->quickProcessImage(neutral, fh / skip, TI_Nearest)); diff --git a/rtengine/rawimage.cc b/rtengine/rawimage.cc index 0706ebec7..6ead97c2f 100644 --- a/rtengine/rawimage.cc +++ b/rtengine/rawimage.cc @@ -461,7 +461,7 @@ int RawImage::loadRaw(bool loadData, unsigned int imageNum, bool closeFile, Prog } if (!strcmp(make, "Fujifilm") && raw_height * raw_width * 2u != raw_size) { - if (raw_width * raw_height * 7 / 4 == raw_size) { + if (raw_width * raw_height * 7u / 4u == raw_size) { load_raw = &RawImage::fuji_14bit_load_raw; } else { parse_fuji_compressed_header(); diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index c831acc74..81dfbb793 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -1520,7 +1520,7 @@ void RawImageSource::vflip(Imagefloat* image) //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -int RawImageSource::load(const Glib::ustring &fname) +int RawImageSource::load (const Glib::ustring &fname, bool firstFrameOnly) { MyTime t1, t2; @@ -1538,8 +1538,7 @@ int RawImageSource::load(const Glib::ustring &fname) if (errCode) { return errCode; } - - numFrames = ri->getFrameCount(); + numFrames = firstFrameOnly ? 1 : ri->getFrameCount(); errCode = 0; diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 9b2213a2b..d55f85885 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -118,7 +118,8 @@ public: RawImageSource(); ~RawImageSource(); - int load(const Glib::ustring &fname); + int load(const Glib::ustring &fname) { return load(fname, false); } + int load(const Glib::ustring &fname, bool firstFrameOnly); void preprocess(const RAWParams &raw, const LensProfParams &lensProf, const CoarseTransformParams& coarse, bool prepareDenoise = true); void demosaic(const RAWParams &raw); void retinex (const ColorManagementParams& cmp, const RetinexParams &deh, const ToneCurveParams& Tc, LUTf & cdcurve, LUTf & mapcurve, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, multi_array2D &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI); diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index 71104d6f4..b1107e7f1 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -36,7 +36,10 @@ #include "jpeg.h" #include "../rtgui/ppversion.h" #include "improccoordinator.h" +#include "settings.h" #include +#include "StopWatch.h" +#include "median.h" namespace { @@ -147,6 +150,8 @@ extern Options options; namespace rtengine { +extern const Settings *settings; + using namespace procparams; Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, int fixwh, double wbEq, bool inspectorMode) @@ -261,13 +266,92 @@ Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, return tpp; } -Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, eSensorType &sensorType, int &w, int &h, int fixwh, bool rotate, bool inspectorMode) + +namespace { + +Image8 *load_inspector_mode(const Glib::ustring &fname, RawMetaDataLocation &rml, eSensorType &sensorType, int &w, int &h) { + BENCHFUN + + RawImageSource src; + int err = src.load(fname, true); + if (err) { + return nullptr; + } + + src.getFullSize(w, h); + sensorType = src.getSensorType(); + + ProcParams neutral; + neutral.raw.bayersensor.method = RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::FAST); + neutral.raw.xtranssensor.method = RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::FAST); + neutral.icm.input = "(camera)"; + neutral.icm.working = "RT_sRGB"; + + src.preprocess(neutral.raw, neutral.lensProf, neutral.coarse, false); + src.demosaic(neutral.raw); + + PreviewProps pp(0, 0, w, h, 1); + + Imagefloat tmp(w, h); + src.getImage(src.getWB(), TR_NONE, &tmp, pp, neutral.toneCurve, neutral.raw); + src.convertColorSpace(&tmp, neutral.icm, src.getWB()); + + Image8 *img = new Image8(w, h); + const float f = 255.f/65535.f; +#ifdef _OPENMP + #pragma omp parallel for +#endif + for (int y = 0; y < h; ++y) { + for (int x = 0; x < w; ++x) { + float r = tmp.r(y, x); + float g = tmp.g(y, x); + float b = tmp.b(y, x); + // avoid magenta highlights + if (r > MAXVALF && b > MAXVALF) { + float v = CLIP((r + g + b) / 3.f) * f; + img->r(y, x) = img->g(y, x) = img->b(y, x) = v; + } else { + img->r(y, x) = Color::gamma_srgbclipped(r) * f; + img->g(y, x) = Color::gamma_srgbclipped(g) * f; + img->b(y, x) = Color::gamma_srgbclipped(b) * f; + } + } + } + + return img; +} + +} // namespace + +Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, eSensorType &sensorType, int &w, int &h, int fixwh, bool rotate, bool inspectorMode, bool forHistogramMatching) +{ + Thumbnail* tpp = new Thumbnail (); + tpp->isRaw = 1; + memset (tpp->colorMatrix, 0, sizeof (tpp->colorMatrix)); + tpp->colorMatrix[0][0] = 1.0; + tpp->colorMatrix[1][1] = 1.0; + tpp->colorMatrix[2][2] = 1.0; + + if (inspectorMode && !forHistogramMatching && settings->thumbnail_inspector_mode == Settings::ThumbnailInspectorMode::RAW) { + Image8 *img = load_inspector_mode(fname, rml, sensorType, w, h); + if (!img) { + delete tpp; + return nullptr; + } + + tpp->scale = 1.; + tpp->thumbImg = img; + + return tpp; + } + RawImage *ri = new RawImage (fname); unsigned int imageNum = 0; int r = ri->loadRaw (false, imageNum, false); if ( r ) { + delete tpp; delete ri; sensorType = ST_NONE; return nullptr; @@ -301,24 +385,33 @@ Thumbnail* Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, RawMetaDataL // did we succeed? if ( err ) { printf ("Could not extract thumb from %s\n", fname.data()); + delete tpp; delete img; delete ri; return nullptr; } - Thumbnail* tpp = new Thumbnail (); - - tpp->isRaw = 1; - memset (tpp->colorMatrix, 0, sizeof (tpp->colorMatrix)); - tpp->colorMatrix[0][0] = 1.0; - tpp->colorMatrix[1][1] = 1.0; - tpp->colorMatrix[2][2] = 1.0; - if (inspectorMode) { // Special case, meaning that we want a full sized thumbnail image (e.g. for the Inspector feature) w = img->getWidth(); h = img->getHeight(); tpp->scale = 1.; + + if (!forHistogramMatching && settings->thumbnail_inspector_mode == Settings::ThumbnailInspectorMode::RAW_IF_NOT_JPEG_FULLSIZE && float(std::max(w, h))/float(std::max(ri->get_width(), ri->get_height())) < 0.9f) { + delete img; + delete ri; + + img = load_inspector_mode(fname, rml, sensorType, w, h); + if (!img) { + delete tpp; + return nullptr; + } + + tpp->scale = 1.; + tpp->thumbImg = img; + + return tpp; + } } else { if (fixwh == 1) { w = h * img->getWidth() / img->getHeight(); diff --git a/rtengine/rtthumbnail.h b/rtengine/rtthumbnail.h index be1340f3c..558d136ee 100644 --- a/rtengine/rtthumbnail.h +++ b/rtengine/rtthumbnail.h @@ -76,7 +76,7 @@ public: int getImageWidth (const procparams::ProcParams& pparams, int rheight, float &ratio); void getDimensions (int& w, int& h, double& scaleFac); - static Thumbnail* loadQuickFromRaw (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, eSensorType &sensorType, int &w, int &h, int fixwh, bool rotate, bool inspectorMode = false); + static Thumbnail* loadQuickFromRaw (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, eSensorType &sensorType, int &w, int &h, int fixwh, bool rotate, bool inspectorMode = false, bool forHistogramMatching = false); static Thumbnail* loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, eSensorType &sensorType, int &w, int &h, int fixwh, double wbEq, bool rotate, bool forHistogramMatching = false); static Thumbnail* loadFromImage (const Glib::ustring& fname, int &w, int &h, int fixwh, double wbEq, bool inspectorMode = false); static RawMetaDataLocation loadMetaDataFromRaw (const Glib::ustring& fname); diff --git a/rtengine/settings.h b/rtengine/settings.h index ae46ea5a7..484f588d7 100644 --- a/rtengine/settings.h +++ b/rtengine/settings.h @@ -90,6 +90,13 @@ public: Glib::ustring lensfunDbDirectory; ///< The directory containing the lensfun database. If empty, the system defaults will be used (as described in http://lensfun.sourceforge.net/manual/dbsearch.html) + + enum class ThumbnailInspectorMode { + JPEG, + RAW, + RAW_IF_NOT_JPEG_FULLSIZE + }; + ThumbnailInspectorMode thumbnail_inspector_mode; /** Creates a new instance of Settings. * @return a pointer to the new Settings instance. */ diff --git a/rtgui/inspector.cc b/rtgui/inspector.cc index 4084e300f..6da62cd3b 100644 --- a/rtgui/inspector.cc +++ b/rtgui/inspector.cc @@ -210,6 +210,23 @@ void Inspector::switchImage (const Glib::ustring &fullPath) return; } + if (delayconn.connected()) { + delayconn.disconnect(); + } + + next_image_path = fullPath; + if (!options.inspectorDelay) { + doSwitchImage(); + } else { + delayconn = Glib::signal_timeout().connect(sigc::mem_fun(*this, &Inspector::doSwitchImage), options.inspectorDelay); + } +} + + +bool Inspector::doSwitchImage() +{ + Glib::ustring fullPath = next_image_path; + // we first check the size of the list, it may have been changed in Preference if (images.size() > size_t(options.maxInspectorBuffers)) { // deleting the last entries @@ -225,7 +242,6 @@ void Inspector::switchImage (const Glib::ustring &fullPath) if (fullPath.empty()) { currImage = nullptr; queue_draw(); - return; } else { bool found = false; @@ -264,6 +280,8 @@ void Inspector::switchImage (const Glib::ustring &fullPath) } } } + + return true; } void Inspector::deleteBuffers () diff --git a/rtgui/inspector.h b/rtgui/inspector.h index f68912dc1..ac8f52ee2 100644 --- a/rtgui/inspector.h +++ b/rtgui/inspector.h @@ -48,9 +48,14 @@ private: double zoom; bool active; + sigc::connection delayconn; + Glib::ustring next_image_path; + bool on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr); void deleteBuffers(); + bool doSwitchImage(); + public: Inspector(); ~Inspector(); diff --git a/rtgui/options.cc b/rtgui/options.cc index 0b9ef150b..cc8b77696 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -433,6 +433,7 @@ void Options::setDefaults () #endif filledProfile = false; maxInspectorBuffers = 2; // a rather conservative value for low specced systems... + inspectorDelay = 0; serializeTiffRead = true; FileBrowserToolbarSingleRow = false; @@ -609,6 +610,8 @@ void Options::setDefaults () rtSettings.lensfunDbDirectory = ""; // set also in main.cc and main-cli.cc cropGuides = CROP_GUIDE_FULL; cropAutoFit = false; + + rtSettings.thumbnail_inspector_mode = rtengine::Settings::ThumbnailInspectorMode::JPEG; } Options* Options::copyFrom (Options* other) @@ -1092,6 +1095,10 @@ void Options::readFromFile (Glib::ustring fname) maxInspectorBuffers = keyFile.get_integer ("Performance", "MaxInspectorBuffers"); } + if (keyFile.has_key ("Performance", "InspectorDelay")) { + inspectorDelay = keyFile.get_integer("Performance", "InspectorDelay"); + } + if (keyFile.has_key ("Performance", "PreviewDemosaicFromSidecar")) { prevdemo = (prevdemo_t)keyFile.get_integer ("Performance", "PreviewDemosaicFromSidecar"); } @@ -1111,6 +1118,10 @@ void Options::readFromFile (Glib::ustring fname) if (keyFile.has_key ("Performance", "SerializeTiffRead")) { serializeTiffRead = keyFile.get_boolean ("Performance", "SerializeTiffRead"); } + + if (keyFile.has_key("Performance", "ThumbnailInspectorMode")) { + rtSettings.thumbnail_inspector_mode = static_cast(keyFile.get_integer("Performance", "ThumbnailInspectorMode")); + } } if (keyFile.has_group ("GUI")) { @@ -1899,10 +1910,12 @@ void Options::saveToFile (Glib::ustring fname) keyFile.set_integer ("Performance", "SIMPLNRAUT", rtSettings.leveldnautsimpl); keyFile.set_integer ("Performance", "ClutCacheSize", clutCacheSize); keyFile.set_integer ("Performance", "MaxInspectorBuffers", maxInspectorBuffers); + keyFile.set_integer ("Performance", "InspectorDelay", inspectorDelay); keyFile.set_integer ("Performance", "PreviewDemosaicFromSidecar", prevdemo); keyFile.set_boolean ("Performance", "Daubechies", rtSettings.daubech); keyFile.set_boolean ("Performance", "SerializeTiffRead", serializeTiffRead); keyFile.set_integer ("Performance", "Localajustqual", locaaju); + keyFile.set_integer("Performance", "ThumbnailInspectorMode", int(rtSettings.thumbnail_inspector_mode)); keyFile.set_string ("Output", "Format", saveFormat.format); diff --git a/rtgui/options.h b/rtgui/options.h index 12d8c8009..2500bd48b 100644 --- a/rtgui/options.h +++ b/rtgui/options.h @@ -278,6 +278,7 @@ public: Glib::ustring clutsDir; int rgbDenoiseThreadLimit; // maximum number of threads for the denoising tool ; 0 = use the maximum available int maxInspectorBuffers; // maximum number of buffers (i.e. images) for the Inspector feature + int inspectorDelay; int clutCacheSize; bool filledProfile; // Used as reminder for the ProfilePanel "mode" prevdemo_t prevdemo; // Demosaicing method used for the <100% preview diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index c54d8f5b3..5b9a694d8 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -675,7 +675,19 @@ Gtk::Widget* Preferences::getPerformancePanel() maxInspectorBuffersSB->set_range(1, 12); // ... we have to set a limit, 12 seem to be enough even for systems with tons of RAM maxIBuffersHB->pack_start(*maxIBufferLbl, Gtk::PACK_SHRINK, 0); maxIBuffersHB->pack_end(*maxInspectorBuffersSB, Gtk::PACK_SHRINK, 0); - finspect->add(*maxIBuffersHB); + + Gtk::VBox *inspectorvb = Gtk::manage(new Gtk::VBox()); + inspectorvb->add(*maxIBuffersHB); + + Gtk::HBox *insphb = Gtk::manage(new Gtk::HBox()); + thumbnailInspectorMode = Gtk::manage(new Gtk::ComboBoxText()); + thumbnailInspectorMode->append(M("PREFERENCES_THUMBNAIL_INSPECTOR_JPEG")); + thumbnailInspectorMode->append(M("PREFERENCES_THUMBNAIL_INSPECTOR_RAW")); + thumbnailInspectorMode->append(M("PREFERENCES_THUMBNAIL_INSPECTOR_RAW_IF_NO_JPEG_FULLSIZE")); + insphb->pack_start(*Gtk::manage(new Gtk::Label(M("PREFERENCES_THUMBNAIL_INSPECTOR_MODE") + ": ")), Gtk::PACK_SHRINK, 4); + insphb->pack_start(*thumbnailInspectorMode); + inspectorvb->pack_start(*insphb); + finspect->add (*inspectorvb); mainContainer->pack_start(*finspect, Gtk::PACK_SHRINK, 4); Gtk::Frame* fdenoise = Gtk::manage(new Gtk::Frame(M("PREFERENCES_NOISE"))); @@ -1865,6 +1877,7 @@ void Preferences::storePreferences() moptions.rgbDenoiseThreadLimit = rgbDenoiseTreadLimitSB->get_value_as_int(); moptions.clutCacheSize = clutCacheSizeSB->get_value_as_int(); moptions.maxInspectorBuffers = maxInspectorBuffersSB->get_value_as_int(); + moptions.rtSettings.thumbnail_inspector_mode = static_cast(thumbnailInspectorMode->get_active_row_number()); // Sounds only on Windows and Linux #if defined(WIN32) || defined(__linux__) @@ -2087,6 +2100,7 @@ void Preferences::fillPreferences() rgbDenoiseTreadLimitSB->set_value(moptions.rgbDenoiseThreadLimit); clutCacheSizeSB->set_value(moptions.clutCacheSize); maxInspectorBuffersSB->set_value(moptions.maxInspectorBuffers); + thumbnailInspectorMode->set_active(int(moptions.rtSettings.thumbnail_inspector_mode)); darkFrameDir->set_current_folder(moptions.rtSettings.darkFramesPath); darkFrameChanged(); diff --git a/rtgui/preferences.h b/rtgui/preferences.h index ce5210f6c..b64c7ee1d 100644 --- a/rtgui/preferences.h +++ b/rtgui/preferences.h @@ -169,6 +169,7 @@ class Preferences : public Gtk::Dialog, public ProfileStoreListener Gtk::SpinButton* rgbDenoiseTreadLimitSB; Gtk::SpinButton* clutCacheSizeSB; Gtk::SpinButton* maxInspectorBuffersSB; + Gtk::ComboBoxText *thumbnailInspectorMode; Gtk::CheckButton* ckbmenuGroupRank; Gtk::CheckButton* ckbmenuGroupLabel;