diff --git a/rtdata/languages/Catala b/rtdata/languages/Catala index c3a7ea1d0..1c89d23c5 100644 --- a/rtdata/languages/Catala +++ b/rtdata/languages/Catala @@ -84,8 +84,6 @@ FILEBROWSER_AUTOFLATFIELD;Auto camp pla FILEBROWSER_BROWSEPATHBUTTONHINT;Clic per navegar al path escollit FILEBROWSER_BROWSEPATHHINT;Escriviu path on buscar.\nCtrl-O dirigir-se al path de la finestra de text.\nEnter / Ctrl-Enter (en el gestor de fitxers) per a navegar allí;\n\nPath dreceres:\n ~ - directori home de l'usuari\n ! - directori de fotografies de l'usuari FILEBROWSER_CACHE;Cau -FILEBROWSER_CACHECLEARFROMFULL;Esborra el cau - tot -FILEBROWSER_CACHECLEARFROMPARTIAL;Esborra el cau - part FILEBROWSER_CLEARPROFILE;Neteja FILEBROWSER_COPYPROFILE;Copia FILEBROWSER_CURRENT_NAME;Nom actual: diff --git a/rtdata/languages/Chinese (Simplified) b/rtdata/languages/Chinese (Simplified) index 077da51c0..05b11dd4f 100644 --- a/rtdata/languages/Chinese (Simplified) +++ b/rtdata/languages/Chinese (Simplified) @@ -95,8 +95,6 @@ FILEBROWSER_AUTODARKFRAME;自动暗场 FILEBROWSER_AUTOFLATFIELD;自动平场 FILEBROWSER_BROWSEPATHBUTTONHINT;点击浏览选择的路径 FILEBROWSER_CACHE;缓存 -FILEBROWSER_CACHECLEARFROMFULL;清空缓存 -FILEBROWSER_CACHECLEARFROMPARTIAL;清理缓存 FILEBROWSER_CLEARPROFILE;清空配置 FILEBROWSER_COPYPROFILE;复制配置 FILEBROWSER_CURRENT_NAME;当前名称: diff --git a/rtdata/languages/Chinese (Traditional) b/rtdata/languages/Chinese (Traditional) index 2b2477748..d58343b6a 100644 --- a/rtdata/languages/Chinese (Traditional) +++ b/rtdata/languages/Chinese (Traditional) @@ -507,8 +507,6 @@ TP_WBALANCE_TEMPERATURE;色溫 !FILEBROWSER_BROWSEPATHBUTTONHINT;Click to browse to the chosen path. !FILEBROWSER_BROWSEPATHHINT;Type a path to navigate to.\n\nKeyboard shortcuts:\nCtrl-o to focus to the path text box.\nEnter / Ctrl-Enter to browse there;\nEsc to clear changes.\nShift-Esc to remove focus.\n\nPath shortcuts:\n~ - user's home directory.\n! - user's pictures directory !FILEBROWSER_CACHE;Cache -!FILEBROWSER_CACHECLEARFROMFULL;Clear from cache - full -!FILEBROWSER_CACHECLEARFROMPARTIAL;Clear from cache - partial !FILEBROWSER_COLORLABEL_TOOLTIP;Color label.\n\nUse dropdown menu or shortcuts:\nShift-Ctrl-0 No Color\nShift-Ctrl-1 Red\nShift-Ctrl-2 Yellow\nShift-Ctrl-3 Green\nShift-Ctrl-4 Blue\nShift-Ctrl-5 Purple !FILEBROWSER_CURRENT_NAME;Current name: !FILEBROWSER_DARKFRAME;Dark-frame diff --git a/rtdata/languages/Czech b/rtdata/languages/Czech index 18af7bf65..dbc606070 100644 --- a/rtdata/languages/Czech +++ b/rtdata/languages/Czech @@ -154,8 +154,6 @@ FILEBROWSER_AUTOFLATFIELD;Auto Flat Field FILEBROWSER_BROWSEPATHBUTTONHINT;Klikněte pro výběr cesty. FILEBROWSER_BROWSEPATHHINT;Vložte cestu pro procházení.\n\nKlávesové zkratky:\nCtrl-o pro přepnutí do adresního řádku.\nEnter/ Ctrl-Enter pro procházení ;\nEsc pro zrušení změn.\nShift-Esc pro zrušení přepnutí.\n\nZkratky pro cesty:\n~\t- domácí složka uživatele.\n!\t- složka s obrázky uživatele. FILEBROWSER_CACHE;Mezipaměť -FILEBROWSER_CACHECLEARFROMFULL;Vymazat z mezipaměti - úplně -FILEBROWSER_CACHECLEARFROMPARTIAL;Vymazat z mezipaměti - částečně FILEBROWSER_CLEARPROFILE;Smazat FILEBROWSER_COLORLABEL_TOOLTIP;Barevný štítek.\n\nPoužijte výběr ze seznamu nebo klávesové zkratky:\nShift-Ctrl-0 Bez barvy\nShift-Ctrl-1 Červený\nShift-Ctrl-2 Žlutý\nShift-Ctrl-3 Zelený\nShift-Ctrl-4 Modrý\nShift-Ctrl-5 Nachový FILEBROWSER_COPYPROFILE;Kopírovat diff --git a/rtdata/languages/Dansk b/rtdata/languages/Dansk index 547c5a6e6..da5616b31 100644 --- a/rtdata/languages/Dansk +++ b/rtdata/languages/Dansk @@ -499,8 +499,6 @@ TP_WBALANCE_TEMPERATURE;Temperatur !FILEBROWSER_BROWSEPATHBUTTONHINT;Click to browse to the chosen path. !FILEBROWSER_BROWSEPATHHINT;Type a path to navigate to.\n\nKeyboard shortcuts:\nCtrl-o to focus to the path text box.\nEnter / Ctrl-Enter to browse there;\nEsc to clear changes.\nShift-Esc to remove focus.\n\nPath shortcuts:\n~ - user's home directory.\n! - user's pictures directory !FILEBROWSER_CACHE;Cache -!FILEBROWSER_CACHECLEARFROMFULL;Clear from cache - full -!FILEBROWSER_CACHECLEARFROMPARTIAL;Clear from cache - partial !FILEBROWSER_COLORLABEL_TOOLTIP;Color label.\n\nUse dropdown menu or shortcuts:\nShift-Ctrl-0 No Color\nShift-Ctrl-1 Red\nShift-Ctrl-2 Yellow\nShift-Ctrl-3 Green\nShift-Ctrl-4 Blue\nShift-Ctrl-5 Purple !FILEBROWSER_CURRENT_NAME;Current name: !FILEBROWSER_DARKFRAME;Dark-frame diff --git a/rtdata/languages/Deutsch b/rtdata/languages/Deutsch index dd0655242..3cf1b32da 100644 --- a/rtdata/languages/Deutsch +++ b/rtdata/languages/Deutsch @@ -185,8 +185,6 @@ FILEBROWSER_AUTOFLATFIELD;Automatisches Weißbild FILEBROWSER_BROWSEPATHBUTTONHINT;Ausgewählten Pfad öffnen. FILEBROWSER_BROWSEPATHHINT;Einen Pfad eingeben:\nTaste:\nStrg + o Setzt den Cursor in das Eingabefeld\nEnter Öffnet den Pfad\nEsc Änderungen verwerfen\nUmschalt + Esc Eingabefeld verlassen\n\nSchnellnavigation:\nTaste:\n~ “Home“-Verzeichnis des Benutzers\n! Bilder-Verzeichnis des Benutzers FILEBROWSER_CACHE;Festplatten-Cache -FILEBROWSER_CACHECLEARFROMFULL;Aus dem Festplatten-Cache entfernen (vollständig) -FILEBROWSER_CACHECLEARFROMPARTIAL;Aus dem Festplatten-Cache entfernen (teilweise) FILEBROWSER_CLEARPROFILE;Profil löschen FILEBROWSER_COLORLABEL_TOOLTIP;Farbmarkierung\n\nTaste: Strg + Umschalt + 0 Ohne\nTaste: Strg + Umschalt + 1 Rot\nTaste: Strg + Umschalt + 2 Gelb\nTaste: Strg + Umschalt + 3 Grün\nTaste: Strg + Umschalt + 4 Blau\nTaste: Strg + Umschalt + 5 Violett FILEBROWSER_COPYPROFILE;Profil kopieren diff --git a/rtdata/languages/English (UK) b/rtdata/languages/English (UK) index 800e23527..8fcaafd56 100644 --- a/rtdata/languages/English (UK) +++ b/rtdata/languages/English (UK) @@ -232,8 +232,6 @@ TP_WBALANCE_EQBLUERED_TOOLTIP;Allows to deviate from the normal behaviour of "wh !FILEBROWSER_BROWSEPATHBUTTONHINT;Click to browse to the chosen path. !FILEBROWSER_BROWSEPATHHINT;Type a path to navigate to.\n\nKeyboard shortcuts:\nCtrl-o to focus to the path text box.\nEnter / Ctrl-Enter to browse there;\nEsc to clear changes.\nShift-Esc to remove focus.\n\nPath shortcuts:\n~ - user's home directory.\n! - user's pictures directory !FILEBROWSER_CACHE;Cache -!FILEBROWSER_CACHECLEARFROMFULL;Clear from cache - full -!FILEBROWSER_CACHECLEARFROMPARTIAL;Clear from cache - partial !FILEBROWSER_CLEARPROFILE;Clear !FILEBROWSER_COPYPROFILE;Copy !FILEBROWSER_CURRENT_NAME;Current name: diff --git a/rtdata/languages/English (US) b/rtdata/languages/English (US) index fc2fa83dd..53a2aec91 100644 --- a/rtdata/languages/English (US) +++ b/rtdata/languages/English (US) @@ -116,8 +116,6 @@ !FILEBROWSER_BROWSEPATHBUTTONHINT;Click to browse to the chosen path. !FILEBROWSER_BROWSEPATHHINT;Type a path to navigate to.\n\nKeyboard shortcuts:\nCtrl-o to focus to the path text box.\nEnter / Ctrl-Enter to browse there;\nEsc to clear changes.\nShift-Esc to remove focus.\n\nPath shortcuts:\n~ - user's home directory.\n! - user's pictures directory !FILEBROWSER_CACHE;Cache -!FILEBROWSER_CACHECLEARFROMFULL;Clear from cache - full -!FILEBROWSER_CACHECLEARFROMPARTIAL;Clear from cache - partial !FILEBROWSER_CLEARPROFILE;Clear !FILEBROWSER_COLORLABEL_TOOLTIP;Color label.\n\nUse dropdown menu or shortcuts:\nShift-Ctrl-0 No Color\nShift-Ctrl-1 Red\nShift-Ctrl-2 Yellow\nShift-Ctrl-3 Green\nShift-Ctrl-4 Blue\nShift-Ctrl-5 Purple !FILEBROWSER_COPYPROFILE;Copy diff --git a/rtdata/languages/Espanol b/rtdata/languages/Espanol index 5402f6579..4284523ab 100644 --- a/rtdata/languages/Espanol +++ b/rtdata/languages/Espanol @@ -149,8 +149,6 @@ FILEBROWSER_AUTOFLATFIELD;Campo plano automático FILEBROWSER_BROWSEPATHBUTTONHINT;Pulsar para examinar la carpeta seleccionada FILEBROWSER_BROWSEPATHHINT;Ingrese la ruta a examinar \nCtrl-O poner el foco en campo con la ruta\nEnter / Ctrl-Enter para examinar allí;\nEscPara quitar los cambios.\nShift-Esc Para quitar el foco.\n\n\nAbreviaturas de ruta:\n ~ - Carpeta hogar del usuario\n ! - Carpeta de imágenes del usuario FILEBROWSER_CACHE;Caché -FILEBROWSER_CACHECLEARFROMFULL;Limpiar del caché - Total -FILEBROWSER_CACHECLEARFROMPARTIAL;Limpiar del caché - Parcial FILEBROWSER_CLEARPROFILE;Borrar perfil FILEBROWSER_COLORLABEL_TOOLTIP;Etiquetar con color\n\nUse menú desplegable o atajos de teclado:\nShift-Ctrl-0 No Color\nShift-Ctrl-1 Rojo\nShift-Ctrl-2 Amarillo\nShift-Ctrl-3 Verde\nShift-Ctrl-4 Azul\nShift-Ctrl-5 Púrpura FILEBROWSER_COPYPROFILE;Copiar perfil diff --git a/rtdata/languages/Euskara b/rtdata/languages/Euskara index 851536a29..a604d6aef 100644 --- a/rtdata/languages/Euskara +++ b/rtdata/languages/Euskara @@ -500,8 +500,6 @@ TP_WBALANCE_TEMPERATURE;Tenperatura !FILEBROWSER_BROWSEPATHBUTTONHINT;Click to browse to the chosen path. !FILEBROWSER_BROWSEPATHHINT;Type a path to navigate to.\n\nKeyboard shortcuts:\nCtrl-o to focus to the path text box.\nEnter / Ctrl-Enter to browse there;\nEsc to clear changes.\nShift-Esc to remove focus.\n\nPath shortcuts:\n~ - user's home directory.\n! - user's pictures directory !FILEBROWSER_CACHE;Cache -!FILEBROWSER_CACHECLEARFROMFULL;Clear from cache - full -!FILEBROWSER_CACHECLEARFROMPARTIAL;Clear from cache - partial !FILEBROWSER_COLORLABEL_TOOLTIP;Color label.\n\nUse dropdown menu or shortcuts:\nShift-Ctrl-0 No Color\nShift-Ctrl-1 Red\nShift-Ctrl-2 Yellow\nShift-Ctrl-3 Green\nShift-Ctrl-4 Blue\nShift-Ctrl-5 Purple !FILEBROWSER_CURRENT_NAME;Current name: !FILEBROWSER_DARKFRAME;Dark-frame diff --git a/rtdata/languages/Francais b/rtdata/languages/Francais index 9c1fcce59..2bf82f6e1 100644 --- a/rtdata/languages/Francais +++ b/rtdata/languages/Francais @@ -111,8 +111,6 @@ FILEBROWSER_AUTOFLATFIELD;Champ Uniforme auto FILEBROWSER_BROWSEPATHBUTTONHINT;Cliquez pour parcourir le chemin saisi FILEBROWSER_BROWSEPATHHINT;Saisissez le chemin à parcourir\nCtrl-O pour placer le focus sur le champ de saisie.\nEntrée / Ctrl-Entrée pour y naviguer;\nEsc pour effacer les modifications.\nShift-Esc pour enlever le focus.\n\n\nRaccourcis pour les chemins:\n ~ - le dossier utilisateur\n ! - le dossier Images de l'utilisateur FILEBROWSER_CACHE;Cache -FILEBROWSER_CACHECLEARFROMFULL;Supprimer du cache (complet) -FILEBROWSER_CACHECLEARFROMPARTIAL;Supprimer du cache (partiel) FILEBROWSER_CLEARPROFILE;Remettre le profil à zéro FILEBROWSER_COLORLABEL_TOOLTIP;Label couleur\n\nUtilisez le menu déroulant ou le raccourci clavier:\nShift-Ctrl-0 Pas de couleur\nShift-Ctrl-1 Rouge\nShift-Ctrl-2 Jaune\nShift-Ctrl-3 Vert\nShift-Ctrl-4 Bleu\nShift-Ctrl-5 Pourpre FILEBROWSER_COPYPROFILE;Copier le profil diff --git a/rtdata/languages/Greek b/rtdata/languages/Greek index 086710b52..0c416e421 100644 --- a/rtdata/languages/Greek +++ b/rtdata/languages/Greek @@ -499,8 +499,6 @@ TP_WBALANCE_TEMPERATURE;Θερμοκρασία !FILEBROWSER_BROWSEPATHBUTTONHINT;Click to browse to the chosen path. !FILEBROWSER_BROWSEPATHHINT;Type a path to navigate to.\n\nKeyboard shortcuts:\nCtrl-o to focus to the path text box.\nEnter / Ctrl-Enter to browse there;\nEsc to clear changes.\nShift-Esc to remove focus.\n\nPath shortcuts:\n~ - user's home directory.\n! - user's pictures directory !FILEBROWSER_CACHE;Cache -!FILEBROWSER_CACHECLEARFROMFULL;Clear from cache - full -!FILEBROWSER_CACHECLEARFROMPARTIAL;Clear from cache - partial !FILEBROWSER_COLORLABEL_TOOLTIP;Color label.\n\nUse dropdown menu or shortcuts:\nShift-Ctrl-0 No Color\nShift-Ctrl-1 Red\nShift-Ctrl-2 Yellow\nShift-Ctrl-3 Green\nShift-Ctrl-4 Blue\nShift-Ctrl-5 Purple !FILEBROWSER_CURRENT_NAME;Current name: !FILEBROWSER_DARKFRAME;Dark-frame diff --git a/rtdata/languages/Hebrew b/rtdata/languages/Hebrew index c7477fd09..358045544 100644 --- a/rtdata/languages/Hebrew +++ b/rtdata/languages/Hebrew @@ -500,8 +500,6 @@ TP_WBALANCE_TEMPERATURE;מידת חום !FILEBROWSER_BROWSEPATHBUTTONHINT;Click to browse to the chosen path. !FILEBROWSER_BROWSEPATHHINT;Type a path to navigate to.\n\nKeyboard shortcuts:\nCtrl-o to focus to the path text box.\nEnter / Ctrl-Enter to browse there;\nEsc to clear changes.\nShift-Esc to remove focus.\n\nPath shortcuts:\n~ - user's home directory.\n! - user's pictures directory !FILEBROWSER_CACHE;Cache -!FILEBROWSER_CACHECLEARFROMFULL;Clear from cache - full -!FILEBROWSER_CACHECLEARFROMPARTIAL;Clear from cache - partial !FILEBROWSER_COLORLABEL_TOOLTIP;Color label.\n\nUse dropdown menu or shortcuts:\nShift-Ctrl-0 No Color\nShift-Ctrl-1 Red\nShift-Ctrl-2 Yellow\nShift-Ctrl-3 Green\nShift-Ctrl-4 Blue\nShift-Ctrl-5 Purple !FILEBROWSER_CURRENT_NAME;Current name: !FILEBROWSER_DARKFRAME;Dark-frame diff --git a/rtdata/languages/Italiano b/rtdata/languages/Italiano index ca048d956..e8a49771a 100644 --- a/rtdata/languages/Italiano +++ b/rtdata/languages/Italiano @@ -92,8 +92,6 @@ FILEBROWSER_AUTOFLATFIELD;Flat Field automatico FILEBROWSER_BROWSEPATHBUTTONHINT;Premi per aprire il percorso inserito FILEBROWSER_BROWSEPATHHINT;Inserisci il percorso da aprire\nCtrl-o seleziona il percorso\nEnter, Ctrl-Enter (solo nel Navigatore) porta alla destinazione ;\nScorciatoie:\n ~ - Cartella home\n ! - Cartella Immagini FILEBROWSER_CACHE;Memoria -FILEBROWSER_CACHECLEARFROMFULL;Rimuovi dalla memoria - totale -FILEBROWSER_CACHECLEARFROMPARTIAL;Rimuovi dalla memoria - parziale FILEBROWSER_CLEARPROFILE;Cancella FILEBROWSER_COLORLABEL_TOOLTIP;Etichetta colore.\n\nUsa il menù o le scorciatoie:\nShift-Ctrl-0 Nessun Colore\nShift-Ctrl-1 Rosso\nShift-Ctrl-2 Giallo\nShift-Ctrl-3 Verde\nShift-Ctrl-4 Blu\nShift-Ctrl-5 Viola FILEBROWSER_COPYPROFILE;Copia diff --git a/rtdata/languages/Japanese b/rtdata/languages/Japanese index fe8b79022..0bc015fe9 100644 --- a/rtdata/languages/Japanese +++ b/rtdata/languages/Japanese @@ -146,8 +146,6 @@ FILEBROWSER_AUTOFLATFIELD;オート・フラットフィールド FILEBROWSER_BROWSEPATHBUTTONHINT;クリックで選択したパスをブラウズ FILEBROWSER_BROWSEPATHHINT;参照するパスを入力します\nCtrl-O パスのテキストボックスにフォーカス\nEnter / Ctrl-Enterその場所をブラウズします\nEsc 変更をクリア\nShift-Escフォーカスを削除\nパスのショートカット:\n ~ - ユーザーのホームディレクトリ\n ! - ユーザーの画像ディレクトリ FILEBROWSER_CACHE;cache -FILEBROWSER_CACHECLEARFROMFULL;cacheをクリア - すべて -FILEBROWSER_CACHECLEARFROMPARTIAL;cacheをクリア - 一部 FILEBROWSER_CLEARPROFILE;プロファイルのクリア FILEBROWSER_COLORLABEL_TOOLTIP;カラー・ラベル\n\nドロップダウン・メニューからか、ショートカット:\nShift-Ctrl-1 レッド\nShift-Ctrl-2 イエロー\nShift-Ctrl-3 グリーン\nShift-Ctrl-4 ブルー\nShift-Ctrl-5 パープル FILEBROWSER_COPYPROFILE;プロファイルをコピー diff --git a/rtdata/languages/Latvian b/rtdata/languages/Latvian index 6689e4f95..23887cfb1 100644 --- a/rtdata/languages/Latvian +++ b/rtdata/languages/Latvian @@ -500,8 +500,6 @@ TP_WBALANCE_TEMPERATURE;Temperatūra !FILEBROWSER_BROWSEPATHBUTTONHINT;Click to browse to the chosen path. !FILEBROWSER_BROWSEPATHHINT;Type a path to navigate to.\n\nKeyboard shortcuts:\nCtrl-o to focus to the path text box.\nEnter / Ctrl-Enter to browse there;\nEsc to clear changes.\nShift-Esc to remove focus.\n\nPath shortcuts:\n~ - user's home directory.\n! - user's pictures directory !FILEBROWSER_CACHE;Cache -!FILEBROWSER_CACHECLEARFROMFULL;Clear from cache - full -!FILEBROWSER_CACHECLEARFROMPARTIAL;Clear from cache - partial !FILEBROWSER_COLORLABEL_TOOLTIP;Color label.\n\nUse dropdown menu or shortcuts:\nShift-Ctrl-0 No Color\nShift-Ctrl-1 Red\nShift-Ctrl-2 Yellow\nShift-Ctrl-3 Green\nShift-Ctrl-4 Blue\nShift-Ctrl-5 Purple !FILEBROWSER_CURRENT_NAME;Current name: !FILEBROWSER_DARKFRAME;Dark-frame diff --git a/rtdata/languages/Magyar b/rtdata/languages/Magyar index d0f806fea..4e463a8fd 100644 --- a/rtdata/languages/Magyar +++ b/rtdata/languages/Magyar @@ -82,8 +82,6 @@ FILEBROWSER_AUTOFLATFIELD;Auto Flat Field FILEBROWSER_BROWSEPATHBUTTONHINT;Kattints a kiválasztott útvonal böngészéséhez FILEBROWSER_BROWSEPATHHINT;Gépeld be az elérni kívánt útvonalat.\nCtrl-O-val tudod a fókuszt a beviteli mezőre vinni.\nEnter / Ctrl-Enter (az állományböngészőben) az ottani böngészéshez;\n\nÚtvonalrövidítések:\n ~ - felhasználói fiók (home) könyvtára\n - a felhasználó képkönyvtára FILEBROWSER_CACHE;Gyorsítótár -FILEBROWSER_CACHECLEARFROMFULL;Gyorsítótár ürítése - teljes -FILEBROWSER_CACHECLEARFROMPARTIAL;Gyorsítótár ürítése - részleges FILEBROWSER_CLEARPROFILE;Feldolgozási paraméter törlése FILEBROWSER_COPYPROFILE;Feldolgozási paraméterek másolása FILEBROWSER_CURRENT_NAME;Aktuális név: diff --git a/rtdata/languages/Nederlands b/rtdata/languages/Nederlands index f5948ef26..fd0036952 100644 --- a/rtdata/languages/Nederlands +++ b/rtdata/languages/Nederlands @@ -123,8 +123,6 @@ FILEBROWSER_AUTOFLATFIELD;Selecteer automatisch vlakveldopname FILEBROWSER_BROWSEPATHBUTTONHINT;Klik om te navigeren naar het gekozen pad FILEBROWSER_BROWSEPATHHINT;Typ het pad naar de doelmap.\nCtrl-O markeer het pad in het tekstveld.\nEnter / Ctrl-Enter open de map.\nEsc maak het tekstveld leeg.\nShift-Esc verwijder markering.\n\n\nSneltoetsen:\n ~ - gebruikers home directory\n ! - gebruikers afbeeldingen map FILEBROWSER_CACHE;Cache -FILEBROWSER_CACHECLEARFROMFULL;Verwijder uit cache - volledig -FILEBROWSER_CACHECLEARFROMPARTIAL;Verwijder uit cache - gedeeltelijk FILEBROWSER_CLEARPROFILE;Verwijder profiel FILEBROWSER_COLORLABEL_TOOLTIP;Kleur label\n\nGebruik keuzemenu of nSneltoets:\nShift-Ctrl-0 Geen kleur\nShift-Ctrl-1 Rood\nShift-Ctrl-2 Geel\nShift-Ctrl-3 Groen\nShift-Ctrl-4 Blauw\nShift-Ctrl-5 Paars FILEBROWSER_COPYPROFILE;Kopieer profiel diff --git a/rtdata/languages/Norsk BM b/rtdata/languages/Norsk BM index 4a76fdcda..4a4995aef 100644 --- a/rtdata/languages/Norsk BM +++ b/rtdata/languages/Norsk BM @@ -499,8 +499,6 @@ TP_WBALANCE_TEMPERATURE;Temperatur !FILEBROWSER_BROWSEPATHBUTTONHINT;Click to browse to the chosen path. !FILEBROWSER_BROWSEPATHHINT;Type a path to navigate to.\n\nKeyboard shortcuts:\nCtrl-o to focus to the path text box.\nEnter / Ctrl-Enter to browse there;\nEsc to clear changes.\nShift-Esc to remove focus.\n\nPath shortcuts:\n~ - user's home directory.\n! - user's pictures directory !FILEBROWSER_CACHE;Cache -!FILEBROWSER_CACHECLEARFROMFULL;Clear from cache - full -!FILEBROWSER_CACHECLEARFROMPARTIAL;Clear from cache - partial !FILEBROWSER_COLORLABEL_TOOLTIP;Color label.\n\nUse dropdown menu or shortcuts:\nShift-Ctrl-0 No Color\nShift-Ctrl-1 Red\nShift-Ctrl-2 Yellow\nShift-Ctrl-3 Green\nShift-Ctrl-4 Blue\nShift-Ctrl-5 Purple !FILEBROWSER_CURRENT_NAME;Current name: !FILEBROWSER_DARKFRAME;Dark-frame diff --git a/rtdata/languages/Polish b/rtdata/languages/Polish index f54de5593..b271178e0 100644 --- a/rtdata/languages/Polish +++ b/rtdata/languages/Polish @@ -96,8 +96,6 @@ FILEBROWSER_AUTOFLATFIELD;Automatyczne użycie klatki typu puste pole FILEBROWSER_BROWSEPATHBUTTONHINT;Należy kliknąć, aby przeglądać wybraną ścieżkę FILEBROWSER_BROWSEPATHHINT;Umożliwia przeglądanie wprowadzonej ścieżki\nCtrl-o zaznaczenie\nEnter, Ctrl-Enter (w menedżerze plików) przeglądanie\nSkróty:\n ~ - katalog domowy użytkownika\n ! - katalog z obrazami użytkownia FILEBROWSER_CACHE;Pamięć podręczna -FILEBROWSER_CACHECLEARFROMFULL;Czyszczenie pamięci podręcznej - pełne -FILEBROWSER_CACHECLEARFROMPARTIAL;Czyszczenie pamięci podręcznej - częściowe FILEBROWSER_CLEARPROFILE;Wyczyść profil FILEBROWSER_COLORLABEL_TOOLTIP;Kolorowe etykiety\n\nUżyj za pomocą rozwijanej listy lub skrótów:\nShift-Ctrl-0 No Color\nShift-Ctrl-1 Czerwona\nShift-Ctrl-2 Żółta\nShift-Ctrl-3 Zielona\nShift-Ctrl-4 Niebieska\nShift-Ctrl-5 Purpurowa FILEBROWSER_COPYPROFILE;Kopiuj profil diff --git a/rtdata/languages/Polish (Latin Characters) b/rtdata/languages/Polish (Latin Characters) index d3e62a777..310a1ed13 100644 --- a/rtdata/languages/Polish (Latin Characters) +++ b/rtdata/languages/Polish (Latin Characters) @@ -96,8 +96,6 @@ FILEBROWSER_AUTOFLATFIELD;Automatyczne uzycie klatki typu puste pole FILEBROWSER_BROWSEPATHBUTTONHINT;Nalezy kliknac, aby przegladac wybrana sciezke FILEBROWSER_BROWSEPATHHINT;Umozliwia przegladanie wprowadzonej sciezki\nCtrl-o zaznaczenie\nEnter, Ctrl-Enter (w menedzerze plikow) przegladanie\nSkroty:\n ~ - katalog domowy uzytkownika\n ! - katalog z obrazami uzytkownia FILEBROWSER_CACHE;Pamiec podreczna -FILEBROWSER_CACHECLEARFROMFULL;Czyszczenie pamieci podrecznej - pelne -FILEBROWSER_CACHECLEARFROMPARTIAL;Czyszczenie pamieci podrecznej - czesciowe FILEBROWSER_CLEARPROFILE;Wyczysc profil FILEBROWSER_COLORLABEL_TOOLTIP;Kolorowe etykiety\n\nUzyj za pomoca rozwijanej listy lub skrotow:\nShift-Ctrl-0 No Color\nShift-Ctrl-1 Czerwona\nShift-Ctrl-2 Zolta\nShift-Ctrl-3 Zielona\nShift-Ctrl-4 Niebieska\nShift-Ctrl-5 Purpurowa FILEBROWSER_COPYPROFILE;Kopiuj profil diff --git a/rtdata/languages/Portugues (Brasil) b/rtdata/languages/Portugues (Brasil) index 7acb91cce..c737ddcfd 100644 --- a/rtdata/languages/Portugues (Brasil) +++ b/rtdata/languages/Portugues (Brasil) @@ -113,8 +113,6 @@ FILEBROWSER_AUTOFLATFIELD;Flat-field automático FILEBROWSER_BROWSEPATHBUTTONHINT;Clique para navegar até o caminho escolhido. FILEBROWSER_BROWSEPATHHINT;Digite um caminho para navegar até.\n\nAtalhos do teclado:\nCtrl-o para focar na caixa de texto do caminho.\nEnter / Ctrl-Enter para navegar lá;\nEsc para limpar as alterações.\nShift-Esc para remover o foco.\n\nAtalhos do caminho:\n~ - diretório home do usuário.\n! - diretório de fotos do usuário FILEBROWSER_CACHE;Cache -FILEBROWSER_CACHECLEARFROMFULL;Limpeza do cache - completa -FILEBROWSER_CACHECLEARFROMPARTIAL;Limpeza do cache - partcial FILEBROWSER_CLEARPROFILE;Perfil de limpeza FILEBROWSER_COLORLABEL_TOOLTIP;Etiqueta de cor.\n\nUse o menu suspenso ou atalhos:\nShift-Ctrl-0 Sem Cor\nShift-Ctrl-1 Vermelho\nShift-Ctrl-2 Amarelo\nShift-Ctrl-3 Verde\nShift-Ctrl-4 Azul\nShift-Ctrl-5 Roxo FILEBROWSER_COPYPROFILE;Copiar perfil diff --git a/rtdata/languages/Russian b/rtdata/languages/Russian index 36b63772e..3c89c4a74 100644 --- a/rtdata/languages/Russian +++ b/rtdata/languages/Russian @@ -105,8 +105,6 @@ FILEBROWSER_AUTOFLATFIELD;Автоматическое плоское поле FILEBROWSER_BROWSEPATHBUTTONHINT;Нажмите кнопку мыши чтобы перейти к выбранному каталогу FILEBROWSER_BROWSEPATHHINT;Введите путь для перехода.\nCtrl-O для перехода на диалог ввода текста.\nEnter / Ctrl-Enter (в обозревателе файлов) для перехода;\n\nЯрлыки путей:\n ~ - домашняя папка пользователя\n ! - папка пользователя с изображениями FILEBROWSER_CACHE;Кэш -FILEBROWSER_CACHECLEARFROMFULL;Удалить из кэша - полностью -FILEBROWSER_CACHECLEARFROMPARTIAL;Удалить из кэша - частично FILEBROWSER_CLEARPROFILE;Удалить профиль FILEBROWSER_COLORLABEL_TOOLTIP;Color label\n\nUse dropdown menu or Shortcuts:\nShift-Ctrl-0 No Color\nShift-Ctrl-1 Red\nShift-Ctrl-2 Yellow\nShift-Ctrl-3 Green\nShift-Ctrl-4 Blue\nShift-Ctrl-5 Purple FILEBROWSER_COPYPROFILE;Скопировать профиль diff --git a/rtdata/languages/Serbian (Cyrilic Characters) b/rtdata/languages/Serbian (Cyrilic Characters) index e69c9b874..34c62bf06 100644 --- a/rtdata/languages/Serbian (Cyrilic Characters) +++ b/rtdata/languages/Serbian (Cyrilic Characters) @@ -85,8 +85,6 @@ FILEBROWSER_AUTOFLATFIELD;Аутоматски одреди равно поље FILEBROWSER_BROWSEPATHBUTTONHINT;Кликните за одлазак на узабрану путању FILEBROWSER_BROWSEPATHHINT;Укуцајте путању за разгледање (Ctrl-o поставља фокус, Ctrl-Enter приказује у разгледачу датотека);nПречице путања: ~ — лични директоријум, ! — директоријум са сликама FILEBROWSER_CACHE;Остава -FILEBROWSER_CACHECLEARFROMFULL;Очисти из оставе — све -FILEBROWSER_CACHECLEARFROMPARTIAL;Очисти из оставе — половично FILEBROWSER_CLEARPROFILE;Обриши профил FILEBROWSER_COLORLABEL_TOOLTIP;Натпис у боји.\n\nКористите приложени мени или пречице:\nShift-Ctrl-0 Без боје\nShift-Ctrl-1 Црвена\nShift-Ctrl-2 Жута\nShift-Ctrl-3 Зелена\nShift-Ctrl-4 Плана\nShift-Ctrl-5 Љубичаста FILEBROWSER_COPYPROFILE;Умножи профил diff --git a/rtdata/languages/Serbian (Latin Characters) b/rtdata/languages/Serbian (Latin Characters) index 727cdeb9a..5dd1fa04d 100644 --- a/rtdata/languages/Serbian (Latin Characters) +++ b/rtdata/languages/Serbian (Latin Characters) @@ -85,8 +85,6 @@ FILEBROWSER_AUTOFLATFIELD;Automatski odredi ravno polje FILEBROWSER_BROWSEPATHBUTTONHINT;Kliknite za odlazak na uzabranu putanju FILEBROWSER_BROWSEPATHHINT;Ukucajte putanju za razgledanje (Ctrl-o postavlja fokus, Ctrl-Enter prikazuje u razgledaču datoteka);nPrečice putanja: ~ — lični direktorijum, ! — direktorijum sa slikama FILEBROWSER_CACHE;Ostava -FILEBROWSER_CACHECLEARFROMFULL;Očisti iz ostave — sve -FILEBROWSER_CACHECLEARFROMPARTIAL;Očisti iz ostave — polovično FILEBROWSER_CLEARPROFILE;Obriši profil FILEBROWSER_COLORLABEL_TOOLTIP;Natpis u boji.\n\nKoristite priloženi meni ili prečice:\nShift-Ctrl-0 Bez boje\nShift-Ctrl-1 Crvena\nShift-Ctrl-2 Žuta\nShift-Ctrl-3 Zelena\nShift-Ctrl-4 Plana\nShift-Ctrl-5 Ljubičasta FILEBROWSER_COPYPROFILE;Umnoži profil diff --git a/rtdata/languages/Slovak b/rtdata/languages/Slovak index 022c715e3..15c4050ad 100644 --- a/rtdata/languages/Slovak +++ b/rtdata/languages/Slovak @@ -578,8 +578,6 @@ ZOOMPANEL_ZOOMOUT;Oddialiť - !FILEBROWSER_BROWSEPATHBUTTONHINT;Click to browse to the chosen path. !FILEBROWSER_BROWSEPATHHINT;Type a path to navigate to.\n\nKeyboard shortcuts:\nCtrl-o to focus to the path text box.\nEnter / Ctrl-Enter to browse there;\nEsc to clear changes.\nShift-Esc to remove focus.\n\nPath shortcuts:\n~ - user's home directory.\n! - user's pictures directory !FILEBROWSER_CACHE;Cache -!FILEBROWSER_CACHECLEARFROMFULL;Clear from cache - full -!FILEBROWSER_CACHECLEARFROMPARTIAL;Clear from cache - partial !FILEBROWSER_COLORLABEL_TOOLTIP;Color label.\n\nUse dropdown menu or shortcuts:\nShift-Ctrl-0 No Color\nShift-Ctrl-1 Red\nShift-Ctrl-2 Yellow\nShift-Ctrl-3 Green\nShift-Ctrl-4 Blue\nShift-Ctrl-5 Purple !FILEBROWSER_DARKFRAME;Dark-frame !FILEBROWSER_DELETEDLGMSGINCLPROC;Are you sure you want to delete the selected %1 files including a queue-processed version? diff --git a/rtdata/languages/Suomi b/rtdata/languages/Suomi index 722bf1b0b..b0d075188 100644 --- a/rtdata/languages/Suomi +++ b/rtdata/languages/Suomi @@ -501,8 +501,6 @@ TP_WBALANCE_TEMPERATURE;Lämpötila [K] !FILEBROWSER_BROWSEPATHBUTTONHINT;Click to browse to the chosen path. !FILEBROWSER_BROWSEPATHHINT;Type a path to navigate to.\n\nKeyboard shortcuts:\nCtrl-o to focus to the path text box.\nEnter / Ctrl-Enter to browse there;\nEsc to clear changes.\nShift-Esc to remove focus.\n\nPath shortcuts:\n~ - user's home directory.\n! - user's pictures directory !FILEBROWSER_CACHE;Cache -!FILEBROWSER_CACHECLEARFROMFULL;Clear from cache - full -!FILEBROWSER_CACHECLEARFROMPARTIAL;Clear from cache - partial !FILEBROWSER_COLORLABEL_TOOLTIP;Color label.\n\nUse dropdown menu or shortcuts:\nShift-Ctrl-0 No Color\nShift-Ctrl-1 Red\nShift-Ctrl-2 Yellow\nShift-Ctrl-3 Green\nShift-Ctrl-4 Blue\nShift-Ctrl-5 Purple !FILEBROWSER_CURRENT_NAME;Current name: !FILEBROWSER_DARKFRAME;Dark-frame diff --git a/rtdata/languages/Swedish b/rtdata/languages/Swedish index 44c5dd475..82b11df1e 100644 --- a/rtdata/languages/Swedish +++ b/rtdata/languages/Swedish @@ -94,8 +94,6 @@ FILEBROWSER_AUTOFLATFIELD;Automatisk plattfältskorrigering FILEBROWSER_BROWSEPATHBUTTONHINT;Klicka för att komma till vald sökväg FILEBROWSER_BROWSEPATHHINT;Skriv in en sökväg och tryck Enter (Ctrl-Enter i filhanteraren).\nCtrl-O för att komma till sökfältet.\nEnter / Ctrl-Enter för att bläddra;\nEsc för att rensa ändringar.\nShift-Esc för att ta bort fokus från sökfältet.\n\n\nPath kortkommando:\n ~ - användarens hemkatalog\n ! - användarens bildkatalog FILEBROWSER_CACHE;Cache -FILEBROWSER_CACHECLEARFROMFULL;Rensa från cachen - fullständigt -FILEBROWSER_CACHECLEARFROMPARTIAL;Rensa från cachen - delvis FILEBROWSER_CLEARPROFILE;Återställ profilen FILEBROWSER_COLORLABEL_TOOLTIP;Färgetikett\n\nAnvänd menyn eller kortkommandona:\nShift-Ctrl-0 No Color\nShift-Ctrl-1 Röd\nShift-Ctrl-2 Gul\nShift-Ctrl-3 Grön\nShift-Ctrl-4 Blå\nShift-Ctrl-5 Lila FILEBROWSER_COPYPROFILE;Kopiera profil diff --git a/rtdata/languages/Turkish b/rtdata/languages/Turkish index a3dd1d5ea..051c99217 100644 --- a/rtdata/languages/Turkish +++ b/rtdata/languages/Turkish @@ -500,8 +500,6 @@ TP_WBALANCE_TEMPERATURE;Isı !FILEBROWSER_BROWSEPATHBUTTONHINT;Click to browse to the chosen path. !FILEBROWSER_BROWSEPATHHINT;Type a path to navigate to.\n\nKeyboard shortcuts:\nCtrl-o to focus to the path text box.\nEnter / Ctrl-Enter to browse there;\nEsc to clear changes.\nShift-Esc to remove focus.\n\nPath shortcuts:\n~ - user's home directory.\n! - user's pictures directory !FILEBROWSER_CACHE;Cache -!FILEBROWSER_CACHECLEARFROMFULL;Clear from cache - full -!FILEBROWSER_CACHECLEARFROMPARTIAL;Clear from cache - partial !FILEBROWSER_COLORLABEL_TOOLTIP;Color label.\n\nUse dropdown menu or shortcuts:\nShift-Ctrl-0 No Color\nShift-Ctrl-1 Red\nShift-Ctrl-2 Yellow\nShift-Ctrl-3 Green\nShift-Ctrl-4 Blue\nShift-Ctrl-5 Purple !FILEBROWSER_CURRENT_NAME;Current name: !FILEBROWSER_DARKFRAME;Dark-frame diff --git a/rtdata/languages/default b/rtdata/languages/default index 0c2c439c5..198f5001d 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -43,6 +43,10 @@ DYNPROFILEEDITOR_DELETE;Delete DYNPROFILEEDITOR_EDIT;Edit DYNPROFILEEDITOR_EDIT_RULE;Edit Dynamic Profile Rule DYNPROFILEEDITOR_ENTRY_TOOLTIP;The matching is case insensitive.\nUse the "re:" prefix to enter\na regular expression. +DYNPROFILEEDITOR_IMGTYPE_ANY;Any +DYNPROFILEEDITOR_IMGTYPE_STD;Standard +DYNPROFILEEDITOR_IMGTYPE_HDR;HDR +DYNPROFILEEDITOR_IMGTYPE_PS;Pixel Shift DYNPROFILEEDITOR_MOVE_DOWN;Move Down DYNPROFILEEDITOR_MOVE_UP;Move Up DYNPROFILEEDITOR_NEW;New @@ -115,8 +119,8 @@ FILEBROWSER_AUTOFLATFIELD;Auto flat-field FILEBROWSER_BROWSEPATHBUTTONHINT;Click to browse to the chosen path. FILEBROWSER_BROWSEPATHHINT;Type a path to navigate to.\n\nKeyboard shortcuts:\nCtrl-o to focus to the path text box.\nEnter / Ctrl-Enter to browse there;\nEsc to clear changes.\nShift-Esc to remove focus.\n\nPath shortcuts:\n~ - user's home directory.\n! - user's pictures directory FILEBROWSER_CACHE;Cache -FILEBROWSER_CACHECLEARFROMFULL;Clear from cache - full -FILEBROWSER_CACHECLEARFROMPARTIAL;Clear from cache - partial +FILEBROWSER_CACHECLEARFROMFULL;Clear all including cached profiles +FILEBROWSER_CACHECLEARFROMPARTIAL;Clear all except cached profiles FILEBROWSER_CLEARPROFILE;Clear FILEBROWSER_COLORLABEL_TOOLTIP;Color label.\n\nUse dropdown menu or shortcuts:\nShift-Ctrl-0 No Color\nShift-Ctrl-1 Red\nShift-Ctrl-2 Yellow\nShift-Ctrl-3 Green\nShift-Ctrl-4 Blue\nShift-Ctrl-5 Purple FILEBROWSER_COPYPROFILE;Copy @@ -842,6 +846,10 @@ HISTORY_MSG_591;Local - Avoid color shift HISTORY_MSG_CLAMPOOG;Clip out-of-gamut colors HISTORY_MSG_COLORTONING_LABGRID_VALUE;CT - Color correction +HISTORY_MSG_DEHAZE_DEPTH;Dehaze - Depth +HISTORY_MSG_DEHAZE_ENABLED;Haze Removal +HISTORY_MSG_DEHAZE_SHOW_DEPTH_MAP;Dehaze - Show depth map +HISTORY_MSG_DEHAZE_STRENGTH;Dehaze - Strength HISTORY_MSG_DUALDEMOSAIC_CONTRAST;Dual demosaic - Contrast threshold HISTORY_MSG_DUALDEMOSAIC_AUTO_CONTRAST;Dual demosaic - Auto threshold HISTORY_MSG_HISTMATCHING;Auto-matched tone curve @@ -1071,6 +1079,7 @@ PARTIALPASTE_CROP;Crop PARTIALPASTE_DARKFRAMEAUTOSELECT;Dark-frame auto-selection PARTIALPASTE_DARKFRAMEFILE;Dark-frame file PARTIALPASTE_DEFRINGE;Defringe +PARTIALPASTE_DEHAZE;Haze removal PARTIALPASTE_DETAILGROUP;Detail Settings PARTIALPASTE_DIALOGLABEL;Partial paste processing profile PARTIALPASTE_DIRPYRDENOISE;Noise reduction @@ -1625,6 +1634,10 @@ TP_DARKFRAME_LABEL;Dark-Frame TP_DEFRINGE_LABEL;Defringe TP_DEFRINGE_RADIUS;Radius TP_DEFRINGE_THRESHOLD;Threshold +TP_DEHAZE_DEPTH;Depth +TP_DEHAZE_LABEL;Haze Removal +TP_DEHAZE_SHOW_DEPTH_MAP;Show Depth Map +TP_DEHAZE_STRENGTH;Strength TP_DIRPYRDENOISE_CHROMINANCE_AMZ;Auto multi-zones TP_DIRPYRDENOISE_CHROMINANCE_AUTOGLOBAL;Automatic global TP_DIRPYRDENOISE_CHROMINANCE_AUTOGLOBAL_TOOLTIP;Try to evaluate chroma noise\nBe careful, this calculation is average, and is quite subjective ! diff --git a/rtdata/themes/TooWaBlue-GTK3-20_.css b/rtdata/themes/TooWaBlue-GTK3-20_.css index aa753727d..041b342e3 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-2018 TooWaBoo - Version 2.82 + Version 2.83 RawTherapee is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -135,6 +135,18 @@ tooltip { tooltip label { color: @text-tooltip; } +.grid-spacing > * { + margin-top: 0.166666666666666666em; + margin-bottom: 0.166666666666666666em; +} +.grid-spacing > label:not(:first-child) { + margin-left: 0.75em; + margin-right: 0.25em; +} +.grid-spacing > label:first-child { + margin-left: 0; + margin-right: 0.25em; +} paned { background-color: @bg-light-grey; @@ -1999,7 +2011,7 @@ entry { } spinbutton { - margin: 0.083333333333333333em 0; + margin: 0.083333333333333333em 0 0.083333333333333333em 0.166666666666666666em; padding: 0; min-height: 1.666666666666666666em; min-width: 0; @@ -2010,7 +2022,7 @@ spinbutton { } #MyExpander spinbutton { - margin: 0.166666666666666666em 0; + margin: 0.083333333333333333em 0 0.083333333333333333em 0.166666666666666666em; padding: 0; min-height: 1.333333333333333333em; min-width: 0; diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index f7318a267..111933141 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -129,6 +129,7 @@ set(RTENGINESOURCEFILES vng4_demosaic_RT.cc ipsoftlight.cc guidedfilter.cc + ipdehaze.cc ) if(LENSFUN_HAS_LOAD_DIRECTORY) diff --git a/rtengine/color.h b/rtengine/color.h index 239997110..97dc8037a 100644 --- a/rtengine/color.h +++ b/rtengine/color.h @@ -206,6 +206,10 @@ public: return r * 0.2126729 + g * 0.7151521 + b * 0.0721750; } + static float rgbLuminance(float r, float g, float b, const double workingspace[3][3]) + { + return r * workingspace[1][0] + g * workingspace[1][1] + b * workingspace[1][2]; + } /** * @brief Convert red/green/blue to L*a*b diff --git a/rtengine/curves.cc b/rtengine/curves.cc index 89fac8825..cc618858e 100644 --- a/rtengine/curves.cc +++ b/rtengine/curves.cc @@ -44,6 +44,42 @@ using namespace std; namespace rtengine { +bool sanitizeCurve(std::vector& curve) +{ + // A curve is valid under one of the following conditions: + // 1) Curve has exactly one entry which is D(F)CT_Linear + // 2) Number of curve entries is > 3 and odd + // 3) curve[0] == DCT_Parametric and curve size is >= 8 and curve[1] .. curve[3] are ordered ascending and are distinct + if (curve.empty()) { + curve.push_back (DCT_Linear); + return true; + } else if(curve.size() == 1 && curve[0] != DCT_Linear) { + curve[0] = DCT_Linear; + return true; + } else if((curve.size() % 2 == 0 || curve.size() < 5) && curve[0] != DCT_Parametric) { + curve.clear(); + curve.push_back (DCT_Linear); + return true; + } else if(curve[0] == DCT_Parametric) { + if (curve.size() < 8) { + curve.clear(); + curve.push_back (DCT_Linear); + return true; + } else { + // curve[1] to curve[3] must be ordered ascending and distinct + for (int i = 1; i < 3; i++) { + if (curve[i] >= curve[i + 1]) { + curve[1] = 0.25f; + curve[2] = 0.5f; + curve[3] = 0.75f; + break; + } + } + } + } + return false; +} + Curve::Curve() : N(0), ppn(0), x(nullptr), y(nullptr), mc(0.0), mfc(0.0), msc(0.0), mhc(0.0), hashSize(1000 /* has to be initialized to the maximum value */), ypp(nullptr), x1(0.0), y1(0.0), x2(0.0), y2(0.0), x3(0.0), y3(0.0), firstPointIncluded(false), increment(0.0), nbr_points(0) {} void Curve::AddPolygons() diff --git a/rtengine/curves.h b/rtengine/curves.h index 3e6c52734..0a0c1d2c3 100644 --- a/rtengine/curves.h +++ b/rtengine/curves.h @@ -19,9 +19,12 @@ #ifndef __CURVES_H__ #define __CURVES_H__ -#include #include #include +#include + +#include + #include "rt_math.h" #include "../rtgui/mycurve.h" #include "../rtgui/myflatcurve.h" @@ -42,6 +45,7 @@ using namespace std; namespace rtengine { + class ToneCurve; class ColorAppearance; @@ -55,6 +59,8 @@ void setUnlessOOG(T &r, T &g, T &b, const T &rr, const T &gg, const T &bb) } } +bool sanitizeCurve(std::vector& curve); + namespace curves { inline void setLutVal(const LUTf &lut, float &val) diff --git a/rtengine/dcrop.cc b/rtengine/dcrop.cc index 856002233..8e262c950 100644 --- a/rtengine/dcrop.cc +++ b/rtengine/dcrop.cc @@ -701,7 +701,7 @@ void Crop::update(int todo) std::unique_ptr fattalCrop; - if ((todo & M_HDR) && params.fattal.enabled) { + if ((todo & M_HDR) && (params.fattal.enabled || params.dehaze.enabled)) { Imagefloat *f = origCrop; int fw = skips(parent->fw, skip); int fh = skips(parent->fh, skip); @@ -750,6 +750,7 @@ void Crop::update(int todo) } if (need_fattal) { + parent->ipf.dehaze(f); parent->ipf.ToneMapFattal02(f); } @@ -1098,6 +1099,8 @@ void Crop::update(int todo) parent->ipf.ip_wavelet(labnCrop, labnCrop, kall, WaveParams, wavCLVCurve, waOpacityCurveRG, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, parent->wavclCurve, skip); } + parent->ipf.softLight(labnCrop); + // } // } diff --git a/rtengine/guidedfilter.cc b/rtengine/guidedfilter.cc index f6b702a73..790245b20 100644 --- a/rtengine/guidedfilter.cc +++ b/rtengine/guidedfilter.cc @@ -52,11 +52,39 @@ namespace rtengine { #endif +namespace { + +int calculate_subsampling(int w, int h, int r) +{ + if (r == 1) { + return 1; + } + + if (max(w, h) <= 600) { + return 1; + } + + for (int s = 5; s > 0; --s) { + if (r % s == 0) { + return s; + } + } + + return LIM(r / 2, 2, 4); +} + +} // namespace + + void guidedFilter(const array2D &guide, const array2D &src, array2D &dst, int r, float epsilon, bool multithread, int subsampling) { const int W = src.width(); const int H = src.height(); + if (subsampling <= 0) { + subsampling = calculate_subsampling(W, H, r); + } + enum Op { MUL, DIVEPSILON, ADD, SUB, ADDMUL, SUBMUL }; const auto apply = @@ -107,11 +135,14 @@ void guidedFilter(const array2D &guide, const array2D &src, array2 const array2D &p = src; array2D &q = dst; + AlignedBuffer blur_buf(I.width() * I.height()); const auto f_mean = - [](array2D &d, array2D &s, int rad) -> void + [&](array2D &d, array2D &s, int rad) -> void { rad = LIM(rad, 0, (min(s.width(), s.height()) - 1) / 2 - 1); - boxblur(s, d, rad, rad, s.width(), s.height()); + float **src = s; + float **dst = d; + boxblur(src, dst, blur_buf.data, rad, rad, s.width(), s.height()); }; const auto f_subsample = @@ -184,7 +215,7 @@ void guidedFilter(const array2D &guide, const array2D &src, array2 f_upsample(meanA, meana); DEBUG_DUMP(meanA); - array2D &meanB = q; + array2D meanB(W, H); f_upsample(meanB, meanb); DEBUG_DUMP(meanB); diff --git a/rtengine/guidedfilter.h b/rtengine/guidedfilter.h index 3f987f80e..6691af251 100644 --- a/rtengine/guidedfilter.h +++ b/rtengine/guidedfilter.h @@ -24,6 +24,6 @@ namespace rtengine { -void guidedFilter(const array2D &guide, const array2D &src, array2D &dst, int r, float epsilon, bool multithread, int subsampling=4); +void guidedFilter(const array2D &guide, const array2D &src, array2D &dst, int r, float epsilon, bool multithread, int subsampling=0); } // namespace rtengine diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc index 7f435ebda..d397de57b 100644 --- a/rtengine/improccoordinator.cc +++ b/rtengine/improccoordinator.cc @@ -448,12 +448,13 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) readyphase++; - if ((todo & M_HDR) && params.fattal.enabled) { + if ((todo & M_HDR) && (params.fattal.enabled || params.dehaze.enabled)) { if (fattal_11_dcrop_cache) { delete fattal_11_dcrop_cache; fattal_11_dcrop_cache = nullptr; } + ipf.dehaze(orig_prev); ipf.ToneMapFattal02(orig_prev); if (oprevi != orig_prev) { @@ -918,7 +919,8 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange) } - + ipf.softLight(nprevl); + if (params.colorappearance.enabled) { //L histo and Chroma histo for ciecam // histogram well be for Lab (Lch) values, because very difficult to do with J,Q, M, s, C @@ -1585,7 +1587,8 @@ void ImProcCoordinator::process() || params.raw != nextParams.raw || params.retinex != nextParams.retinex || params.wavelet != nextParams.wavelet - || params.dirpyrequalizer != nextParams.dirpyrequalizer; + || params.dirpyrequalizer != nextParams.dirpyrequalizer + || params.dehaze != nextParams.dehaze; params = nextParams; int change = changeSinceLast; diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc index 53c10f2e6..e8ce2796d 100644 --- a/rtengine/improcfun.cc +++ b/rtengine/improcfun.cc @@ -3229,7 +3229,7 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer } } - softLight(rtemp, gtemp, btemp, istart, jstart, tW, tH, TS); + //softLight(rtemp, gtemp, btemp, istart, jstart, tW, tH, TS); if (!blackwhite) { if (editImgFloat || editWhatever) { diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 1fa082487..ab20311da 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -396,11 +396,12 @@ public: void Badpixelscam(CieImage * ncie, double radius, int thresh, int mode, float chrom, bool hotbad); void BadpixelsLab(LabImage * lab, double radius, int thresh, float chrom); + void dehaze(Imagefloat *rgb); void ToneMapFattal02(Imagefloat *rgb); void localContrast(LabImage *lab); void colorToningLabGrid(LabImage *lab, int xstart, int xend, int ystart, int yend, bool MultiThread); void shadowsHighlights(LabImage *lab); - void softLight(float *red, float *green, float *blue, int istart, int jstart, int tW, int tH, int TS); + void softLight(LabImage *lab); Image8* lab2rgb(LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, bool consider_histogram_settings = true); Imagefloat* lab2rgbOut(LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm); diff --git a/rtengine/ipdehaze.cc b/rtengine/ipdehaze.cc new file mode 100644 index 000000000..fecc73e7d --- /dev/null +++ b/rtengine/ipdehaze.cc @@ -0,0 +1,337 @@ +/* -*- C++ -*- + * + * This file is part of RawTherapee. + * + * Copyright (c) 2018 Alberto Griggio + * + * 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 . + */ + +/* + * Haze removal using the algorithm described in the paper: + * + * Single Image Haze Removal Using Dark Channel Prior + * by He, Sun and Tang + * + * using a guided filter for the "soft matting" of the transmission map + * + */ + +#include "improcfun.h" +#include "guidedfilter.h" +#include "rt_math.h" +#include "rt_algo.h" +#include +#include + +extern Options options; + +namespace rtengine { + +namespace { + +#if 0 +# define DEBUG_DUMP(arr) \ + do { \ + Imagefloat im(arr.width(), arr.height()); \ + const char *out = "/tmp/" #arr ".tif"; \ + for (int y = 0; y < im.getHeight(); ++y) { \ + for (int x = 0; x < im.getWidth(); ++x) { \ + im.r(y, x) = im.g(y, x) = im.b(y, x) = arr[y][x] * 65535.f; \ + } \ + } \ + im.saveTIFF(out, 16); \ + } while (false) +#else +# define DEBUG_DUMP(arr) +#endif + + +int get_dark_channel(const array2D &R, const array2D &G, const array2D &B, array2D &dst, int patchsize, float *ambient, bool clip, bool multithread) +{ + const int W = R.width(); + const int H = R.height(); + + int npatches = 0; + +#ifdef _OPENMP + #pragma omp parallel for if (multithread) +#endif + for (int y = 0; y < H; y += patchsize) { + int pH = min(y+patchsize, H); + for (int x = 0; x < W; x += patchsize, ++npatches) { + float val = RT_INFINITY_F; + int pW = min(x+patchsize, W); + for (int yy = y; yy < pH; ++yy) { + float yval = RT_INFINITY_F; + for (int xx = x; xx < pW; ++xx) { + float r = R[yy][xx]; + float g = G[yy][xx]; + float b = B[yy][xx]; + if (ambient) { + r /= ambient[0]; + g /= ambient[1]; + b /= ambient[2]; + } + yval = min(yval, r, g, b); + } + val = min(val, yval); + } + if (clip) { + val = LIM01(val); + } + for (int yy = y; yy < pH; ++yy) { + std::fill(dst[yy]+x, dst[yy]+pW, val); + } + } + } + + return npatches; +} + + +float estimate_ambient_light(const array2D &R, const array2D &G, const array2D &B, const array2D &dark, int patchsize, int npatches, float ambient[3]) +{ + const int W = R.width(); + const int H = R.height(); + + const auto get_percentile = + [](std::priority_queue &q, float prcnt) -> float + { + size_t n = LIM(q.size() * prcnt, 1, q.size()); + while (q.size() > n) { + q.pop(); + } + return q.top(); + }; + + float darklim = RT_INFINITY_F; + { + std::priority_queue p; + for (int y = 0; y < H; y += patchsize) { + for (int x = 0; x < W; x += patchsize) { + if (!OOG(dark[y][x], 1.f)) { + p.push(dark[y][x]); + } + } + } + darklim = get_percentile(p, 0.95); + } + + std::vector> patches; + patches.reserve(npatches); + + for (int y = 0; y < H; y += patchsize) { + for (int x = 0; x < W; x += patchsize) { + if (dark[y][x] >= darklim && !OOG(dark[y][x], 1.f)) { + patches.push_back(std::make_pair(x, y)); + } + } + } + + if (options.rtSettings.verbose) { + std::cout << "dehaze: computing ambient light from " << patches.size() + << " patches" << std::endl; + } + + float bright_lim = RT_INFINITY_F; + { + std::priority_queue l; + + for (auto &p : patches) { + const int pW = min(p.first+patchsize, W); + const int pH = min(p.second+patchsize, H); + + for (int y = p.second; y < pH; ++y) { + for (int x = p.first; x < pW; ++x) { + l.push(R[y][x] + G[y][x] + B[y][x]); + } + } + } + + bright_lim = get_percentile(l, 0.95); + } + + double rr = 0, gg = 0, bb = 0; + int n = 0; + for (auto &p : patches) { + const int pW = min(p.first+patchsize, W); + const int pH = min(p.second+patchsize, H); + + for (int y = p.second; y < pH; ++y) { + for (int x = p.first; x < pW; ++x) { + float r = R[y][x]; + float g = G[y][x]; + float b = B[y][x]; + if (r + g + b >= bright_lim) { + rr += r; + gg += g; + bb += b; + ++n; + } + } + } + } + ambient[0] = rr / n; + ambient[1] = gg / n; + ambient[2] = bb / n; + + // taken from darktable + return darklim > 0 ? -1.125f * std::log(darklim) : std::log(std::numeric_limits::max()) / 2; +} + + +void extract_channels(Imagefloat *img, array2D &r, array2D &g, array2D &b, int radius, float epsilon, bool multithread) +{ + const int W = img->getWidth(); + const int H = img->getHeight(); + +#ifdef _OPENMP + #pragma omp parallel for if (multithread) +#endif + for (int y = 0; y < H; ++y) { + for (int x = 0; x < W; ++x) { + r[y][x] = img->r(y, x); + g[y][x] = img->g(y, x); + b[y][x] = img->b(y, x); + } + } + + guidedFilter(r, r, r, radius, epsilon, multithread); + guidedFilter(g, g, g, radius, epsilon, multithread); + guidedFilter(b, b, b, radius, epsilon, multithread); +} + + +} // namespace + + +void ImProcFunctions::dehaze(Imagefloat *img) +{ + if (!params->dehaze.enabled) { + return; + } + + img->normalizeFloatTo1(); + + const int W = img->getWidth(); + const int H = img->getHeight(); + float strength = LIM01(float(params->dehaze.strength) / 100.f * 0.9f); + + if (options.rtSettings.verbose) { + std::cout << "dehaze: strength = " << strength << std::endl; + } + + array2D dark(W, H); + + int patchsize = max(int(5 / scale), 2); + int npatches = 0; + float ambient[3]; + array2D &t_tilde = dark; + float max_t = 0.f; + + { + array2D R(W, H); + array2D G(W, H); + array2D B(W, H); + extract_channels(img, R, G, B, patchsize, 1e-1, multiThread); + + patchsize = max(max(W, H) / 600, 2); + npatches = get_dark_channel(R, G, B, dark, patchsize, nullptr, false, multiThread); + DEBUG_DUMP(dark); + + max_t = estimate_ambient_light(R, G, B, dark, patchsize, npatches, ambient); + + if (options.rtSettings.verbose) { + std::cout << "dehaze: ambient light is " + << ambient[0] << ", " << ambient[1] << ", " << ambient[2] + << std::endl; + } + + get_dark_channel(R, G, B, dark, patchsize, ambient, true, multiThread); + } + + if (min(ambient[0], ambient[1], ambient[2]) < 0.01f) { + if (options.rtSettings.verbose) { + std::cout << "dehaze: no haze detected" << std::endl; + } + img->normalizeFloatTo65535(); + return; // probably no haze at all + } + + DEBUG_DUMP(t_tilde); + +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int y = 0; y < H; ++y) { + for (int x = 0; x < W; ++x) { + dark[y][x] = 1.f - strength * dark[y][x]; + } + } + + const int radius = patchsize * 4; + const float epsilon = 1e-5; + array2D &t = t_tilde; + + { + array2D guideB(W, H, img->b.ptrs, ARRAY2D_BYREFERENCE); + guidedFilter(guideB, t_tilde, t, radius, epsilon, multiThread); + } + + DEBUG_DUMP(t); + + if (options.rtSettings.verbose) { + std::cout << "dehaze: max distance is " << max_t << std::endl; + } + + float depth = -float(params->dehaze.depth) / 100.f; + const float t0 = max(1e-3f, std::exp(depth * max_t)); + const float teps = 1e-3f; +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + for (int y = 0; y < H; ++y) { + for (int x = 0; x < W; ++x) { + // ensure that the transmission is such that to avoid clipping... + float rgb[3] = { img->r(y, x), img->g(y, x), img->b(y, x) }; + // ... t >= tl to avoid negative values + float tl = 1.f - min(rgb[0]/ambient[0], rgb[1]/ambient[1], rgb[2]/ambient[2]); + // ... t >= tu to avoid values > 1 + float tu = t0 - teps; + for (int c = 0; c < 3; ++c) { + if (ambient[c] < 1) { + tu = max(tu, (rgb[c] - ambient[c])/(1.f - ambient[c])); + } + } + float mt = max(t[y][x], t0, tl + teps, tu + teps); + if (params->dehaze.showDepthMap) { + img->r(y, x) = img->g(y, x) = img->b(y, x) = 1.f - mt; + } else { + float r = (rgb[0] - ambient[0]) / mt + ambient[0]; + float g = (rgb[1] - ambient[1]) / mt + ambient[1]; + float b = (rgb[2] - ambient[2]) / mt + ambient[2]; + + img->r(y, x) = r; + img->g(y, x) = g; + img->b(y, x) = b; + } + } + } + + img->normalizeFloatTo65535(); +} + + +} // namespace rtengine diff --git a/rtengine/ipsoftlight.cc b/rtengine/ipsoftlight.cc index 35bf9577a..74fb543aa 100644 --- a/rtengine/ipsoftlight.cc +++ b/rtengine/ipsoftlight.cc @@ -26,48 +26,49 @@ namespace rtengine { -void ImProcFunctions::softLight(float *red, float *green, float *blue, int istart, int jstart, int tW, int tH, int TS) +namespace { + +inline float sl(float blend, float x) +{ + if (!OOG(x)) { + const float orig = 1.f - blend; + float v = Color::gamma_srgb(x) / MAXVALF; + // Pegtop's formula from + // https://en.wikipedia.org/wiki/Blend_modes#Soft_Light + float v2 = v * v; + float v22 = v2 * 2.f; + v = v2 + v22 - v22 * v; + x = blend * Color::igamma_srgb(v * MAXVALF) + orig * x; + } + return x; +} + +} // namespace + + +void ImProcFunctions::softLight(LabImage *lab) { if (!params->softlight.enabled || !params->softlight.strength) { return; } + Imagefloat working(lab->W, lab->H); + lab2rgb(*lab, working, params->icm.workingProfile); + const float blend = params->softlight.strength / 100.f; - const float orig = 1.f - blend; - - const auto apply = - [=](float x) -> float - { - if (!OOG(x)) { - float v = Color::gamma_srgb(x) / MAXVALF; - // Pegtop's formula from - // https://en.wikipedia.org/wiki/Blend_modes#Soft_Light - float v2 = v * v; - float v22 = v2 * 2.f; - v = v2 + v22 - v22 * v; - x = blend * Color::igamma_srgb(v * MAXVALF) + orig * x; - } - return x; - }; #ifdef _OPENMP - #pragma omp parallel if (multiThread) + #pragma omp parallel for #endif - { - int ti = 0; -#ifdef _OPENMP - #pragma omp for -#endif - for (int i = istart; i < tH; i++) { - for (int j = jstart, tj = 0; j < tW; j++, tj++) { - const int idx = ti * TS + tj; - red[idx] = apply(red[idx]); - green[idx] = apply(green[idx]); - blue[idx] = apply(blue[idx]); - } - ++ti; + for (int y = 0; y < working.getHeight(); ++y) { + for (int x = 0; x < working.getWidth(); ++x) { + working.r(y, x) = sl(blend, working.r(y, x)); + working.g(y, x) = sl(blend, working.g(y, x)); + working.b(y, x) = sl(blend, working.b(y, x)); } } + + rgb2lab(working, *lab, params->icm.workingProfile); } } // namespace rtengine diff --git a/rtengine/pixelshift.cc b/rtengine/pixelshift.cc index cdf4f990a..76d1f836c 100644 --- a/rtengine/pixelshift.cc +++ b/rtengine/pixelshift.cc @@ -326,7 +326,7 @@ BENCHFUN if (bayerParams.pixelShiftDemosaicMethod == bayerParams.getPSDemosaicMethodString(RAWParams::BayerSensor::PSDemosaicMethod::LMMSE)) { lmmse_interpolate_omp(winw, winh, *(rawDataFrames[0]), red, green, blue, bayerParams.lmmse_iterations); } else if (bayerParams.pixelShiftDemosaicMethod == bayerParams.getPSDemosaicMethodString(RAWParams::BayerSensor::PSDemosaicMethod::AMAZEVNG4)) { - dual_demosaic_RT (true, rawParamsIn, winw, winh, *(rawDataFrames[0]), red, green, blue, bayerParams.dualDemosaicContrast); + dual_demosaic_RT (true, rawParamsIn, winw, winh, *(rawDataFrames[0]), red, green, blue, bayerParams.dualDemosaicContrast, true); } else { amaze_demosaic_RT(winx, winy, winw, winh, *(rawDataFrames[0]), red, green, blue); } @@ -338,7 +338,7 @@ BENCHFUN if (bayerParams.pixelShiftDemosaicMethod == bayerParams.getPSDemosaicMethodString(RAWParams::BayerSensor::PSDemosaicMethod::LMMSE)) { lmmse_interpolate_omp(winw, winh, *(rawDataFrames[i + 1]), redTmp[i], greenTmp[i], blueTmp[i], bayerParams.lmmse_iterations); } else if (bayerParams.pixelShiftDemosaicMethod == bayerParams.getPSDemosaicMethodString(RAWParams::BayerSensor::PSDemosaicMethod::AMAZEVNG4)) { - dual_demosaic_RT (true, rawParamsIn, winw, winh, *(rawDataFrames[i + 1]), redTmp[i], greenTmp[i], blueTmp[i], bayerParams.dualDemosaicContrast); + dual_demosaic_RT (true, rawParamsIn, winw, winh, *(rawDataFrames[i + 1]), redTmp[i], greenTmp[i], blueTmp[i], bayerParams.dualDemosaicContrast, true); } else { amaze_demosaic_RT(winx, winy, winw, winh, *(rawDataFrames[i + 1]), redTmp[i], greenTmp[i], blueTmp[i]); } @@ -367,7 +367,7 @@ BENCHFUN } else if (bayerParams.pixelShiftDemosaicMethod == bayerParams.getPSDemosaicMethodString(RAWParams::BayerSensor::PSDemosaicMethod::AMAZEVNG4)) { RAWParams rawParamsTmp = rawParamsIn; rawParamsTmp.bayersensor.method = RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::AMAZEVNG4); - dual_demosaic_RT (true, rawParamsTmp, winw, winh, rawData, red, green, blue, bayerParams.dualDemosaicContrast); + dual_demosaic_RT (true, rawParamsTmp, winw, winh, rawData, red, green, blue, bayerParams.dualDemosaicContrast, true); } else { amaze_demosaic_RT(winx, winy, winw, winh, rawData, red, green, blue); } diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 5d449b44c..f3af4a249 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -87,13 +87,6 @@ Glib::ustring relativePathIfInside(const Glib::ustring &procparams_fname, bool f return prefix + embedded_fname.substr(dir1.length()); } -void avoidEmptyCurve(std::vector &curve) -{ - if (curve.empty()) { - curve.push_back(FCT_Linear); - } -} - void getFromKeyfile( const Glib::KeyFile& keyfile, const Glib::ustring& group_name, @@ -142,7 +135,7 @@ void getFromKeyfile( ) { value = keyfile.get_double_list(group_name, key); - avoidEmptyCurve(value); + rtengine::sanitizeCurve(value); } template @@ -2620,6 +2613,30 @@ bool SoftLightParams::operator !=(const SoftLightParams& other) const return !(*this == other); } + +DehazeParams::DehazeParams() : + enabled(false), + strength(50), + showDepthMap(false), + depth(25) +{ +} + +bool DehazeParams::operator ==(const DehazeParams& other) const +{ + return + enabled == other.enabled + && strength == other.strength + && showDepthMap == other.showDepthMap + && depth == other.depth; +} + +bool DehazeParams::operator !=(const DehazeParams& other) const +{ + return !(*this == other); +} + + RAWParams::BayerSensor::BayerSensor() : method(getMethodString(Method::AMAZE)), border(4), @@ -2980,6 +2997,8 @@ void ProcParams::setDefaults() softlight = SoftLightParams(); + dehaze = DehazeParams(); + raw = RAWParams(); metadata = MetaDataParams(); @@ -3290,6 +3309,12 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || pedited->defringe.threshold, "Defringing", "Threshold", defringe.threshold, keyFile); saveToKeyfile(!pedited || pedited->defringe.huecurve, "Defringing", "HueCurve", defringe.huecurve, keyFile); +// Dehaze + saveToKeyfile(!pedited || pedited->dehaze.enabled, "Dehaze", "Enabled", dehaze.enabled, keyFile); + saveToKeyfile(!pedited || pedited->dehaze.strength, "Dehaze", "Strength", dehaze.strength, keyFile); + saveToKeyfile(!pedited || pedited->dehaze.showDepthMap, "Dehaze", "ShowDepthMap", dehaze.showDepthMap, keyFile); + saveToKeyfile(!pedited || pedited->dehaze.depth, "Dehaze", "Depth", dehaze.depth, keyFile); + // Directional pyramid denoising saveToKeyfile(!pedited || pedited->dirpyrDenoise.enabled, "Directional Pyramid Denoising", "Enabled", dirpyrDenoise.enabled, keyFile); saveToKeyfile(!pedited || pedited->dirpyrDenoise.enhance, "Directional Pyramid Denoising", "Enhance", dirpyrDenoise.enhance, keyFile); @@ -4828,7 +4853,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) if (ppVersion >= 339) { assignFromKeyfile(keyFile, "Resize", "AllowUpscaling", pedited, resize.allowUpscaling, pedited->resize.allowUpscaling); } else { - resize.allowUpscaling = true; + resize.allowUpscaling = false; if (pedited) { pedited->resize.allowUpscaling = true; } @@ -5240,6 +5265,13 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "SoftLight", "Strength", pedited, softlight.strength, pedited->softlight.strength); } + if (keyFile.has_group("Dehaze")) { + assignFromKeyfile(keyFile, "Dehaze", "Enabled", pedited, dehaze.enabled, pedited->dehaze.enabled); + assignFromKeyfile(keyFile, "Dehaze", "Strength", pedited, dehaze.strength, pedited->dehaze.strength); + assignFromKeyfile(keyFile, "Dehaze", "ShowDepthMap", pedited, dehaze.showDepthMap, pedited->dehaze.showDepthMap); + assignFromKeyfile(keyFile, "Dehaze", "Depth", pedited, dehaze.depth, pedited->dehaze.depth); + } + if (keyFile.has_group("Film Simulation")) { assignFromKeyfile(keyFile, "Film Simulation", "Enabled", pedited, filmSimulation.enabled, pedited->filmSimulation.enabled); assignFromKeyfile(keyFile, "Film Simulation", "ClutFilename", pedited, filmSimulation.clutFilename, pedited->filmSimulation.clutFilename); @@ -5660,7 +5692,8 @@ bool ProcParams::operator ==(const ProcParams& other) const && colorToning == other.colorToning && metadata == other.metadata && exif == other.exif - && iptc == other.iptc; + && iptc == other.iptc + && dehaze == other.dehaze; } bool ProcParams::operator !=(const ProcParams& other) const diff --git a/rtengine/procparams.h b/rtengine/procparams.h index b53ec6c4d..1ba6c080c 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1357,6 +1357,19 @@ struct SoftLightParams { }; +struct DehazeParams { + bool enabled; + int strength; + bool showDepthMap; + int depth; + + DehazeParams(); + + bool operator==(const DehazeParams &other) const; + bool operator!=(const DehazeParams &other) const; +}; + + /** * Parameters for RAW demosaicing, common to all sensor type */ @@ -1571,6 +1584,7 @@ public: HSVEqualizerParams hsvequalizer; ///< hsv wavelet parameters FilmSimulationParams filmSimulation; ///< film simulation parameters SoftLightParams softlight; ///< softlight parameters + DehazeParams dehaze; ///< dehaze parameters int rank; ///< Custom image quality ranking int colorlabel; ///< Custom color label bool inTrash; ///< Marks deleted image diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index 1b9698974..f725d634f 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -271,7 +271,7 @@ protected: void nodemosaic(bool bw); void eahd_demosaic(); void hphd_demosaic(); - void vng4_demosaic(const array2D &rawData, array2D &red, array2D &green, array2D &blue, bool keepGreens = false); + void vng4_demosaic(const array2D &rawData, array2D &red, array2D &green, array2D &blue); void ppg_demosaic(); void jdl_interpolate_omp(); void igv_interpolate(int winw, int winh); diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc index afea47a26..3bdf8bb28 100644 --- a/rtengine/rtthumbnail.cc +++ b/rtengine/rtthumbnail.cc @@ -279,6 +279,11 @@ Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, printf ("loadFromImage: Unsupported image type \"%s\"!\n", img->getType()); } + ProcParams paramsForAutoExp; // Dummy for constructor + ImProcFunctions ipf (¶msForAutoExp, false); + ipf.getAutoExp (tpp->aeHistogram, tpp->aeHistCompression, 0.02, tpp->aeExposureCompensation, tpp->aeLightness, tpp->aeContrast, tpp->aeBlack, tpp->aeHighlightCompression, tpp->aeHighlightCompressionThreshold); + tpp->aeValid = true; + if (n > 0) { ColorTemp cTemp; @@ -923,6 +928,11 @@ Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocati } } } + ProcParams paramsForAutoExp; // Dummy for constructor + ImProcFunctions ipf (¶msForAutoExp, false); + ipf.getAutoExp (tpp->aeHistogram, tpp->aeHistCompression, 0.02, tpp->aeExposureCompensation, tpp->aeLightness, tpp->aeContrast, tpp->aeBlack, tpp->aeHighlightCompression, tpp->aeHighlightCompressionThreshold); + tpp->aeValid = true; + if (ri->get_colors() == 1) { pixSum[0] = pixSum[1] = pixSum[2] = 1.; n[0] = n[1] = n[2] = 1; @@ -993,6 +1003,13 @@ Thumbnail::Thumbnail () : wbEqual (-1.0), wbTempBias (0.0), aeHistCompression (3), + aeValid(false), + aeExposureCompensation(0.0), + aeLightness(0), + aeContrast(0), + aeBlack(0), + aeHighlightCompression(0), + aeHighlightCompressionThreshold(0), embProfileLength (0), embProfileData (nullptr), embProfile (nullptr), @@ -1200,9 +1217,8 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT ipf.firstAnalysis (baseImg, params, hist16); - if (params.fattal.enabled) { - ipf.ToneMapFattal02(baseImg); - } + ipf.dehaze(baseImg); + ipf.ToneMapFattal02(baseImg); // perform transform if (ipf.needsTransform()) { @@ -1224,8 +1240,17 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT int hlcompr = params.toneCurve.hlcompr; int hlcomprthresh = params.toneCurve.hlcomprthresh; - if (params.toneCurve.autoexp && aeHistogram) { - ipf.getAutoExp (aeHistogram, aeHistCompression, params.toneCurve.clip, expcomp, bright, contr, black, hlcompr, hlcomprthresh); + if (params.toneCurve.autoexp) { + if (aeValid) { + expcomp = aeExposureCompensation; + bright = aeLightness; + contr = aeContrast; + black = aeBlack; + hlcompr = aeHighlightCompression; + hlcomprthresh = aeHighlightCompressionThreshold; + } else if (aeHistogram) { + ipf.getAutoExp (aeHistogram, aeHistCompression, 0.02, expcomp, bright, contr, black, hlcompr, hlcomprthresh); + } } LUTf curve1 (65536); @@ -1369,6 +1394,8 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT ipf.EPDToneMap (labView, 5, 6); } + ipf.softLight(labView); + if (params.colorappearance.enabled) { CurveFactory::curveLightBrightColor ( params.colorappearance.curve, @@ -1991,6 +2018,38 @@ bool Thumbnail::readData (const Glib::ustring& fname) aeHistCompression = keyFile.get_integer ("LiveThumbData", "AEHistCompression"); } + aeValid = true; + if (keyFile.has_key ("LiveThumbData", "AEExposureCompensation")) { + aeExposureCompensation = keyFile.get_double ("LiveThumbData", "AEExposureCompensation"); + } else { + aeValid = false; + } + if (keyFile.has_key ("LiveThumbData", "AELightness")) { + aeLightness = keyFile.get_integer ("LiveThumbData", "AELightness"); + } else { + aeValid = false; + } + if (keyFile.has_key ("LiveThumbData", "AEContrast")) { + aeContrast = keyFile.get_integer ("LiveThumbData", "AEContrast"); + } else { + aeValid = false; + } + if (keyFile.has_key ("LiveThumbData", "AEBlack")) { + aeBlack = keyFile.get_integer ("LiveThumbData", "AEBlack"); + } else { + aeValid = false; + } + if (keyFile.has_key ("LiveThumbData", "AEHighlightCompression")) { + aeHighlightCompression = keyFile.get_integer ("LiveThumbData", "AEHighlightCompression"); + } else { + aeValid = false; + } + if (keyFile.has_key ("LiveThumbData", "AEHighlightCompressionThreshold")) { + aeHighlightCompressionThreshold = keyFile.get_integer ("LiveThumbData", "AEHighlightCompressionThreshold"); + } else { + aeValid = false; + } + if (keyFile.has_key ("LiveThumbData", "RedMultiplier")) { redMultiplier = keyFile.get_double ("LiveThumbData", "RedMultiplier"); } @@ -2064,7 +2123,12 @@ bool Thumbnail::writeData (const Glib::ustring& fname) keyFile.set_double ("LiveThumbData", "RedAWBMul", redAWBMul); keyFile.set_double ("LiveThumbData", "GreenAWBMul", greenAWBMul); keyFile.set_double ("LiveThumbData", "BlueAWBMul", blueAWBMul); - keyFile.set_integer ("LiveThumbData", "AEHistCompression", aeHistCompression); + keyFile.set_double ("LiveThumbData", "AEExposureCompensation", aeExposureCompensation); + keyFile.set_integer ("LiveThumbData", "AELightness", aeLightness); + keyFile.set_integer ("LiveThumbData", "AEContrast", aeContrast); + keyFile.set_integer ("LiveThumbData", "AEBlack", aeBlack); + keyFile.set_integer ("LiveThumbData", "AEHighlightCompression", aeHighlightCompression); + keyFile.set_integer ("LiveThumbData", "AEHighlightCompressionThreshold", aeHighlightCompressionThreshold); keyFile.set_double ("LiveThumbData", "RedMultiplier", redMultiplier); keyFile.set_double ("LiveThumbData", "GreenMultiplier", greenMultiplier); keyFile.set_double ("LiveThumbData", "BlueMultiplier", blueMultiplier); diff --git a/rtengine/rtthumbnail.h b/rtengine/rtthumbnail.h index 558d136ee..667d8e1c9 100644 --- a/rtengine/rtthumbnail.h +++ b/rtengine/rtthumbnail.h @@ -50,6 +50,13 @@ class Thumbnail double autoWBTemp, autoWBGreen, wbEqual, wbTempBias; // autoWBTemp and autoWBGreen are updated each time autoWB is requested and if wbEqual has been modified LUTu aeHistogram; int aeHistCompression; + bool aeValid; + double aeExposureCompensation; + int aeLightness; + int aeContrast; + int aeBlack; + int aeHighlightCompression; + int aeHighlightCompressionThreshold; int embProfileLength; unsigned char* embProfileData; cmsHPROFILE embProfile; @@ -100,6 +107,7 @@ public: bool readAEHistogram (const Glib::ustring& fname); bool writeAEHistogram (const Glib::ustring& fname); + bool isAeValid() { return aeValid; }; unsigned char* getImage8Data(); // accessor to the 8bit image if it is one, which should be the case for the "Inspector" mode. // Hombre: ... let's hope that proper template can make this cleaner diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc index 065819f40..333e553f4 100644 --- a/rtengine/simpleprocess.cc +++ b/rtengine/simpleprocess.cc @@ -862,9 +862,8 @@ private: ipf.firstAnalysis(baseImg, params, hist16); - if (params.fattal.enabled) { - ipf.ToneMapFattal02(baseImg); - } + ipf.dehaze(baseImg); + ipf.ToneMapFattal02(baseImg); // perform transform (excepted resizing) if (ipf.needsTransform()) { @@ -1249,6 +1248,8 @@ private: wavCLVCurve.Reset(); + ipf.softLight(labView); + //Colorappearance and tone-mapping associated int f_w = 1, f_h = 1; diff --git a/rtengine/tmo_fattal02.cc b/rtengine/tmo_fattal02.cc index dc7826501..124cdbfb1 100644 --- a/rtengine/tmo_fattal02.cc +++ b/rtengine/tmo_fattal02.cc @@ -952,7 +952,7 @@ inline void rescale_nearest (const Array2Df &src, Array2Df &dst, bool multithrea inline float luminance (float r, float g, float b, TMatrix ws) { - return r * ws[1][0] + g * ws[1][1] + b * ws[1][2]; + return Color::rgbLuminance(r, g, b, ws); } @@ -1014,6 +1014,10 @@ inline int find_fast_dim (int dim) void ImProcFunctions::ToneMapFattal02 (Imagefloat *rgb) { + if (!params->fattal.enabled) { + return; + } + BENCHFUN const int detail_level = 3; diff --git a/rtengine/vng4_demosaic_RT.cc b/rtengine/vng4_demosaic_RT.cc index 8ed05dd09..1c7f27dea 100644 --- a/rtengine/vng4_demosaic_RT.cc +++ b/rtengine/vng4_demosaic_RT.cc @@ -22,16 +22,45 @@ #include "rtengine.h" #include "rawimagesource.h" -#include "rawimagesource_i.h" #include "../rtgui/multilangmgr.h" //#define BENCHMARK #include "StopWatch.h" +namespace { + +using namespace rtengine; + +inline void vng4interpolate_row_redblue (const RawImage *ri, const array2D &rawData, float* ar, float* ab, const float * const pg, const float * const cg, const float * const ng, int i, int width) +{ + if (ri->ISBLUE(i, 0) || ri->ISBLUE(i, 1)) { + std::swap(ar, ab); + } + + // RGRGR or GRGRGR line + for (int j = 3; j < width - 3; ++j) { + if (!ri->ISGREEN(i, j)) { + // keep original value + ar[j] = rawData[i][j]; + // cross interpolation of red/blue + float rb = (rawData[i - 1][j - 1] - pg[j - 1] + rawData[i + 1][j - 1] - ng[j - 1]); + rb += (rawData[i - 1][j + 1] - pg[j + 1] + rawData[i + 1][j + 1] - ng[j + 1]); + ab[j] = cg[j] + rb * 0.25f; + } else { + // linear R/B-G interpolation horizontally + ar[j] = cg[j] + (rawData[i][j - 1] - cg[j - 1] + rawData[i][j + 1] - cg[j + 1]) / 2; + // linear B/R-G interpolation vertically + ab[j] = cg[j] + (rawData[i - 1][j] - pg[j] + rawData[i + 1][j] - ng[j]) / 2; + } + } +} +} + namespace rtengine + { #define fc(row,col) (prefilters >> ((((row) << 1 & 14) + ((col) & 1)) << 1) & 3) -typedef unsigned short ushort; -void RawImageSource::vng4_demosaic (const array2D &rawData, array2D &red, array2D &green, array2D &blue, bool keepGreens) + +void RawImageSource::vng4_demosaic (const array2D &rawData, array2D &red, array2D &green, array2D &blue) { BENCHFUN const signed short int *cp, terms[] = { @@ -71,91 +100,130 @@ void RawImageSource::vng4_demosaic (const array2D &rawData, array2Dprefilters; const int width = W, height = H; constexpr unsigned int colors = 4; - float (*image)[4]; - image = (float (*)[4]) calloc (height * width, sizeof * image); + float (*image)[4] = (float (*)[4]) calloc (height * width, sizeof * image); -#ifdef _OPENMP - #pragma omp parallel for -#endif + int lcode[16][16][32]; + float mul[16][16][8]; + float csum[16][16][3]; - for (int ii = 0; ii < H; ii++) - for (int jj = 0; jj < W; jj++) { - image[ii * W + jj][fc(ii, jj)] = rawData[ii][jj]; + // first linear interpolation + for (int row = 0; row < 16; row++) + for (int col = 0; col < 16; col++) { + int * ip = lcode[row][col]; + int mulcount = 0; + float sum[4] = {}; + + for (int y = -1; y <= 1; y++) + for (int x = -1; x <= 1; x++) { + int shift = (y == 0) + (x == 0); + + if (shift == 2) { + continue; + } + + int color = fc(row + y, col + x); + *ip++ = (width * y + x) * 4 + color; + + mul[row][col][mulcount] = (1 << shift); + *ip++ = color; + sum[color] += (1 << shift); + mulcount++; + } + + int colcount = 0; + + for (unsigned int c = 0; c < colors; c++) + if (c != fc(row, col)) { + *ip++ = c; + csum[row][col][colcount] = 1.f / sum[c]; + colcount ++; + } } - { - int lcode[16][16][32]; - float mul[16][16][8]; - float csum[16][16][4]; - -// first linear interpolation - for (int row = 0; row < 16; row++) - for (int col = 0; col < 16; col++) { - int * ip = lcode[row][col]; - int mulcount = 0; - float sum[4]; - memset (sum, 0, sizeof sum); - - for (int y = -1; y <= 1; y++) - for (int x = -1; x <= 1; x++) { - int shift = (y == 0) + (x == 0); - - if (shift == 2) { - continue; - } - - int color = fc(row + y, col + x); - *ip++ = (width * y + x) * 4 + color; - - mul[row][col][mulcount] = (1 << shift); - *ip++ = color; - sum[color] += (1 << shift); - mulcount++; - } - - int colcount = 0; - - for (unsigned int c = 0; c < colors; c++) - if (c != fc(row, col)) { - *ip++ = c; - csum[row][col][colcount] = sum[c]; - colcount ++; - } - } - #ifdef _OPENMP - #pragma omp parallel for + #pragma omp parallel +#endif + { + int firstRow = -1; + int lastRow = -1; +#ifdef _OPENMP + // note, static scheduling is important in this implementation + #pragma omp for schedule(static) #endif - for (int row = 1; row < height - 1; row++) { + for (int ii = 0; ii < H; ii++) { + if (firstRow == -1) { + firstRow = ii; + } + lastRow = ii; + for (int jj = 0; jj < W; jj++) { + image[ii * W + jj][fc(ii, jj)] = rawData[ii][jj]; + } + if (ii - 1 > firstRow) { + int row = ii - 1; + for (int col = 1; col < width - 1; col++) { + float * pix = image[row * width + col]; + int * ip = lcode[row & 15][col & 15]; + float sum[4] = {}; + + for (int i = 0; i < 8; i++, ip += 2) { + sum[ip[1]] += pix[ip[0]] * mul[row & 15][col & 15][i]; + } + + for (unsigned int i = 0; i < colors - 1; i++, ip++) { + pix[ip[0]] = sum[ip[0]] * csum[row & 15][col & 15][i]; + } + } + } + } + + // now all rows are processed except the first and last row of each chunk + // let's process them now but skip row 0 and row H - 1 + if (firstRow > 0 && firstRow < H - 1) { + const int row = firstRow; for (int col = 1; col < width - 1; col++) { float * pix = image[row * width + col]; int * ip = lcode[row & 15][col & 15]; - float sum[4]; - memset (sum, 0, sizeof sum); + float sum[4] = {}; for (int i = 0; i < 8; i++, ip += 2) { sum[ip[1]] += pix[ip[0]] * mul[row & 15][col & 15][i]; } for (unsigned int i = 0; i < colors - 1; i++, ip++) { - pix[ip[0]] = sum[ip[0]] / csum[row & 15][col & 15][i]; + pix[ip[0]] = sum[ip[0]] * csum[row & 15][col & 15][i]; + } + } + } + + if (lastRow > 0 && lastRow < H - 1) { + const int row = lastRow; + for (int col = 1; col < width - 1; col++) { + float * pix = image[row * width + col]; + int * ip = lcode[row & 15][col & 15]; + float sum[4] = {}; + + for (int i = 0; i < 8; i++, ip += 2) { + sum[ip[1]] += pix[ip[0]] * mul[row & 15][col & 15][i]; + } + + for (unsigned int i = 0; i < colors - 1; i++, ip++) { + pix[ip[0]] = sum[ip[0]] * csum[row & 15][col & 15][i]; } } } } - const int prow = 7, pcol = 1; - int *code[8][2]; - int t, g; - int * ip = (int *) calloc ((prow + 1) * (pcol + 1), 1280); + constexpr int prow = 7, pcol = 1; + int32_t *code[8][2]; + int32_t * ip = (int32_t *) calloc ((prow + 1) * (pcol + 1), 1280); for (int row = 0; row <= prow; row++) /* Precalculate for VNG */ for (int col = 0; col <= pcol; col++) { code[row][col] = ip; - - for (cp = terms, t = 0; t < 64; t++) { + cp = terms; + for (int t = 0; t < 64; t++) { int y1 = *cp++; int x1 = *cp++; int y2 = *cp++; @@ -176,9 +244,13 @@ void RawImageSource::vng4_demosaic (const array2D &rawData, array2D(ip++) = 1 << weight; +#else + *ip++ = 1 << weight; +#endif + for (int g = 0; g < 8; g++) if (grads & (1 << g)) { *ip++ = g; } @@ -188,7 +260,8 @@ void RawImageSource::vng4_demosaic (const array2D &rawData, array2D &rawData, array2DsetProgress (progress); } @@ -211,92 +284,79 @@ void RawImageSource::vng4_demosaic (const array2D &rawData, array2D float conversions + const float diff = std::fabs(pix[ip[0]] - pix[ip[1]]) * reinterpret_cast(ip)[2]; +#else + const float diff = std::fabs(pix[ip[0]] - pix[ip[1]]) * ip[2]; +#endif + gval[ip[3]] += diff; + ip += 5; + if (UNLIKELY(ip[-1] != -1)) { + gval[ip[-1]] += diff; + ip++; } - - ip++; - { - float gmin, gmax; - gmin = gmax = gval[0]; /* Choose a threshold */ - - for (g = 1; g < 8; g++) { - if (gmin > gval[g]) { - gmin = gval[g]; - } - - if (gmax < gval[g]) { - gmax = gval[g]; - } - } - - thold = gmin + (gmax / 2); - } - memset (sum, 0, sizeof sum); - float t1, t2; - t1 = t2 = pix[color]; - - if(color & 1) { - int num = 0; - - for (g = 0; g < 8; g++, ip += 2) { /* Average the neighbors */ - if (gval[g] <= thold) { - if(ip[1]) { - sum[0] += (t1 + pix[ip[1]]) * 0.5f; - } - - sum[1] += pix[ip[0] + (color ^ 2)]; - num++; - } - } - - t1 += (sum[1] - sum[0]) / num; - } else { - int num = 0; - - for (g = 0; g < 8; g++, ip += 2) { /* Average the neighbors */ - if (gval[g] <= thold) { - sum[1] += pix[ip[0] + 1]; - sum[2] += pix[ip[0] + 3]; - - if(ip[1]) { - sum[0] += (t1 + pix[ip[1]]) * 0.5f; - } - - num++; - } - } - - t1 += (sum[1] - sum[0]) / num; - t2 += (sum[2] - sum[0]) / num; - } - - green[row][col] = 0.5f * (t1 + t2); } + ip++; + + const float thold = rtengine::min(gval[0], gval[1], gval[2], gval[3], gval[4], gval[5], gval[6], gval[7]) + + rtengine::max(gval[0], gval[1], gval[2], gval[3], gval[4], gval[5], gval[6], gval[7]) * 0.5f; + + float sum0 = 0.f; + float sum1 = 0.f; + const float greenval = pix[color]; + int num = 0; + + if(color & 1) { + color ^= 2; + for (int g = 0; g < 8; g++, ip += 2) { /* Average the neighbors */ + if (gval[g] <= thold) { + if(ip[1]) { + sum0 += greenval + pix[ip[1]]; + } + + sum1 += pix[ip[0] + color]; + num++; + } + } + sum0 *= 0.5f; + } else { + for (int g = 0; g < 8; g++, ip += 2) { /* Average the neighbors */ + if (gval[g] <= thold) { + if(ip[1]) { + sum0 += greenval + pix[ip[1]]; + } + + sum1 += pix[ip[0] + 1] + pix[ip[0] + 3]; + num++; + } + } + } + green[row][col] = greenval + (sum1 - sum0) / (2 * num); + } + if (row - 1 > firstRow) { + vng4interpolate_row_redblue(ri, rawData, red[row - 1], blue[row - 1], green[row - 2], green[row - 1], green[row], row - 1, W); } if(plistenerActive) { @@ -311,32 +371,24 @@ void RawImageSource::vng4_demosaic (const array2D &rawData, array2D 2 && firstRow < H - 3) { + vng4interpolate_row_redblue(ri, rawData, red[firstRow], blue[firstRow], green[firstRow - 1], green[firstRow], green[firstRow + 1], firstRow, W); + } - if(plistenerActive) { - plistener->setProgress (0.98); - } - - // Interpolate R and B + if (lastRow > 2 && lastRow < H - 3) { + vng4interpolate_row_redblue(ri, rawData, red[lastRow], blue[lastRow], green[lastRow - 1], green[lastRow], green[lastRow + 1], lastRow, W); + } #ifdef _OPENMP - #pragma omp parallel for + #pragma omp single #endif - - for (int i = 0; i < H; i++) { - if (i == 0) - // rm, gm, bm must be recovered - //interpolate_row_rb_mul_pp (red, blue, NULL, green[i], green[i+1], i, rm, gm, bm, 0, W, 1); { - interpolate_row_rb_mul_pp (rawData, red[i], blue[i], nullptr, green[i], green[i + 1], i, 1.0, 1.0, 1.0, 0, W, 1); - } else if (i == H - 1) { - interpolate_row_rb_mul_pp (rawData, red[i], blue[i], green[i - 1], green[i], nullptr, i, 1.0, 1.0, 1.0, 0, W, 1); - } else { - interpolate_row_rb_mul_pp (rawData, red[i], blue[i], green[i - 1], green[i], green[i + 1], i, 1.0, 1.0, 1.0, 0, W, 1); + // let the first thread, which is out of work, do the border interpolation + border_interpolate2(W, H, 3, rawData, red, green, blue); } } - border_interpolate2(W, H, 3, rawData, red, green, blue); + + free (code[0][0]); + free (image); if(plistenerActive) { plistener->setProgress (1.0); diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt index 4cd789d79..71757533b 100644 --- a/rtgui/CMakeLists.txt +++ b/rtgui/CMakeLists.txt @@ -158,6 +158,7 @@ set(NONCLISOURCEFILES metadatapanel.cc labgrid.cc softlight.cc + dehaze.cc ) include_directories(BEFORE "${CMAKE_CURRENT_BINARY_DIR}") diff --git a/rtgui/addsetids.h b/rtgui/addsetids.h index 8cf39aa29..1d9c621eb 100644 --- a/rtgui/addsetids.h +++ b/rtgui/addsetids.h @@ -142,6 +142,7 @@ enum { ADDSET_BAYER_DUALDEMOZCONTRAST, ADDSET_XTRANS_FALSE_COLOR_SUPPRESSION, ADDSET_SOFTLIGHT_STRENGTH, + ADDSET_DEHAZE_STRENGTH, ADDSET_PARAM_NUM // THIS IS USED AS A DELIMITER!! }; diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc index 1d52c96e6..a66fda153 100644 --- a/rtgui/batchqueue.cc +++ b/rtgui/batchqueue.cc @@ -45,7 +45,7 @@ namespace struct NLParams { BatchQueueListener* listener; int qsize; - bool queueEmptied; + bool queueRunning; bool queueError; Glib::ustring queueErrorMessage; }; @@ -53,7 +53,7 @@ struct NLParams { int bqnotifylistenerUI (void* data) { NLParams* params = static_cast(data); - params->listener->queueSizeChanged (params->qsize, params->queueEmptied, params->queueError, params->queueErrorMessage); + params->listener->queueSizeChanged (params->qsize, params->queueRunning, params->queueError, params->queueErrorMessage); delete params; return 0; } @@ -229,7 +229,7 @@ void BatchQueue::addEntries (const std::vector& entries, bool saveBatchQueue (); redraw (); - notifyListener (false); + notifyListener (true); } bool BatchQueue::saveBatchQueue () @@ -387,7 +387,7 @@ bool BatchQueue::loadBatchQueue () } redraw (); - notifyListener (false); + notifyListener (true); return !fd.empty (); } @@ -460,7 +460,7 @@ void BatchQueue::cancelItems (const std::vector& items) saveBatchQueue (); redraw (); - notifyListener (false); + notifyListener (true); } void BatchQueue::headItems (const std::vector& items) @@ -640,7 +640,7 @@ void BatchQueue::error(const Glib::ustring& descr) if (listener) { NLParams* params = new NLParams; params->listener = listener; - params->queueEmptied = false; + params->queueRunning = false; params->queueError = true; params->queueErrorMessage = descr; idle_register.add(bqnotifylistenerUI, params); @@ -706,7 +706,6 @@ rtengine::ProcessingJob* BatchQueue::imageReady(rtengine::IImagefloat* img) Glib::ustring processedParams = processing->savedParamsFile; // delete from the queue - bool queueEmptied = false; bool remove_button_set = false; { @@ -718,9 +717,7 @@ rtengine::ProcessingJob* BatchQueue::imageReady(rtengine::IImagefloat* img) fd.erase (fd.begin()); // return next job - if (fd.empty()) { - queueEmptied = true; - } else if (listener && listener->canStartNext ()) { + if (!fd.empty() && listener && listener->canStartNext ()) { BatchQueueEntry* next = static_cast(fd[0]); // tag it as selected and set sequence next->processing = true; @@ -778,7 +775,8 @@ rtengine::ProcessingJob* BatchQueue::imageReady(rtengine::IImagefloat* img) } redraw (); - notifyListener (queueEmptied); + const bool queueRunning = processing; + notifyListener (queueRunning); return processing ? processing->job : nullptr; } @@ -973,7 +971,7 @@ void BatchQueue::buttonPressed (LWButton* button, int actionCode, void* actionDa } } -void BatchQueue::notifyListener (bool queueEmptied) +void BatchQueue::notifyListener (bool queueRunning) { if (listener) { @@ -983,7 +981,7 @@ void BatchQueue::notifyListener (bool queueEmptied) MYREADERLOCK(l, entryRW); params->qsize = fd.size(); } - params->queueEmptied = queueEmptied; + params->queueRunning = queueRunning; params->queueError = false; idle_register.add(bqnotifylistenerUI, params); } diff --git a/rtgui/batchqueue.h b/rtgui/batchqueue.h index 41c30da3f..6b0e047cb 100644 --- a/rtgui/batchqueue.h +++ b/rtgui/batchqueue.h @@ -31,7 +31,7 @@ class BatchQueueListener public: virtual ~BatchQueueListener() = default; - virtual void queueSizeChanged(int qsize, bool queueEmptied, bool queueError, const Glib::ustring& queueErrorMessage) = 0; + virtual void queueSizeChanged(int qsize, bool queueRunning, bool queueError, const Glib::ustring& queueErrorMessage) = 0; virtual bool canStartNext() = 0; }; @@ -93,7 +93,7 @@ protected: Glib::ustring autoCompleteFileName (const Glib::ustring& fileName, const Glib::ustring& format); Glib::ustring getTempFilenameForParams( const Glib::ustring &filename ); bool saveBatchQueue (); - void notifyListener (bool queueEmptied); + void notifyListener (bool queueRunning); BatchQueueEntry* processing; // holds the currently processed image FileCatalog* fileCatalog; diff --git a/rtgui/batchqueuepanel.cc b/rtgui/batchqueuepanel.cc index 83a0f37ae..8da66183a 100644 --- a/rtgui/batchqueuepanel.cc +++ b/rtgui/batchqueuepanel.cc @@ -245,22 +245,24 @@ void BatchQueuePanel::updateTab (int qsize, int forceOrientation) } } -void BatchQueuePanel::queueSizeChanged(int qsize, bool queueEmptied, bool queueError, const Glib::ustring& queueErrorMessage) +void BatchQueuePanel::queueSizeChanged(int qsize, bool queueRunning, bool queueError, const Glib::ustring& queueErrorMessage) { updateTab (qsize); - if (qsize == 0 || (qsize == 1 && !fdir->get_sensitive())) { + if (qsize == 0 || (qsize == 1 && queueRunning)) { qStartStop->set_sensitive(false); } else { qStartStop->set_sensitive(true); } - if (queueEmptied || queueError) { + if (!queueRunning) { stopBatchProc (); fdir->set_sensitive (true); fformat->set_sensitive (true); - SoundManager::playSoundAsync(options.sndBatchQueueDone); + if (qsize == 0) { + SoundManager::playSoundAsync(options.sndBatchQueueDone); + } } if (queueError) { @@ -284,6 +286,7 @@ void BatchQueuePanel::startBatchProc () // Update switch when queue started programmatically qStartStopConn.block (true); qStartStop->set_active(true); + qStartStopState = true; qStartStopConn.block (false); if (batchQueue->hasJobs()) { @@ -306,6 +309,7 @@ void BatchQueuePanel::stopBatchProc () // Update switch when queue started programmatically qStartStopConn.block (true); qStartStop->set_active(false); + qStartStopState = false; qStartStopConn.block (false); updateTab (batchQueue->getEntries().size()); @@ -320,18 +324,6 @@ void BatchQueuePanel::addBatchQueueJobs(const std::vector& ent } } -bool BatchQueuePanel::canStartNext () -{ -// GThreadLock lock; - if (qStartStop->get_active()) { - return true; - } else { - fdir->set_sensitive (true); - fformat->set_sensitive (true); - return false; - } -} - void BatchQueuePanel::saveOptions () { @@ -340,6 +332,33 @@ void BatchQueuePanel::saveOptions () options.procQueueEnabled = qAutoStart->get_active(); } +bool BatchQueuePanel::handleShortcutKey (GdkEventKey* event) +{ + bool ctrl = event->state & GDK_CONTROL_MASK; + + if (ctrl) { + switch(event->keyval) { + case GDK_KEY_s: + if (qStartStop->get_active()) { + stopBatchProc(); + } else { + startBatchProc(); + } + + return true; + } + } + + return batchQueue->keyPressed (event); +} + +bool BatchQueuePanel::canStartNext () +{ + // This function is called from the background BatchQueue thread. + // It cannot call UI functions, so grab the stored state of qStartStop. + return qStartStopState; +} + void BatchQueuePanel::pathFolderButtonPressed () { @@ -369,23 +388,3 @@ void BatchQueuePanel::formatChanged(const Glib::ustring& format) { options.saveFormatBatch = saveFormatPanel->getFormat(); } - -bool BatchQueuePanel::handleShortcutKey (GdkEventKey* event) -{ - bool ctrl = event->state & GDK_CONTROL_MASK; - - if (ctrl) { - switch(event->keyval) { - case GDK_KEY_s: - if (qStartStop->get_active()) { - stopBatchProc(); - } else { - startBatchProc(); - } - - return true; - } - } - - return batchQueue->keyPressed (event); -} diff --git a/rtgui/batchqueuepanel.h b/rtgui/batchqueuepanel.h index 3f1da85ce..74c9750e7 100644 --- a/rtgui/batchqueuepanel.h +++ b/rtgui/batchqueuepanel.h @@ -19,6 +19,8 @@ #ifndef _BATCHQUEUEPANEL_ #define _BATCHQUEUEPANEL_ +#include + #include #include "batchqueue.h" #include "saveformatpanel.h" @@ -51,6 +53,8 @@ class BatchQueuePanel : public Gtk::VBox, Gtk::HBox* bottomBox; Gtk::HBox* topBox; + std::atomic qStartStopState; + IdleRegister idle_register; public: @@ -60,22 +64,23 @@ public: void init (RTWindow* parent); void addBatchQueueJobs(const std::vector& entries , bool head = false); + void saveOptions (); + + bool handleShortcutKey (GdkEventKey* event); // batchqueuelistener interface - void queueSizeChanged(int qsize, bool queueEmptied, bool queueError, const Glib::ustring& queueErrorMessage); + void queueSizeChanged(int qsize, bool queueRunning, bool queueError, const Glib::ustring& queueErrorMessage); bool canStartNext(); +private: void startBatchProc (); void stopBatchProc (); void startOrStopBatchProc(); - void saveOptions (); void pathFolderChanged (); void pathFolderButtonPressed (); void formatChanged(const Glib::ustring& format) override; void updateTab (int qsize, int forceOrientation = 0); // forceOrientation=0: base on options / 1: horizontal / 2: vertical - - bool handleShortcutKey (GdkEventKey* event); }; #endif diff --git a/rtgui/batchtoolpanelcoord.cc b/rtgui/batchtoolpanelcoord.cc index d80086d75..cc9fa96e4 100644 --- a/rtgui/batchtoolpanelcoord.cc +++ b/rtgui/batchtoolpanelcoord.cc @@ -204,6 +204,7 @@ void BatchToolPanelCoordinator::initSession () colortoning->setAdjusterBehavior (options.baBehav[ADDSET_COLORTONING_SPLIT], options.baBehav[ADDSET_COLORTONING_SATTHRESHOLD], options.baBehav[ADDSET_COLORTONING_SATOPACITY], options.baBehav[ADDSET_COLORTONING_STRENGTH], options.baBehav[ADDSET_COLORTONING_BALANCE]); filmSimulation->setAdjusterBehavior(options.baBehav[ADDSET_FILMSIMULATION_STRENGTH]); softlight->setAdjusterBehavior(options.baBehav[ADDSET_SOFTLIGHT_STRENGTH]); + dehaze->setAdjusterBehavior(options.baBehav[ADDSET_DEHAZE_STRENGTH]); retinex->setAdjusterBehavior (options.baBehav[ADDSET_RETI_STR], options.baBehav[ADDSET_RETI_NEIGH], options.baBehav[ADDSET_RETI_LIMD], options.baBehav[ADDSET_RETI_OFFS], options.baBehav[ADDSET_RETI_VART], options.baBehav[ADDSET_RETI_GAM], options.baBehav[ADDSET_RETI_SLO]); chmixer->setAdjusterBehavior (options.baBehav[ADDSET_CHMIXER] ); @@ -294,6 +295,7 @@ void BatchToolPanelCoordinator::initSession () if (options.baBehav[ADDSET_COLORTONING_STRENGTH]) { pparams.colorToning.strength = 0; } if (options.baBehav[ADDSET_FILMSIMULATION_STRENGTH]) { pparams.filmSimulation.strength = 0; } if (options.baBehav[ADDSET_SOFTLIGHT_STRENGTH]) { pparams.softlight.strength = 0; } + if (options.baBehav[ADDSET_DEHAZE_STRENGTH]) { pparams.dehaze.strength = 0; } if (options.baBehav[ADDSET_ROTATE_DEGREE]) { pparams.rotate.degree = 0; } if (options.baBehav[ADDSET_RESIZE_SCALE]) { pparams.resize.scale = 0; } if (options.baBehav[ADDSET_DIST_AMOUNT]) { pparams.distortion.amount = 0; } diff --git a/rtgui/cachemanager.cc b/rtgui/cachemanager.cc index 61b9f772b..5fabbc533 100644 --- a/rtgui/cachemanager.cc +++ b/rtgui/cachemanager.cc @@ -57,7 +57,9 @@ void CacheManager::init () auto error = g_mkdir_with_parents (baseDir.c_str(), cacheDirMode); for (const auto& cacheDir : cacheDirs) { - error |= g_mkdir_with_parents (Glib::build_filename (baseDir, cacheDir).c_str(), cacheDirMode); + if (strncmp(cacheDir, "aehistograms", 12)) { // don't create aehistograms folder. + error |= g_mkdir_with_parents (Glib::build_filename (baseDir, cacheDir).c_str(), cacheDirMode); + } } if (error != 0 && options.rtSettings.verbose) { @@ -178,7 +180,7 @@ void CacheManager::deleteEntry (const Glib::ustring& fname) void CacheManager::clearFromCache (const Glib::ustring& fname, bool purge) const { - deleteFiles (fname, getMD5 (fname), purge, purge); + deleteFiles (fname, getMD5 (fname), true, purge); } void CacheManager::renameEntry (const std::string& oldfilename, const std::string& oldmd5, const std::string& newfilename) @@ -189,9 +191,6 @@ void CacheManager::renameEntry (const std::string& oldfilename, const std::strin auto error = g_rename (getCacheFileName ("profiles", oldfilename, paramFileExtension, oldmd5).c_str (), getCacheFileName ("profiles", newfilename, paramFileExtension, newmd5).c_str ()); error |= g_rename (getCacheFileName ("images", oldfilename, ".rtti", oldmd5).c_str (), getCacheFileName ("images", newfilename, ".rtti", newmd5).c_str ()); - error |= g_rename (getCacheFileName ("images", oldfilename, ".cust16", oldmd5).c_str (), getCacheFileName ("images", newfilename, ".cust16", newmd5).c_str ()); - error |= g_rename (getCacheFileName ("images", oldfilename, ".cust", oldmd5).c_str (), getCacheFileName ("images", newfilename, ".cust", newmd5).c_str ()); - error |= g_rename (getCacheFileName ("images", oldfilename, ".jpg", oldmd5).c_str (), getCacheFileName ("images", newfilename, ".jpg", newmd5).c_str ()); error |= g_rename (getCacheFileName ("aehistograms", oldfilename, "", oldmd5).c_str (), getCacheFileName ("aehistograms", newfilename, "", newmd5).c_str ()); error |= g_rename (getCacheFileName ("embprofiles", oldfilename, ".icc", oldmd5).c_str (), getCacheFileName ("embprofiles", newfilename, ".icc", newmd5).c_str ()); error |= g_rename (getCacheFileName ("data", oldfilename, ".txt", oldmd5).c_str (), getCacheFileName ("data", newfilename, ".txt", newmd5).c_str ()); @@ -245,6 +244,7 @@ void CacheManager::clearImages () const { MyMutex::MyLock lock (mutex); + deleteDir ("data"); deleteDir ("images"); deleteDir ("aehistograms"); deleteDir ("embprofiles"); @@ -285,9 +285,6 @@ void CacheManager::deleteFiles (const Glib::ustring& fname, const std::string& m } auto error = g_remove (getCacheFileName ("images", fname, ".rtti", md5).c_str ()); - error |= g_remove (getCacheFileName ("images", fname, ".cust16", md5).c_str ()); - error |= g_remove (getCacheFileName ("images", fname, ".cust", md5).c_str ()); - error |= g_remove (getCacheFileName ("images", fname, ".jpg", md5).c_str ()); error |= g_remove (getCacheFileName ("aehistograms", fname, "", md5).c_str ()); error |= g_remove (getCacheFileName ("embprofiles", fname, ".icc", md5).c_str ()); diff --git a/rtgui/dehaze.cc b/rtgui/dehaze.cc new file mode 100644 index 000000000..0f0892ac6 --- /dev/null +++ b/rtgui/dehaze.cc @@ -0,0 +1,151 @@ +/** -*- C++ -*- + * + * This file is part of RawTherapee. + * + * Copyright (c) 2018 Alberto Griggio + * + * 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 . + */ +#include "dehaze.h" +#include "eventmapper.h" +#include +#include + +using namespace rtengine; +using namespace rtengine::procparams; + +Dehaze::Dehaze(): FoldableToolPanel(this, "dehaze", M("TP_DEHAZE_LABEL"), false, true) +{ + auto m = ProcEventMapper::getInstance(); + EvDehazeEnabled = m->newEvent(HDR, "HISTORY_MSG_DEHAZE_ENABLED"); + EvDehazeStrength = m->newEvent(HDR, "HISTORY_MSG_DEHAZE_STRENGTH"); + EvDehazeShowDepthMap = m->newEvent(HDR, "HISTORY_MSG_DEHAZE_SHOW_DEPTH_MAP"); + EvDehazeDepth = m->newEvent(HDR, "HISTORY_MSG_DEHAZE_DEPTH"); + + strength = Gtk::manage(new Adjuster(M("TP_DEHAZE_STRENGTH"), 0., 100., 1., 50.)); + strength->setAdjusterListener(this); + strength->show(); + + depth = Gtk::manage(new Adjuster(M("TP_DEHAZE_DEPTH"), 0., 100., 1., 25.)); + depth->setAdjusterListener(this); + depth->show(); + + showDepthMap = Gtk::manage(new Gtk::CheckButton(M("TP_DEHAZE_SHOW_DEPTH_MAP"))); + showDepthMap->signal_toggled().connect(sigc::mem_fun(*this, &Dehaze::showDepthMapChanged)); + showDepthMap->show(); + + pack_start(*strength); + pack_start(*depth); + pack_start(*showDepthMap); +} + + +void Dehaze::read(const ProcParams *pp, const ParamsEdited *pedited) +{ + disableListener(); + + if (pedited) { + strength->setEditedState(pedited->dehaze.strength ? Edited : UnEdited); + depth->setEditedState(pedited->dehaze.depth ? Edited : UnEdited); + set_inconsistent(multiImage && !pedited->dehaze.enabled); + showDepthMap->set_inconsistent(!pedited->dehaze.showDepthMap); + } + + setEnabled(pp->dehaze.enabled); + strength->setValue(pp->dehaze.strength); + depth->setValue(pp->dehaze.depth); + showDepthMap->set_active(pp->dehaze.showDepthMap); + + enableListener(); +} + + +void Dehaze::write(ProcParams *pp, ParamsEdited *pedited) +{ + pp->dehaze.strength = strength->getValue(); + pp->dehaze.depth = depth->getValue(); + pp->dehaze.enabled = getEnabled(); + pp->dehaze.showDepthMap = showDepthMap->get_active(); + + if (pedited) { + pedited->dehaze.strength = strength->getEditedState(); + pedited->dehaze.depth = depth->getEditedState(); + pedited->dehaze.enabled = !get_inconsistent(); + pedited->dehaze.showDepthMap = !showDepthMap->get_inconsistent(); + } +} + +void Dehaze::setDefaults(const ProcParams *defParams, const ParamsEdited *pedited) +{ + strength->setDefault(defParams->dehaze.strength); + depth->setDefault(defParams->dehaze.depth); + + if (pedited) { + strength->setDefaultEditedState(pedited->dehaze.strength ? Edited : UnEdited); + depth->setDefaultEditedState(pedited->dehaze.depth ? Edited : UnEdited); + } else { + strength->setDefaultEditedState(Irrelevant); + depth->setDefaultEditedState(Irrelevant); + } +} + + +void Dehaze::adjusterChanged(Adjuster* a, double newval) +{ + if (listener && getEnabled()) { + if (a == strength) { + listener->panelChanged(EvDehazeStrength, a->getTextValue()); + } else if (a == depth) { + listener->panelChanged(EvDehazeDepth, a->getTextValue()); + } + } +} + + +void Dehaze::enabledChanged () +{ + if (listener) { + if (get_inconsistent()) { + listener->panelChanged(EvDehazeEnabled, M("GENERAL_UNCHANGED")); + } else if (getEnabled()) { + listener->panelChanged(EvDehazeEnabled, M("GENERAL_ENABLED")); + } else { + listener->panelChanged(EvDehazeEnabled, M("GENERAL_DISABLED")); + } + } +} + + +void Dehaze::showDepthMapChanged() +{ + if (listener) { + listener->panelChanged(EvDehazeShowDepthMap, showDepthMap->get_active() ? M("GENERAL_ENABLED") : M("GENERAL_DISABLED")); + } +} + + +void Dehaze::setBatchMode(bool batchMode) +{ + ToolPanel::setBatchMode(batchMode); + + strength->showEditedCB(); + depth->showEditedCB(); +} + + +void Dehaze::setAdjusterBehavior(bool strengthAdd) +{ + strength->setAddMode(strengthAdd); +} + diff --git a/rtgui/dehaze.h b/rtgui/dehaze.h new file mode 100644 index 000000000..0ae7749e4 --- /dev/null +++ b/rtgui/dehaze.h @@ -0,0 +1,53 @@ +/** -*- C++ -*- + * + * This file is part of RawTherapee. + * + * Copyright (c) 2018 Alberto Griggio + * + * 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 . + */ +#pragma once + +#include +#include "adjuster.h" +#include "toolpanel.h" + +class Dehaze: public ToolParamBlock, public AdjusterListener, public FoldableToolPanel +{ +private: + Adjuster *strength; + Adjuster *depth; + Gtk::CheckButton *showDepthMap; + + rtengine::ProcEvent EvDehazeEnabled; + rtengine::ProcEvent EvDehazeStrength; + rtengine::ProcEvent EvDehazeDepth; + rtengine::ProcEvent EvDehazeShowDepthMap; + +public: + + Dehaze(); + + void read(const rtengine::procparams::ProcParams *pp, const ParamsEdited *pedited=nullptr); + void write(rtengine::procparams::ProcParams *pp, ParamsEdited *pedited=nullptr); + void setDefaults(const rtengine::procparams::ProcParams *defParams, const ParamsEdited *pedited=nullptr); + void setBatchMode(bool batchMode); + + void adjusterChanged(Adjuster *a, double newval); + void enabledChanged(); + void showDepthMapChanged(); + void setAdjusterBehavior(bool strengthAdd); + void adjusterAutoToggled(Adjuster* a, bool newval) {} +}; + diff --git a/rtgui/diagonalcurveeditorsubgroup.cc b/rtgui/diagonalcurveeditorsubgroup.cc index a022c8650..c23b25f9a 100644 --- a/rtgui/diagonalcurveeditorsubgroup.cc +++ b/rtgui/diagonalcurveeditorsubgroup.cc @@ -32,6 +32,8 @@ #include "diagonalcurveeditorsubgroup.h" #include "rtimage.h" +#include "../rtengine/curves.h" + DiagonalCurveEditorSubGroup::DiagonalCurveEditorSubGroup (CurveEditorGroup* prt, Glib::ustring& curveDir) : CurveEditorSubGroup(curveDir) { @@ -814,6 +816,8 @@ void DiagonalCurveEditorSubGroup::loadPressed () } } + rtengine::sanitizeCurve(p); + if (p[0] == (double)(DCT_Spline)) { customCurve->setPoints (p); customCurve->queue_draw (); diff --git a/rtgui/dynamicprofilepanel.cc b/rtgui/dynamicprofilepanel.cc index d7e8f356a..d83c70669 100644 --- a/rtgui/dynamicprofilepanel.cc +++ b/rtgui/dynamicprofilepanel.cc @@ -41,7 +41,17 @@ DynamicProfilePanel::EditDialog::EditDialog (const Glib::ustring &title, Gtk::Wi add_optional (M ("EXIFFILTER_CAMERA"), has_camera_, camera_); add_optional (M ("EXIFFILTER_LENS"), has_lens_, lens_); - add_optional (M ("EXIFFILTER_IMAGETYPE"), has_imagetype_, imagetype_); + + imagetype_ = Gtk::manage (new MyComboBoxText()); + imagetype_->append(Glib::ustring("(") + M("DYNPROFILEEDITOR_IMGTYPE_ANY") + ")"); + imagetype_->append(M("DYNPROFILEEDITOR_IMGTYPE_STD")); + imagetype_->append(M("DYNPROFILEEDITOR_IMGTYPE_HDR")); + imagetype_->append(M("DYNPROFILEEDITOR_IMGTYPE_PS")); + imagetype_->set_active(0); + hb = Gtk::manage (new Gtk::HBox()); + hb->pack_start (*Gtk::manage (new Gtk::Label (M ("EXIFFILTER_IMAGETYPE"))), false, false, 4); + hb->pack_start (*imagetype_, true, true, 2); + get_content_area()->pack_start (*hb, Gtk::PACK_SHRINK, 4); add_range (M ("EXIFFILTER_ISO"), iso_min_, iso_max_); add_range (M ("EXIFFILTER_APERTURE"), fnumber_min_, fnumber_max_); @@ -82,8 +92,17 @@ void DynamicProfilePanel::EditDialog::set_rule ( has_lens_->set_active (rule.lens.enabled); lens_->set_text (rule.lens.value); - has_imagetype_->set_active (rule.imagetype.enabled); - imagetype_->set_text (rule.imagetype.value); + if (!rule.imagetype.enabled) { + imagetype_->set_active(0); + } else if (rule.imagetype.value == "STD") { + imagetype_->set_active(1); + } else if (rule.imagetype.value == "HDR") { + imagetype_->set_active(2); + } else if (rule.imagetype.value == "PS") { + imagetype_->set_active(3); + } else { + imagetype_->set_active(0); + } profilepath_->updateProfileList(); @@ -116,8 +135,20 @@ DynamicProfileRule DynamicProfilePanel::EditDialog::get_rule() ret.lens.enabled = has_lens_->get_active(); ret.lens.value = lens_->get_text(); - ret.imagetype.enabled = has_imagetype_->get_active(); - ret.imagetype.value = imagetype_->get_text(); + ret.imagetype.enabled = imagetype_->get_active_row_number() > 0; + switch (imagetype_->get_active_row_number()) { + case 1: + ret.imagetype.value = "STD"; + break; + case 2: + ret.imagetype.value = "HDR"; + break; + case 3: + ret.imagetype.value = "PS"; + break; + default: + ret.imagetype.value = ""; + } ret.profilepath = profilepath_->getFullPathFromActiveRow(); @@ -478,7 +509,14 @@ void DynamicProfilePanel::render_lens ( void DynamicProfilePanel::render_imagetype ( Gtk::CellRenderer *cell, const Gtk::TreeModel::iterator &iter) { - RENDER_OPTIONAL_ (imagetype); + auto row = *iter; + Gtk::CellRendererText *ct = static_cast(cell); + DynamicProfileRule::Optional o = row[columns_.imagetype]; + if (o.enabled) { + ct->property_text() = M(std::string("DYNPROFILEEDITOR_IMGTYPE_") + o.value); + } else { \ + ct->property_text() = ""; + } } #undef RENDER_OPTIONAL_ diff --git a/rtgui/dynamicprofilepanel.h b/rtgui/dynamicprofilepanel.h index 3b5bec4df..e271edc5a 100644 --- a/rtgui/dynamicprofilepanel.h +++ b/rtgui/dynamicprofilepanel.h @@ -112,8 +112,7 @@ private: Gtk::CheckButton *has_lens_; Gtk::Entry *lens_; - Gtk::CheckButton *has_imagetype_; - Gtk::Entry *imagetype_; + MyComboBoxText *imagetype_; ProfileStoreComboBox *profilepath_; }; diff --git a/rtgui/flatcurveeditorsubgroup.cc b/rtgui/flatcurveeditorsubgroup.cc index 2cc96a184..27b7ac940 100644 --- a/rtgui/flatcurveeditorsubgroup.cc +++ b/rtgui/flatcurveeditorsubgroup.cc @@ -33,6 +33,8 @@ #include "flatcurveeditorsubgroup.h" #include "rtimage.h" +#include "../rtengine/curves.h" + FlatCurveEditorSubGroup::FlatCurveEditorSubGroup (CurveEditorGroup* prt, Glib::ustring& curveDir) : CurveEditorSubGroup(curveDir) { @@ -418,6 +420,8 @@ void FlatCurveEditorSubGroup::loadPressed () } } + rtengine::sanitizeCurve(p); + if (p[0] == (double)(FCT_MinMaxCPoints)) { CPointsCurve->setPoints (p); CPointsCurve->queue_draw (); diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index ca1448a82..481ae14c0 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -683,6 +683,10 @@ void ParamsEdited::set(bool v) filmSimulation.strength = v; softlight.enabled = v; softlight.strength = v; + dehaze.enabled = v; + dehaze.strength = v; + dehaze.showDepthMap = v; + dehaze.depth = v; metadata.mode = v; exif = v; @@ -1353,6 +1357,10 @@ void ParamsEdited::initFrom(const std::vector& filmSimulation.strength = filmSimulation.strength && p.filmSimulation.strength == other.filmSimulation.strength; softlight.enabled = softlight.enabled && p.softlight.enabled == other.softlight.enabled; softlight.strength = softlight.strength && p.softlight.strength == other.softlight.strength; + dehaze.enabled = dehaze.enabled && p.dehaze.enabled == other.dehaze.enabled; + dehaze.strength = dehaze.strength && p.dehaze.strength == other.dehaze.strength; + dehaze.showDepthMap = dehaze.showDepthMap && p.dehaze.showDepthMap == other.dehaze.showDepthMap; + dehaze.depth = dehaze.depth && p.dehaze.depth == other.dehaze.depth; metadata.mode = metadata.mode && p.metadata.mode == other.metadata.mode; // How the hell can we handle that??? @@ -3761,7 +3769,23 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng if (softlight.strength) { toEdit.softlight.strength = dontforceSet && options.baBehav[ADDSET_SOFTLIGHT_STRENGTH] ? toEdit.softlight.strength + mods.softlight.strength : mods.softlight.strength; } + + if (dehaze.enabled) { + toEdit.dehaze.enabled = mods.dehaze.enabled; + } + + if (dehaze.strength) { + toEdit.dehaze.strength = dontforceSet && options.baBehav[ADDSET_DEHAZE_STRENGTH] ? toEdit.dehaze.strength + mods.dehaze.strength : mods.dehaze.strength; + } + if (dehaze.depth) { + toEdit.dehaze.depth = mods.dehaze.depth; + } + + if (dehaze.showDepthMap) { + toEdit.dehaze.showDepthMap = mods.dehaze.showDepthMap; + } + if (metadata.mode) { toEdit.metadata.mode = mods.metadata.mode; } diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 6978ca6f3..18d11fcc7 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -837,6 +837,16 @@ public: bool strength; }; +class DehazeParamsEdited +{ +public: + bool enabled; + bool strength; + bool showDepthMap; + bool depth; +}; + + class RAWParamsEdited { @@ -981,6 +991,7 @@ public: HSVEqualizerParamsEdited hsvequalizer; FilmSimulationParamsEdited filmSimulation; SoftLightParamsEdited softlight; + DehazeParamsEdited dehaze; MetaDataParamsEdited metadata; bool exif; bool iptc; diff --git a/rtgui/partialpastedlg.cc b/rtgui/partialpastedlg.cc index 91e542e85..e0e6a7219 100644 --- a/rtgui/partialpastedlg.cc +++ b/rtgui/partialpastedlg.cc @@ -65,6 +65,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren dirpyrden = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_DIRPYRDENOISE"))); defringe = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_DEFRINGE"))); dirpyreq = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_DIRPYREQUALIZER"))); + dehaze = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_DEHAZE")) ); // Advanced Settings: retinex = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_RETINEX"))); @@ -168,6 +169,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren vboxes[1]->pack_start (*dirpyrden, Gtk::PACK_SHRINK, 2); vboxes[1]->pack_start (*defringe, Gtk::PACK_SHRINK, 2); vboxes[1]->pack_start (*dirpyreq, Gtk::PACK_SHRINK, 2); + vboxes[1]->pack_start (*dehaze, Gtk::PACK_SHRINK, 2); //COLOR vboxes[2]->pack_start (*color, Gtk::PACK_SHRINK, 2); @@ -327,6 +329,7 @@ PartialPasteDlg::PartialPasteDlg (const Glib::ustring &title, Gtk::Window* paren dirpyrdenConn = dirpyrden->signal_toggled().connect (sigc::bind (sigc::mem_fun(*detail, &Gtk::CheckButton::set_inconsistent), true)); defringeConn = defringe->signal_toggled().connect (sigc::bind (sigc::mem_fun(*detail, &Gtk::CheckButton::set_inconsistent), true)); dirpyreqConn = dirpyreq->signal_toggled().connect (sigc::bind (sigc::mem_fun(*detail, &Gtk::CheckButton::set_inconsistent), true)); + dehazeConn = dehaze->signal_toggled().connect (sigc::bind (sigc::mem_fun(*detail, &Gtk::CheckButton::set_inconsistent), true)); // Advanced Settings: retinexConn = retinex->signal_toggled().connect (sigc::bind (sigc::mem_fun(*advanced, &Gtk::CheckButton::set_inconsistent), true)); @@ -534,6 +537,7 @@ void PartialPasteDlg::detailToggled () ConnectionBlocker dirpyrdenBlocker(dirpyrdenConn); ConnectionBlocker defringeBlocker(defringeConn); ConnectionBlocker dirpyreqBlocker(dirpyreqConn); + ConnectionBlocker dehazeBlocker(dehazeConn); detail->set_inconsistent (false); @@ -545,6 +549,7 @@ void PartialPasteDlg::detailToggled () dirpyrden->set_active (detail->get_active ()); defringe->set_active (detail->get_active ()); dirpyreq->set_active (detail->get_active ()); + dehaze->set_active (detail->get_active ()); } void PartialPasteDlg::advancedToggled () @@ -762,6 +767,10 @@ void PartialPasteDlg::applyPaste (rtengine::procparams::ProcParams* dstPP, Param filterPE.softlight = falsePE.softlight; } + if (!dehaze->get_active ()) { + filterPE.dehaze = falsePE.dehaze; + } + if (!rgbcurves->get_active ()) { filterPE.rgbCurves = falsePE.rgbCurves; } diff --git a/rtgui/partialpastedlg.h b/rtgui/partialpastedlg.h index 5195d0756..f551ac134 100644 --- a/rtgui/partialpastedlg.h +++ b/rtgui/partialpastedlg.h @@ -63,6 +63,7 @@ public: Gtk::CheckButton* dirpyrden; Gtk::CheckButton* defringe; Gtk::CheckButton* dirpyreq; + Gtk::CheckButton* dehaze; // options in wavelet Gtk::CheckButton* wavelet; @@ -131,7 +132,7 @@ public: sigc::connection everythingConn, basicConn, detailConn, colorConn, lensConn, compositionConn, metaConn, rawConn, advancedConn; sigc::connection wbConn, exposureConn, localcontrastConn, shConn, pcvignetteConn, gradientConn, labcurveConn, colorappearanceConn; - sigc::connection sharpenConn, gradsharpenConn, microcontrastConn, impdenConn, dirpyrdenConn, defringeConn, epdConn, fattalConn, dirpyreqConn, waveletConn, retinexConn; + sigc::connection sharpenConn, gradsharpenConn, microcontrastConn, impdenConn, dirpyrdenConn, defringeConn, epdConn, fattalConn, dirpyreqConn, waveletConn, retinexConn, dehazeConn; sigc::connection vibranceConn, chmixerConn, hsveqConn, rgbcurvesConn, chmixerbwConn, colortoningConn, filmSimulationConn, softlightConn; sigc::connection distortionConn, cacorrConn, vignettingConn, lcpConn; sigc::connection coarserotConn, finerotConn, cropConn, resizeConn, prsharpeningConn, perspectiveConn, commonTransConn; diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index bafa7dddf..c1c19a15b 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -256,6 +256,10 @@ Gtk::Widget* Preferences::getBatchProcPanel() appendBehavList (mi, M ("TP_DIRPYRDENOISE_MEDIAN_PASSES"), ADDSET_DIRPYRDN_PASSES, true); mi = behModel->append(); + mi->set_value ( behavColumns.label, M ("TP_DEHAZE_LABEL") ); + appendBehavList ( mi, M ( "TP_DEHAZE_STRENGTH" ), ADDSET_DEHAZE_STRENGTH, true ); + + mi = behModel->append (); mi->set_value(behavColumns.label, M("TP_WBALANCE_LABEL")); appendBehavList(mi, M("TP_WBALANCE_TEMPERATURE"), ADDSET_WB_TEMPERATURE, true); appendBehavList(mi, M("TP_WBALANCE_GREEN"), ADDSET_WB_GREEN, true); diff --git a/rtgui/softlight.cc b/rtgui/softlight.cc index 0ee4c64b9..072c45e98 100644 --- a/rtgui/softlight.cc +++ b/rtgui/softlight.cc @@ -28,8 +28,8 @@ using namespace rtengine::procparams; SoftLight::SoftLight(): FoldableToolPanel(this, "softlight", M("TP_SOFTLIGHT_LABEL"), false, true) { auto m = ProcEventMapper::getInstance(); - EvSoftLightEnabled = m->newEvent(RGBCURVE, "HISTORY_MSG_SOFTLIGHT_ENABLED"); - EvSoftLightStrength = m->newEvent(RGBCURVE, "HISTORY_MSG_SOFTLIGHT_STRENGTH"); + EvSoftLightEnabled = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_SOFTLIGHT_ENABLED"); + EvSoftLightStrength = m->newEvent(LUMINANCECURVE, "HISTORY_MSG_SOFTLIGHT_STRENGTH"); strength = Gtk::manage(new Adjuster(M("TP_SOFTLIGHT_STRENGTH"), 0., 100., 1., 30.)); strength->setAdjusterListener(this); diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc index 81ff190d3..846802e2c 100644 --- a/rtgui/thumbnail.cc +++ b/rtgui/thumbnail.cc @@ -449,7 +449,8 @@ void Thumbnail::setProcParams (const ProcParams& pp, ParamsEdited* pe, int whoCh || pparams.icm != pp.icm || pparams.hsvequalizer != pp.hsvequalizer || pparams.filmSimulation != pp.filmSimulation - || pparams.softlight != pp.softlight; + || pparams.softlight != pp.softlight + || pparams.dehaze != pp.dehaze; { MyMutex::MyLock lock(mutex); @@ -855,8 +856,10 @@ void Thumbnail::_loadThumbnail(bool firstTrial) } if ( cfs.thumbImgType == CacheImageData::FULL_THUMBNAIL ) { - // load aehistogram - tpp->readAEHistogram (getCacheFileName ("aehistograms", "")); + if(!tpp->isAeValid()) { + // load aehistogram + tpp->readAEHistogram (getCacheFileName ("aehistograms", "")); + } // load embedded profile tpp->readEmbProfile (getCacheFileName ("embprofiles", ".icc")); @@ -898,19 +901,15 @@ void Thumbnail::_saveThumbnail () return; } - if (g_remove (getCacheFileName ("images", ".rtti").c_str ()) != 0) { - // No file deleted, so we try to deleted obsolete files, if any - g_remove (getCacheFileName ("images", ".cust").c_str ()); - g_remove (getCacheFileName ("images", ".cust16").c_str ()); - g_remove (getCacheFileName ("images", ".jpg").c_str ()); - } + g_remove (getCacheFileName ("images", ".rtti").c_str ()); // save thumbnail image tpp->writeImage (getCacheFileName ("images", "")); - // save aehistogram - tpp->writeAEHistogram (getCacheFileName ("aehistograms", "")); - + if(!tpp->isAeValid()) { + // save aehistogram + tpp->writeAEHistogram (getCacheFileName ("aehistograms", "")); + } // save embedded profile tpp->writeEmbProfile (getCacheFileName ("embprofiles", ".icc")); diff --git a/rtgui/toolpanelcoord.cc b/rtgui/toolpanelcoord.cc index 7b3cb5e14..79e2f5ba5 100644 --- a/rtgui/toolpanelcoord.cc +++ b/rtgui/toolpanelcoord.cc @@ -79,6 +79,7 @@ ToolPanelCoordinator::ToolPanelCoordinator(bool batch) : ipc(nullptr), hasChange hsvequalizer = Gtk::manage(new HSVEqualizer()); filmSimulation = Gtk::manage(new FilmSimulation()); softlight = Gtk::manage(new SoftLight()); + dehaze = Gtk::manage(new Dehaze()); sensorbayer = Gtk::manage(new SensorBayer()); sensorxtrans = Gtk::manage(new SensorXTrans()); bayerprocess = Gtk::manage(new BayerProcess()); @@ -127,6 +128,7 @@ ToolPanelCoordinator::ToolPanelCoordinator(bool batch) : ipc(nullptr), hasChange addPanel(detailsPanel, dirpyrdenoise); addPanel(detailsPanel, defringe); addPanel(detailsPanel, dirpyrequalizer); + addPanel (detailsPanel, dehaze); addPanel(advancedPanel, wavelet); addPanel(locallabPanel, locallab); addPanel(transformPanel, crop); diff --git a/rtgui/toolpanelcoord.h b/rtgui/toolpanelcoord.h index 3cd05655e..c92001607 100644 --- a/rtgui/toolpanelcoord.h +++ b/rtgui/toolpanelcoord.h @@ -81,6 +81,7 @@ #include "fattaltonemap.h" #include "localcontrast.h" #include "softlight.h" +#include "dehaze.h" #include "guiutils.h" class ImageEditorCoordinator; @@ -137,6 +138,7 @@ protected: DirPyrEqualizer* dirpyrequalizer; HSVEqualizer* hsvequalizer; SoftLight *softlight; + Dehaze *dehaze; FilmSimulation *filmSimulation; SensorBayer * sensorbayer; SensorXTrans * sensorxtrans;