From c05dbf0eb018bbf7632f660665ddb96fc950bf3b Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sat, 6 Jan 2018 16:43:28 +0100 Subject: [PATCH 1/9] Segfault when changing to Saturation & Value Blending curve, fixes #4279 --- rtengine/curves.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rtengine/curves.h b/rtengine/curves.h index f9c991e8e..6a37b7e46 100644 --- a/rtengine/curves.h +++ b/rtengine/curves.h @@ -1118,6 +1118,10 @@ inline void SatAndValueBlendingToneCurve::Apply (float& r, float& g, float& b) c const float lum = (r + g + b) / 3.f; const float newLum = lutToneCurve[lum]; + if (newLum == lum) { + return; + } + float h, s, v; Color::rgb2hsvtc(r, g, b, h, s, v); From 857f39eb881c9358be9a22eec2861e263c781b35 Mon Sep 17 00:00:00 2001 From: Alberto Griggio Date: Sat, 6 Jan 2018 18:01:54 +0100 Subject: [PATCH 2/9] swapped shortcuts for "zoom to fit" and "zoom to fit crop" --- rtdata/languages/default | 4 ++-- rtgui/editorpanel.cc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index 7fbe7260a..dd0a63fc6 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -2190,7 +2190,7 @@ TP_WBALANCE_WATER_HEADER;UnderWater ZOOMPANEL_100;(100%) ZOOMPANEL_NEWCROPWINDOW;Open (new) detail window ZOOMPANEL_ZOOM100;Zoom to 100%\nShortcut: z -ZOOMPANEL_ZOOMFITCROPSCREEN;Fit crop to screen\nShortcut: Alt-f -ZOOMPANEL_ZOOMFITSCREEN;Fit whole image to screen\nShortcut: f +ZOOMPANEL_ZOOMFITCROPSCREEN;Fit crop to screen\nShortcut: f +ZOOMPANEL_ZOOMFITSCREEN;Fit whole image to screen\nShortcut: Alt-f ZOOMPANEL_ZOOMIN;Zoom In\nShortcut: + ZOOMPANEL_ZOOMOUT;Zoom Out\nShortcut: - diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc index 643803075..e9964073a 100644 --- a/rtgui/editorpanel.cc +++ b/rtgui/editorpanel.cc @@ -1643,7 +1643,7 @@ bool EditorPanel::handleShortcutKey (GdkEventKey* event) return true; case GDK_KEY_f: - iareapanel->imageArea->zoomPanel->zoomFitClicked(); + iareapanel->imageArea->zoomPanel->zoomFitCropClicked(); return true; case GDK_KEY_F5: @@ -1718,7 +1718,7 @@ bool EditorPanel::handleShortcutKey (GdkEventKey* event) return true; case GDK_KEY_f: - iareapanel->imageArea->zoomPanel->zoomFitCropClicked(); + iareapanel->imageArea->zoomPanel->zoomFitClicked(); return true; } } From 309eef696be1022860cc51e07062915bfa4c1b00 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sat, 6 Jan 2018 18:46:20 +0100 Subject: [PATCH 3/9] Set gtk language based on selected language in RT, fixes #4278, kudos to @agriggio --- rtgui/multilangmgr.cc | 28 +++++++++++++++++++++++++++- rtgui/multilangmgr.h | 2 +- rtgui/options.cc | 2 +- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/rtgui/multilangmgr.cc b/rtgui/multilangmgr.cc index 7cc79d19a..b4896d69a 100644 --- a/rtgui/multilangmgr.cc +++ b/rtgui/multilangmgr.cc @@ -94,10 +94,34 @@ struct LocaleToLang : private std::map, return "default"; } + + std::string getLocale(const Glib::ustring &language) const + { + for (auto &p : *this) { + if (p.second == language) { + std::string ret = p.first.first; + if (!p.first.second.empty()) { + ret += "_" + p.first.second; + } + return ret; + } + } + return "C"; + } }; const LocaleToLang localeToLang; +void setGtkLanguage(const Glib::ustring &language) +{ + auto l = localeToLang.getLocale(language); +#ifdef WIN32 + putenv(("LANG=" + l).c_str()); +#else + setenv("LANG", l.c_str(), true); +#endif +} + } MultiLangMgr langMgr; @@ -106,8 +130,10 @@ MultiLangMgr::MultiLangMgr () { } -void MultiLangMgr::load (const std::vector &fnames) +void MultiLangMgr::load(const Glib::ustring &language, const std::vector &fnames) { + setGtkLanguage(language); + translations.clear(); for (const auto& fname : fnames) { diff --git a/rtgui/multilangmgr.h b/rtgui/multilangmgr.h index d439307e3..649865217 100644 --- a/rtgui/multilangmgr.h +++ b/rtgui/multilangmgr.h @@ -30,7 +30,7 @@ class MultiLangMgr public: MultiLangMgr (); - void load(const std::vector &fnames); + void load(const Glib::ustring &language, const std::vector &fnames); Glib::ustring getStr(const std::string& key) const; static bool isOSLanguageDetectSupported(); static Glib::ustring getOSUserLanguage(); diff --git a/rtgui/options.cc b/rtgui/options.cc index 449aa3809..6e538059f 100644 --- a/rtgui/options.cc +++ b/rtgui/options.cc @@ -2323,7 +2323,7 @@ void Options::load (bool lightweight) } } - langMgr.load ({localeTranslation, languageTranslation, defaultTranslation}); + langMgr.load (options.language, {localeTranslation, languageTranslation, defaultTranslation}); rtengine::init (&options.rtSettings, argv0, rtdir, !lightweight); } From f3c0c2f0893cceaa5f85e2e8a7ddd9e810524022 Mon Sep 17 00:00:00 2001 From: TooWaBoo Date: Sun, 7 Jan 2018 11:59:56 +0100 Subject: [PATCH 4/9] Update TooWaBlue theme to version 2.61 Queue switch --- rtdata/themes/TooWaBlue-GTK3-20_.css | 67 ++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 13 deletions(-) diff --git a/rtdata/themes/TooWaBlue-GTK3-20_.css b/rtdata/themes/TooWaBlue-GTK3-20_.css index 1e196bff8..af7fb00af 100644 --- a/rtdata/themes/TooWaBlue-GTK3-20_.css +++ b/rtdata/themes/TooWaBlue-GTK3-20_.css @@ -2,7 +2,7 @@ This file is part of RawTherapee. Copyright (c) 2016-2017 TooWaBoo - Version 2.60 + Version 2.61 RawTherapee is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -213,10 +213,6 @@ dialog frame > label { padding-left: 0.91667em; } -#BatchQueueButtons { - margin-top: 0.66667em; -} - frame > label { margin: 0; padding: 0.5em 0; @@ -637,6 +633,11 @@ scale:disabled trough { background-image: none; } +#BatchQueueButtonsMainContainer scale:disabled slider, +#BatchQueueButtonsMainContainer scale:disabled trough { + background-color: shade(@bg-light-grey,.85); +} + /*** end ***************************************************************************************/ /*** Progressbar *******************************************************************************/ @@ -1225,6 +1226,51 @@ popover.background modelbutton:hover { } /** end ****************************************************************************************/ +/*** Switch ***********************************************************************************/ +switch { + min-height: 2.16667em; + min-width: 11em; + margin: 0; + padding: 0; + border-radius: 0.2em; + background-image: none; + box-shadow: inset 0.08334em 0.08334em rgba(0, 0, 0, 0.08), 0 0.08334em rgba(242, 242, 242, 0.1); + border: 0.08334em solid @bg-entry-border; + background-color: @bg-scale-entry; + margin-bottom: 0.5em; +} + +switch slider { + border: 0.08334em solid @bg-entry-border; + background-image: linear-gradient(to bottom, shade (@accent-color2,1.15), shade (@accent-color2,.85)); + border: 0.08334em solid @bg-entry-border; + box-shadow: inset 0 0.08334em rgba(242, 242, 242, 0.1); + border-radius: 0.2em 0 0 0.2em; +} +switch:checked slider{ + border-radius: 0 0.2em 0.2em 0; +} + +switch:hover slider { + background-image: linear-gradient(to bottom, shade (@accent-color2,1.20), shade (@accent-color2,.90)); +} + +switch:checked { + background-color: rgb(140,0,20); + color: @headline-big; +} + +switch:disabled:not(:checked) { + box-shadow: none; + background-image: none; + background-color: shade (@bg-light-grey, .85); +} +switch:disabled slider { + background-image: linear-gradient(to bottom, rgba(125,125,125,.4), rgba(60,60,60,.4)); + background-color: shade (@bg-light-grey, .85); +} +/** end ****************************************************************************************/ + /*** Buttons ***********************************************************************************/ button { min-height: 2.16667em; @@ -1355,6 +1401,7 @@ button.MiddleH { /**/ /* Button base format for Toolbox and dialogs */ +#ToolPanelNotebook > stack > box > box > combobox .combo, dialog button, #MyExpander button, #BatchQueueButtonsMainContainer button { @@ -1371,7 +1418,7 @@ combobox .combo, dialog combobox .combo, #ToolPanelNotebook combobox .combo, #BatchQueueButtonsMainContainer combobox .combo { - padding: 0 0.208334em; + padding: 0 0.26667em; } /**/ @@ -1386,6 +1433,7 @@ dialog combobox .combo, #MyExpander combobox + label */ { margin-left: 0.16667em; } + #MyExpander label + * > button:not(.flat).Left, #MyExpander label + combobox:not(:first-child):not(:only-child), #MyExpander label + button:not(.flat):not(spinbutton) { @@ -1455,13 +1503,6 @@ messagedialog .dialog-action-area button:not(:only-child):nth-child(2) { } /**/ -/* Queue */ -#BatchQueueButtons button { - min-height: 2.16667em; - min-width: 10em; -} -/**/ - /* View & Filechooser Buttons */ dialog .view button, window .view button { From d1d89d7f7203c58af2038ce726eddbbfa27a45c5 Mon Sep 17 00:00:00 2001 From: TooWaBoo Date: Sun, 7 Jan 2018 12:00:58 +0100 Subject: [PATCH 5/9] Update Deutsch local --- rtdata/languages/Deutsch | 57 ++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/rtdata/languages/Deutsch b/rtdata/languages/Deutsch index 1daaa9119..e6cb9f96d 100644 --- a/rtdata/languages/Deutsch +++ b/rtdata/languages/Deutsch @@ -48,6 +48,7 @@ #47 19.11.2017 HDR-Dynamikkompression (TooWaBoo) RT 5.3 #48 13.12.2017 Erweiterung (TooWaBoo) RT 5.3 #49 21.12.2017 Lokaler Kontrast (TooWaBoo) RT 5.3 +#50 07.01.2018 Crop Settings (TooWaBoo) RT 5.3 ABOUT_TAB_BUILD;Version ABOUT_TAB_CREDITS;Danksagungen @@ -572,9 +573,9 @@ HISTORY_MSG_281;(Farbanpassungen)\nSättigung schützen\nIntensität HISTORY_MSG_282;(Farbanpassungen)\nSättigung schützen\nSchwelle HISTORY_MSG_283;(Farbanpassungen)\nIntensität HISTORY_MSG_284;(Farbanpassungen)\nSättigung schützen\nAutomatisch -HISTORY_MSG_285;(Rauschreduzierung)\nMedianmethode +HISTORY_MSG_285;(Rauschreduzierung)\nMedianfilter - Methode HISTORY_MSG_286;(Rauschreduzierung)\nMediantyp -HISTORY_MSG_287;(Rauschreduzierung)\nMedianiterationen +HISTORY_MSG_287;(Rauschreduzierung)\nMedianfilter - Iterationen HISTORY_MSG_288;(Weißbild)\nKontrolle zu heller Bereiche HISTORY_MSG_289;(Weißbild)\nAuto-Kontrolle zu\nheller Bereiche HISTORY_MSG_290;(Sensor-Matrix)\nSchwarzpunkt - Rot @@ -1151,7 +1152,7 @@ PREFERENCES_REMEMBERZOOMPAN;Zoom und Bildposition merken PREFERENCES_REMEMBERZOOMPAN_TOOLTIP;Öffnen eines neuen Bildes mit den Zoom- und Positionswerten\ndes vorangegangenen Bildes.\n\nFunktioniert nur unter folgenden Bedingungen:\nEin-Reitermodus aktiv\n“Demosaikmethode für 100%-Ansicht“ muss auf “Wie im Bild-\nverarbeitungsprofil vorgegeben“ eingestellt sein. PREFERENCES_RGBDTL_LABEL;Maximale Anzahl Threads für Rauschreduzierung PREFERENCES_RGBDTL_TOOLTIP;Die Rauschreduzierung benötigt mindestens 128MB RAM für ein 10 Megapixel-Bild oder 512MB für ein 40 Megapixel-Bild, und zusätzlich 128MB RAM pro Thread. Je mehr Threads parallel ablaufen, desto schneller ist die Berechnung. Bei Einstellung "0" werden so viele Threads wie möglich benutzt. -PREFERENCES_SAVE_TP_OPEN_NOW;Werkzeugstatus jetzt sichern +PREFERENCES_SAVE_TP_OPEN_NOW;Werkzeugstatus jetzt speichern PREFERENCES_SELECTFONT;Schriftart PREFERENCES_SELECTFONT_COLPICKER;Schriftart für die Farbwähler PREFERENCES_SELECTLANG;Sprache @@ -1513,7 +1514,7 @@ TP_DIRPYRDENOISE_LUMINANCE_CURVE;Luminanzkurve TP_DIRPYRDENOISE_LUMINANCE_DETAIL;Luminanzdetails TP_DIRPYRDENOISE_LUMINANCE_FRAME;Luminanz TP_DIRPYRDENOISE_LUMINANCE_SMOOTHING;Luminanz -TP_DIRPYRDENOISE_MAIN_COLORSPACE;Methode +TP_DIRPYRDENOISE_MAIN_COLORSPACE;Farbraum TP_DIRPYRDENOISE_MAIN_COLORSPACE_LAB;L*a*b* TP_DIRPYRDENOISE_MAIN_COLORSPACE_LABEL;Rauschreduzierung TP_DIRPYRDENOISE_MAIN_COLORSPACE_RGB;RGB @@ -1524,7 +1525,7 @@ TP_DIRPYRDENOISE_MAIN_MODE;Qualität TP_DIRPYRDENOISE_MAIN_MODE_AGGRESSIVE;Hoch TP_DIRPYRDENOISE_MAIN_MODE_CONSERVATIVE;Standard TP_DIRPYRDENOISE_MAIN_MODE_TOOLTIP;Einstellung der Qualität der Rauschreduzierung.\nDie Einstellung “Hoch“ verbessert die Rausch-\nreduzierung auf Kosten der Verarbeitungszeit. -TP_DIRPYRDENOISE_MEDIAN_METHOD;Medianmethode +TP_DIRPYRDENOISE_MEDIAN_METHOD;Methode TP_DIRPYRDENOISE_MEDIAN_METHOD_CHROMINANCE;Nur Farbe TP_DIRPYRDENOISE_MEDIAN_METHOD_LAB;L*a*b* TP_DIRPYRDENOISE_MEDIAN_METHOD_LABEL;Medianfilter @@ -1532,7 +1533,7 @@ TP_DIRPYRDENOISE_MEDIAN_METHOD_LUMINANCE;Nur Luminanz TP_DIRPYRDENOISE_MEDIAN_METHOD_RGB;RGB TP_DIRPYRDENOISE_MEDIAN_METHOD_TOOLTIP;Bei der Methode “Nur Luminanz“ und “L*a*b*“,\nwird der Medianfilter nach den Waveletschritten\nverarbeitet.\nBei RGB wird der Medianfilter am Ende der\nRauschreduzierung verarbeitet. TP_DIRPYRDENOISE_MEDIAN_METHOD_WEIGHTED;Gewichtet L* (wenig) + a*b* (normal) -TP_DIRPYRDENOISE_MEDIAN_PASSES;Medianiterationen +TP_DIRPYRDENOISE_MEDIAN_PASSES;Iterationen TP_DIRPYRDENOISE_MEDIAN_PASSES_TOOLTIP;Manchmal führt ein kleines 3×3-Fenster mit\nmehreren Iterationen zu besseren Ergebnissen\nals ein 7×7-Fenster mit nur einer Iteration. TP_DIRPYRDENOISE_MEDIAN_TYPE;Mediantyp TP_DIRPYRDENOISE_MEDIAN_TYPE_TOOLTIP;Einen Medianfilter mit der gewünschten Fenstergröße auswählen.\nJe größer das Fenster, umso länger dauert die Verarbeitungszeit.\n\n3×3 weich: Nutzt 5 Pixel in einem 3×3-Pixelfenster.\n3×3: Nutzt 9 Pixel in einem 3×3-Pixelfenster.\n5×5 weich: Nutzt 13 Pixel in einem 5×5-Pixelfenster.\n5×5: Nutzt 25 Pixel in einem 5×5-Pixelfenster.\n7×7: Nutzt 49 Pixel in einem 7×7-Pixelfenster.\n9×9: Nutzt 81 Pixel in einem 9×9-Pixelfenster.\n\nManchmal ist das Ergebnis mit einem kleineren Fenster und mehreren Iterationen besser, als mit einem größeren und nur einer Iteration. @@ -2226,25 +2227,25 @@ ZOOMPANEL_ZOOMOUT;Herauszoomen\nTaste: - ! Untranslated keys follow; remove the ! prefix after an entry is translated. !!!!!!!!!!!!!!!!!!!!!!!!! -!BATCHQUEUE_STARTSTOPHINT;Start or stop processing the images in the queue.\n\nShortcut: Ctrl+s -!GENERAL_SLIDER;Slider -!HISTORY_MSG_173;NR - Detail recovery -!HISTORY_MSG_203;NR - Color space -!HISTORY_MSG_256;NR - Median - Type -!HISTORY_MSG_297;NR - Mode -!HISTORY_MSG_METADATA_MODE;Metadata copy mode -!PREFERENCES_CROP;Crop editing -!PREFERENCES_CROP_AUTO_FIT;Automatically zoom to fit the crop area -!PREFERENCES_CROP_GUIDES;Guides shown when not editing the crop -!PREFERENCES_CROP_GUIDES_FRAME;Frame -!PREFERENCES_CROP_GUIDES_FULL;Original -!PREFERENCES_CROP_GUIDES_NONE;None -!PREFERENCES_EDITORCMDLINE;Custom command line -!TP_DIRPYRDENOISE_CHROMINANCE_CURVE_TOOLTIP;Increase (multiply) the value of all chrominance sliders.\nThis curve lets you adjust the strength of chromatic noise reduction as a function of chromaticity, for instance to increase the action in areas of low saturation and to decrease it in those of high saturation. -!TP_DIRPYRDENOISE_LABEL;Noise Reduction -!TP_METADATA_EDIT;Apply modifications -!TP_METADATA_MODE;Metadata copy mode -!TP_METADATA_STRIP;Strip all metadata -!TP_METADATA_TUNNEL;Copy unchanged -!TP_RAW_PIXELSHIFTONEGREEN;Use one green instead of average -!TP_RAW_PIXELSHIFTONEGREEN_TOOLTIP;Use one green instead of averaging two greens for regions without motion. +BATCHQUEUE_STARTSTOPHINT;Startet / Stoppt die Verarbeitung\nder Warteschlange.\n\nTaste: Strg + s +GENERAL_SLIDER;Regler +HISTORY_MSG_173;(Rauschreduzierung)\nLuminanzdetails +HISTORY_MSG_203;(Rauschreduzierung)\nFarbraum +HISTORY_MSG_256;(Rauschreduzierung)\nMedianfilter - Mediantyp +HISTORY_MSG_297;(Rauschreduzierung)\nQualität +HISTORY_MSG_METADATA_MODE;(Metadaten)\nKopiermodus +PREFERENCES_CROP;Einstelleung des Ausschnittswerkzeuges +PREFERENCES_CROP_AUTO_FIT;Automatischer Zoom des Ausschnitts +PREFERENCES_CROP_GUIDES;Hilfslinien anzeigen wenn Ausschnitt nicht verändert wird +PREFERENCES_CROP_GUIDES_FRAME;Rahmen +PREFERENCES_CROP_GUIDES_FULL;Vorgabe des Ausschnittswerkzeuges +PREFERENCES_CROP_GUIDES_NONE;Keine +PREFERENCES_EDITORCMDLINE;Benutzerdefinierte Befehlszeile +TP_DIRPYRDENOISE_CHROMINANCE_CURVE_TOOLTIP;Erhöht / Reduziert die Intensität der\nChrominanz-Rauschreduzierung in\nAbhängigkeit der Farbsättigung.\n +TP_DIRPYRDENOISE_LABEL;Rauschreduzierung +TP_METADATA_EDIT;Veränderte Daten +TP_METADATA_MODE;Kopiermodus +TP_METADATA_STRIP;Keine +TP_METADATA_TUNNEL;Unveränderte Daten +TP_RAW_PIXELSHIFTONEGREEN;Benutze ein Grün +TP_RAW_PIXELSHIFTONEGREEN_TOOLTIP;Benutze ein Grün anstelle des\nDurchschnitts beider Grüns für\nBereiche ohne Bewegung. From 4305cb74a75a681856f7dbc2a04c8492696ffab4 Mon Sep 17 00:00:00 2001 From: TooWaBoo Date: Sun, 7 Jan 2018 19:31:27 +0100 Subject: [PATCH 6/9] Update Deutsch --- rtdata/languages/Deutsch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtdata/languages/Deutsch b/rtdata/languages/Deutsch index e6cb9f96d..9e6012d53 100644 --- a/rtdata/languages/Deutsch +++ b/rtdata/languages/Deutsch @@ -2234,7 +2234,7 @@ HISTORY_MSG_203;(Rauschreduzierung)\nFarbraum HISTORY_MSG_256;(Rauschreduzierung)\nMedianfilter - Mediantyp HISTORY_MSG_297;(Rauschreduzierung)\nQualität HISTORY_MSG_METADATA_MODE;(Metadaten)\nKopiermodus -PREFERENCES_CROP;Einstelleung des Ausschnittswerkzeuges +PREFERENCES_CROP;Einstellung des Ausschnittswerkzeuges PREFERENCES_CROP_AUTO_FIT;Automatischer Zoom des Ausschnitts PREFERENCES_CROP_GUIDES;Hilfslinien anzeigen wenn Ausschnitt nicht verändert wird PREFERENCES_CROP_GUIDES_FRAME;Rahmen From 12f1aa853ae4fb3b202f9449552032690877f646 Mon Sep 17 00:00:00 2001 From: TooWaBoo Date: Sun, 7 Jan 2018 19:35:47 +0100 Subject: [PATCH 7/9] Update Deutsch --- rtdata/languages/Deutsch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rtdata/languages/Deutsch b/rtdata/languages/Deutsch index 9e6012d53..f502e61cc 100644 --- a/rtdata/languages/Deutsch +++ b/rtdata/languages/Deutsch @@ -2241,7 +2241,7 @@ PREFERENCES_CROP_GUIDES_FRAME;Rahmen PREFERENCES_CROP_GUIDES_FULL;Vorgabe des Ausschnittswerkzeuges PREFERENCES_CROP_GUIDES_NONE;Keine PREFERENCES_EDITORCMDLINE;Benutzerdefinierte Befehlszeile -TP_DIRPYRDENOISE_CHROMINANCE_CURVE_TOOLTIP;Erhöht / Reduziert die Intensität der\nChrominanz-Rauschreduzierung in\nAbhängigkeit der Farbsättigung.\n +TP_DIRPYRDENOISE_CHROMINANCE_CURVE_TOOLTIP;Erhöht / Reduziert die Intensität der\nChrominanz-Rauschreduzierung in\nAbhängigkeit der Farbsättigung. TP_DIRPYRDENOISE_LABEL;Rauschreduzierung TP_METADATA_EDIT;Veränderte Daten TP_METADATA_MODE;Kopiermodus From 393d62bdb69afc16dc9bc9256f018fd60e4acbff Mon Sep 17 00:00:00 2001 From: heckflosse Date: Sun, 7 Jan 2018 22:59:24 +0100 Subject: [PATCH 8/9] =?UTF-8?q?=C3=82Some=20speedups=20for=20scalar=20slee?= =?UTF-8?q?f=20functions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- rtengine/curves.h.save-failed | 1142 +++++++++++++++++++++++++++++++++ rtengine/rt_math.h | 2 + rtengine/sleef.c | 13 +- 3 files changed, 1150 insertions(+), 7 deletions(-) create mode 100644 rtengine/curves.h.save-failed diff --git a/rtengine/curves.h.save-failed b/rtengine/curves.h.save-failed new file mode 100644 index 000000000..47ab0fc6f --- /dev/null +++ b/rtengine/curves.h.save-failed @@ -0,0 +1,1142 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2010 Gabor Horvath + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ +#ifndef __CURVES_H__ +#define __CURVES_H__ + +#include +#include +#include +#include "rt_math.h" +#include "../rtgui/mycurve.h" +#include "../rtgui/myflatcurve.h" +#include "../rtgui/mydiagonalcurve.h" +#include "color.h" +#include "procparams.h" +#include "pipettebuffer.h" + +#include "LUT.h" + +#define CURVES_MIN_POLY_POINTS 1000 + +#include "rt_math.h" + +#define CLIPI(a) ((a)>0?((a)<65534?(a):65534):0) + +using namespace std; + +namespace rtengine +{ +class ToneCurve; +class ColorAppearance; + +class CurveFactory +{ + + friend class Curve; + +protected: + + // functions calculating the parameters of the contrast curve based on the desired slope at the center + static double solve_upper (double m, double c, double deriv); + static double solve_lower (double m, double c, double deriv); + static double dupper (const double b, const double m, const double c); + static double dlower (const double b, const double m, const double c); + + // basic convex function between (0,0) and (1,1). m1 and m2 controls the slope at the start and end point + static inline double basel (double x, double m1, double m2) + { + if (x == 0.0) { + return 0.0; + } + + double k = sqrt ((m1 - 1.0) * (m1 - m2) * 0.5) / (1.0 - m2); + double l = (m1 - m2) / (1.0 - m2) + k; + double lx = xlog(x); + return m2 * x + (1.0 - m2) * (2.0 - xexp(k * lx)) * xexp(l * lx); + } + // basic concave function between (0,0) and (1,1). m1 and m2 controls the slope at the start and end point + static inline double baseu (double x, double m1, double m2) + { + return 1.0 - basel(1.0 - x, m1, m2); + } + // convex curve between (0,0) and (1,1) with slope m at (0,0). hr controls the highlight recovery + static inline double cupper (double x, double m, double hr) + { + if (hr > 1.0) { + return baseu (x, m, 2.0 * (hr - 1.0) / m); + } + + double x1 = (1.0 - hr) / m; + double x2 = x1 + hr; + + if (x >= x2) { + return 1.0; + } + + if (x < x1) { + return x * m; + } + + return 1.0 - hr + hr * baseu((x - x1) / hr, m, 0); + } + // concave curve between (0,0) and (1,1) with slope m at (1,1). sr controls the shadow recovery + static inline double clower (double x, double m, double sr) + { + return 1.0 - cupper(1.0 - x, m, sr); + } + // convex curve between (0,0) and (1,1) with slope m at (0,0). hr controls the highlight recovery + static inline double cupper2 (double x, double m, double hr) + { + double x1 = (1.0 - hr) / m; + double x2 = x1 + hr; + + if (x >= x2) { + return 1.0; + } + + if (x < x1) { + return x * m; + } + + return 1.0 - hr + hr * baseu((x - x1) / hr, m, 0.3 * hr); + } + static inline double clower2 (double x, double m, double sr) + { + //curve for b<0; starts with positive slope and then rolls over toward straight line to x=y=1 + double x1 = sr / 1.5 + 0.00001; + + if (x > x1 || sr < 0.001) { + return 1 - (1 - x) * m; + } else { + double y1 = 1 - (1 - x1) * m; + return y1 + m * (x - x1) - (1 - m) * SQR(SQR(1 - x / x1)); + } + } + // tone curve base. a: slope (from exp.comp.), b: black point normalized by 65535, + // D: max. x value (can be>1), hr,sr: highlight,shadow recovery + static inline double basecurve (double x, double a, double b, double D, double hr, double sr) + { + if (b < 0) { + double m = 0.5;//midpoint + double slope = 1.0 + b; //slope of straight line between (0,-b) and (1,1) + double y = -b + m * slope; //value at midpoint + + if (x > m) { + return y + (x - m) * slope; //value on straight line between (m,y) and (1,1) + } else { + return y * clower2(x / m, slope * m / y, 2.0 - sr); + } + } else { + double slope = a / (1.0 - b); + double m = a * D > 1.0 ? b / a + (0.25) / slope : b + (1 - b) / 4; + double y = a * D > 1.0 ? 0.25 : (m - b / a) * slope; + + if (x <= m) { + return b == 0 ? x * slope : clower (x / m, slope * m / y, sr) * y; + } else if (a * D > 1.0) { + return y + (1.0 - y) * cupper2((x - m) / (D - m), slope * (D - m) / (1.0 - y), hr); + } else { + return y + (x - m) * slope; + } + } + } + static inline double simplebasecurve (double x, double b, double sr) + { + // a = 1, D = 1, hr = 0 (unused for a = D = 1) + if (b == 0.0) { + return x; + } else if (b < 0) { + double m = 0.5;//midpoint + double slope = 1.0 + b; //slope of straight line between (0,-b) and (1,1) + double y = -b + m * slope; //value at midpoint + + if (x > m) { + return y + (x - m) * slope; //value on straight line between (m,y) and (1,1) + } else { + return y * clower2(x / m, slope * m / y, 2.0 - sr); + } + } else { + double slope = 1.0 / (1.0 - b); + double m = b + (1 - b) * 0.25; + double y = (m - b) * slope; + + if (x <= m) { + return clower (x / m, slope * m / y, sr) * y; + } else { + return y + (x - m) * slope; + } + } + } + + +public: + const static double sRGBGamma; // standard average gamma + const static double sRGBGammaCurve; // 2.4 in the curve + + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // accurately determine value from integer array with float as index + //linearly interpolate from ends of range if arg is out of bounds + static inline float interp(int *array, float f) + { + int index = CLIPI(floor(f)); + float part = (float)((f) - index) * (float)(array[index + 1] - array[index]); + return (float)array[index] + part; + } + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + // accurately determine value from float array with float as index + //linearly interpolate from ends of range if arg is out of bounds + static inline float flinterp(float *array, float f) + { + int index = CLIPI(floor(f)); + float part = ((f) - (float)index) * (array[index + 1] - array[index]); + return array[index] + part; + } + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + static inline double centercontrast (double x, double b, double m); + + // standard srgb gamma and its inverse + static inline double gamma2 (double x) + { + return x <= 0.00304 ? x * 12.92 : 1.055 * exp(log(x) / sRGBGammaCurve) - 0.055; + } + static inline double igamma2 (double x) + { + return x <= 0.03928 ? x / 12.92 : exp(log((x + 0.055) / 1.055) * sRGBGammaCurve); + } + static inline float gamma2 (float x) + { + return x <= 0.00304 ? x * 12.92 : 1.055 * expf(logf(x) / sRGBGammaCurve) - 0.055; + } + static inline float igamma2 (float x) + { + return x <= 0.03928 ? x / 12.92 : expf(logf((x + 0.055) / 1.055) * sRGBGammaCurve); + } + // gamma function with adjustable parameters + static inline double gamma (double x, double gamma, double start, double slope, double mul, double add) + { + return (x <= start ? x*slope : exp(log(x) / gamma) * mul - add); + } + static inline double igamma (double x, double gamma, double start, double slope, double mul, double add) + { + return (x <= start * slope ? x / slope : exp(log((x + add) / mul) * gamma) ); + } + static inline float gamma (float x, float gamma, float start, float slope, float mul, float add) + { + return (x <= start ? x*slope : xexpf(xlogf(x) / gamma) * mul - add); + } + static inline float igamma (float x, float gamma, float start, float slope, float mul, float add) + { + return (x <= start * slope ? x / slope : xexpf(xlogf((x + add) / mul) * gamma) ); + } +#ifdef __SSE2__ + static inline vfloat igamma (vfloat x, vfloat gamma, vfloat start, vfloat slope, vfloat mul, vfloat add) + { +#if !defined(__clang__) + return (x <= start * slope ? x / slope : xexpf(xlogf((x + add) / mul) * gamma) ); +#else + return vself(vmaskf_le(x, start * slope), x / slope, xexpf(xlogf((x + add) / mul) * gamma)); +#endif + } +#endif + static inline float hlcurve (const float exp_scale, const float comp, const float hlrange, float level) + { + if (comp > 0.0) { + float val = level + (hlrange - 65536.0); + + if(val == 0.0f) { // to avoid division by zero + val = 0.000001f; + } + + float Y = val * exp_scale / hlrange; + Y *= comp; + + if(Y <= -1.0) { // to avoid log(<=0) + Y = -.999999f; + } + + float R = hlrange / (val * comp); + return log1p(Y) * R; + } else { + return exp_scale; + } + } + +public: + static void complexCurve (double ecomp, double black, double hlcompr, double hlcomprthresh, double shcompr, double br, double contr, + const std::vector& curvePoints, const std::vector& curvePoints2, + LUTu & histogram, LUTf & hlCurve, LUTf & shCurve, LUTf & outCurve, LUTu & outBeforeCCurveHistogram, ToneCurve & outToneCurve, ToneCurve & outToneCurve2, + + int skip = 1); + static void curveBW (const std::vector& curvePointsbw, const std::vector& curvePointsbw2, const LUTu & histogrambw, LUTu & outBeforeCCurveHistogrambw, + ToneCurve & customToneCurvebw1, ToneCurve & customToneCurvebw2, int skip); + + static void curveCL ( bool & clcutili, const std::vector& clcurvePoints, LUTf & clCurve, int skip); + + static void curveWavContL ( bool & wavcontlutili, const std::vector& wavclcurvePoints, LUTf & wavclCurve,/* LUTu & histogramwavcl, LUTu & outBeforeWavCLurveHistogram,*/int skip); + static void curveDehaContL ( bool & dehacontlutili, const std::vector& dehaclcurvePoints, LUTf & dehaclCurve, int skip, const LUTu & histogram, LUTu & outBeforeCurveHistogram); + static void mapcurve ( bool & mapcontlutili, const std::vector& mapcurvePoints, LUTf & mapcurve, int skip, const LUTu & histogram, LUTu & outBeforeCurveHistogram); + + static void curveToning ( const std::vector& curvePoints, LUTf & ToningCurve, int skip); + + static void complexsgnCurve ( bool & autili, bool & butili, bool & ccutili, bool & clcutili, const std::vector& acurvePoints, + const std::vector& bcurvePoints, const std::vector& cccurvePoints, const std::vector& lccurvePoints, LUTf & aoutCurve, LUTf & boutCurve, LUTf & satCurve, LUTf & lhskCurve, + int skip = 1); + static void complexLCurve (double br, double contr, const std::vector& curvePoints, const LUTu & histogram, LUTf & outCurve, LUTu & outBeforeCCurveHistogram, int skip, bool & utili); + + static void curveLightBrightColor ( + const std::vector& curvePoints, + const std::vector& curvePoints2, + const std::vector& curvePoints3, + const LUTu & histogram, LUTu & outBeforeCCurveHistogram, + const LUTu & histogramC, LUTu & outBeforeCCurveHistogramC, + ColorAppearance & outColCurve1, + ColorAppearance & outColCurve2, + ColorAppearance & outColCurve3, + int skip = 1); + static void RGBCurve (const std::vector& curvePoints, LUTf & outCurve, int skip); + +}; + +class Curve +{ + + class HashEntry + { + public: + unsigned short smallerValue; + unsigned short higherValue; + }; +protected: + int N; + int ppn; // targeted polyline point number + double* x; + double* y; + // begin of variables used in Parametric curves only + double mc; + double mfc; + double msc; + double mhc; + // end of variables used in Parametric curves only + std::vector poly_x; // X points of the faceted curve + std::vector poly_y; // Y points of the faceted curve + std::vector dyByDx; + std::vector hash; + unsigned short hashSize; // hash table's size, between [10, 100, 1000] + + double* ypp; + + // Fields for the elementary curve polygonisation + double x1, y1, x2, y2, x3, y3; + bool firstPointIncluded; + double increment; + int nbr_points; + + static inline double p00 (double x, double prot) + { + return CurveFactory::clower (x, 2.0, prot); + } + static inline double p11 (double x, double prot) + { + return CurveFactory::cupper (x, 2.0, prot); + } + static inline double p01 (double x, double prot) + { + return x <= 0.5 ? CurveFactory::clower (x * 2, 2.0, prot) * 0.5 : 0.5 + CurveFactory::cupper ((x - 0.5) * 2, 2.0, prot) * 0.5; + } + static inline double p10 (double x, double prot) + { + return x <= 0.5 ? CurveFactory::cupper (x * 2, 2.0, prot) * 0.5 : 0.5 + CurveFactory::clower ((x - 0.5) * 2, 2.0, prot) * 0.5; + } + static inline double pfull (double x, double prot, double sh, double hl) + { + return (1 - sh) * (1 - hl) * p00(x, prot) + sh * hl * p11(x, prot) + (1 - sh) * hl * p01(x, prot) + sh * (1 - hl) * p10(x, prot); + } + + void fillHash(); + void fillDyByDx(); + +public: + Curve (); + virtual ~Curve () {}; + void AddPolygons (); + int getSize () const; // return the number of control points + void getControlPoint(int cpNum, double &x, double &y) const; + virtual double getVal (double t) const = 0; + virtual void getVal (const std::vector& t, std::vector& res) const = 0; + + virtual bool isIdentity () const = 0; +}; + +class DiagonalCurve : public Curve +{ + +protected: + DiagonalCurveType kind; + + void spline_cubic_set (); + void NURBS_set (); + +public: + DiagonalCurve (const std::vector& points, int ppn = CURVES_MIN_POLY_POINTS); + virtual ~DiagonalCurve (); + + double getVal (double t) const; + void getVal (const std::vector& t, std::vector& res) const; + bool isIdentity () const + { + return kind == DCT_Empty; + }; +}; + +class FlatCurve : public Curve +{ + +private: + FlatCurveType kind; + double* leftTangent; + double* rightTangent; + double identityValue; + bool periodic; + + void CtrlPoints_set (); + +public: + + FlatCurve (const std::vector& points, bool isPeriodic = true, int ppn = CURVES_MIN_POLY_POINTS); + virtual ~FlatCurve (); + + double getVal (double t) const; + void getVal (const std::vector& t, std::vector& res) const; + bool setIdentityValue (double iVal); + bool isIdentity () const + { + return kind == FCT_Empty; + }; +}; + +class RetinextransmissionCurve +{ +private: + LUTf luttransmission; // 0xffff range + void Set(const Curve &pCurve); + +public: + virtual ~RetinextransmissionCurve() {}; + RetinextransmissionCurve(); + + void Reset(); + void Set(const Curve *pCurve); + void Set(const std::vector &curvePoints); + float operator[](float index) const + { + return luttransmission[index]; + } + + operator bool (void) const + { + return luttransmission; + } +}; + +class RetinexgaintransmissionCurve +{ +private: + LUTf lutgaintransmission; // 0xffff range + void Set(const Curve &pCurve); + +public: + virtual ~RetinexgaintransmissionCurve() {}; + RetinexgaintransmissionCurve(); + + void Reset(); + void Set(const Curve *pCurve); + void Set(const std::vector &curvePoints); + float operator[](float index) const + { + return lutgaintransmission[index]; + } + + operator bool (void) const + { + return lutgaintransmission; + } +}; + + + +class ToneCurve +{ +public: + LUTf lutToneCurve; // 0xffff range + + virtual ~ToneCurve() {}; + + void Reset(); + void Set(const Curve &pCurve, float gamma = 0); + operator bool (void) const + { + return lutToneCurve; + } +}; + +class OpacityCurve +{ +public: + LUTf lutOpacityCurve; // 0xffff range + + virtual ~OpacityCurve() {}; + + void Reset(); + void Set(const Curve *pCurve); + void Set(const std::vector &curvePoints, bool &opautili); + + // TODO: transfer this method to the Color class... + float blend (float x, float lower, float upper) const + { + return (upper - lower) * lutOpacityCurve[x * 500.f] + lower; + } + void blend3f (float x, float lower1, float upper1, float &result1, float lower2, float upper2, float &result2, float lower3, float upper3, float &result3) const + { + float opacity = lutOpacityCurve[x * 500.f]; + result1 = (upper1 - lower1) * opacity + lower1; + result2 = (upper2 - lower2) * opacity + lower2; + result3 = (upper3 - lower3) * opacity + lower3; + } + + operator bool (void) const + { + return lutOpacityCurve; + } +}; + +class WavCurve +{ +private: + LUTf lutWavCurve; // 0xffff range + void Set(const Curve &pCurve); + +public: + float sum; + + virtual ~WavCurve() {}; + WavCurve(); + void Reset(); + void Set(const std::vector &curvePoints); + float getSum() const + { + return sum; + } + + float operator[](float index) const + { + return lutWavCurve[index]; + } + operator bool (void) const + { + return lutWavCurve; + } +}; + +class WavOpacityCurveRG +{ +private: + LUTf lutOpacityCurveRG; // 0xffff range + void Set(const Curve &pCurve); +public: + virtual ~WavOpacityCurveRG() {}; + WavOpacityCurveRG(); + + void Reset(); + // void Set(const std::vector &curvePoints, bool &opautili); + void Set(const std::vector &curvePoints); + float operator[](float index) const + { + return lutOpacityCurveRG[index]; + } + + operator bool (void) const + { + return lutOpacityCurveRG; + } +}; +class WavOpacityCurveBY +{ +private: + LUTf lutOpacityCurveBY; // 0xffff range + void Set(const Curve &pCurve); + +public: + virtual ~WavOpacityCurveBY() {}; + WavOpacityCurveBY(); + + void Reset(); + void Set(const Curve *pCurve); + void Set(const std::vector &curvePoints); + float operator[](float index) const + { + return lutOpacityCurveBY[index]; + } + + operator bool (void) const + { + return lutOpacityCurveBY; + } +}; +class WavOpacityCurveW +{ +private: + LUTf lutOpacityCurveW; // 0xffff range + void Set(const Curve &pCurve); + +public: + virtual ~WavOpacityCurveW() {}; + WavOpacityCurveW(); + + void Reset(); + void Set(const Curve *pCurve); + void Set(const std::vector &curvePoints); + float operator[](float index) const + { + return lutOpacityCurveW[index]; + } + + operator bool (void) const + { + return lutOpacityCurveW; + } +}; + +class WavOpacityCurveWL +{ +private: + LUTf lutOpacityCurveWL; // 0xffff range + void Set(const Curve &pCurve); + +public: + virtual ~WavOpacityCurveWL() {}; + WavOpacityCurveWL(); + + void Reset(); + void Set(const Curve *pCurve); + void Set(const std::vector &curvePoints); + float operator[](float index) const + { + return lutOpacityCurveWL[index]; + } + + operator bool (void) const + { + return lutOpacityCurveWL; + } +}; + +class NoiseCurve +{ +private: + LUTf lutNoiseCurve; // 0xffff range + float sum; + void Set(const Curve &pCurve); + +public: + virtual ~NoiseCurve() {}; + NoiseCurve(); + void Reset(); + void Set(const std::vector &curvePoints); + + float getSum() const + { + return sum; + } + float operator[](float index) const + { + return lutNoiseCurve[index]; + } + operator bool (void) const + { + return lutNoiseCurve; + } +}; + +class ColorGradientCurve +{ +public: + LUTf lut1; // [0.;1.] range (float values) + LUTf lut2; // [0.;1.] range (float values) + LUTf lut3; // [0.;1.] range (float values) + double low; + double high; + + virtual ~ColorGradientCurve() {}; + + void Reset(); + void SetXYZ(const Curve *pCurve, const double xyz_rgb[3][3], float satur, float lumin); + void SetXYZ(const std::vector &curvePoints, const double xyz_rgb[3][3], float satur, float lumin); + void SetRGB(const Curve *pCurve); + void SetRGB(const std::vector &curvePoints); + + /** + * @brief Get the value of Red, Green and Blue corresponding to the requested index + * @param index value in the [0 ; 1] range + * @param r corresponding red value [0 ; 65535] (return value) + * @param g corresponding green value [0 ; 65535] (return value) + * @param b corresponding blue value [0 ; 65535] (return value) + */ + void getVal(float index, float &r, float &g, float &b) const; + operator bool (void) const + { + return lut1 && lut2 && lut3; + } +}; + +class ColorAppearance +{ +public: + LUTf lutColCurve; // 0xffff range + + virtual ~ColorAppearance() {}; + + void Reset(); + void Set(const Curve &pCurve); + operator bool (void) const + { + return lutColCurve; + } +}; + +class Lightcurve : public ColorAppearance +{ +public: + void Apply(float& Li) const; +}; + +//lightness curve +inline void Lightcurve::Apply (float& Li) const +{ + + assert (lutColCurve); + + Li = lutColCurve[Li]; +} + +class Brightcurve : public ColorAppearance +{ +public: + void Apply(float& Br) const; +}; + +//brightness curve +inline void Brightcurve::Apply (float& Br) const +{ + + assert (lutColCurve); + + Br = lutColCurve[Br]; +} + +class Chromacurve : public ColorAppearance +{ +public: + void Apply(float& Cr) const; +}; + +//Chroma curve +inline void Chromacurve::Apply (float& Cr) const +{ + + assert (lutColCurve); + + Cr = lutColCurve[Cr]; +} +class Saturcurve : public ColorAppearance +{ +public: + void Apply(float& Sa) const; +}; + +//Saturation curve +inline void Saturcurve::Apply (float& Sa) const +{ + + assert (lutColCurve); + + Sa = lutColCurve[Sa]; +} + +class Colorfcurve : public ColorAppearance +{ +public: + void Apply(float& Cf) const; +}; + +//Colorfullness curve +inline void Colorfcurve::Apply (float& Cf) const +{ + + assert (lutColCurve); + + Cf = lutColCurve[Cf]; +} + + +class StandardToneCurve : public ToneCurve +{ +public: + void Apply(float& r, float& g, float& b) const; + + // Applies the tone curve to `r`, `g`, `b` arrays, starting at `r[start]` + // and ending at `r[end]` (and respectively for `b` and `g`). Uses SSE + // and requires that `r`, `g`, and `b` pointers have the same alignment. + void BatchApply( + const size_t start, const size_t end, + float *r, float *g, float *b) const; +}; + +class AdobeToneCurve : public ToneCurve +{ +private: + void RGBTone(float& r, float& g, float& b) const; // helper for tone curve + +public: + void Apply(float& r, float& g, float& b) const; +}; + +class SatAndValueBlendingToneCurve : public ToneCurve +{ +public: + void Apply(float& r, float& g, float& b) const; +}; + +class WeightedStdToneCurve : public ToneCurve +{ +private: + float Triangle(float refX, float refY, float X2) const; +#if defined( __SSE2__ ) && defined( __x86_64__ ) + vfloat Triangle(vfloat refX, vfloat refY, vfloat X2) const; +#endif +public: + void Apply(float& r, float& g, float& b) const; + void BatchApply(const size_t start, const size_t end, float *r, float *g, float *b) const; +}; + +class LuminanceToneCurve : public ToneCurve +{ +public: + void Apply(float& r, float& g, float& b) const; +}; + +class PerceptualToneCurveState +{ +public: + float Working2Prophoto[3][3]; + float Prophoto2Working[3][3]; + float cmul_contrast; + bool isProphoto; +}; + +// Tone curve whose purpose is to keep the color appearance constant, that is the curve changes contrast +// but colors appears to have the same hue and saturation as before. As contrast and saturation is tightly +// coupled in human vision saturation is modulated based on the curve's contrast, and that way the appearance +// can be kept perceptually constant (within limits). +class PerceptualToneCurve : public ToneCurve +{ +private: + static float cf_range[2]; + static float cf[1000]; + // for ciecam02 + static float f, c, nc, yb, la, xw, yw, zw, gamut; + static float n, d, nbb, ncb, cz, aw, wh, pfl, fl, pow1; + + static void cubic_spline(const float x[], const float y[], const int len, const float out_x[], float out_y[], const int out_len); + static float find_minimum_interval_halving(float (*func)(float x, void *arg), void *arg, float a, float b, float tol, int nmax); + static float find_tc_slope_fun(float k, void *arg); + static float get_curve_val(float x, float range[2], float lut[], size_t lut_size); + float calculateToneCurveContrastValue() const; +public: + static void init(); + void initApplyState(PerceptualToneCurveState & state, Glib::ustring workingSpace) const; + void BatchApply(const size_t start, const size_t end, float *r, float *g, float *b, const PerceptualToneCurveState &state) const; +}; + +// Standard tone curve +inline void StandardToneCurve::Apply (float& r, float& g, float& b) const +{ + + assert (lutToneCurve); + + r = lutToneCurve[r]; + g = lutToneCurve[g]; + b = lutToneCurve[b]; +} + +inline void StandardToneCurve::BatchApply( + const size_t start, const size_t end, + float *r, float *g, float *b) const { + assert (lutToneCurve); + assert (lutToneCurve.getClip() & LUT_CLIP_BELOW); + assert (lutToneCurve.getClip() & LUT_CLIP_ABOVE); + + // All pointers must have the same alignment for SSE usage. In the loop body below, + // we will only check `r`, assuming that the same result would hold for `g` and `b`. + assert (reinterpret_cast(r) % 16 == reinterpret_cast(g) % 16); + assert (reinterpret_cast(g) % 16 == reinterpret_cast(b) % 16); + + size_t i = start; + while (true) { + if (i >= end) { + // If we get to the end before getting to an aligned address, just return. + // (Or, for non-SSE mode, if we get to the end.) + return; +#if defined( __SSE2__ ) && defined( __x86_64__ ) + } else if (reinterpret_cast(&r[i]) % 16 == 0) { + // Otherwise, we get to the first aligned address; go to the SSE part. + break; +#endif + } + r[i] = lutToneCurve[r[i]]; + g[i] = lutToneCurve[g[i]]; + b[i] = lutToneCurve[b[i]]; + i++; + } + +#if defined( __SSE2__ ) && defined( __x86_64__ ) + for (; i + 3 < end; i += 4) { + __m128 r_val = LVF(r[i]); + __m128 g_val = LVF(g[i]); + __m128 b_val = LVF(b[i]); + STVF(r[i], lutToneCurve[r_val]); + STVF(g[i], lutToneCurve[g_val]); + STVF(b[i], lutToneCurve[b_val]); + } + + // Remainder in non-SSE. + for (; i < end; ++i) { + r[i] = lutToneCurve[r[i]]; + g[i] = lutToneCurve[g[i]]; + b[i] = lutToneCurve[b[i]]; + } +#endif +} + +// Tone curve according to Adobe's reference implementation +// values in 0xffff space +// inlined to make sure there will be no cache flush when used +inline void AdobeToneCurve::Apply (float& r, float& g, float& b) const +{ + + assert (lutToneCurve); + + if (r >= g) { + if (g > b) { + RGBTone (r, g, b); // Case 1: r >= g > b + } else if (b > r) { + RGBTone (b, r, g); // Case 2: b > r >= g + } else if (b > g) { + RGBTone (r, b, g); // Case 3: r >= b > g + } else { // Case 4: r >= g == b + r = lutToneCurve[r]; + g = lutToneCurve[g]; + b = g; + } + } else { + if (r >= b) { + RGBTone (g, r, b); // Case 5: g > r >= b + } else if (b > g) { + RGBTone (b, g, r); // Case 6: b > g > r + } else { + RGBTone (g, b, r); // Case 7: g >= b > r + } + } +} + +inline void AdobeToneCurve::RGBTone (float& r, float& g, float& b) const +{ + float rold = r, gold = g, bold = b; + + r = lutToneCurve[rold]; + b = lutToneCurve[bold]; + g = b + ((r - b) * (gold - bold) / (rold - bold)); +} + +// Modifying the Luminance channel only +inline void LuminanceToneCurve::Apply(float &r, float &g, float &b) const +{ + assert (lutToneCurve); + + float currLuminance = r * 0.2126729f + g * 0.7151521f + b * 0.0721750f; + const float newLuminance = lutToneCurve[currLuminance]; + currLuminance = currLuminance == 0.f ? 0.00001f : currLuminance; + const float coef = newLuminance / currLuminance; + r = LIM(r * coef, 0.f, 65535.f); + g = LIM(g * coef, 0.f, 65535.f); + b = LIM(b * coef, 0.f, 65535.f); +} + +inline float WeightedStdToneCurve::Triangle(float a, float a1, float b) const +{ + if (a != b) { + float b1; + float a2 = a1 - a; + + if (b < a) { + b1 = b + a2 * b / a ; + } else { + b1 = b + a2 * (65535.f - b) / (65535.f - a); + } + + return b1; + } + + return a1; +} + +#if defined( __SSE2__ ) && defined( __x86_64__ ) +inline vfloat WeightedStdToneCurve::Triangle(vfloat a, vfloat a1, vfloat b) const +{ + vfloat a2 = a1 - a; + vmask cmask = vmaskf_lt(b, a); + vfloat b3 = vself(cmask, b, F2V(65535.f) - b); + vfloat a3 = vself(cmask, a, F2V(65535.f) - a); + return b + a2 * b3 / a3; +} +#endif + +// Tone curve modifying the value channel only, preserving hue and saturation +// values in 0xffff space +inline void WeightedStdToneCurve::Apply (float& r, float& g, float& b) const +{ + + assert (lutToneCurve); + + r = CLIP(r); + g = CLIP(g); + b = CLIP(b); + float r1 = lutToneCurve[r]; + float g1 = Triangle(r, r1, g); + float b1 = Triangle(r, r1, b); + + float g2 = lutToneCurve[g]; + float r2 = Triangle(g, g2, r); + float b2 = Triangle(g, g2, b); + + float b3 = lutToneCurve[b]; + float r3 = Triangle(b, b3, r); + float g3 = Triangle(b, b3, g); + + r = CLIP(r1 * 0.50f + r2 * 0.25f + r3 * 0.25f); + g = CLIP(g1 * 0.25f + g2 * 0.50f + g3 * 0.25f); + b = CLIP(b1 * 0.25f + b2 * 0.25f + b3 * 0.50f); +} + +inline void WeightedStdToneCurve::BatchApply(const size_t start, const size_t end, float *r, float *g, float *b) const { + assert (lutToneCurve); + assert (lutToneCurve.getClip() & LUT_CLIP_BELOW); + assert (lutToneCurve.getClip() & LUT_CLIP_ABOVE); + + // All pointers must have the same alignment for SSE usage. In the loop body below, + // we will only check `r`, assuming that the same result would hold for `g` and `b`. + assert (reinterpret_cast(r) % 16 == reinterpret_cast(g) % 16); + assert (reinterpret_cast(g) % 16 == reinterpret_cast(b) % 16); + + size_t i = start; + while (true) { + if (i >= end) { + // If we get to the end before getting to an aligned address, just return. + // (Or, for non-SSE mode, if we get to the end.) + return; +#if defined( __SSE2__ ) && defined( __x86_64__ ) + } else if (reinterpret_cast(&r[i]) % 16 == 0) { + // Otherwise, we get to the first aligned address; go to the SSE part. + break; +#endif + } + Apply(r[i], g[i], b[i]); + i++; + } + +#if defined( __SSE2__ ) && defined( __x86_64__ ) + const vfloat c65535v = F2V(65535.f); + const vfloat zd5v = F2V(0.5f); + const vfloat zd25v = F2V(0.25f); + + for (; i + 3 < end; i += 4) { + vfloat r_val = LIMV(LVF(r[i]), ZEROV, c65535v); + vfloat g_val = LIMV(LVF(g[i]), ZEROV, c65535v); + vfloat b_val = LIMV(LVF(b[i]), ZEROV, c65535v); + vfloat r1 = lutToneCurve[r_val]; + vfloat g1 = Triangle(r_val, r1, g_val); + vfloat b1 = Triangle(r_val, r1, b_val); + + vfloat g2 = lutToneCurve[g_val]; + vfloat r2 = Triangle(g_val, g2, r_val); + vfloat b2 = Triangle(g_val, g2, b_val); + + vfloat b3 = lutToneCurve[b_val]; + vfloat r3 = Triangle(b_val, b3, r_val); + vfloat g3 = Triangle(b_val, b3, g_val); + + STVF(r[i], LIMV(r1 * zd5v + r2 * zd25v + r3 * zd25v, ZEROV, c65535v)); + STVF(g[i], LIMV(g1 * zd25v + g2 * zd5v + g3 * zd25v, ZEROV, c65535v)); + STVF(b[i], LIMV(b1 * zd25v + b2 * zd25v + b3 * zd5v, ZEROV, c65535v)); + } + + // Remainder in non-SSE. + for (; i < end; ++i) { + Apply(r[i], g[i], b[i]); + } +#endif +} + +// Tone curve modifying the value channel only, preserving hue and saturation +// values in 0xffff space +inline void SatAndValueBlendingToneCurve::Apply (float& r, float& g, float& b) const +{ + + assert (lutToneCurve); + + r = CLIP(r); + g = CLIP(g); + b = CLIP(b); + + const float lum = (r + g + b) / 3.f; + const float newLum = lutToneCurve[lum]; + + float h, s, v; + Color::rgb2hsvtc(r, g, b, h, s, v); + + float dV; + if (newLum >= lum) { + // Linearly targeting Value = 1 and Saturation = 0 + const float coef = (newLum - lum) / (65535.f - lum); + dV = (1.f - v) * coef; + s *= 1.f - coef; + } else { + // Linearly targeting Value = 0 + const float coef = (newLum - lum) / lum ; + dV = v * coef; + } + Color::hsv2rgbdcp(h, s, v + dV, r, g, b); +} + +} + +#undef CLIPI + +#endif diff --git a/rtengine/rt_math.h b/rtengine/rt_math.h index 4bdfe6f06..787e2e63f 100644 --- a/rtengine/rt_math.h +++ b/rtengine/rt_math.h @@ -25,6 +25,8 @@ constexpr double RT_NAN = std::numeric_limits::quiet_NaN(); constexpr float RT_PI_F = RT_PI; constexpr float RT_PI_F_2 = RT_PI_2; constexpr float RT_PI_F_180 = RT_PI_180; +constexpr float RT_1_PI_F = RT_1_PI; +constexpr float RT_2_PI_F = RT_2_PI; constexpr float RT_INFINITY_F = std::numeric_limits::infinity(); constexpr float RT_NAN_F = std::numeric_limits::quiet_NaN(); diff --git a/rtengine/sleef.c b/rtengine/sleef.c index 17dfccc0f..f03c9f1b3 100644 --- a/rtengine/sleef.c +++ b/rtengine/sleef.c @@ -923,9 +923,8 @@ __inline float mulsignf(float x, float y) { return intBitsToFloat(floatToRawIntBits(x) ^ (floatToRawIntBits(y) & (1 << 31))); } -__inline float signf(float d) { return mulsignf(1, d); } +__inline float signf(float d) { return copysign(1, d); } __inline float mlaf(float x, float y, float z) { return x * y + z; } -__inline float xrintf(float x) { return x < 0 ? (int)(x - 0.5f) : (int)(x + 0.5f); } __inline int xisnanf(float x) { return x != x; } __inline int xisinff(float x) { return x == rtengine::RT_INFINITY_F || x == -rtengine::RT_INFINITY_F; } @@ -984,7 +983,7 @@ __inline float xsinf(float d) { int q; float u, s; - q = (int)xrintf(d * (float)rtengine::RT_1_PI); + q = rint(d * rtengine::RT_1_PI_F); d = mlaf(q, -PI4_Af*4, d); d = mlaf(q, -PI4_Bf*4, d); @@ -1009,7 +1008,7 @@ __inline float xcosf(float d) { int q; float u, s; - q = 1 + 2*(int)xrintf(d * (float)rtengine::RT_1_PI - 0.5f); + q = 1 + 2*rint(d * rtengine::RT_1_PI_F - 0.5f); d = mlaf(q, -PI4_Af*2, d); d = mlaf(q, -PI4_Bf*2, d); @@ -1035,7 +1034,7 @@ __inline float2 xsincosf(float d) { float u, s, t; float2 r; - q = (int)rint(d * ((float)(2 * rtengine::RT_1_PI))); + q = rint(d * rtengine::RT_2_PI_F); s = d; @@ -1076,7 +1075,7 @@ __inline float xtanf(float d) { int q; float u, s, x; - q = (int)xrintf(d * (float)(2 * rtengine::RT_1_PI)); + q = rint(d * (float)(2 * rtengine::RT_1_PI)); x = d; @@ -1202,7 +1201,7 @@ __inline float xlogf(float d) { __inline float xexpf(float d) { if(d<=-104.0f) return 0.0f; - int q = (int)xrintf(d * R_LN2f); + int q = rint(d * R_LN2f); float s, u; s = mlaf(q, -L2Uf, d); From 1006dd1ebf98a3baaa89f35441da8005398838d1 Mon Sep 17 00:00:00 2001 From: heckflosse Date: Mon, 8 Jan 2018 13:19:44 +0100 Subject: [PATCH 9/9] removed accidently committed file --- rtengine/curves.h.save-failed | 1142 --------------------------------- 1 file changed, 1142 deletions(-) delete mode 100644 rtengine/curves.h.save-failed diff --git a/rtengine/curves.h.save-failed b/rtengine/curves.h.save-failed deleted file mode 100644 index 47ab0fc6f..000000000 --- a/rtengine/curves.h.save-failed +++ /dev/null @@ -1,1142 +0,0 @@ -/* - * This file is part of RawTherapee. - * - * Copyright (c) 2004-2010 Gabor Horvath - * - * RawTherapee is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * RawTherapee is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with RawTherapee. If not, see . - */ -#ifndef __CURVES_H__ -#define __CURVES_H__ - -#include -#include -#include -#include "rt_math.h" -#include "../rtgui/mycurve.h" -#include "../rtgui/myflatcurve.h" -#include "../rtgui/mydiagonalcurve.h" -#include "color.h" -#include "procparams.h" -#include "pipettebuffer.h" - -#include "LUT.h" - -#define CURVES_MIN_POLY_POINTS 1000 - -#include "rt_math.h" - -#define CLIPI(a) ((a)>0?((a)<65534?(a):65534):0) - -using namespace std; - -namespace rtengine -{ -class ToneCurve; -class ColorAppearance; - -class CurveFactory -{ - - friend class Curve; - -protected: - - // functions calculating the parameters of the contrast curve based on the desired slope at the center - static double solve_upper (double m, double c, double deriv); - static double solve_lower (double m, double c, double deriv); - static double dupper (const double b, const double m, const double c); - static double dlower (const double b, const double m, const double c); - - // basic convex function between (0,0) and (1,1). m1 and m2 controls the slope at the start and end point - static inline double basel (double x, double m1, double m2) - { - if (x == 0.0) { - return 0.0; - } - - double k = sqrt ((m1 - 1.0) * (m1 - m2) * 0.5) / (1.0 - m2); - double l = (m1 - m2) / (1.0 - m2) + k; - double lx = xlog(x); - return m2 * x + (1.0 - m2) * (2.0 - xexp(k * lx)) * xexp(l * lx); - } - // basic concave function between (0,0) and (1,1). m1 and m2 controls the slope at the start and end point - static inline double baseu (double x, double m1, double m2) - { - return 1.0 - basel(1.0 - x, m1, m2); - } - // convex curve between (0,0) and (1,1) with slope m at (0,0). hr controls the highlight recovery - static inline double cupper (double x, double m, double hr) - { - if (hr > 1.0) { - return baseu (x, m, 2.0 * (hr - 1.0) / m); - } - - double x1 = (1.0 - hr) / m; - double x2 = x1 + hr; - - if (x >= x2) { - return 1.0; - } - - if (x < x1) { - return x * m; - } - - return 1.0 - hr + hr * baseu((x - x1) / hr, m, 0); - } - // concave curve between (0,0) and (1,1) with slope m at (1,1). sr controls the shadow recovery - static inline double clower (double x, double m, double sr) - { - return 1.0 - cupper(1.0 - x, m, sr); - } - // convex curve between (0,0) and (1,1) with slope m at (0,0). hr controls the highlight recovery - static inline double cupper2 (double x, double m, double hr) - { - double x1 = (1.0 - hr) / m; - double x2 = x1 + hr; - - if (x >= x2) { - return 1.0; - } - - if (x < x1) { - return x * m; - } - - return 1.0 - hr + hr * baseu((x - x1) / hr, m, 0.3 * hr); - } - static inline double clower2 (double x, double m, double sr) - { - //curve for b<0; starts with positive slope and then rolls over toward straight line to x=y=1 - double x1 = sr / 1.5 + 0.00001; - - if (x > x1 || sr < 0.001) { - return 1 - (1 - x) * m; - } else { - double y1 = 1 - (1 - x1) * m; - return y1 + m * (x - x1) - (1 - m) * SQR(SQR(1 - x / x1)); - } - } - // tone curve base. a: slope (from exp.comp.), b: black point normalized by 65535, - // D: max. x value (can be>1), hr,sr: highlight,shadow recovery - static inline double basecurve (double x, double a, double b, double D, double hr, double sr) - { - if (b < 0) { - double m = 0.5;//midpoint - double slope = 1.0 + b; //slope of straight line between (0,-b) and (1,1) - double y = -b + m * slope; //value at midpoint - - if (x > m) { - return y + (x - m) * slope; //value on straight line between (m,y) and (1,1) - } else { - return y * clower2(x / m, slope * m / y, 2.0 - sr); - } - } else { - double slope = a / (1.0 - b); - double m = a * D > 1.0 ? b / a + (0.25) / slope : b + (1 - b) / 4; - double y = a * D > 1.0 ? 0.25 : (m - b / a) * slope; - - if (x <= m) { - return b == 0 ? x * slope : clower (x / m, slope * m / y, sr) * y; - } else if (a * D > 1.0) { - return y + (1.0 - y) * cupper2((x - m) / (D - m), slope * (D - m) / (1.0 - y), hr); - } else { - return y + (x - m) * slope; - } - } - } - static inline double simplebasecurve (double x, double b, double sr) - { - // a = 1, D = 1, hr = 0 (unused for a = D = 1) - if (b == 0.0) { - return x; - } else if (b < 0) { - double m = 0.5;//midpoint - double slope = 1.0 + b; //slope of straight line between (0,-b) and (1,1) - double y = -b + m * slope; //value at midpoint - - if (x > m) { - return y + (x - m) * slope; //value on straight line between (m,y) and (1,1) - } else { - return y * clower2(x / m, slope * m / y, 2.0 - sr); - } - } else { - double slope = 1.0 / (1.0 - b); - double m = b + (1 - b) * 0.25; - double y = (m - b) * slope; - - if (x <= m) { - return clower (x / m, slope * m / y, sr) * y; - } else { - return y + (x - m) * slope; - } - } - } - - -public: - const static double sRGBGamma; // standard average gamma - const static double sRGBGammaCurve; // 2.4 in the curve - - - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - // accurately determine value from integer array with float as index - //linearly interpolate from ends of range if arg is out of bounds - static inline float interp(int *array, float f) - { - int index = CLIPI(floor(f)); - float part = (float)((f) - index) * (float)(array[index + 1] - array[index]); - return (float)array[index] + part; - } - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - // accurately determine value from float array with float as index - //linearly interpolate from ends of range if arg is out of bounds - static inline float flinterp(float *array, float f) - { - int index = CLIPI(floor(f)); - float part = ((f) - (float)index) * (array[index + 1] - array[index]); - return array[index] + part; - } - //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - static inline double centercontrast (double x, double b, double m); - - // standard srgb gamma and its inverse - static inline double gamma2 (double x) - { - return x <= 0.00304 ? x * 12.92 : 1.055 * exp(log(x) / sRGBGammaCurve) - 0.055; - } - static inline double igamma2 (double x) - { - return x <= 0.03928 ? x / 12.92 : exp(log((x + 0.055) / 1.055) * sRGBGammaCurve); - } - static inline float gamma2 (float x) - { - return x <= 0.00304 ? x * 12.92 : 1.055 * expf(logf(x) / sRGBGammaCurve) - 0.055; - } - static inline float igamma2 (float x) - { - return x <= 0.03928 ? x / 12.92 : expf(logf((x + 0.055) / 1.055) * sRGBGammaCurve); - } - // gamma function with adjustable parameters - static inline double gamma (double x, double gamma, double start, double slope, double mul, double add) - { - return (x <= start ? x*slope : exp(log(x) / gamma) * mul - add); - } - static inline double igamma (double x, double gamma, double start, double slope, double mul, double add) - { - return (x <= start * slope ? x / slope : exp(log((x + add) / mul) * gamma) ); - } - static inline float gamma (float x, float gamma, float start, float slope, float mul, float add) - { - return (x <= start ? x*slope : xexpf(xlogf(x) / gamma) * mul - add); - } - static inline float igamma (float x, float gamma, float start, float slope, float mul, float add) - { - return (x <= start * slope ? x / slope : xexpf(xlogf((x + add) / mul) * gamma) ); - } -#ifdef __SSE2__ - static inline vfloat igamma (vfloat x, vfloat gamma, vfloat start, vfloat slope, vfloat mul, vfloat add) - { -#if !defined(__clang__) - return (x <= start * slope ? x / slope : xexpf(xlogf((x + add) / mul) * gamma) ); -#else - return vself(vmaskf_le(x, start * slope), x / slope, xexpf(xlogf((x + add) / mul) * gamma)); -#endif - } -#endif - static inline float hlcurve (const float exp_scale, const float comp, const float hlrange, float level) - { - if (comp > 0.0) { - float val = level + (hlrange - 65536.0); - - if(val == 0.0f) { // to avoid division by zero - val = 0.000001f; - } - - float Y = val * exp_scale / hlrange; - Y *= comp; - - if(Y <= -1.0) { // to avoid log(<=0) - Y = -.999999f; - } - - float R = hlrange / (val * comp); - return log1p(Y) * R; - } else { - return exp_scale; - } - } - -public: - static void complexCurve (double ecomp, double black, double hlcompr, double hlcomprthresh, double shcompr, double br, double contr, - const std::vector& curvePoints, const std::vector& curvePoints2, - LUTu & histogram, LUTf & hlCurve, LUTf & shCurve, LUTf & outCurve, LUTu & outBeforeCCurveHistogram, ToneCurve & outToneCurve, ToneCurve & outToneCurve2, - - int skip = 1); - static void curveBW (const std::vector& curvePointsbw, const std::vector& curvePointsbw2, const LUTu & histogrambw, LUTu & outBeforeCCurveHistogrambw, - ToneCurve & customToneCurvebw1, ToneCurve & customToneCurvebw2, int skip); - - static void curveCL ( bool & clcutili, const std::vector& clcurvePoints, LUTf & clCurve, int skip); - - static void curveWavContL ( bool & wavcontlutili, const std::vector& wavclcurvePoints, LUTf & wavclCurve,/* LUTu & histogramwavcl, LUTu & outBeforeWavCLurveHistogram,*/int skip); - static void curveDehaContL ( bool & dehacontlutili, const std::vector& dehaclcurvePoints, LUTf & dehaclCurve, int skip, const LUTu & histogram, LUTu & outBeforeCurveHistogram); - static void mapcurve ( bool & mapcontlutili, const std::vector& mapcurvePoints, LUTf & mapcurve, int skip, const LUTu & histogram, LUTu & outBeforeCurveHistogram); - - static void curveToning ( const std::vector& curvePoints, LUTf & ToningCurve, int skip); - - static void complexsgnCurve ( bool & autili, bool & butili, bool & ccutili, bool & clcutili, const std::vector& acurvePoints, - const std::vector& bcurvePoints, const std::vector& cccurvePoints, const std::vector& lccurvePoints, LUTf & aoutCurve, LUTf & boutCurve, LUTf & satCurve, LUTf & lhskCurve, - int skip = 1); - static void complexLCurve (double br, double contr, const std::vector& curvePoints, const LUTu & histogram, LUTf & outCurve, LUTu & outBeforeCCurveHistogram, int skip, bool & utili); - - static void curveLightBrightColor ( - const std::vector& curvePoints, - const std::vector& curvePoints2, - const std::vector& curvePoints3, - const LUTu & histogram, LUTu & outBeforeCCurveHistogram, - const LUTu & histogramC, LUTu & outBeforeCCurveHistogramC, - ColorAppearance & outColCurve1, - ColorAppearance & outColCurve2, - ColorAppearance & outColCurve3, - int skip = 1); - static void RGBCurve (const std::vector& curvePoints, LUTf & outCurve, int skip); - -}; - -class Curve -{ - - class HashEntry - { - public: - unsigned short smallerValue; - unsigned short higherValue; - }; -protected: - int N; - int ppn; // targeted polyline point number - double* x; - double* y; - // begin of variables used in Parametric curves only - double mc; - double mfc; - double msc; - double mhc; - // end of variables used in Parametric curves only - std::vector poly_x; // X points of the faceted curve - std::vector poly_y; // Y points of the faceted curve - std::vector dyByDx; - std::vector hash; - unsigned short hashSize; // hash table's size, between [10, 100, 1000] - - double* ypp; - - // Fields for the elementary curve polygonisation - double x1, y1, x2, y2, x3, y3; - bool firstPointIncluded; - double increment; - int nbr_points; - - static inline double p00 (double x, double prot) - { - return CurveFactory::clower (x, 2.0, prot); - } - static inline double p11 (double x, double prot) - { - return CurveFactory::cupper (x, 2.0, prot); - } - static inline double p01 (double x, double prot) - { - return x <= 0.5 ? CurveFactory::clower (x * 2, 2.0, prot) * 0.5 : 0.5 + CurveFactory::cupper ((x - 0.5) * 2, 2.0, prot) * 0.5; - } - static inline double p10 (double x, double prot) - { - return x <= 0.5 ? CurveFactory::cupper (x * 2, 2.0, prot) * 0.5 : 0.5 + CurveFactory::clower ((x - 0.5) * 2, 2.0, prot) * 0.5; - } - static inline double pfull (double x, double prot, double sh, double hl) - { - return (1 - sh) * (1 - hl) * p00(x, prot) + sh * hl * p11(x, prot) + (1 - sh) * hl * p01(x, prot) + sh * (1 - hl) * p10(x, prot); - } - - void fillHash(); - void fillDyByDx(); - -public: - Curve (); - virtual ~Curve () {}; - void AddPolygons (); - int getSize () const; // return the number of control points - void getControlPoint(int cpNum, double &x, double &y) const; - virtual double getVal (double t) const = 0; - virtual void getVal (const std::vector& t, std::vector& res) const = 0; - - virtual bool isIdentity () const = 0; -}; - -class DiagonalCurve : public Curve -{ - -protected: - DiagonalCurveType kind; - - void spline_cubic_set (); - void NURBS_set (); - -public: - DiagonalCurve (const std::vector& points, int ppn = CURVES_MIN_POLY_POINTS); - virtual ~DiagonalCurve (); - - double getVal (double t) const; - void getVal (const std::vector& t, std::vector& res) const; - bool isIdentity () const - { - return kind == DCT_Empty; - }; -}; - -class FlatCurve : public Curve -{ - -private: - FlatCurveType kind; - double* leftTangent; - double* rightTangent; - double identityValue; - bool periodic; - - void CtrlPoints_set (); - -public: - - FlatCurve (const std::vector& points, bool isPeriodic = true, int ppn = CURVES_MIN_POLY_POINTS); - virtual ~FlatCurve (); - - double getVal (double t) const; - void getVal (const std::vector& t, std::vector& res) const; - bool setIdentityValue (double iVal); - bool isIdentity () const - { - return kind == FCT_Empty; - }; -}; - -class RetinextransmissionCurve -{ -private: - LUTf luttransmission; // 0xffff range - void Set(const Curve &pCurve); - -public: - virtual ~RetinextransmissionCurve() {}; - RetinextransmissionCurve(); - - void Reset(); - void Set(const Curve *pCurve); - void Set(const std::vector &curvePoints); - float operator[](float index) const - { - return luttransmission[index]; - } - - operator bool (void) const - { - return luttransmission; - } -}; - -class RetinexgaintransmissionCurve -{ -private: - LUTf lutgaintransmission; // 0xffff range - void Set(const Curve &pCurve); - -public: - virtual ~RetinexgaintransmissionCurve() {}; - RetinexgaintransmissionCurve(); - - void Reset(); - void Set(const Curve *pCurve); - void Set(const std::vector &curvePoints); - float operator[](float index) const - { - return lutgaintransmission[index]; - } - - operator bool (void) const - { - return lutgaintransmission; - } -}; - - - -class ToneCurve -{ -public: - LUTf lutToneCurve; // 0xffff range - - virtual ~ToneCurve() {}; - - void Reset(); - void Set(const Curve &pCurve, float gamma = 0); - operator bool (void) const - { - return lutToneCurve; - } -}; - -class OpacityCurve -{ -public: - LUTf lutOpacityCurve; // 0xffff range - - virtual ~OpacityCurve() {}; - - void Reset(); - void Set(const Curve *pCurve); - void Set(const std::vector &curvePoints, bool &opautili); - - // TODO: transfer this method to the Color class... - float blend (float x, float lower, float upper) const - { - return (upper - lower) * lutOpacityCurve[x * 500.f] + lower; - } - void blend3f (float x, float lower1, float upper1, float &result1, float lower2, float upper2, float &result2, float lower3, float upper3, float &result3) const - { - float opacity = lutOpacityCurve[x * 500.f]; - result1 = (upper1 - lower1) * opacity + lower1; - result2 = (upper2 - lower2) * opacity + lower2; - result3 = (upper3 - lower3) * opacity + lower3; - } - - operator bool (void) const - { - return lutOpacityCurve; - } -}; - -class WavCurve -{ -private: - LUTf lutWavCurve; // 0xffff range - void Set(const Curve &pCurve); - -public: - float sum; - - virtual ~WavCurve() {}; - WavCurve(); - void Reset(); - void Set(const std::vector &curvePoints); - float getSum() const - { - return sum; - } - - float operator[](float index) const - { - return lutWavCurve[index]; - } - operator bool (void) const - { - return lutWavCurve; - } -}; - -class WavOpacityCurveRG -{ -private: - LUTf lutOpacityCurveRG; // 0xffff range - void Set(const Curve &pCurve); -public: - virtual ~WavOpacityCurveRG() {}; - WavOpacityCurveRG(); - - void Reset(); - // void Set(const std::vector &curvePoints, bool &opautili); - void Set(const std::vector &curvePoints); - float operator[](float index) const - { - return lutOpacityCurveRG[index]; - } - - operator bool (void) const - { - return lutOpacityCurveRG; - } -}; -class WavOpacityCurveBY -{ -private: - LUTf lutOpacityCurveBY; // 0xffff range - void Set(const Curve &pCurve); - -public: - virtual ~WavOpacityCurveBY() {}; - WavOpacityCurveBY(); - - void Reset(); - void Set(const Curve *pCurve); - void Set(const std::vector &curvePoints); - float operator[](float index) const - { - return lutOpacityCurveBY[index]; - } - - operator bool (void) const - { - return lutOpacityCurveBY; - } -}; -class WavOpacityCurveW -{ -private: - LUTf lutOpacityCurveW; // 0xffff range - void Set(const Curve &pCurve); - -public: - virtual ~WavOpacityCurveW() {}; - WavOpacityCurveW(); - - void Reset(); - void Set(const Curve *pCurve); - void Set(const std::vector &curvePoints); - float operator[](float index) const - { - return lutOpacityCurveW[index]; - } - - operator bool (void) const - { - return lutOpacityCurveW; - } -}; - -class WavOpacityCurveWL -{ -private: - LUTf lutOpacityCurveWL; // 0xffff range - void Set(const Curve &pCurve); - -public: - virtual ~WavOpacityCurveWL() {}; - WavOpacityCurveWL(); - - void Reset(); - void Set(const Curve *pCurve); - void Set(const std::vector &curvePoints); - float operator[](float index) const - { - return lutOpacityCurveWL[index]; - } - - operator bool (void) const - { - return lutOpacityCurveWL; - } -}; - -class NoiseCurve -{ -private: - LUTf lutNoiseCurve; // 0xffff range - float sum; - void Set(const Curve &pCurve); - -public: - virtual ~NoiseCurve() {}; - NoiseCurve(); - void Reset(); - void Set(const std::vector &curvePoints); - - float getSum() const - { - return sum; - } - float operator[](float index) const - { - return lutNoiseCurve[index]; - } - operator bool (void) const - { - return lutNoiseCurve; - } -}; - -class ColorGradientCurve -{ -public: - LUTf lut1; // [0.;1.] range (float values) - LUTf lut2; // [0.;1.] range (float values) - LUTf lut3; // [0.;1.] range (float values) - double low; - double high; - - virtual ~ColorGradientCurve() {}; - - void Reset(); - void SetXYZ(const Curve *pCurve, const double xyz_rgb[3][3], float satur, float lumin); - void SetXYZ(const std::vector &curvePoints, const double xyz_rgb[3][3], float satur, float lumin); - void SetRGB(const Curve *pCurve); - void SetRGB(const std::vector &curvePoints); - - /** - * @brief Get the value of Red, Green and Blue corresponding to the requested index - * @param index value in the [0 ; 1] range - * @param r corresponding red value [0 ; 65535] (return value) - * @param g corresponding green value [0 ; 65535] (return value) - * @param b corresponding blue value [0 ; 65535] (return value) - */ - void getVal(float index, float &r, float &g, float &b) const; - operator bool (void) const - { - return lut1 && lut2 && lut3; - } -}; - -class ColorAppearance -{ -public: - LUTf lutColCurve; // 0xffff range - - virtual ~ColorAppearance() {}; - - void Reset(); - void Set(const Curve &pCurve); - operator bool (void) const - { - return lutColCurve; - } -}; - -class Lightcurve : public ColorAppearance -{ -public: - void Apply(float& Li) const; -}; - -//lightness curve -inline void Lightcurve::Apply (float& Li) const -{ - - assert (lutColCurve); - - Li = lutColCurve[Li]; -} - -class Brightcurve : public ColorAppearance -{ -public: - void Apply(float& Br) const; -}; - -//brightness curve -inline void Brightcurve::Apply (float& Br) const -{ - - assert (lutColCurve); - - Br = lutColCurve[Br]; -} - -class Chromacurve : public ColorAppearance -{ -public: - void Apply(float& Cr) const; -}; - -//Chroma curve -inline void Chromacurve::Apply (float& Cr) const -{ - - assert (lutColCurve); - - Cr = lutColCurve[Cr]; -} -class Saturcurve : public ColorAppearance -{ -public: - void Apply(float& Sa) const; -}; - -//Saturation curve -inline void Saturcurve::Apply (float& Sa) const -{ - - assert (lutColCurve); - - Sa = lutColCurve[Sa]; -} - -class Colorfcurve : public ColorAppearance -{ -public: - void Apply(float& Cf) const; -}; - -//Colorfullness curve -inline void Colorfcurve::Apply (float& Cf) const -{ - - assert (lutColCurve); - - Cf = lutColCurve[Cf]; -} - - -class StandardToneCurve : public ToneCurve -{ -public: - void Apply(float& r, float& g, float& b) const; - - // Applies the tone curve to `r`, `g`, `b` arrays, starting at `r[start]` - // and ending at `r[end]` (and respectively for `b` and `g`). Uses SSE - // and requires that `r`, `g`, and `b` pointers have the same alignment. - void BatchApply( - const size_t start, const size_t end, - float *r, float *g, float *b) const; -}; - -class AdobeToneCurve : public ToneCurve -{ -private: - void RGBTone(float& r, float& g, float& b) const; // helper for tone curve - -public: - void Apply(float& r, float& g, float& b) const; -}; - -class SatAndValueBlendingToneCurve : public ToneCurve -{ -public: - void Apply(float& r, float& g, float& b) const; -}; - -class WeightedStdToneCurve : public ToneCurve -{ -private: - float Triangle(float refX, float refY, float X2) const; -#if defined( __SSE2__ ) && defined( __x86_64__ ) - vfloat Triangle(vfloat refX, vfloat refY, vfloat X2) const; -#endif -public: - void Apply(float& r, float& g, float& b) const; - void BatchApply(const size_t start, const size_t end, float *r, float *g, float *b) const; -}; - -class LuminanceToneCurve : public ToneCurve -{ -public: - void Apply(float& r, float& g, float& b) const; -}; - -class PerceptualToneCurveState -{ -public: - float Working2Prophoto[3][3]; - float Prophoto2Working[3][3]; - float cmul_contrast; - bool isProphoto; -}; - -// Tone curve whose purpose is to keep the color appearance constant, that is the curve changes contrast -// but colors appears to have the same hue and saturation as before. As contrast and saturation is tightly -// coupled in human vision saturation is modulated based on the curve's contrast, and that way the appearance -// can be kept perceptually constant (within limits). -class PerceptualToneCurve : public ToneCurve -{ -private: - static float cf_range[2]; - static float cf[1000]; - // for ciecam02 - static float f, c, nc, yb, la, xw, yw, zw, gamut; - static float n, d, nbb, ncb, cz, aw, wh, pfl, fl, pow1; - - static void cubic_spline(const float x[], const float y[], const int len, const float out_x[], float out_y[], const int out_len); - static float find_minimum_interval_halving(float (*func)(float x, void *arg), void *arg, float a, float b, float tol, int nmax); - static float find_tc_slope_fun(float k, void *arg); - static float get_curve_val(float x, float range[2], float lut[], size_t lut_size); - float calculateToneCurveContrastValue() const; -public: - static void init(); - void initApplyState(PerceptualToneCurveState & state, Glib::ustring workingSpace) const; - void BatchApply(const size_t start, const size_t end, float *r, float *g, float *b, const PerceptualToneCurveState &state) const; -}; - -// Standard tone curve -inline void StandardToneCurve::Apply (float& r, float& g, float& b) const -{ - - assert (lutToneCurve); - - r = lutToneCurve[r]; - g = lutToneCurve[g]; - b = lutToneCurve[b]; -} - -inline void StandardToneCurve::BatchApply( - const size_t start, const size_t end, - float *r, float *g, float *b) const { - assert (lutToneCurve); - assert (lutToneCurve.getClip() & LUT_CLIP_BELOW); - assert (lutToneCurve.getClip() & LUT_CLIP_ABOVE); - - // All pointers must have the same alignment for SSE usage. In the loop body below, - // we will only check `r`, assuming that the same result would hold for `g` and `b`. - assert (reinterpret_cast(r) % 16 == reinterpret_cast(g) % 16); - assert (reinterpret_cast(g) % 16 == reinterpret_cast(b) % 16); - - size_t i = start; - while (true) { - if (i >= end) { - // If we get to the end before getting to an aligned address, just return. - // (Or, for non-SSE mode, if we get to the end.) - return; -#if defined( __SSE2__ ) && defined( __x86_64__ ) - } else if (reinterpret_cast(&r[i]) % 16 == 0) { - // Otherwise, we get to the first aligned address; go to the SSE part. - break; -#endif - } - r[i] = lutToneCurve[r[i]]; - g[i] = lutToneCurve[g[i]]; - b[i] = lutToneCurve[b[i]]; - i++; - } - -#if defined( __SSE2__ ) && defined( __x86_64__ ) - for (; i + 3 < end; i += 4) { - __m128 r_val = LVF(r[i]); - __m128 g_val = LVF(g[i]); - __m128 b_val = LVF(b[i]); - STVF(r[i], lutToneCurve[r_val]); - STVF(g[i], lutToneCurve[g_val]); - STVF(b[i], lutToneCurve[b_val]); - } - - // Remainder in non-SSE. - for (; i < end; ++i) { - r[i] = lutToneCurve[r[i]]; - g[i] = lutToneCurve[g[i]]; - b[i] = lutToneCurve[b[i]]; - } -#endif -} - -// Tone curve according to Adobe's reference implementation -// values in 0xffff space -// inlined to make sure there will be no cache flush when used -inline void AdobeToneCurve::Apply (float& r, float& g, float& b) const -{ - - assert (lutToneCurve); - - if (r >= g) { - if (g > b) { - RGBTone (r, g, b); // Case 1: r >= g > b - } else if (b > r) { - RGBTone (b, r, g); // Case 2: b > r >= g - } else if (b > g) { - RGBTone (r, b, g); // Case 3: r >= b > g - } else { // Case 4: r >= g == b - r = lutToneCurve[r]; - g = lutToneCurve[g]; - b = g; - } - } else { - if (r >= b) { - RGBTone (g, r, b); // Case 5: g > r >= b - } else if (b > g) { - RGBTone (b, g, r); // Case 6: b > g > r - } else { - RGBTone (g, b, r); // Case 7: g >= b > r - } - } -} - -inline void AdobeToneCurve::RGBTone (float& r, float& g, float& b) const -{ - float rold = r, gold = g, bold = b; - - r = lutToneCurve[rold]; - b = lutToneCurve[bold]; - g = b + ((r - b) * (gold - bold) / (rold - bold)); -} - -// Modifying the Luminance channel only -inline void LuminanceToneCurve::Apply(float &r, float &g, float &b) const -{ - assert (lutToneCurve); - - float currLuminance = r * 0.2126729f + g * 0.7151521f + b * 0.0721750f; - const float newLuminance = lutToneCurve[currLuminance]; - currLuminance = currLuminance == 0.f ? 0.00001f : currLuminance; - const float coef = newLuminance / currLuminance; - r = LIM(r * coef, 0.f, 65535.f); - g = LIM(g * coef, 0.f, 65535.f); - b = LIM(b * coef, 0.f, 65535.f); -} - -inline float WeightedStdToneCurve::Triangle(float a, float a1, float b) const -{ - if (a != b) { - float b1; - float a2 = a1 - a; - - if (b < a) { - b1 = b + a2 * b / a ; - } else { - b1 = b + a2 * (65535.f - b) / (65535.f - a); - } - - return b1; - } - - return a1; -} - -#if defined( __SSE2__ ) && defined( __x86_64__ ) -inline vfloat WeightedStdToneCurve::Triangle(vfloat a, vfloat a1, vfloat b) const -{ - vfloat a2 = a1 - a; - vmask cmask = vmaskf_lt(b, a); - vfloat b3 = vself(cmask, b, F2V(65535.f) - b); - vfloat a3 = vself(cmask, a, F2V(65535.f) - a); - return b + a2 * b3 / a3; -} -#endif - -// Tone curve modifying the value channel only, preserving hue and saturation -// values in 0xffff space -inline void WeightedStdToneCurve::Apply (float& r, float& g, float& b) const -{ - - assert (lutToneCurve); - - r = CLIP(r); - g = CLIP(g); - b = CLIP(b); - float r1 = lutToneCurve[r]; - float g1 = Triangle(r, r1, g); - float b1 = Triangle(r, r1, b); - - float g2 = lutToneCurve[g]; - float r2 = Triangle(g, g2, r); - float b2 = Triangle(g, g2, b); - - float b3 = lutToneCurve[b]; - float r3 = Triangle(b, b3, r); - float g3 = Triangle(b, b3, g); - - r = CLIP(r1 * 0.50f + r2 * 0.25f + r3 * 0.25f); - g = CLIP(g1 * 0.25f + g2 * 0.50f + g3 * 0.25f); - b = CLIP(b1 * 0.25f + b2 * 0.25f + b3 * 0.50f); -} - -inline void WeightedStdToneCurve::BatchApply(const size_t start, const size_t end, float *r, float *g, float *b) const { - assert (lutToneCurve); - assert (lutToneCurve.getClip() & LUT_CLIP_BELOW); - assert (lutToneCurve.getClip() & LUT_CLIP_ABOVE); - - // All pointers must have the same alignment for SSE usage. In the loop body below, - // we will only check `r`, assuming that the same result would hold for `g` and `b`. - assert (reinterpret_cast(r) % 16 == reinterpret_cast(g) % 16); - assert (reinterpret_cast(g) % 16 == reinterpret_cast(b) % 16); - - size_t i = start; - while (true) { - if (i >= end) { - // If we get to the end before getting to an aligned address, just return. - // (Or, for non-SSE mode, if we get to the end.) - return; -#if defined( __SSE2__ ) && defined( __x86_64__ ) - } else if (reinterpret_cast(&r[i]) % 16 == 0) { - // Otherwise, we get to the first aligned address; go to the SSE part. - break; -#endif - } - Apply(r[i], g[i], b[i]); - i++; - } - -#if defined( __SSE2__ ) && defined( __x86_64__ ) - const vfloat c65535v = F2V(65535.f); - const vfloat zd5v = F2V(0.5f); - const vfloat zd25v = F2V(0.25f); - - for (; i + 3 < end; i += 4) { - vfloat r_val = LIMV(LVF(r[i]), ZEROV, c65535v); - vfloat g_val = LIMV(LVF(g[i]), ZEROV, c65535v); - vfloat b_val = LIMV(LVF(b[i]), ZEROV, c65535v); - vfloat r1 = lutToneCurve[r_val]; - vfloat g1 = Triangle(r_val, r1, g_val); - vfloat b1 = Triangle(r_val, r1, b_val); - - vfloat g2 = lutToneCurve[g_val]; - vfloat r2 = Triangle(g_val, g2, r_val); - vfloat b2 = Triangle(g_val, g2, b_val); - - vfloat b3 = lutToneCurve[b_val]; - vfloat r3 = Triangle(b_val, b3, r_val); - vfloat g3 = Triangle(b_val, b3, g_val); - - STVF(r[i], LIMV(r1 * zd5v + r2 * zd25v + r3 * zd25v, ZEROV, c65535v)); - STVF(g[i], LIMV(g1 * zd25v + g2 * zd5v + g3 * zd25v, ZEROV, c65535v)); - STVF(b[i], LIMV(b1 * zd25v + b2 * zd25v + b3 * zd5v, ZEROV, c65535v)); - } - - // Remainder in non-SSE. - for (; i < end; ++i) { - Apply(r[i], g[i], b[i]); - } -#endif -} - -// Tone curve modifying the value channel only, preserving hue and saturation -// values in 0xffff space -inline void SatAndValueBlendingToneCurve::Apply (float& r, float& g, float& b) const -{ - - assert (lutToneCurve); - - r = CLIP(r); - g = CLIP(g); - b = CLIP(b); - - const float lum = (r + g + b) / 3.f; - const float newLum = lutToneCurve[lum]; - - float h, s, v; - Color::rgb2hsvtc(r, g, b, h, s, v); - - float dV; - if (newLum >= lum) { - // Linearly targeting Value = 1 and Saturation = 0 - const float coef = (newLum - lum) / (65535.f - lum); - dV = (1.f - v) * coef; - s *= 1.f - coef; - } else { - // Linearly targeting Value = 0 - const float coef = (newLum - lum) / lum ; - dV = v * coef; - } - Color::hsv2rgbdcp(h, s, v + dV, r, g, b); -} - -} - -#undef CLIPI - -#endif