diff --git a/COMPILE.txt b/COMPILE.txt
index 9892d7582..08ba4ae59 100644
--- a/COMPILE.txt
+++ b/COMPILE.txt
@@ -1,3 +1,6 @@
+If you have problems with the compilation, identified the reason and fixed
+the bug, please send me the updated build scripts (CMakeLists.txt files) to:
+hgabor@rawtherapee.com
Windows
-------
@@ -28,32 +31,50 @@ Windows
- Type: mingw32-make.exe install
- You find the compiled program in the "release" directory
-
Linux
-----
-Requirements:
-- CMake
-- GTK and GTKMM development packages
-- libtiff, libpng, libjpeg, lcms, libiptcdata development packages
-- ...did I forget something?
+ Requirements:
+ - CMake
+ - GTK and GTKMM development packages
+ - libtiff, libpng, libjpeg, lcms, libiptcdata development packages
+ - ...did I forget something?
-On Ubuntu/Debian the requirements can be installed by running:
-sudo apt-get install build-essential cmake libgtk2.0-dev libgtkmm-2.4-dev libtiff-dev libpng-dev libjpeg-dev liblcms-dev libiptcdata-dev merciurial
+ On Ubuntu/Debian the requirements can be installed by running:
+ sudo apt-get install build-essential cmake libgtk2.0-dev libgtkmm-2.4-dev libtiff-dev libpng-dev libjpeg-dev liblcms-dev libiptcdata-dev merciurial
-Compile:
-- Enter the root directory of the RawTherapee source tree
-- Type: cmake -DCMAKE_INSTALL_PREFIX=./release -DBINDIR=. -DDATADIR=. -DLIBDIR=.
-- Type: make install
-- You find the compiled program in the release directory (you can copy it
-anywhere you want)
+ Compile:
+ - Enter the root directory of the RawTherapee source tree
+ - Type: cmake -DCMAKE_INSTALL_PREFIX=./release -DBINDIR=. -DDATADIR=. -DLIBDIR=.
+ - Type: make install
+ - You find the compiled program in the release directory (you can copy it
+ anywhere you want)
-(By changing the cmake flags, you can change where the release is. By removing all flags it should go to the standard system install location).
+ (By changing the cmake flags, you can change where the release is. By removing all flags it should go to the standard system install location).
-...If you have problems with the compilation, identified the reason and fixed
-the bug, please send me the updated build scripts (CMakeLists.txt files) to:
-hgabor@rawtherapee.com
+ Using Eclipse under Linux:
+
+ Eclipse mercurial plugin:
+ click Help -> Install new Software.
+ The Eclipse Update Site for MercurialEclipse is available at this URL:
+ http://cbes.javaforge.com/update
+
+ Import the rawtherapee mercurial repository:
+ File->new->'other'->mercurial->Clone existing repository
+ fill in URL: https://rawtherapee.googlecode.com/hg
+
+ Enter root directory of RawTherapee source tree from a terminal window.
+ configure the source for Eclipse with:
+ cmake -G "Eclipse CDT4 - Unix Makefiles" -DCMAKE_INSTALL_PREFIX=./release -DBINDIR=. -DDATADIR=. -DLIBDIR=. -DCMAKE_BUILD_TYPE=Release
+
+ Eclipse does not do 'make install' but only 'make all' so to get the release there are 2 ways.
+ 1. type 'make install' in the console or,
+ 2. in 'Project'->'properties'->'C/C++ Make Project'->'Build (incremental build)' change 'all' to 'install'
+
+
+...
+
OSX
---
diff --git a/rtdata/languages/English b/rtdata/languages/English
index 632e1c8e0..1776f0002 100644
--- a/rtdata/languages/English
+++ b/rtdata/languages/English
@@ -409,9 +409,6 @@
!PREFERENCES_CACHETHUMBFORM;Cache Thumbnail Format
!PREFERENCES_CACHETHUMBHEIGHT;Maximal Thumbnail Height
!PREFERENCES_CACORRECTION;Apply CA auto correction
-!PREFERENCES_CLEARDLG_LINE1;Clearing cache
-!PREFERENCES_CLEARDLG_LINE2;This may take a few seconds.
-!PREFERENCES_CLEARDLG_TITLE;Please wait
!PREFERENCES_CLIPPINGIND;Clipping indication
!PREFERENCES_CMETRICINTENT;Colorimetric Intent
!PREFERENCES_DATEFORMAT;Date Format
@@ -455,9 +452,9 @@
!PREFERENCES_OUTDIR;Output Directory
!PREFERENCES_OUTDIRFOLDER;Save to folder
!PREFERENCES_OUTDIRFOLDERHINT;Put the saved images to the selected folder
-!PREFERENCES_OUTDIRHINT;You can use the following formatting strings:n%f, %d1, %d2, ..., %p1, %p2, ...nnThese formatting strings refer to the directories and sub-paths of the path of the raw file.nnFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:n%f=dsc0012, %d1=02-09-2006, %d2=image, ...n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, %p3=/home/tom, ...nnIf you want to save the output image where the original is, write:n%p1/%fnnIf you want to save the output image in a directory 'converted' located the directory of the original, write:n%p1/converted/%fnnIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:n%p2/converted/%d1/%f
+!PREFERENCES_OUTDIRHINT;You can use the following formatting strings:n%f, %d1, %d2, ..., %p1, %p2, ...nnThese formatting strings refer to the different parts of the photo's pathname.nnFor example, if the photo being processed has the following pathname:n/home/tom/photos/2010-10-31/dsc0042.nefnthe meaning of the formatting strings are:n%d4 = homen%d3 = tomn%d2 = photosn%d1 = 2010-10-31n%f = dsc0042n%p1 = /home/tom/photos/2010-10-31/n%p2 = /home/tom/photos/n%p3 = /home/tom/n%p4 = /home/nnIf you want to save the output image where the original is, write:n%p1/%fnnIf you want to save the output image in a directory named "converted" located in the directory of the opened image, write:n%p1/converted/%fnnIf you want to save the output image in a directory named "/home/tom/photos/converted/2010-10-31", write:n%p2/converted/%d1/%f
!PREFERENCES_OUTDIRTEMPLATE;Use Template
-!PREFERENCES_OUTDIRTEMPLATEHINT;You can use the following formatting strings:n%f, %d1, %d2, ..., %p1, %p2, ...nnThese formatting strings refer to the directories and sub-paths of the path of the raw file.nnFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:n%f=dsc0012, %d1=02-09-2006, %d2=image, ...n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, %p3=/home/tom, ...nnIf you want to save the output image where the original is, write:n%p1/%fnnIf you want to save the output image in a directory 'converted' located the directory of the original, write:n%p1/converted/%fnnIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:n%p2/converted/%d1/%f
+!PREFERENCES_OUTDIRTEMPLATEHINT;You can use the following formatting strings:n%f, %d1, %d2, ..., %p1, %p2, ...nnThese formatting strings refer to the different parts of the photo's pathname.nnFor example, if the photo being processed has the following pathname:n/home/tom/photos/2010-10-31/dsc0042.nefnthe meaning of the formatting strings are:n%d4 = homen%d3 = tomn%d2 = photosn%d1 = 2010-10-31n%f = dsc0042n%p1 = /home/tom/photos/2010-10-31/n%p2 = /home/tom/photos/n%p3 = /home/tom/n%p4 = /home/nnIf you want to save the output image where the original is, write:n%p1/%fnnIf you want to save the output image in a directory named "converted" located in the directory of the opened image, write:n%p1/converted/%fnnIf you want to save the output image in a directory named "/home/tom/photos/converted/2010-10-31", write:n%p2/converted/%d1/%f
!PREFERENCES_OVERLAY_FILENAMES;Overlay filenames on thumbnails
!PREFERENCES_PARSEDEXT;Parsed Extensions
!PREFERENCES_PARSEDEXTADD;Add Extension
@@ -610,15 +607,15 @@
!TP_EXPOSURE_BLACKLEVEL;Black
!TP_EXPOSURE_BRIGHTNESS;Brightness
!TP_EXPOSURE_CLIP;Clip
-!TP_EXPOSURE_COMPRHIGHLIGHTS;Highlight rolloff
-!TP_EXPOSURE_COMPRSHADOWS;Shadow compression
+!TP_EXPOSURE_COMPRHIGHLIGHTS;Highlight recovery
+!TP_EXPOSURE_COMPRSHADOWS;Shadow recovery
!TP_EXPOSURE_CONTRAST;Contrast
!TP_EXPOSURE_CURVEEDITOR;Tone Curve
!TP_EXPOSURE_EXPCOMP;Exp. Comp.
!TP_EXPOSURE_LABEL;Exposure
!TP_HLREC_CIELAB;CIELab Blending
!TP_HLREC_COLOR;Color Propagation
-!TP_HLREC_LABEL;Highlight Recovery
+!TP_HLREC_LABEL;Highlight Reconstruction
!TP_HLREC_LUMINANCE;Luminance Recovery
!TP_HLREC_METHOD;Method:
!TP_ICM_FILEDLGFILTERANY;Any files
diff --git a/rtdata/languages/English (UK) b/rtdata/languages/English (UK)
index b3ca450ff..8d0099ac2 100644
--- a/rtdata/languages/English (UK)
+++ b/rtdata/languages/English (UK)
@@ -412,9 +412,6 @@ TP_HLREC_COLOR;Colour Propagation
!PREFERENCES_CACHETHUMBFORM;Cache Thumbnail Format
!PREFERENCES_CACHETHUMBHEIGHT;Maximal Thumbnail Height
!PREFERENCES_CACORRECTION;Apply CA auto correction
-!PREFERENCES_CLEARDLG_LINE1;Clearing cache
-!PREFERENCES_CLEARDLG_LINE2;This may take a few seconds.
-!PREFERENCES_CLEARDLG_TITLE;Please wait
!PREFERENCES_CLIPPINGIND;Clipping indication
!PREFERENCES_CMETRICINTENT;Colorimetric Intent
!PREFERENCES_DATEFORMAT;Date Format
@@ -457,9 +454,9 @@ TP_HLREC_COLOR;Colour Propagation
!PREFERENCES_OUTDIR;Output Directory
!PREFERENCES_OUTDIRFOLDER;Save to folder
!PREFERENCES_OUTDIRFOLDERHINT;Put the saved images to the selected folder
-!PREFERENCES_OUTDIRHINT;You can use the following formatting strings:n%f, %d1, %d2, ..., %p1, %p2, ...nnThese formatting strings refer to the directories and sub-paths of the path of the raw file.nnFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:n%f=dsc0012, %d1=02-09-2006, %d2=image, ...n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, %p3=/home/tom, ...nnIf you want to save the output image where the original is, write:n%p1/%fnnIf you want to save the output image in a directory 'converted' located the directory of the original, write:n%p1/converted/%fnnIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:n%p2/converted/%d1/%f
+!PREFERENCES_OUTDIRHINT;You can use the following formatting strings:n%f, %d1, %d2, ..., %p1, %p2, ...nnThese formatting strings refer to the different parts of the photo's pathname.nnFor example, if the photo being processed has the following pathname:n/home/tom/photos/2010-10-31/dsc0042.nefnthe meaning of the formatting strings are:n%d4 = homen%d3 = tomn%d2 = photosn%d1 = 2010-10-31n%f = dsc0042n%p1 = /home/tom/photos/2010-10-31/n%p2 = /home/tom/photos/n%p3 = /home/tom/n%p4 = /home/nnIf you want to save the output image where the original is, write:n%p1/%fnnIf you want to save the output image in a directory named "converted" located in the directory of the opened image, write:n%p1/converted/%fnnIf you want to save the output image in a directory named "/home/tom/photos/converted/2010-10-31", write:n%p2/converted/%d1/%f
!PREFERENCES_OUTDIRTEMPLATE;Use Template
-!PREFERENCES_OUTDIRTEMPLATEHINT;You can use the following formatting strings:n%f, %d1, %d2, ..., %p1, %p2, ...nnThese formatting strings refer to the directories and sub-paths of the path of the raw file.nnFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:n%f=dsc0012, %d1=02-09-2006, %d2=image, ...n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, %p3=/home/tom, ...nnIf you want to save the output image where the original is, write:n%p1/%fnnIf you want to save the output image in a directory 'converted' located the directory of the original, write:n%p1/converted/%fnnIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:n%p2/converted/%d1/%f
+!PREFERENCES_OUTDIRTEMPLATEHINT;You can use the following formatting strings:n%f, %d1, %d2, ..., %p1, %p2, ...nnThese formatting strings refer to the different parts of the photo's pathname.nnFor example, if the photo being processed has the following pathname:n/home/tom/photos/2010-10-31/dsc0042.nefnthe meaning of the formatting strings are:n%d4 = homen%d3 = tomn%d2 = photosn%d1 = 2010-10-31n%f = dsc0042n%p1 = /home/tom/photos/2010-10-31/n%p2 = /home/tom/photos/n%p3 = /home/tom/n%p4 = /home/nnIf you want to save the output image where the original is, write:n%p1/%fnnIf you want to save the output image in a directory named "converted" located in the directory of the opened image, write:n%p1/converted/%fnnIf you want to save the output image in a directory named "/home/tom/photos/converted/2010-10-31", write:n%p2/converted/%d1/%f
!PREFERENCES_OVERLAY_FILENAMES;Overlay filenames on thumbnails
!PREFERENCES_PARSEDEXT;Parsed Extensions
!PREFERENCES_PARSEDEXTADD;Add Extension
@@ -607,14 +604,14 @@ TP_HLREC_COLOR;Colour Propagation
!TP_EXPOSURE_BLACKLEVEL;Black
!TP_EXPOSURE_BRIGHTNESS;Brightness
!TP_EXPOSURE_CLIP;Clip
-!TP_EXPOSURE_COMPRHIGHLIGHTS;Highlight rolloff
-!TP_EXPOSURE_COMPRSHADOWS;Shadow compression
+!TP_EXPOSURE_COMPRHIGHLIGHTS;Highlight recovery
+!TP_EXPOSURE_COMPRSHADOWS;Shadow recovery
!TP_EXPOSURE_CONTRAST;Contrast
!TP_EXPOSURE_CURVEEDITOR;Tone Curve
!TP_EXPOSURE_EXPCOMP;Exp. Comp.
!TP_EXPOSURE_LABEL;Exposure
!TP_HLREC_CIELAB;CIELab Blending
-!TP_HLREC_LABEL;Highlight Recovery
+!TP_HLREC_LABEL;Highlight Reconstruction
!TP_HLREC_LUMINANCE;Luminance Recovery
!TP_HLREC_METHOD;Method:
!TP_ICM_FILEDLGFILTERANY;Any files
diff --git a/rtdata/languages/English (US) b/rtdata/languages/English (US)
index bcbe9b60d..b1307a18e 100644
--- a/rtdata/languages/English (US)
+++ b/rtdata/languages/English (US)
@@ -409,9 +409,6 @@
!PREFERENCES_CACHETHUMBFORM;Cache Thumbnail Format
!PREFERENCES_CACHETHUMBHEIGHT;Maximal Thumbnail Height
!PREFERENCES_CACORRECTION;Apply CA auto correction
-!PREFERENCES_CLEARDLG_LINE1;Clearing cache
-!PREFERENCES_CLEARDLG_LINE2;This may take a few seconds.
-!PREFERENCES_CLEARDLG_TITLE;Please wait
!PREFERENCES_CLIPPINGIND;Clipping indication
!PREFERENCES_CMETRICINTENT;Colorimetric Intent
!PREFERENCES_DATEFORMAT;Date Format
@@ -455,9 +452,9 @@
!PREFERENCES_OUTDIR;Output Directory
!PREFERENCES_OUTDIRFOLDER;Save to folder
!PREFERENCES_OUTDIRFOLDERHINT;Put the saved images to the selected folder
-!PREFERENCES_OUTDIRHINT;You can use the following formatting strings:n%f, %d1, %d2, ..., %p1, %p2, ...nnThese formatting strings refer to the directories and sub-paths of the path of the raw file.nnFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:n%f=dsc0012, %d1=02-09-2006, %d2=image, ...n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, %p3=/home/tom, ...nnIf you want to save the output image where the original is, write:n%p1/%fnnIf you want to save the output image in a directory 'converted' located the directory of the original, write:n%p1/converted/%fnnIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:n%p2/converted/%d1/%f
+!PREFERENCES_OUTDIRHINT;You can use the following formatting strings:n%f, %d1, %d2, ..., %p1, %p2, ...nnThese formatting strings refer to the different parts of the photo's pathname.nnFor example, if the photo being processed has the following pathname:n/home/tom/photos/2010-10-31/dsc0042.nefnthe meaning of the formatting strings are:n%d4 = homen%d3 = tomn%d2 = photosn%d1 = 2010-10-31n%f = dsc0042n%p1 = /home/tom/photos/2010-10-31/n%p2 = /home/tom/photos/n%p3 = /home/tom/n%p4 = /home/nnIf you want to save the output image where the original is, write:n%p1/%fnnIf you want to save the output image in a directory named "converted" located in the directory of the opened image, write:n%p1/converted/%fnnIf you want to save the output image in a directory named "/home/tom/photos/converted/2010-10-31", write:n%p2/converted/%d1/%f
!PREFERENCES_OUTDIRTEMPLATE;Use Template
-!PREFERENCES_OUTDIRTEMPLATEHINT;You can use the following formatting strings:n%f, %d1, %d2, ..., %p1, %p2, ...nnThese formatting strings refer to the directories and sub-paths of the path of the raw file.nnFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:n%f=dsc0012, %d1=02-09-2006, %d2=image, ...n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, %p3=/home/tom, ...nnIf you want to save the output image where the original is, write:n%p1/%fnnIf you want to save the output image in a directory 'converted' located the directory of the original, write:n%p1/converted/%fnnIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:n%p2/converted/%d1/%f
+!PREFERENCES_OUTDIRTEMPLATEHINT;You can use the following formatting strings:n%f, %d1, %d2, ..., %p1, %p2, ...nnThese formatting strings refer to the different parts of the photo's pathname.nnFor example, if the photo being processed has the following pathname:n/home/tom/photos/2010-10-31/dsc0042.nefnthe meaning of the formatting strings are:n%d4 = homen%d3 = tomn%d2 = photosn%d1 = 2010-10-31n%f = dsc0042n%p1 = /home/tom/photos/2010-10-31/n%p2 = /home/tom/photos/n%p3 = /home/tom/n%p4 = /home/nnIf you want to save the output image where the original is, write:n%p1/%fnnIf you want to save the output image in a directory named "converted" located in the directory of the opened image, write:n%p1/converted/%fnnIf you want to save the output image in a directory named "/home/tom/photos/converted/2010-10-31", write:n%p2/converted/%d1/%f
!PREFERENCES_OVERLAY_FILENAMES;Overlay filenames on thumbnails
!PREFERENCES_PARSEDEXT;Parsed Extensions
!PREFERENCES_PARSEDEXTADD;Add Extension
@@ -610,15 +607,15 @@
!TP_EXPOSURE_BLACKLEVEL;Black
!TP_EXPOSURE_BRIGHTNESS;Brightness
!TP_EXPOSURE_CLIP;Clip
-!TP_EXPOSURE_COMPRHIGHLIGHTS;Highlight rolloff
-!TP_EXPOSURE_COMPRSHADOWS;Shadow compression
+!TP_EXPOSURE_COMPRHIGHLIGHTS;Highlight recovery
+!TP_EXPOSURE_COMPRSHADOWS;Shadow recovery
!TP_EXPOSURE_CONTRAST;Contrast
!TP_EXPOSURE_CURVEEDITOR;Tone Curve
!TP_EXPOSURE_EXPCOMP;Exp. Comp.
!TP_EXPOSURE_LABEL;Exposure
!TP_HLREC_CIELAB;CIELab Blending
!TP_HLREC_COLOR;Color Propagation
-!TP_HLREC_LABEL;Highlight Recovery
+!TP_HLREC_LABEL;Highlight Reconstruction
!TP_HLREC_LUMINANCE;Luminance Recovery
!TP_HLREC_METHOD;Method:
!TP_ICM_FILEDLGFILTERANY;Any files
diff --git a/rtdata/languages/Slovak b/rtdata/languages/Slovak
index 1fd723db9..519973d6d 100644
--- a/rtdata/languages/Slovak
+++ b/rtdata/languages/Slovak
@@ -4,11 +4,14 @@
#02 01.02.2009
#03 23.10.2010
#04 (Slapo)
+
+
+
ADJUSTER_RESET_TO_DEFAULT;Resetovať na predvolené nastavenia
BATCHQUEUE_AUTOSTART;Auto štart
BATCH_PROCESSING;Dávkové spracovanie
CURVEEDITOR_CUSTOM;Vlastné
-CURVEEDITOR_DARKS;Hlboké tiene
+CURVEEDITOR_DARKS;Tiene
CURVEEDITOR_FILEDLGFILTERANY;Všetky súbory
CURVEEDITOR_FILEDLGFILTERCURVE;Súbory kriviek
CURVEEDITOR_HIGHLIGHTS;Najvyššie svetlá
@@ -18,7 +21,7 @@ CURVEEDITOR_LOADDLGLABEL;Načítať krivku...
CURVEEDITOR_NURBS;Kontrolná klietka
CURVEEDITOR_PARAMETRIC;Parametricky
CURVEEDITOR_SAVEDLGLABEL;Uložiť krivku...
-CURVEEDITOR_SHADOWS;Tiene
+CURVEEDITOR_SHADOWS;Hlboké tiene
CURVEEDITOR_TOOLTIPLINEAR;Resetovať krivku na lineárnu
CURVEEDITOR_TOOLTIPLOAD;Načítať krivku zo súboru
CURVEEDITOR_TOOLTIPSAVE;Uložiť súčasnú krivku
@@ -129,11 +132,12 @@ HISTOGRAM_TOOLTIP_B;Zobraziť/Schovať MODRÝ histogram
HISTOGRAM_TOOLTIP_G;Zobraziť/Schovať ZELENÝ histogram
HISTOGRAM_TOOLTIP_L;Zobraziť/Schovať histogram CIELAB svietivosti
HISTOGRAM_TOOLTIP_R;Zobraziť/Schovať ČERVENÝ histogram
-HISTORY_CHANGED;Zmenené
HISTORY_CUSTOMCURVE;Vlastná krivka
HISTORY_DELSNAPSHOT;Odstrániť Snímok
HISTORY_FROMCLIPBOARD;Zo schránky
+HISTORY_CHANGED;Zmenené
HISTORY_LABEL;História
+HISTORY_MSG_1;Fotka načítaná
HISTORY_MSG_10;Kompresia tieňov
HISTORY_MSG_11;Krivka tónov
HISTORY_MSG_12;Auto expozícia
@@ -144,7 +148,7 @@ HISTORY_MSG_16;Čierna svietivosti
HISTORY_MSG_17;Kompresia najvyšších svetiel v oblasti svietivosti
HISTORY_MSG_18;Kompresia tieňov v oblasti svietivosti
HISTORY_MSG_19;Krivka svietivosti
-HISTORY_MSG_1;Fotka načítaná
+HISTORY_MSG_2;Profil načítaný
HISTORY_MSG_20;Doostrenie
HISTORY_MSG_21;Polomer doostrenia
HISTORY_MSG_22;Množstvo doostrenia
@@ -155,7 +159,7 @@ HISTORY_MSG_26;Tolerancia okrajov pri doostrení
HISTORY_MSG_27;Kontrola svätožiary pri doostrení
HISTORY_MSG_28;Množstvo kontroly svätožiary
HISTORY_MSG_29;Doostrovacia metóda
-HISTORY_MSG_2;Profil načítaný
+HISTORY_MSG_3;Profil zmenený
HISTORY_MSG_30;Polomer dekonvolúcie
HISTORY_MSG_31;Množstvo dekonvolúcie
HISTORY_MSG_32;Tlmenie dekonvolúcie
@@ -166,7 +170,7 @@ HISTORY_MSG_36;Hranica sýtosti
HISTORY_MSG_37;Zosilnenie farieb
HISTORY_MSG_38;Metóda vyváženia bielej
HISTORY_MSG_39;Farebná teplota
-HISTORY_MSG_3;Profil zmenený
+HISTORY_MSG_4;História prehliadania
HISTORY_MSG_40;Nádych vyváženia bielej
HISTORY_MSG_41;Farebný posun "A"
HISTORY_MSG_42;Farebný posun "B"
@@ -177,7 +181,7 @@ HISTORY_MSG_46;Farebné odšumenie
HISTORY_MSG_47;Polomer farebného odšumenia
HISTORY_MSG_48;Tolerancia okrajov farebného odšumenia
HISTORY_MSG_49;Citlivosť na okraje pri farebnom odšumení
-HISTORY_MSG_4;História prehliadania
+HISTORY_MSG_5;Jas
HISTORY_MSG_50;Nástroj Tiene/Najvyššie svetlá
HISTORY_MSG_51;Zosilnenie najvyšších svetiel
HISTORY_MSG_52;Zosilnenie tieňov
@@ -188,7 +192,7 @@ HISTORY_MSG_56;Polomer Tiene/Najvyššie svetlá
HISTORY_MSG_57;Hrubé otočenie
HISTORY_MSG_58;Horizontálne preklápanie
HISTORY_MSG_59;Vertikálne preklápanie
-HISTORY_MSG_5;Jas
+HISTORY_MSG_6;Kontrast
HISTORY_MSG_60;Otočenie
HISTORY_MSG_61;Otočenie
HISTORY_MSG_62;Korekcia zakrivenia objektívu
@@ -199,7 +203,7 @@ HISTORY_MSG_66;Obnova najvyšších svetiel
HISTORY_MSG_67;Množstvo obnovy najvyšších svetiel
HISTORY_MSG_68;Metóda obnovy najvyšších svetiel
HISTORY_MSG_69;Pracovný farebný priestor
-HISTORY_MSG_6;Kontrast
+HISTORY_MSG_7;Čierna
HISTORY_MSG_70;Výstupný farebný priestor
HISTORY_MSG_71;Vstupný farebný priestor
HISTORY_MSG_72;Korekcia vignetácie
@@ -208,11 +212,11 @@ HISTORY_MSG_74;Zmeniť veľkosť - Rozmer
HISTORY_MSG_75;Zmeniť veľkosť - Metóda
HISTORY_MSG_76;Exif Metadáta
HISTORY_MSG_77;IPTC Metadáta
-HISTORY_MSG_78;Data specified for resize
-HISTORY_MSG_79;Resize width
-HISTORY_MSG_7;Čierna
-HISTORY_MSG_80;Resize height
-HISTORY_MSG_81;Resize enabled
+HISTORY_MSG_78;Zadané údaje pre zmenu veľkosti
+HISTORY_MSG_79;Zmena veľkosti podľa šírky
+HISTORY_MSG_8;Kompenzácia expozície
+HISTORY_MSG_80;Zmena veľkosti podľa výšky
+HISTORY_MSG_81;Zmena veľkosti povolená
HISTORY_MSG_82;Profil zmenený
HISTORY_MSG_83;Tiene/najvyšie svetlá vyskokej kvality
HISTORY_MSG_84;Náprava perspektívy
@@ -220,11 +224,10 @@ HISTORY_MSG_85;Koeficienty vlnky
HISTORY_MSG_86;Vyrovnávač vlnky
HISTORY_MSG_87;Impulzná redukcia šumu
HISTORY_MSG_89;Smerová pyramída
-HISTORY_MSG_8;Kompenzácia expozície
+HISTORY_MSG_9;Kompresia najvyšších svetiel
HISTORY_MSG_90;Svietivosť smerovej pyramídy
HISTORY_MSG_91;Farebnosť smerovej pyramídy
HISTORY_MSG_92;Gamma smerovej pyramídy
-HISTORY_MSG_9;Kompresia najvyšších svetiel
HISTORY_NEWSNAPSHOT;Nový Snímok
HISTORY_NEWSNAPSHOTAS;Ako...
HISTORY_NEWSSDIALOGLABEL;Menovka snímku:
@@ -295,8 +298,8 @@ MAIN_BUTTON_PUTTOQUEUE;Vložiť do radu
MAIN_BUTTON_PUTTOQUEUE_TOOLTIP;Pridať súčasný obrázok do radu na spracovanie Ctrl+Q
MAIN_BUTTON_QUEUE;Vložiť do radu
MAIN_BUTTON_SAVE;Uložiť obrázok
-MAIN_BUTTON_SAVEAS;Ako...
MAIN_BUTTON_SAVE_TOOLTIP;Uložiť súčasný obrázok Ctrl+S
+MAIN_BUTTON_SAVEAS;Ako...
MAIN_BUTTON_SENDTOEDITOR;Odoslať do editora
MAIN_BUTTON_SENDTOEDITOR_TOOLTIP;Upraviť súčasný obrázok v externom editore Ctrl+E
MAIN_BUTTON_UNFULLSCREEN;Ukončiť zobrazenie na celú obrazovku
@@ -387,6 +390,7 @@ PREFERENCES_APPLNEXTSTARTUP;Aplikovaný pri ďalšom spustení
PREFERENCES_BATCH_PROCESSING;dávkové spracovanie
PREFERENCES_BEHAVIOR;Správanie sa
PREFERENCES_BLINKCLIPPED;Blikať orezanými miestami
+PREFERENCES_CACORRECTION;Použiť automatickú úpravu CA
PREFERENCES_CACHECLEARALL;Vyčistiť všetko
PREFERENCES_CACHECLEARPROFILES;Vyčistiť profily
PREFERENCES_CACHECLEARTHUMBS;Vyčistiť zmenšeniny
@@ -394,12 +398,11 @@ PREFERENCES_CACHEFORMAT1;Vlastné (rýchlejšie a kvalitnejšie)
PREFERENCES_CACHEFORMAT2;JPEG (menšia veľkosť na disku)
PREFERENCES_CACHEMAXENTRIES;Maximálny počet vstupov v cache
PREFERENCES_CACHEOPTS;Možnosti cache
+PREFERENCES_CACHESTRAT;Stratégia použitia cache
PREFERENCES_CACHESTRAT1;Uprednostniť rýchlosť pred malou spotrebou pamäte
PREFERENCES_CACHESTRAT2;Uprednostniť malú spotrebu pamäte pred rýchlosťou
-PREFERENCES_CACHESTRAT;Stratégia použitia cache
PREFERENCES_CACHETHUMBFORM;Formát zmenšenín pre cache
PREFERENCES_CACHETHUMBHEIGHT;Maximálna výška zmenšenín
-PREFERENCES_CACORRECTION;Použiť automatickú úpravu CA
PREFERENCES_CLEARDLG_LINE1;Čistím cache
PREFERENCES_CLEARDLG_LINE2;Môže to pár sekúnd trvať.
PREFERENCES_CLEARDLG_TITLE;Prosím, čakajte.
@@ -544,10 +547,10 @@ TP_COARSETRAF_TOOLTIP_HFLIP;Prevrátiť horizontálne
TP_COARSETRAF_TOOLTIP_ROTLEFT;Otočiť doľava
TP_COARSETRAF_TOOLTIP_ROTRIGHT;Otočiť doprava
TP_COARSETRAF_TOOLTIP_VFLIP;Prevrátiť vertikálne
-TP_COLORBOOST_ACHANNEL;kanál "a"
+TP_COLORBOOST_ACHANNEL;Kanál "a"
TP_COLORBOOST_AMOUNT;Množstvo
TP_COLORBOOST_AVOIDCOLORCLIP;Vyhnúť sa orezaniu farieb
-TP_COLORBOOST_BCHANNEL;kanál "b"
+TP_COLORBOOST_BCHANNEL;Kanál "b"
TP_COLORBOOST_CHAB;a & b
TP_COLORBOOST_CHANNEL;Kanál
TP_COLORBOOST_CHSEPARATE;oddelené
@@ -717,16 +720,3 @@ ZOOMPANEL_ZOOM100;Priblíženie na 100% 1
ZOOMPANEL_ZOOMFITSCREEN;Prispôsobiť obrazovke F
ZOOMPANEL_ZOOMIN;Priblížiť +
ZOOMPANEL_ZOOMOUT;Oddialiť -
-
-
-!!!!!!!!!!!!!!!!!!!!!!!!!
-! Untranslated keys follow; remove the ! prefix after an entry is translated.
-!!!!!!!!!!!!!!!!!!!!!!!!!
-
-
-!NAVIGATOR_LAB_A_NA;A = n/a
-!NAVIGATOR_LAB_A_VALUE;A = %1
-!NAVIGATOR_LAB_B_NA;B = n/a
-!NAVIGATOR_LAB_B_VALUE;B = %1
-!NAVIGATOR_LAB_L_NA;L = n/a
-!NAVIGATOR_LAB_L_VALUE;L = %1
diff --git a/rtdata/languages/default b/rtdata/languages/default
index 31229b41a..0b14fb18c 100644
--- a/rtdata/languages/default
+++ b/rtdata/languages/default
@@ -402,9 +402,6 @@ PREFERENCES_CACHESTRAT;Cache Strategy
PREFERENCES_CACHETHUMBFORM;Cache Thumbnail Format
PREFERENCES_CACHETHUMBHEIGHT;Maximal Thumbnail Height
PREFERENCES_CACORRECTION;Apply CA auto correction
-PREFERENCES_CLEARDLG_LINE1;Clearing cache
-PREFERENCES_CLEARDLG_LINE2;This may take a few seconds.
-PREFERENCES_CLEARDLG_TITLE;Please wait
PREFERENCES_CLIPPINGIND;Clipping indication
PREFERENCES_CMETRICINTENT;Colorimetric Intent
PREFERENCES_DATEFORMAT;Date Format
@@ -448,9 +445,9 @@ PREFERENCES_MULTITAB;Multiple tabs mode
PREFERENCES_OUTDIR;Output Directory
PREFERENCES_OUTDIRFOLDER;Save to folder
PREFERENCES_OUTDIRFOLDERHINT;Put the saved images to the selected folder
-PREFERENCES_OUTDIRHINT;You can use the following formatting strings:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nThese formatting strings refer to the directories and sub-paths of the path of the raw file.\n\nFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, %p3=/home/tom, ...\n\nIf you want to save the output image where the original is, write:\n%p1/%f\n\nIf you want to save the output image in a directory 'converted' located the directory of the original, write:\n%p1/converted/%f\n\nIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:\n%p2/converted/%d1/%f
+PREFERENCES_OUTDIRHINT;You can use the following formatting strings:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nThese formatting strings refer to the different parts of the photo's pathname.\n\nFor example, if the photo being processed has the following pathname:\n/home/tom/photos/2010-10-31/dsc0042.nef\nthe meaning of the formatting strings are:\n%d4 = home\n%d3 = tom\n%d2 = photos\n%d1 = 2010-10-31\n%f = dsc0042\n%p1 = /home/tom/photos/2010-10-31/\n%p2 = /home/tom/photos/\n%p3 = /home/tom/\n%p4 = /home/\n\nIf you want to save the output image where the original is, write:\n%p1/%f\n\nIf you want to save the output image in a directory named "converted" located in the directory of the opened image, write:\n%p1/converted/%f\n\nIf you want to save the output image in a directory named "/home/tom/photos/converted/2010-10-31", write:\n%p2/converted/%d1/%f
PREFERENCES_OUTDIRTEMPLATE;Use Template
-PREFERENCES_OUTDIRTEMPLATEHINT;You can use the following formatting strings:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nThese formatting strings refer to the directories and sub-paths of the path of the raw file.\n\nFor example, if /home/tom/image/02-09-2006/dsc0012.nefhas been opened, the meaning of the formatting strings are:\n%f=dsc0012, %d1=02-09-2006, %d2=image, ...\n%p1=/home/tom/image/02-09-2006, %p2=/home/tom/image, %p3=/home/tom, ...\n\nIf you want to save the output image where the original is, write:\n%p1/%f\n\nIf you want to save the output image in a directory 'converted' located the directory of the original, write:\n%p1/converted/%f\n\nIf you want to save the output image in directory '/home/tom/converted' with keeping the same subdirectory of dates, write:\n%p2/converted/%d1/%f
+PREFERENCES_OUTDIRTEMPLATEHINT;You can use the following formatting strings:\n%f, %d1, %d2, ..., %p1, %p2, ...\n\nThese formatting strings refer to the different parts of the photo's pathname.\n\nFor example, if the photo being processed has the following pathname:\n/home/tom/photos/2010-10-31/dsc0042.nef\nthe meaning of the formatting strings are:\n%d4 = home\n%d3 = tom\n%d2 = photos\n%d1 = 2010-10-31\n%f = dsc0042\n%p1 = /home/tom/photos/2010-10-31/\n%p2 = /home/tom/photos/\n%p3 = /home/tom/\n%p4 = /home/\n\nIf you want to save the output image where the original is, write:\n%p1/%f\n\nIf you want to save the output image in a directory named "converted" located in the directory of the opened image, write:\n%p1/converted/%f\n\nIf you want to save the output image in a directory named "/home/tom/photos/converted/2010-10-31", write:\n%p2/converted/%d1/%f
PREFERENCES_OVERLAY_FILENAMES;Overlay filenames on thumbnails
PREFERENCES_PARSEDEXT;Parsed Extensions
PREFERENCES_PARSEDEXTADD;Add Extension
@@ -603,15 +600,15 @@ TP_EXPOSURE_AUTOLEVELS;Auto Levels
TP_EXPOSURE_BLACKLEVEL;Black
TP_EXPOSURE_BRIGHTNESS;Brightness
TP_EXPOSURE_CLIP;Clip
-TP_EXPOSURE_COMPRHIGHLIGHTS;Highlight rolloff
-TP_EXPOSURE_COMPRSHADOWS;Shadow compression
+TP_EXPOSURE_COMPRHIGHLIGHTS;Highlight recovery
+TP_EXPOSURE_COMPRSHADOWS;Shadow recovery
TP_EXPOSURE_CONTRAST;Contrast
TP_EXPOSURE_CURVEEDITOR;Tone Curve
TP_EXPOSURE_EXPCOMP;Exp. Comp.
TP_EXPOSURE_LABEL;Exposure
TP_HLREC_CIELAB;CIELab Blending
TP_HLREC_COLOR;Color Propagation
-TP_HLREC_LABEL;Highlight Recovery
+TP_HLREC_LABEL;Highlight Reconstruction
TP_HLREC_LUMINANCE;Luminance Recovery
TP_HLREC_METHOD;Method:
TP_ICM_FILEDLGFILTERANY;Any files
@@ -689,6 +686,10 @@ TP_SHARPENING_USM;Unsharp Mask
TP_VIGNETTING_AMOUNT;Amount
TP_VIGNETTING_LABEL;Vignetting Correction
TP_VIGNETTING_RADIUS;Radius
+TP_VIGNETTING_STRENGTH;Strength
+TP_VIGNETTING_CENTER_X;Center X
+TP_VIGNETTING_CENTER_Y;Center Y
+TP_VIGNETTING_CENTER;Center
TP_WBALANCE_AUTO;Auto
TP_WBALANCE_CAMERA;Camera
TP_WBALANCE_CUSTOM;Custom
diff --git a/rtdata/options/options.lin b/rtdata/options/options.lin
index 54b5a2c01..02016e9e4 100644
--- a/rtdata/options/options.lin
+++ b/rtdata/options/options.lin
@@ -41,6 +41,9 @@ RenameUseTemplates=false
ThumbnailZoomRatios=0.2;0.3;0.45;0.6;0.8;1;
OverlayedFileNames=true
+# if TRUE, only fast, internal preview images are taken if the image is not edited yet
+InternalThumbIfUntouched=true
+
[Clipping Indication]
HighlightThreshold=253
ShadowThreshold=8
@@ -57,6 +60,8 @@ PathTemplate=%p1/converted/%f
PathFolder=
UsePathTemplate=true
LastSaveAsPath=
+
+# if TRUE, existing output JPGs/PNGs are overwritten, instead of adding ..-1.jpg, -2.jpg etc.
OverwriteOutputFile=false
[Profiles]
diff --git a/rtdata/options/options.osx b/rtdata/options/options.osx
index 1793efe78..f05215ae6 100644
--- a/rtdata/options/options.osx
+++ b/rtdata/options/options.osx
@@ -41,6 +41,9 @@ RenameUseTemplates=false
ThumbnailZoomRatios=0.2;0.3;0.45;0.6;0.8;1;
OverlayedFileNames=true
+# if TRUE, only fast, internal preview images are taken if the image is not edited yet
+InternalThumbIfUntouched=true
+
[Clipping Indication]
HighlightThreshold=253
ShadowThreshold=8
@@ -57,6 +60,8 @@ PathTemplate=%p1/converted/%f
PathFolder=
UsePathTemplate=true
LastSaveAsPath=
+
+# if TRUE, existing output JPGs/PNGs are overwritten, instead of adding ..-1.jpg, -2.jpg etc.
OverwriteOutputFile=false
[Profiles]
diff --git a/rtdata/options/options.win b/rtdata/options/options.win
index 519c5bdd3..8834ed124 100644
--- a/rtdata/options/options.win
+++ b/rtdata/options/options.win
@@ -41,6 +41,9 @@ RenameUseTemplates=false
ThumbnailZoomRatios=0.2;0.3;0.45;0.6;0.8;1;
OverlayedFileNames=true
+# if TRUE, only fast, internal preview images are taken if the image is not edited yet
+InternalThumbIfUntouched=true
+
[Clipping Indication]
HighlightThreshold=253
ShadowThreshold=8
@@ -57,6 +60,8 @@ PathTemplate=%p1/converted/%f
PathFolder=
UsePathTemplate=true
LastSaveAsPath=
+
+# if TRUE, existing output JPGs/PNGs are overwritten, instead of adding ..-1.jpg, -2.jpg etc.
OverwriteOutputFile=false
[Profiles]
diff --git a/rtdata/profiles/crisp.pp3 b/rtdata/profiles/crisp.pp3
index b49fe52b4..75b7910cc 100644
--- a/rtdata/profiles/crisp.pp3
+++ b/rtdata/profiles/crisp.pp3
@@ -1,16 +1,16 @@
[Version]
-Version=231
+Version=466
[Exposure]
Auto=true
-Clip=0.02
+Clip=0.001
Compensation=0
Brightness=0
Contrast=12
Black=0
-HighlightCompr=100
-ShadowCompr=100
+HighlightCompr=70
+ShadowCompr=25
Curve=1;0;0;1;1;
[Channel Mixer]
diff --git a/rtdata/profiles/default.pp3 b/rtdata/profiles/default.pp3
index a76f8d10c..fd8f1c188 100644
--- a/rtdata/profiles/default.pp3
+++ b/rtdata/profiles/default.pp3
@@ -1,16 +1,16 @@
[Version]
-Version=231
+Version=466
[Exposure]
Auto=true
-Clip=0.01
+Clip=0.001
Compensation=0
Brightness=0
Contrast=0
Black=0
-HighlightCompr=100
-ShadowCompr=100
+HighlightCompr=70
+ShadowCompr=25
Curve=1;0;0;1;1;
[Channel Mixer]
diff --git a/rtdata/profiles/neutral.pp3 b/rtdata/profiles/neutral.pp3
index 7d9000170..6c8070367 100644
--- a/rtdata/profiles/neutral.pp3
+++ b/rtdata/profiles/neutral.pp3
@@ -1,16 +1,16 @@
[Version]
-Version=231
+Version=466
[Exposure]
Auto=false
-Clip=0.01
+Clip=0.001
Compensation=0
Brightness=0
Contrast=0
Black=0
-HighlightCompr=100
-ShadowCompr=100
+HighlightCompr=70
+ShadowCompr=25
Curve=1;0;0;1;1;
[Channel Mixer]
diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt
index 688c7455e..d8ce097bd 100644
--- a/rtengine/CMakeLists.txt
+++ b/rtengine/CMakeLists.txt
@@ -13,6 +13,7 @@ set (RTENGINESOURCEFILES colortemp.cc curves.cc dcraw.cc iccstore.cc
stdimagesource.cc myfile.cc iccjpeg.c hlmultipliers.cc improccoordinator.cc
processingjob.cc rtthumbnail.cc utils.cc labimage.cc
iplab2rgb.cc ipsharpen.cc iptransform.cc ipresize.cc
+ jpeg_memsrc.c
wavelet_dec.cc ipequalizer.cc dirpyrLab_denoise.cc dirpyrLab_equalizer.cc dirpyr_equalizer.cc)
add_library (rtengine ${RTENGINESOURCEFILES})
diff --git a/rtengine/curves.cc b/rtengine/curves.cc
index 69876a737..236c95b58 100644
--- a/rtengine/curves.cc
+++ b/rtengine/curves.cc
@@ -621,7 +621,7 @@ void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, dou
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
std::vector satcurvePoints;
satcurvePoints.push_back((double)((CurveType)NURBS));
- if (saturation>-99.5) {
+ if (saturation>0) {
satcurvePoints.push_back(0); //black point. Value in [0 ; 1] range
satcurvePoints.push_back(0); //black point. Value in [0 ; 1] range
@@ -635,10 +635,10 @@ void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, dou
satcurvePoints.push_back(1); // value at white point
} else {
satcurvePoints.push_back(0);
- satcurvePoints.push_back(0.5);
+ satcurvePoints.push_back(-0.5*(saturation/100.0));
satcurvePoints.push_back(1);
- satcurvePoints.push_back(0.5);
+ satcurvePoints.push_back(1+saturation/200.0);
}
Curve* satcurve = NULL;
satcurve = new Curve (satcurvePoints, CURVES_MIN_POLY_POINTS/skip); // Actually, CURVES_MIN_POLY_POINTS = 1000,
@@ -728,9 +728,11 @@ void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, dou
std::vector basecurvePoints;
basecurvePoints.push_back((double)((CurveType)NURBS));
- float toex = MIN(1,black/(a*def_mul));
- float toey = toex*a*def_mul*(1-shcompr/100.0);
- float shoulderx = 1/(a*def_mul);//point in x at which line of slope a starting at (0,0) reaches y=1
+ //float toex = MIN(1,black/(a*def_mul));
+ //float toey = MAX(0,toex*a*def_mul*(shcompr/25.0-1));
+ float toex = black;
+ float toey = MAX(0,toex*(shcompr/25.0-1));
+ float shoulderx = MAX(black,1/(a*def_mul));//point in x at which line of slope a starting at (0,0) reaches y=1
float shouldery=1;
float toneslope=(shouldery-toey)/(shoulderx-toex);
if (shoulderx<1) {//a>1; positive EC
@@ -752,7 +754,7 @@ void CurveFactory::complexCurve (double ecomp, double black, double hlcompr, dou
shouldery = toey + (1-toex)*a;
}*/
- basecurvePoints.push_back(0); //black point. Value in [0 ; 1] range
+ basecurvePoints.push_back(MAX(0,0.99*toex*(1-shcompr/25.0))); //black point. Value in [0 ; 1] range
basecurvePoints.push_back(0); //black point. Value in [0 ; 1] range
basecurvePoints.push_back(toex); //toe point
diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc
index ca4957228..5ddd16e27 100644
--- a/rtengine/dcraw.cc
+++ b/rtengine/dcraw.cc
@@ -1,6 +1,5 @@
/*RT*/#include
/*RT*/#include
-/*RT*/int ciff_base, ciff_len, exif_base, pre_filters;
/*RT*/#undef MAX
/*RT*/#undef MIN
/*RT*/#define NO_LCMS
@@ -111,60 +110,70 @@ typedef unsigned long long UINT64;
typedef unsigned char uchar;
typedef unsigned short ushort;
+// RT specify thread local storage
+#ifdef __GNUC__
+#define THREAD_LOCAL static __thread
+#define THREAD_LOCK
+#else
+#define THREAD_LOCAL
+#define THREAD_LOCK Glib::Mutex::Lock locker(*dcrMutex);
+#endif
+
/*
All global variables are defined here, and all functions that
access them are prefixed with "CLASS". Note that a thread-safe
C++ class cannot have non-const static local variables.
*/
-/*RT*/IMFILE *ifp;
-FILE * ofp;
-short order;
-const char *ifname;
-char *meta_data;
-char cdesc[5], desc[512], make[64], model[64], model2[64], artist[64];
-float flash_used, canon_ev, iso_speed, shutter, aperture, focal_len;
-time_t timestamp;
-unsigned shot_order, kodak_cbpp, filters, exif_cfa, unique_id;
-off_t strip_offset, data_offset;
-off_t thumb_offset, meta_offset, profile_offset;
-unsigned thumb_length, meta_length, profile_length;
-unsigned thumb_misc, *oprof, fuji_layout, shot_select=0, multi_out=0;
-unsigned tiff_nifds, tiff_samples, tiff_bps, tiff_compress;
-unsigned black, cblack[8], maximum, mix_green, raw_color, zero_is_bad;
-unsigned zero_after_ff, is_raw, dng_version, is_foveon, data_error;
-unsigned tile_width, tile_length, gpsdata[32], load_flags;
-ushort raw_height, raw_width, height, width, top_margin, left_margin;
-ushort shrink, iheight, iwidth, fuji_width, thumb_width, thumb_height;
-int flip, tiff_flip, colors;
-double pixel_aspect, aber[4]={1,1,1,1}, gamm[6]={ 0.45,4.5,0,0,0,0 };
-ushort (*image)[4], white[8][8], curve[0x10000], cr2_slice[3], sraw_mul[4];
-float bright=1, user_mul[4]={0,0,0,0}, threshold=0;
-int half_size=0, four_color_rgb=0, document_mode=0, highlight=0;
-int verbose=0, use_auto_wb=0, use_camera_wb=0, use_camera_matrix=-1;
-int output_color=1, output_bps=8, output_tiff=0, med_passes=0;
-int no_auto_bright=0;
-unsigned greybox[4] = { 0, 0, UINT_MAX, UINT_MAX };
-float cam_mul[4], pre_mul[4], cmatrix[3][4], rgb_cam[3][4];
-const double xyz_rgb[3][3] = { /* XYZ from RGB */
+/*RT*/THREAD_LOCAL int ciff_base, ciff_len, exif_base, pre_filters;
+/*RT*/THREAD_LOCAL IMFILE *ifp;
+THREAD_LOCAL FILE * ofp;
+THREAD_LOCAL short order;
+THREAD_LOCAL const char *ifname;
+THREAD_LOCAL char *meta_data;
+THREAD_LOCAL char cdesc[5], desc[512], make[64], model[64], model2[64], artist[64];
+THREAD_LOCAL float flash_used, canon_ev, iso_speed, shutter, aperture, focal_len;
+THREAD_LOCAL time_t timestamp;
+THREAD_LOCAL unsigned shot_order, kodak_cbpp, filters, exif_cfa, unique_id;
+THREAD_LOCAL off_t strip_offset, data_offset;
+THREAD_LOCAL off_t thumb_offset, meta_offset, profile_offset;
+THREAD_LOCAL unsigned thumb_length, meta_length, profile_length;
+THREAD_LOCAL unsigned thumb_misc, *oprof, fuji_layout, shot_select=0, multi_out=0;
+THREAD_LOCAL unsigned tiff_nifds, tiff_samples, tiff_bps, tiff_compress;
+THREAD_LOCAL unsigned black, cblack[8], maximum, mix_green, raw_color, zero_is_bad;
+THREAD_LOCAL unsigned zero_after_ff, is_raw, dng_version, is_foveon, data_error;
+THREAD_LOCAL unsigned tile_width, tile_length, gpsdata[32], load_flags;
+THREAD_LOCAL ushort raw_height, raw_width, height, width, top_margin, left_margin;
+THREAD_LOCAL ushort shrink, iheight, iwidth, fuji_width, thumb_width, thumb_height;
+THREAD_LOCAL int flip, tiff_flip, colors;
+THREAD_LOCAL double pixel_aspect, aber[4]={1,1,1,1}, gamm[6]={ 0.45,4.5,0,0,0,0 };
+THREAD_LOCAL ushort (*image)[4], white[8][8], curve[0x10000], cr2_slice[3], sraw_mul[4];
+THREAD_LOCAL float bright=1, user_mul[4]={0,0,0,0}, threshold=0;
+THREAD_LOCAL int half_size=0, four_color_rgb=0, document_mode=0, highlight=0;
+THREAD_LOCAL int verbose=0, use_auto_wb=0, use_camera_wb=0, use_camera_matrix=-1;
+THREAD_LOCAL int output_color=1, output_bps=8, output_tiff=0, med_passes=0;
+THREAD_LOCAL int no_auto_bright=0;
+THREAD_LOCAL unsigned greybox[4] = { 0, 0, UINT_MAX, UINT_MAX };
+THREAD_LOCAL float cam_mul[4], pre_mul[4], cmatrix[3][4], rgb_cam[3][4];
+static const double xyz_rgb[3][3] = { /* XYZ from RGB */
{ 0.412453, 0.357580, 0.180423 },
{ 0.212671, 0.715160, 0.072169 },
{ 0.019334, 0.119193, 0.950227 } };
-const float d65_white[3] = { 0.950456, 1, 1.088754 };
-int histogram[4][0x2000];
-void (*write_thumb)(), (*write_fun)();
-void (*load_raw)(), (*thumb_load_raw)();
-jmp_buf failure;
+static const float d65_white[3] = { 0.950456, 1, 1.088754 };
+THREAD_LOCAL int histogram[4][0x2000];
+THREAD_LOCAL void (*write_thumb)(), (*write_fun)();
+THREAD_LOCAL void (*load_raw)(), (*thumb_load_raw)();
+THREAD_LOCAL jmp_buf failure;
-struct decode {
+THREAD_LOCAL struct decode {
struct decode *branch[2];
int leaf;
} first_decode[2048], *second_decode, *free_decode;
-struct tiff_ifd {
+THREAD_LOCAL struct tiff_ifd {
int width, height, bps, comp, phint, offset, flip, samples, bytes;
} tiff_ifd[10];
-struct ph1 {
+THREAD_LOCAL struct ph1 {
int format, key_off, black, black_off, split_col, tag_21a;
float tag_210;
} ph1;
@@ -555,8 +564,8 @@ int CLASS canon_s2is()
*/
unsigned CLASS getbithuff (int nbits, ushort *huff)
{
- static unsigned bitbuf=0;
- static int vbits=0, reset=0;
+ THREAD_LOCAL unsigned bitbuf=0;
+ THREAD_LOCAL int vbits=0, reset=0;
unsigned c;
if (nbits == -1)
@@ -1577,8 +1586,8 @@ void CLASS phase_one_load_raw()
unsigned CLASS ph1_bithuff (int nbits, ushort *huff)
{
- static UINT64 bitbuf=0;
- static int vbits=0;
+ THREAD_LOCAL UINT64 bitbuf=0;
+ THREAD_LOCAL int vbits=0;
unsigned c;
if (nbits == -1)
@@ -1840,8 +1849,8 @@ void CLASS nokia_load_raw()
unsigned CLASS pana_bits (int nbits)
{
- static uchar buf[0x4000];
- static int vbits;
+ THREAD_LOCAL uchar buf[0x4000];
+ THREAD_LOCAL int vbits;
int byte;
if (!nbits) return vbits=0;
@@ -2130,7 +2139,7 @@ void CLASS kodak_jpeg_load_raw() {}
METHODDEF(boolean)
fill_input_buffer (j_decompress_ptr cinfo)
{
- static uchar jpeg_buffer[4096];
+ THREAD_LOCAL uchar jpeg_buffer[4096];
size_t nbytes;
nbytes = fread (jpeg_buffer, 1, 4096, ifp);
@@ -2408,7 +2417,7 @@ void CLASS kodak_thumb_load_raw()
void CLASS sony_decrypt (unsigned *data, int len, int start, int key)
{
- static unsigned pad[128], p;
+ THREAD_LOCAL unsigned pad[128], p;
if (start) {
for (p=0; p < 4; p++)
@@ -2655,7 +2664,7 @@ void CLASS smal_v9_load_raw()
void CLASS foveon_decoder (unsigned size, unsigned code)
{
- static unsigned huff[1024];
+ THREAD_LOCAL unsigned huff[1024];
struct decode *cur;
int i, len;
@@ -7227,6 +7236,8 @@ canon_cr2:
} else if (!strcmp(model,"D1X")) {
width -= 4;
pixel_aspect = 0.5;
+ } else if (!strcmp(model,"D7000")) {
+ width -= 40;
} else if (!strcmp(model,"D40X") ||
!strcmp(model,"D60") ||
!strcmp(model,"D80") ||
@@ -8935,7 +8946,7 @@ int loadRaw (const char* fname, struct RawImage *ri) {
{ 0.222507, 0.716888, 0.060608 },
{ 0.013930, 0.097097, 0.714022 } };
-dcrMutex->lock ();
+ THREAD_LOCK
ifname = fname;//strdup (fname);
image = NULL;
@@ -8950,7 +8961,6 @@ dcrMutex->lock ();
ri->profile_data = NULL;
ifp = gfopen (fname);
if (!ifp) {
- dcrMutex->unlock ();
return 3;
}
@@ -8962,7 +8972,6 @@ dcrMutex->lock ();
use_camera_wb = 1;
if (!is_raw) {
fclose(ifp);
- dcrMutex->unlock ();
return 2;
}
@@ -8981,7 +8990,6 @@ dcrMutex->lock ();
if (ri->data)
free(ri->data);
fclose (ifp);
- dcrMutex->unlock ();
return 100;
}
@@ -9068,15 +9076,14 @@ dcrMutex->lock ();
ri->coeff[a][b] = rgb_cam[a][b];
free (image);
-dcrMutex->unlock ();
return 0;
}
int getRawFileBasicInfo (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, int& rotation, int& thumbWidth, int& thumbHeight, int& thumbOffset, int& thumbType) {
- int status=0;
+ THREAD_LOCK
-dcrMutex->lock ();
+ int status=0;
exif_base = -1;
ciff_base = -1;
@@ -9095,14 +9102,12 @@ dcrMutex->lock ();
ifname = fname.c_str();
if (!(ifp = gfopen (ifname))) {
status = 2;
- dcrMutex->unlock ();
return status;
}
identify ();
if (!is_raw || colors>3) {
status = 3;
fclose (ifp);
- dcrMutex->unlock ();
return status;
}
@@ -9134,15 +9139,78 @@ dcrMutex->lock ();
rml.ciffLength = ciff_len;
fclose (ifp);
-dcrMutex->unlock ();
return !is_raw;
}
#include
+rtengine::Thumbnail* rtengine::Thumbnail::loadQuickFromRaw (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, int &w, int &h, int fixwh) {
+
+ THREAD_LOCK
+
+ image = NULL;
+ ifname = fname.c_str();
+ exif_base = -1;
+ ciff_base = -1;
+ ciff_len = -1;
+ verbose = settings->verbose;
+ oprof = NULL;
+ ifp = gfopen (fname.c_str());
+ if (!ifp) {
+ printf("DCRAW: failed0\n");
+ return NULL;
+ }
+
+ if (setjmp (failure)) {
+ printf("DCRAW: failed1\n");
+ fclose (ifp);
+ return NULL;
+ }
+
+ identify ();
+ if (!is_raw || colors>3) {
+ printf("DCRAW: failed2\n");
+ fclose(ifp);
+ return NULL;
+ }
+
+ rml.exifBase = exif_base;
+ rml.ciffBase = ciff_base;
+ rml.ciffLength = ciff_len;
+
+ char thumb_buffer[thumb_length];
+ fseek(ifp,thumb_offset,SEEK_SET);
+ fread(thumb_buffer,1,thumb_length,ifp);
+ fclose(ifp);
+
+ rtengine::Thumbnail* tpp = rtengine::Thumbnail::loadFromMemory(thumb_buffer,thumb_length,w,h,fixwh);
+ if ( tpp == 0 )
+ {
+ printf("DCRAW: failed3\n");
+ return NULL;
+ }
+
+ int deg = 0;
+ if (flip==5)
+ deg = 270;
+ else if (flip==3)
+ deg = 180;
+ else if (flip==6)
+ deg = 90;
+
+ if (deg>0) {
+ Image16* rot = tpp->thumbImg->rotate (deg);
+ delete tpp->thumbImg;
+ tpp->thumbImg = rot;
+ }
+
+ return tpp;
+}
+
rtengine::Thumbnail* rtengine::Thumbnail::loadFromRaw (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, int &w, int &h, int fixwh) {
-dcrMutex->lock ();
+ THREAD_LOCK
+
MyTime t0, t1, t2, t3, t4, t5, t6;
t0.set ();
@@ -9155,7 +9223,6 @@ t0.set ();
oprof = NULL;
ifp = gfopen (fname.c_str());
if (!ifp) {
- dcrMutex->unlock ();
return NULL;
}
@@ -9165,7 +9232,6 @@ t1.set ();
if (image)
free (image);
fclose (ifp);
- dcrMutex->unlock ();
return NULL;
}
@@ -9177,7 +9243,6 @@ t1.set ();
use_camera_wb = 1;
if (!is_raw || colors>3) {
fclose(ifp);
- dcrMutex->unlock ();
return NULL;
}
@@ -9439,8 +9504,6 @@ if (settings->verbose) printf ("0: %d, 1: %d, 2: %d, 3: %d, 4: %d, 5: %d All: %d
free (image);
-dcrMutex->unlock ();
-
return tpp;
}
diff --git a/rtengine/dcraw.patch b/rtengine/dcraw.patch
index 826580dff..fec902bbc 100644
--- a/rtengine/dcraw.patch
+++ b/rtengine/dcraw.patch
@@ -1,9 +1,8 @@
---- dcraw.c 2010-06-30 10:40:16.000000000 -0600
-+++ dcraw.cc 2010-06-30 10:36:00.000000000 -0600
-@@ -1,3 +1,16 @@
+--- dcraw.c 2010-10-25 09:45:14.000000000 -0400
++++ dcraw.cc 2010-10-27 11:30:33.000000000 -0400
+@@ -1,3 +1,15 @@
+/*RT*/#include
+/*RT*/#include
-+/*RT*/int ciff_base, ciff_len, exif_base, pre_filters;
+/*RT*/#undef MAX
+/*RT*/#undef MIN
+/*RT*/#define NO_LCMS
@@ -17,7 +16,7 @@
/*
dcraw.c -- Dave Coffin's raw photo decoder
Copyright 1997-2010 by Dave Coffin, dcoffin a cybercom o net
-@@ -46,7 +59,9 @@
+@@ -46,7 +58,9 @@
NO_LCMS disables the "-p" option.
*/
#ifndef NO_JPEG
@@ -28,17 +27,115 @@
#endif
#ifndef NO_LCMS
#include
-@@ -101,7 +116,8 @@
+@@ -96,59 +110,70 @@
+ typedef unsigned char uchar;
+ typedef unsigned short ushort;
+
++// RT specify thread local storage
++#ifdef __GNUC__
++#define THREAD_LOCAL static __thread
++#define THREAD_LOCK
++#else
++#define THREAD_LOCAL
++#define THREAD_LOCK Glib::Mutex::Lock locker(*dcrMutex);
++#endif
++
+ /*
+ All global variables are defined here, and all functions that
access them are prefixed with "CLASS". Note that a thread-safe
C++ class cannot have non-const static local variables.
*/
-FILE *ifp, *ofp;
-+/*RT*/IMFILE *ifp;
-+FILE * ofp;
- short order;
- const char *ifname;
- char *meta_data;
-@@ -271,6 +287,7 @@
+-short order;
+-const char *ifname;
+-char *meta_data;
+-char cdesc[5], desc[512], make[64], model[64], model2[64], artist[64];
+-float flash_used, canon_ev, iso_speed, shutter, aperture, focal_len;
+-time_t timestamp;
+-unsigned shot_order, kodak_cbpp, filters, exif_cfa, unique_id;
+-off_t strip_offset, data_offset;
+-off_t thumb_offset, meta_offset, profile_offset;
+-unsigned thumb_length, meta_length, profile_length;
+-unsigned thumb_misc, *oprof, fuji_layout, shot_select=0, multi_out=0;
+-unsigned tiff_nifds, tiff_samples, tiff_bps, tiff_compress;
+-unsigned black, cblack[8], maximum, mix_green, raw_color, zero_is_bad;
+-unsigned zero_after_ff, is_raw, dng_version, is_foveon, data_error;
+-unsigned tile_width, tile_length, gpsdata[32], load_flags;
+-ushort raw_height, raw_width, height, width, top_margin, left_margin;
+-ushort shrink, iheight, iwidth, fuji_width, thumb_width, thumb_height;
+-int flip, tiff_flip, colors;
+-double pixel_aspect, aber[4]={1,1,1,1}, gamm[6]={ 0.45,4.5,0,0,0,0 };
+-ushort (*image)[4], white[8][8], curve[0x10000], cr2_slice[3], sraw_mul[4];
+-float bright=1, user_mul[4]={0,0,0,0}, threshold=0;
+-int half_size=0, four_color_rgb=0, document_mode=0, highlight=0;
+-int verbose=0, use_auto_wb=0, use_camera_wb=0, use_camera_matrix=-1;
+-int output_color=1, output_bps=8, output_tiff=0, med_passes=0;
+-int no_auto_bright=0;
+-unsigned greybox[4] = { 0, 0, UINT_MAX, UINT_MAX };
+-float cam_mul[4], pre_mul[4], cmatrix[3][4], rgb_cam[3][4];
+-const double xyz_rgb[3][3] = { /* XYZ from RGB */
++/*RT*/THREAD_LOCAL int ciff_base, ciff_len, exif_base, pre_filters;
++/*RT*/THREAD_LOCAL IMFILE *ifp;
++THREAD_LOCAL FILE * ofp;
++THREAD_LOCAL short order;
++THREAD_LOCAL const char *ifname;
++THREAD_LOCAL char *meta_data;
++THREAD_LOCAL char cdesc[5], desc[512], make[64], model[64], model2[64], artist[64];
++THREAD_LOCAL float flash_used, canon_ev, iso_speed, shutter, aperture, focal_len;
++THREAD_LOCAL time_t timestamp;
++THREAD_LOCAL unsigned shot_order, kodak_cbpp, filters, exif_cfa, unique_id;
++THREAD_LOCAL off_t strip_offset, data_offset;
++THREAD_LOCAL off_t thumb_offset, meta_offset, profile_offset;
++THREAD_LOCAL unsigned thumb_length, meta_length, profile_length;
++THREAD_LOCAL unsigned thumb_misc, *oprof, fuji_layout, shot_select=0, multi_out=0;
++THREAD_LOCAL unsigned tiff_nifds, tiff_samples, tiff_bps, tiff_compress;
++THREAD_LOCAL unsigned black, cblack[8], maximum, mix_green, raw_color, zero_is_bad;
++THREAD_LOCAL unsigned zero_after_ff, is_raw, dng_version, is_foveon, data_error;
++THREAD_LOCAL unsigned tile_width, tile_length, gpsdata[32], load_flags;
++THREAD_LOCAL ushort raw_height, raw_width, height, width, top_margin, left_margin;
++THREAD_LOCAL ushort shrink, iheight, iwidth, fuji_width, thumb_width, thumb_height;
++THREAD_LOCAL int flip, tiff_flip, colors;
++THREAD_LOCAL double pixel_aspect, aber[4]={1,1,1,1}, gamm[6]={ 0.45,4.5,0,0,0,0 };
++THREAD_LOCAL ushort (*image)[4], white[8][8], curve[0x10000], cr2_slice[3], sraw_mul[4];
++THREAD_LOCAL float bright=1, user_mul[4]={0,0,0,0}, threshold=0;
++THREAD_LOCAL int half_size=0, four_color_rgb=0, document_mode=0, highlight=0;
++THREAD_LOCAL int verbose=0, use_auto_wb=0, use_camera_wb=0, use_camera_matrix=-1;
++THREAD_LOCAL int output_color=1, output_bps=8, output_tiff=0, med_passes=0;
++THREAD_LOCAL int no_auto_bright=0;
++THREAD_LOCAL unsigned greybox[4] = { 0, 0, UINT_MAX, UINT_MAX };
++THREAD_LOCAL float cam_mul[4], pre_mul[4], cmatrix[3][4], rgb_cam[3][4];
++static const double xyz_rgb[3][3] = { /* XYZ from RGB */
+ { 0.412453, 0.357580, 0.180423 },
+ { 0.212671, 0.715160, 0.072169 },
+ { 0.019334, 0.119193, 0.950227 } };
+-const float d65_white[3] = { 0.950456, 1, 1.088754 };
+-int histogram[4][0x2000];
+-void (*write_thumb)(), (*write_fun)();
+-void (*load_raw)(), (*thumb_load_raw)();
+-jmp_buf failure;
++static const float d65_white[3] = { 0.950456, 1, 1.088754 };
++THREAD_LOCAL int histogram[4][0x2000];
++THREAD_LOCAL void (*write_thumb)(), (*write_fun)();
++THREAD_LOCAL void (*load_raw)(), (*thumb_load_raw)();
++THREAD_LOCAL jmp_buf failure;
+
+-struct decode {
++THREAD_LOCAL struct decode {
+ struct decode *branch[2];
+ int leaf;
+ } first_decode[2048], *second_decode, *free_decode;
+
+-struct tiff_ifd {
++THREAD_LOCAL struct tiff_ifd {
+ int width, height, bps, comp, phint, offset, flip, samples, bytes;
+ } tiff_ifd[10];
+
+-struct ph1 {
++THREAD_LOCAL struct ph1 {
+ int format, key_off, black, black_off, split_col, tag_21a;
+ float tag_210;
+ } ph1;
+@@ -271,6 +296,7 @@
fprintf (stderr,_("Corrupt data near 0x%llx\n"), (INT64) ftello(ifp));
}
data_error++;
@@ -46,7 +143,7 @@
}
ushort CLASS sget2 (uchar *s)
-@@ -344,7 +361,7 @@
+@@ -344,7 +370,7 @@
{
if (fread (pixel, 2, count, ifp) < count) derror();
if ((order == 0x4949) == (ntohs(0x1234) == 0x1234))
@@ -55,7 +152,45 @@
}
void CLASS canon_600_fixed_wb (int temp)
-@@ -2117,7 +2134,7 @@
+@@ -538,8 +564,8 @@
+ */
+ unsigned CLASS getbithuff (int nbits, ushort *huff)
+ {
+- static unsigned bitbuf=0;
+- static int vbits=0, reset=0;
++ THREAD_LOCAL unsigned bitbuf=0;
++ THREAD_LOCAL int vbits=0, reset=0;
+ unsigned c;
+
+ if (nbits == -1)
+@@ -1560,8 +1586,8 @@
+
+ unsigned CLASS ph1_bithuff (int nbits, ushort *huff)
+ {
+- static UINT64 bitbuf=0;
+- static int vbits=0;
++ THREAD_LOCAL UINT64 bitbuf=0;
++ THREAD_LOCAL int vbits=0;
+ unsigned c;
+
+ if (nbits == -1)
+@@ -1823,8 +1849,8 @@
+
+ unsigned CLASS pana_bits (int nbits)
+ {
+- static uchar buf[0x4000];
+- static int vbits;
++ THREAD_LOCAL uchar buf[0x4000];
++ THREAD_LOCAL int vbits;
+ int byte;
+
+ if (!nbits) return vbits=0;
+@@ -2113,11 +2139,11 @@
+ METHODDEF(boolean)
+ fill_input_buffer (j_decompress_ptr cinfo)
+ {
+- static uchar jpeg_buffer[4096];
++ THREAD_LOCAL uchar jpeg_buffer[4096];
size_t nbytes;
nbytes = fread (jpeg_buffer, 1, 4096, ifp);
@@ -64,7 +199,25 @@
cinfo->src->next_input_byte = jpeg_buffer;
cinfo->src->bytes_in_buffer = nbytes;
return TRUE;
-@@ -3765,6 +3782,7 @@
+@@ -2391,7 +2417,7 @@
+
+ void CLASS sony_decrypt (unsigned *data, int len, int start, int key)
+ {
+- static unsigned pad[128], p;
++ THREAD_LOCAL unsigned pad[128], p;
+
+ if (start) {
+ for (p=0; p < 4; p++)
+@@ -2638,7 +2664,7 @@
+
+ void CLASS foveon_decoder (unsigned size, unsigned code)
+ {
+- static unsigned huff[1024];
++ THREAD_LOCAL unsigned huff[1024];
+ struct decode *cur;
+ int i, len;
+
+@@ -3765,6 +3791,7 @@
for (row = FC(1,0) >> 1; row < height; row+=2)
for (col = FC(row,1) & 1; col < width; col+=2)
image[row*width+col][1] = image[row*width+col][3];
@@ -72,7 +225,7 @@
filters &= ~((filters & 0x55555555) << 1);
}
}
-@@ -4817,7 +4835,7 @@
+@@ -4817,7 +4844,7 @@
unsigned sony_curve[] = { 0,0,0,0,0,4095 };
unsigned *buf, sony_offset=0, sony_length=0, sony_key=0;
struct jhead jh;
@@ -81,7 +234,7 @@
if (tiff_nifds >= sizeof tiff_ifd / sizeof tiff_ifd[0])
return 1;
-@@ -5225,12 +5243,13 @@
+@@ -5225,12 +5252,13 @@
fread (buf, sony_length, 1, ifp);
sony_decrypt (buf, sony_length/4, 1, sony_key);
sfp = ifp;
@@ -100,7 +253,7 @@
ifp = sfp;
free (buf);
}
-@@ -5256,6 +5275,8 @@
+@@ -5256,6 +5284,8 @@
int doff, max_samp=0, raw=-1, thm=-1, i;
struct jhead jh;
@@ -109,7 +262,7 @@
fseek (ifp, base, SEEK_SET);
order = get2();
if (order != 0x4949 && order != 0x4d4d) return;
-@@ -5424,7 +5445,7 @@
+@@ -5424,7 +5454,7 @@
{
const char *file, *ext;
char *jname, *jfile, *jext;
@@ -118,7 +271,7 @@
ext = strrchr (ifname, '.');
file = strrchr (ifname, '/');
-@@ -5452,7 +5473,8 @@
+@@ -5452,7 +5482,8 @@
*jext = '0';
}
if (strcmp (jname, ifname)) {
@@ -128,7 +281,7 @@
if (verbose)
fprintf (stderr,_("Reading metadata from %s ...\n"), jname);
parse_tiff (12);
-@@ -5790,7 +5812,11 @@
+@@ -5790,7 +5821,11 @@
order = get2();
hlen = get4();
if (get4() == 0x48454150) /* "HEAP" */
@@ -140,7 +293,7 @@
parse_tiff (save+6);
fseek (ifp, save+len, SEEK_SET);
}
-@@ -6738,6 +6764,12 @@
+@@ -6738,6 +6773,12 @@
fread (head, 1, 32, ifp);
fseek (ifp, 0, SEEK_END);
flen = fsize = ftell(ifp);
@@ -153,7 +306,7 @@
if ((cp = (char *) memmem (head, 32, "MMMM", 4)) ||
(cp = (char *) memmem (head, 32, "IIII", 4))) {
parse_phase_one (cp-head);
-@@ -6745,6 +6777,8 @@
+@@ -6745,6 +6786,8 @@
} else if (order == 0x4949 || order == 0x4d4d) {
if (!memcmp (head+6,"HEAPCCDR",8)) {
data_offset = hlen;
@@ -162,7 +315,25 @@
parse_ciff (hlen, flen - hlen);
} else {
parse_tiff(0);
-@@ -8494,13 +8528,13 @@
+@@ -6858,6 +6901,8 @@
+ if (height == 3136 && width == 4736) /* Pentax K-7 */
+ { height = 3122; width = 4684;
+ top_margin = 2; filters = 0x16161616; }
++ if (height == 2868 && width == 4352) /* Pentax K-x */
++ width = 4308;
+ if (height == 3014 && width == 4096) /* Ricoh GX200 */
+ width = 4014;
+ if (dng_version) {
+@@ -7405,7 +7450,7 @@
+ } else if (!strcmp(model,"K20D")) {
+ filters = 0x16161616;
+ } else if (!strcmp(model,"K-x")) {
+- width = 4309;
++ width = 4308;
+ filters = 0x16161616;
+ } else if (!strcmp(model,"Optio S")) {
+ if (fsize == 3178560) {
+@@ -8494,13 +8539,13 @@
FORCC ppm [col*colors+c] = curve[image[soff][c]] >> 8;
else FORCC ppm2[col*colors+c] = curve[image[soff][c]];
if (output_bps == 16 && !output_tiff && htons(0x55aa) != 0x55aa)
@@ -178,7 +349,7 @@
{
int arg, status=0;
int timestamp_only=0, thumbnail_only=0, identify_only=0;
-@@ -8613,7 +8647,7 @@
+@@ -8613,7 +8658,7 @@
case 'i': identify_only = 1; break;
case 'c': write_to_stdout = 1; break;
case 'v': verbose = 1; break;
@@ -187,7 +358,7 @@
case 'f': four_color_rgb = 1; break;
case 'A': FORC4 greybox[c] = atoi(argv[arg++]);
case 'a': use_auto_wb = 1; break;
-@@ -8877,3 +8911,537 @@
+@@ -8877,3 +8922,526 @@
}
return status;
}
@@ -213,7 +384,7 @@
+ { 0.222507, 0.716888, 0.060608 },
+ { 0.013930, 0.097097, 0.714022 } };
+
-+dcrMutex->lock ();
++ THREAD_LOCK
+
+ ifname = fname;//strdup (fname);
+ image = NULL;
@@ -228,7 +399,6 @@
+ ri->profile_data = NULL;
+ ifp = gfopen (fname);
+ if (!ifp) {
-+ dcrMutex->unlock ();
+ return 3;
+ }
+
@@ -240,7 +410,6 @@
+ use_camera_wb = 1;
+ if (!is_raw) {
+ fclose(ifp);
-+ dcrMutex->unlock ();
+ return 2;
+ }
+
@@ -259,7 +428,6 @@
+ if (ri->data)
+ free(ri->data);
+ fclose (ifp);
-+ dcrMutex->unlock ();
+ return 100;
+ }
+
@@ -346,15 +514,14 @@
+ ri->coeff[a][b] = rgb_cam[a][b];
+
+ free (image);
-+dcrMutex->unlock ();
+ return 0;
+}
+
+int getRawFileBasicInfo (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, int& rotation, int& thumbWidth, int& thumbHeight, int& thumbOffset, int& thumbType) {
+
-+ int status=0;
++ THREAD_LOCK
+
-+dcrMutex->lock ();
++ int status=0;
+
+ exif_base = -1;
+ ciff_base = -1;
@@ -373,14 +540,12 @@
+ ifname = fname.c_str();
+ if (!(ifp = gfopen (ifname))) {
+ status = 2;
-+ dcrMutex->unlock ();
+ return status;
+ }
+ identify ();
+ if (!is_raw || colors>3) {
+ status = 3;
+ fclose (ifp);
-+ dcrMutex->unlock ();
+ return status;
+ }
+
@@ -412,7 +577,6 @@
+ rml.ciffLength = ciff_len;
+
+ fclose (ifp);
-+dcrMutex->unlock ();
+ return !is_raw;
+}
+
@@ -420,7 +584,8 @@
+
+rtengine::Thumbnail* rtengine::Thumbnail::loadFromRaw (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, int &w, int &h, int fixwh) {
+
-+dcrMutex->lock ();
++ THREAD_LOCK
++
+MyTime t0, t1, t2, t3, t4, t5, t6;
+t0.set ();
+
@@ -433,7 +598,6 @@
+ oprof = NULL;
+ ifp = gfopen (fname.c_str());
+ if (!ifp) {
-+ dcrMutex->unlock ();
+ return NULL;
+ }
+
@@ -443,7 +607,6 @@
+ if (image)
+ free (image);
+ fclose (ifp);
-+ dcrMutex->unlock ();
+ return NULL;
+ }
+
@@ -455,7 +618,6 @@
+ use_camera_wb = 1;
+ if (!is_raw || colors>3) {
+ fclose(ifp);
-+ dcrMutex->unlock ();
+ return NULL;
+ }
+
@@ -610,7 +772,7 @@
+
+ // generate histogram for auto exposure
+ tpp->aeHistCompression = 3;
-+ tpp->aeHistogram = new int[65536>>tpp->aeHistCompression];
++ tpp->aeHistogram = new unsigned int[65536>>tpp->aeHistCompression];
+ memset (tpp->aeHistogram, 0, (65536>>tpp->aeHistCompression)*sizeof(int));
+ int radd = 4;
+ int gadd = 2;
@@ -717,8 +879,6 @@
+
+ free (image);
+
-+dcrMutex->unlock ();
-+
+ return tpp;
+}
+
diff --git a/rtengine/iccstore.cc b/rtengine/iccstore.cc
index 748a3046d..f5e96f713 100644
--- a/rtengine/iccstore.cc
+++ b/rtengine/iccstore.cc
@@ -27,8 +27,6 @@
namespace rtengine {
-ICCStore iccStore;
-
const double (*wprofiles[])[3] = {sRGB_d50, adobe_d50, prophoto_d50, widegamut_d50, bruce_d50, beta_d50, best_d50};
const double (*iwprofiles[])[3] = {d50_sRGB, d50_adobe, d50_prophoto, d50_widegamut, d50_bruce, d50_beta, d50_best};
const char* wpnames[] = {"sRGB", "Adobe RGB", "ProPhoto", "WideGamut", "BruceRGB", "Beta RGB", "BestRGB"};
@@ -43,11 +41,13 @@ std::vector getWorkingProfiles () {
std::vector getOutputProfiles () {
- return iccStore.getOutputProfiles ();
+ return iccStore->getOutputProfiles ();
}
std::vector ICCStore::getOutputProfiles () {
+ Glib::Mutex::Lock lock(mutex_);
+
std::vector res;
for (std::map::iterator i=fileProfiles.begin(); i!=fileProfiles.end(); i++)
res.push_back (i->first);
@@ -55,14 +55,30 @@ std::vector ICCStore::getOutputProfiles () {
}
-ICCStore::ICCStore () {
+ICCStore*
+ICCStore::getInstance(void)
+{
+ static ICCStore* instance_ = 0;
+ if ( instance_ == 0 )
+ {
+ static Glib::Mutex smutex_;
+ Glib::Mutex::Lock lock(smutex_);
+ if ( instance_ == 0 )
+ {
+ instance_ = new ICCStore();
+ }
+ }
+ return instance_;
+}
+ICCStore::ICCStore ()
+{
cmsErrorAction (LCMS_ERROR_SHOW);
int N = sizeof(wpnames)/sizeof(wpnames[0]);
for (int i=0; i::iterator r = fileProfiles.find (name);
if (r!=fileProfiles.end())
@@ -137,11 +154,15 @@ cmsHPROFILE ICCStore::getProfile (Glib::ustring name) {
ProfileContent ICCStore::getContent (Glib::ustring name) {
+ Glib::Mutex::Lock lock(mutex_);
+
return fileProfileContents[name];
}
std::vector ICCStore::parseDir (Glib::ustring pdir) {
+ Glib::Mutex::Lock lock(mutex_);
+
fileProfiles.clear ();
fileProfileContents.clear ();
std::vector result;
@@ -309,6 +330,8 @@ cmsHPROFILE ICCStore::createFromMatrix (const double matrix[3][3], bool gamma, G
strcpy ((char *)oprof+pbody[5]+12, name.c_str());
- return cmsOpenProfileFromMem (oprof, ntohl(oprof[0]));
+ cmsHPROFILE p = cmsOpenProfileFromMem (oprof, ntohl(oprof[0]));
+ delete [] oprof;
+ return p;
}
}
diff --git a/rtengine/iccstore.h b/rtengine/iccstore.h
index 3c0a9dc49..5e67b55a7 100644
--- a/rtengine/iccstore.h
+++ b/rtengine/iccstore.h
@@ -54,9 +54,14 @@ class ICCStore {
cmsHPROFILE xyz;
cmsHPROFILE srgb;
+
+ Glib::Mutex mutex_;
+
+ ICCStore ();
public:
- ICCStore ();
+
+ static ICCStore* getInstance(void);
int numOfWProfiles ();
cmsHPROFILE createFromMatrix (const double matrix[3][3], bool gamma=false, Glib::ustring name="");
@@ -74,7 +79,7 @@ class ICCStore {
std::vector getOutputProfiles ();
};
-extern ICCStore iccStore;
+#define iccStore ICCStore::getInstance()
//extern const char* wpnames[];
}
diff --git a/rtengine/image16.cc b/rtengine/image16.cc
index 1afe0e258..1f6227f98 100644
--- a/rtengine/image16.cc
+++ b/rtengine/image16.cc
@@ -17,6 +17,7 @@
* along with RawTherapee. If not, see .
*/
#include
+#include
#include
#include
@@ -239,3 +240,19 @@ Image16* Image16::resize (int nw, int nh, TypeInterpolation interp) {
}
return NULL;
}
+
+Image8*
+Image16::to8() const
+{
+ Image8* img8 = new Image8(width,height);
+ for ( int h = 0; h < height; ++h )
+ {
+ for ( int w = 0; w < width; ++w )
+ {
+ img8->r(h,w,r[h][w] >> 8);
+ img8->g(h,w,g[h][w] >> 8);
+ img8->b(h,w,b[h][w] >> 8);
+ }
+ }
+ return img8;
+}
diff --git a/rtengine/image16.h b/rtengine/image16.h
index 8a778215b..ba719535b 100644
--- a/rtengine/image16.h
+++ b/rtengine/image16.h
@@ -29,6 +29,8 @@ namespace rtengine {
enum TypeInterpolation { TI_Nearest, TI_Bilinear };
+class Image8;
+
class Image16 : public ImageIO, public IImage16 {
private:
@@ -54,6 +56,8 @@ class Image16 : public ImageIO, public IImage16 {
Image16* copy ();
+ Image8* to8() const;
+
Image16* rotate (int deg);
Image16* hflip ();
Image16* vflip ();
diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc
index 59c32ebc5..432fafae2 100644
--- a/rtengine/imageio.cc
+++ b/rtengine/imageio.cc
@@ -259,6 +259,75 @@ int ImageIO::loadPNG (Glib::ustring fname) {
extern jmp_buf jpeg_jmp_buf;
+extern "C" {
+void jpeg_memory_src (jpeg_decompress_struct* cinfo, const char* buffer, int bufsize);
+}
+
+int ImageIO::loadJPEGFromMemory (const char* buffer, int bufsize)
+{
+ jpeg_decompress_struct cinfo;
+ jpeg_error_mgr jerr;
+ cinfo.err = my_jpeg_std_error(&jerr);
+ jpeg_create_decompress(&cinfo);
+ jpeg_memory_src (&cinfo,buffer,bufsize);
+
+ if (pl) {
+ pl->setProgressStr ("Loading JPEG file...");
+ pl->setProgress (0.0);
+
+ }
+
+ setup_read_icc_profile (&cinfo);
+
+ if (!setjmp(jpeg_jmp_buf)) {
+ jpeg_memory_src (&cinfo,buffer,bufsize);
+ jpeg_read_header(&cinfo, TRUE);
+
+ unsigned int proflen;
+ delete loadedProfileData;
+ loadedProfileData = NULL;
+ bool hasprofile = read_icc_profile (&cinfo, (JOCTET**)&loadedProfileData, (unsigned int*)&loadedProfileLength);
+ if (hasprofile)
+ embProfile = cmsOpenProfileFromMem (loadedProfileData, loadedProfileLength);
+ else
+ embProfile = NULL;
+
+ jpeg_start_decompress(&cinfo);
+
+ int width = cinfo.output_width;
+ int height = cinfo.output_height;
+
+ allocate (width, height);
+
+ unsigned char *row=new unsigned char[width*3];
+ while (cinfo.output_scanline < height) {
+ if (jpeg_read_scanlines(&cinfo,&row,1) < 1) {
+ jpeg_finish_decompress(&cinfo);
+ jpeg_destroy_decompress(&cinfo);
+ delete [] row;
+ return IMIO_READERROR;
+ }
+ setScanline (cinfo.output_scanline-1, row, 8);
+
+ if (pl && !(cinfo.output_scanline%100))
+ pl->setProgress ((double)(cinfo.output_scanline)/cinfo.output_height);
+ }
+ delete [] row;
+
+ jpeg_finish_decompress(&cinfo);
+ jpeg_destroy_decompress(&cinfo);
+ if (pl) {
+ pl->setProgressStr ("Ready.");
+ pl->setProgress (1.0);
+ }
+ return IMIO_SUCCESS;
+ }
+ else {
+ jpeg_destroy_decompress(&cinfo);
+ return IMIO_READERROR;
+ }
+}
+
int ImageIO::loadJPEG (Glib::ustring fname) {
FILE *file=g_fopen(fname.c_str(),"rb");
diff --git a/rtengine/imageio.h b/rtengine/imageio.h
index 5c7a2a033..a036060b0 100644
--- a/rtengine/imageio.h
+++ b/rtengine/imageio.h
@@ -72,6 +72,8 @@ class ImageIO {
int loadJPEG (Glib::ustring fname);
int loadTIFF (Glib::ustring fname);
+ int loadJPEGFromMemory (const char* buffer, int bufsize);
+
int savePNG (Glib::ustring fname, int compression = -1, int bps = -1);
int saveJPEG (Glib::ustring fname, int quality = 100);
int saveTIFF (Glib::ustring fname, int bps = -1, bool uncompressed = false);
diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc
index 8107175f7..07e771092 100644
--- a/rtengine/improcfun.cc
+++ b/rtengine/improcfun.cc
@@ -124,7 +124,7 @@ void ImProcFunctions::setScale (double iscale) {
void ImProcFunctions::firstAnalysis_ (Image16* original, Glib::ustring wprofile, unsigned int* histogram, int* chroma_radius, int row_from, int row_to) {
- TMatrix wprof = iccStore.workingSpaceMatrix (wprofile);
+ TMatrix wprof = iccStore->workingSpaceMatrix (wprofile);
int toxyz[3][3];
toxyz[0][0] = round(32768.0 * wprof[0][0] / 0.96422);
toxyz[1][0] = round(32768.0 * wprof[1][0] / 0.96422);
@@ -184,12 +184,12 @@ void ImProcFunctions::firstAnalysis (Image16* original, const ProcParams* params
if (monitorTransform)
cmsDeleteTransform (monitorTransform);
monitorTransform = NULL;
- cmsHPROFILE monitor = iccStore.getProfile ("file:"+settings->monitorProfile);
+ cmsHPROFILE monitor = iccStore->getProfile ("file:"+settings->monitorProfile);
if (monitor) {
- cmsHPROFILE iprof = iccStore.getXYZProfile ();
- cmsHPROFILE oprof = iccStore.getProfile (params->icm.output);
+ cmsHPROFILE iprof = iccStore->getXYZProfile ();
+ cmsHPROFILE oprof = iccStore->getProfile (params->icm.output);
if (!oprof)
- oprof = iccStore.getsRGBProfile ();
+ oprof = iccStore->getsRGBProfile ();
lcmsMutex->lock ();
monitorTransform = cmsCreateTransform (iprof, TYPE_RGB_16, monitor, TYPE_RGB_8, settings->colorimetricIntent, 0);
lcmsMutex->unlock ();
@@ -257,7 +257,7 @@ void ImProcFunctions::rgbProc (Image16* working, LabImage* lab, int* tonecurve1,
bool processLCE = params->sh.enabled && shmap!=NULL && params->sh.localcontrast>0;
double lceamount = params->sh.localcontrast / 200.0;
- TMatrix wprof = iccStore.workingSpaceMatrix (params->icm.working);
+ TMatrix wprof = iccStore->workingSpaceMatrix (params->icm.working);
int toxyz[3][3] = {
{
floor(32768.0 * wprof[0][0] / 0.96422),
@@ -324,19 +324,39 @@ void ImProcFunctions::rgbProc (Image16* working, LabImage* lab, int* tonecurve1,
/*r = tonecurve[r];
g = tonecurve[g];
b = tonecurve[b];*/
- int Y = (int)(0.299*r + 0.587*g + 0.114*b);
- float tonefactor = (Y>0 ? (float)tonecurve1[Y]/Y : 1);
- /*float rtonefactor = (r>0 ? (float)tonecurve1[r]/r : 1);
- float gtonefactor = (g>0 ? (float)tonecurve1[g]/g : 1);
- float btonefactor = (b>0 ? (float)tonecurve1[b]/b : 1);
- float tonefactor = MIN(rtonefactor, MIN(gtonefactor,btonefactor));*/
+ int Y = (0.299*r + 0.587*g + 0.114*b);
+ int Ynew = tonecurve1[Y];
+ float tonefactor = (Y>0 ? (float)Ynew/Y : 1);
r *= tonefactor;
g *= tonefactor;
b *= tonefactor;
+ /*float maxfactor = 1;
+ if (r>65535)
+ maxfactor = MIN(maxfactor, (float)(65535.0f-Ynew)/(r-Ynew));
+ if (g>65535)
+ maxfactor = MIN(maxfactor, (float)(65535.0f-Ynew)/(g-Ynew));
+ if (b>65535)
+ maxfactor = MIN(maxfactor, (float)(65535.0f-Ynew)/(b-Ynew));
+
+ if (r<0)
+ maxfactor = MIN(maxfactor, ((float)Ynew)/(Ynew-r));
+ if (g<0)
+ maxfactor = MIN(maxfactor, ((float)Ynew)/(Ynew-g));
+ if (b<0)
+ maxfactor = MIN(maxfactor, ((float)Ynew)/(Ynew-b));
+
+ float U = (float)(-0.14713*r - 0.28886*g + 0.436*b)*maxfactor;
+ float V = (float)(0.615*r - 0.51499*g - 0.10001*b)*maxfactor;
+
+ r = CLIP(Ynew + 1.13983*V);
+ g = CLIP(Ynew - 0.39465*U - 0.58060*V);
+ b = CLIP(Ynew + 2.03211*U);*/
+
r = tonecurve2[CLIP(r)];
g = tonecurve2[CLIP(g)];
b = tonecurve2[CLIP(b)];
+
int x = (toxyz[0][0] * r + toxyz[1][0] * g + toxyz[2][0] * b) >> 15;
int y = (toxyz[0][1] * r + toxyz[1][1] * g + toxyz[2][1] * b) >> 15;
@@ -347,7 +367,6 @@ void ImProcFunctions::rgbProc (Image16* working, LabImage* lab, int* tonecurve1,
z = CLIPTO(z,0,2*65536-1);
int L = cacheL[y];
- //int L = cacheL[tonecurve[y]];//for luminance tone curve, use this (and comment out rgb tonecurves)
lab->L[i][j] = L;
lab->a[i][j] = CLIPC(((cachea[x] - cachea[y]) * chroma_scale) >> 15);
lab->b[i][j] = CLIPC(((cacheb[y] - cacheb[z]) * chroma_scale) >> 15);
@@ -540,7 +559,7 @@ void ImProcFunctions::getAutoExp (unsigned int* histogram, int histcompr, doubl
double corr = pow(2.0, expcomp);
// black point selection is based on the linear result (yielding better visual results)
- bl = (int)(shc * corr);
+ bl = (int)(shc /* * corr*/);
// compute the white point of the exp. compensated gamma corrected image
double awg = (int)(CurveFactory::gamma2 (aw * corr / 65536.0) * 65536.0);
diff --git a/rtengine/init.cc b/rtengine/init.cc
index 167ca3e3a..6e8874160 100644
--- a/rtengine/init.cc
+++ b/rtengine/init.cc
@@ -32,7 +32,7 @@ Glib::Mutex* lcmsMutex = NULL;
int init (const Settings* s) {
settings = s;
- iccStore.parseDir (s->iccDirectory);
+ iccStore->parseDir (s->iccDirectory);
CurveFactory::init ();
ImProcFunctions::initCache ();
delete dcrMutex;
diff --git a/rtengine/iplab2rgb.cc b/rtengine/iplab2rgb.cc
index cf94f25e7..95900da69 100644
--- a/rtengine/iplab2rgb.cc
+++ b/rtengine/iplab2rgb.cc
@@ -114,10 +114,10 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch,
Image8* image = new Image8 (cw, ch);
- cmsHPROFILE oprof = iccStore.getProfile (profile);
+ cmsHPROFILE oprof = iccStore->getProfile (profile);
if (oprof) {
- cmsHPROFILE iprof = iccStore.getXYZProfile ();
+ cmsHPROFILE iprof = iccStore->getXYZProfile ();
lcmsMutex->lock ();
cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_RGB_16, oprof, TYPE_RGB_8, settings->colorimetricIntent, 0);
lcmsMutex->unlock ();
@@ -193,7 +193,7 @@ Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int
Image16* image = new Image16 (cw, ch);
- cmsHPROFILE oprof = iccStore.getProfile (profile);
+ cmsHPROFILE oprof = iccStore->getProfile (profile);
if (oprof) {
#pragma omp parallel for if (multiThread)
@@ -222,7 +222,7 @@ Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int
za[j-cx] = CLIP(z_);
}
}
- cmsHPROFILE iprof = iccStore.getXYZProfile ();
+ cmsHPROFILE iprof = iccStore->getXYZProfile ();
lcmsMutex->lock ();
cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_RGB_16_PLANAR, oprof, TYPE_RGB_16_PLANAR, settings->colorimetricIntent, 0);
lcmsMutex->unlock ();
diff --git a/rtengine/iptransform.cc b/rtengine/iptransform.cc
index ae053c1e9..682738f16 100644
--- a/rtengine/iptransform.cc
+++ b/rtengine/iptransform.cc
@@ -223,25 +223,42 @@ void ImProcFunctions::transform (Image16* original, Image16* transformed, int cx
transformSep (original, transformed, cx, cy, sx, sy, oW, oH);
}
+void calcVignettingParams(int oW, int oH, const VignettingParams& vignetting, double &w2, double &h2, double& maxRadius, double &v, double &b, double &mul)
+{
+ // vignette center is a point with coordinates between -1 and +1
+ double x = vignetting.centerX / 100.0;
+ double y = vignetting.centerY / 100.0;
+
+ // calculate vignette center in pixels
+ w2 = (double) oW / 2.0 - 0.5 + x * oW;
+ h2 = (double) oH / 2.0 - 0.5 + y * oH;
+
+ // max vignette radius in pixels
+ maxRadius = sqrt( (double)( oW*oW + oH*oH ) ) / 2.;
+
+ // vignette variables with applied strength
+ v = 1.0 - vignetting.strength * vignetting.amount * 3.0 / 400.0;
+ b = 1.0 + vignetting.radius * 7.0 / 100.0;
+ mul = (1.0-v) / tanh(b);
+}
+
void ImProcFunctions::vignetting (Image16* original, Image16* transformed, int cx, int cy, int oW, int oH) {
- double w2 = (double) oW / 2.0 - 0.5;
- double h2 = (double) oH / 2.0 - 0.5;
-
- double maxRadius = sqrt( (double)( oW*oW + oH*oH ) ) / 2.;
-
- double v = 1.0 - params->vignetting.amount * 3.0 / 400.0;
- double b = 1.0 + params->vignetting.radius * 7.0 / 100.0;
-
- double mul = (1.0-v) / tanh(b);
+ double vig_w2;
+ double vig_h2;
+ double maxRadius;
+ double v;
+ double b;
+ double mul;
+ calcVignettingParams(oW, oH, params->vignetting, vig_w2, vig_h2, maxRadius, v, b, mul);
#pragma omp parallel for if (multiThread)
for (int y=0; yheight; y++) {
- double y_d = (double) (y + cy) - h2 ;
+ double vig_y_d = (double) (y + cy) - vig_h2 ;
int val;
for (int x=0; xwidth; x++) {
- double x_d = (double) (x + cx) - w2 ;
- double r = sqrt(x_d*x_d + y_d*y_d);
+ double vig_x_d = (double) (x + cx) - vig_w2 ;
+ double r = sqrt(vig_x_d*vig_x_d + vig_y_d*vig_y_d);
double vign = v + mul * tanh (b*(maxRadius-r) / maxRadius);
val = original->r[y][x] / vign;
transformed->r[y][x] = CLIP(val);
@@ -255,9 +272,16 @@ void ImProcFunctions::vignetting (Image16* original, Image16* transformed, int c
#include "cubint.cc"
void ImProcFunctions::transformNonSep (Image16* original, Image16* transformed, int cx, int cy, int sx, int sy, int oW, int oH) {
+ double w2 = (double) oW / 2.0 - 0.5;
+ double h2 = (double) oH / 2.0 - 0.5;
- double w2 = (double) oW / 2.0 - 0.5;
- double h2 = (double) oH / 2.0 - 0.5;
+ double vig_w2;
+ double vig_h2;
+ double maxRadius;
+ double v;
+ double b;
+ double mul;
+ calcVignettingParams(oW, oH, params->vignetting, vig_w2, vig_h2, maxRadius, v, b, mul);
// auxiliary variables for distortion correction
double a = params->distortion.amount;
@@ -266,11 +290,6 @@ void ImProcFunctions::transformNonSep (Image16* original, Image16* transformed,
double cost = cos(params->rotate.degree * 3.14/180.0);
double sint = sin(params->rotate.degree * 3.14/180.0);
- // auxiliary variables for vignetting
- double maxRadius = sqrt( (double)( oW*oW + oH*oH ) ) / 2.;
- double v = 1.0 - params->vignetting.amount * 3.0 / 400.0;
- double b = 1.0 + params->vignetting.radius * 7.0 / 100.0;
- double mul = (1.0-v) / tanh(b);
bool dovign = params->vignetting.amount != 0;
// auxiliary variables for vertical perspective correction
@@ -293,6 +312,8 @@ void ImProcFunctions::transformNonSep (Image16* original, Image16* transformed,
for (int x=0; xwidth; x++) {
double x_d = ascale * (x + cx - w2); // centering x coord & scale
double y_d = ascale * (y + cy - h2); // centering y coord & scale
+ double vig_x_d = ascale * (x + cx - vig_w2); // centering x coord & scale
+ double vig_y_d = ascale * (y + cy - vig_h2); // centering y coord & scale
// horizontal perspective transformation
y_d = y_d * maxRadius / (maxRadius + x_d*hptanpt);
@@ -308,11 +329,14 @@ void ImProcFunctions::transformNonSep (Image16* original, Image16* transformed,
// distortion correction
double r = sqrt(Dx*Dx + Dy*Dy) / maxRadius;
- double r2 = sqrt(Dx*Dx + Dy*Dy);
double s = 1.0 - a + a * r ;
Dx *= s;
Dy *= s;
+ double vig_Dx = vig_x_d * cost - vig_y_d * sint;
+ double vig_Dy = vig_x_d * sint + vig_y_d * cost;
+ double r2 = sqrt(vig_Dx*vig_Dx + vig_Dy*vig_Dy);
+
// de-center
Dx += w2;
Dy += h2;
@@ -357,8 +381,16 @@ void ImProcFunctions::transformNonSep (Image16* original, Image16* transformed,
#include "cubintch.cc"
void ImProcFunctions::transformSep (Image16* original, Image16* transformed, int cx, int cy, int sx, int sy, int oW, int oH) {
- double w2 = (double) oW / 2.0 - 0.5;
- double h2 = (double) oH / 2.0 - 0.5;
+ double w2 = (double) oW / 2.0 - 0.5;
+ double h2 = (double) oH / 2.0 - 0.5;
+
+ double vig_w2;
+ double vig_h2;
+ double maxRadius;
+ double v;
+ double b;
+ double mul;
+ calcVignettingParams(oW, oH, params->vignetting, vig_w2, vig_h2, maxRadius, v, b, mul);
// auxiliary variables for c/a correction
double cdist[3];
@@ -381,11 +413,6 @@ void ImProcFunctions::transformSep (Image16* original, Image16* transformed, int
double cost = cos(params->rotate.degree * 3.14/180.0);
double sint = sin(params->rotate.degree * 3.14/180.0);
- // auxiliary variables for vignetting
- double maxRadius = sqrt( (double)( oW*oW + oH*oH ) ) / 2.;
- double v = 1.0 - params->vignetting.amount * 3.0 / 400.0;
- double b = 1.0 + params->vignetting.radius * 7.0 / 100.0;
- double mul = (1.0-v) / tanh(b);
bool dovign = params->vignetting.amount != 0;
// auxiliary variables for vertical perspective correction
@@ -408,6 +435,8 @@ void ImProcFunctions::transformSep (Image16* original, Image16* transformed, int
for (int x=0; xwidth; x++) {
double x_d = ascale * (x + cx - w2); // centering x coord & scale
double y_d = ascale * (y + cy - h2); // centering y coord & scale
+ double vig_x_d = ascale * (x + cx - vig_w2); // centering x coord & scale
+ double vig_y_d = ascale * (y + cy - vig_h2); // centering y coord & scale
// horizontal perspective transformation
y_d = y_d * maxRadius / (maxRadius + x_d*hptanpt);
@@ -423,9 +452,12 @@ void ImProcFunctions::transformSep (Image16* original, Image16* transformed, int
// distortion correction
double r = sqrt(Dxc*Dxc + Dyc*Dyc) / maxRadius;
- double r2 = sqrt(Dxc*Dxc + Dyc*Dyc);
double s = 1.0 - a + a * r ;
+ double vig_Dx = vig_x_d * cost - vig_y_d * sint;
+ double vig_Dy = vig_x_d * sint + vig_y_d * cost;
+ double r2 = sqrt(vig_Dx*vig_Dx + vig_Dy*vig_Dy);
+
for (int c=0; c<3; c++) {
double Dx = Dxc * (s + cdist[c]);
@@ -468,8 +500,16 @@ void ImProcFunctions::transformSep (Image16* original, Image16* transformed, int
void ImProcFunctions::simpltransform (Image16* original, Image16* transformed, int cx, int cy, int sx, int sy, int oW, int oH) {
- double w2 = (double) oW / 2.0 - 0.5;
- double h2 = (double) oH / 2.0 - 0.5;
+ double w2 = (double) oW / 2.0 - 0.5;
+ double h2 = (double) oH / 2.0 - 0.5;
+
+ double vig_w2;
+ double vig_h2;
+ double maxRadius;
+ double v;
+ double b;
+ double mul;
+ calcVignettingParams(oW, oH, params->vignetting, vig_w2, vig_h2, maxRadius, v, b, mul);
// auxiliary variables for distortion correction
double a = params->distortion.amount;
@@ -478,11 +518,6 @@ void ImProcFunctions::simpltransform (Image16* original, Image16* transformed, i
double cost = cos(params->rotate.degree * 3.14/180.0);
double sint = sin(params->rotate.degree * 3.14/180.0);
- // auxiliary variables for vignetting
- double maxRadius = sqrt( (double)( oW*oW + oH*oH ) ) / 2.;
- double v = 1.0 - params->vignetting.amount * 3.0 / 400.0;
- double b = 1.0 + params->vignetting.radius * 7.0 / 100.0;
- double mul = (1.0-v) / tanh(b);
bool dovign = params->vignetting.amount != 0;
// auxiliary variables for vertical perspective correction
@@ -505,6 +540,8 @@ void ImProcFunctions::simpltransform (Image16* original, Image16* transformed, i
for (int x=0; xwidth; x++) {
double y_d = ascale * (y + cy - h2); // centering y coord & scale
double x_d = ascale * (x + cx - w2); // centering x coord & scale
+ double vig_x_d = ascale * (x + cx - vig_w2); // centering x coord & scale
+ double vig_y_d = ascale * (y + cy - vig_h2); // centering y coord & scale
// horizontal perspective transformation
y_d = y_d * maxRadius / (maxRadius + x_d*hptanpt);
@@ -520,11 +557,14 @@ void ImProcFunctions::simpltransform (Image16* original, Image16* transformed, i
// distortion correction
double r = sqrt(Dx*Dx + Dy*Dy) / maxRadius;
- double r2 = sqrt(Dx*Dx + Dy*Dy);
double s = 1.0 - a + a * r ;
Dx *= s;
Dy *= s;
+ double vig_Dx = vig_x_d * cost - vig_y_d * sint;
+ double vig_Dy = vig_x_d * sint + vig_y_d * cost;
+ double r2 = sqrt(vig_Dx*vig_Dx + vig_Dy*vig_Dy);
+
// de-center
Dx += w2;
Dy += h2;
diff --git a/rtengine/jpeg_memsrc.c b/rtengine/jpeg_memsrc.c
new file mode 100644
index 000000000..595649b85
--- /dev/null
+++ b/rtengine/jpeg_memsrc.c
@@ -0,0 +1,167 @@
+/*
+ * memsrc.c
+ *
+ * Copyright (C) 1994-1996, Thomas G. Lane.
+ * This file is part of the Independent JPEG Group's software.
+ * For conditions of distribution and use, see the accompanying README file.
+ *
+ * This file contains decompression data source routines for the case of
+ * reading JPEG data from a memory buffer that is preloaded with the entire
+ * JPEG file. This would not seem especially useful at first sight, but
+ * a number of people have asked for it.
+ * This is really just a stripped-down version of jdatasrc.c. Comparison
+ * of this code with jdatasrc.c may be helpful in seeing how to make
+ * custom source managers for other purposes.
+ */
+
+/* this is not a core library module, so it doesn't define JPEG_INTERNALS */
+//#include "jinclude.h"
+//#include "jmorecfg.h"
+//#include "jpeglib.h"
+//#include "jerror.h"
+#include
+#include
+#include
+
+
+/* Expanded data source object for memory input */
+
+typedef struct {
+ struct jpeg_source_mgr pub; /* public fields */
+
+ JOCTET eoi_buffer[2]; /* a place to put a dummy EOI */
+} my_source_mgr;
+
+typedef my_source_mgr * my_src_ptr;
+
+
+/*
+ * Initialize source --- called by jpeg_read_header
+ * before any data is actually read.
+ */
+
+static void
+init_source (j_decompress_ptr cinfo)
+{
+ /* No work, since jpeg_memory_src set up the buffer pointer and count.
+ * Indeed, if we want to read multiple JPEG images from one buffer,
+ * this *must* not do anything to the pointer.
+ */
+}
+
+
+/*
+ * Fill the input buffer --- called whenever buffer is emptied.
+ *
+ * In this application, this routine should never be called; if it is called,
+ * the decompressor has overrun the end of the input buffer, implying we
+ * supplied an incomplete or corrupt JPEG datastream. A simple error exit
+ * might be the most appropriate response.
+ *
+ * But what we choose to do in this code is to supply dummy EOI markers
+ * in order to force the decompressor to finish processing and supply
+ * some sort of output image, no matter how corrupted.
+ */
+
+static int
+fill_input_buffer(j_decompress_ptr cinfo)
+{
+ my_src_ptr src = (my_src_ptr) cinfo->src;
+
+ WARNMS(cinfo, JWRN_JPEG_EOF);
+
+ /* Create a fake EOI marker */
+ src->eoi_buffer[0] = (JOCTET) 0xFF;
+ src->eoi_buffer[1] = (JOCTET) JPEG_EOI;
+ src->pub.next_input_byte = src->eoi_buffer;
+ src->pub.bytes_in_buffer = 2;
+
+ return TRUE;
+}
+
+
+/*
+ * Skip data --- used to skip over a potentially large amount of
+ * uninteresting data (such as an APPn marker).
+ *
+ * If we overrun the end of the buffer, we let fill_input_buffer deal with
+ * it. An extremely large skip could cause some time-wasting here, but
+ * it really isn't supposed to happen ... and the decompressor will never
+ * skip more than 64K anyway.
+ */
+
+static void
+skip_input_data (j_decompress_ptr cinfo, long num_bytes)
+{
+ my_src_ptr src = (my_src_ptr) cinfo->src;
+
+ if (num_bytes > 0) {
+ while (num_bytes > (long) src->pub.bytes_in_buffer) {
+ num_bytes -= (long) src->pub.bytes_in_buffer;
+ (void) fill_input_buffer(cinfo);
+ /* note we assume that fill_input_buffer will never return FALSE,
+ * so suspension need not be handled.
+ */
+ }
+ src->pub.next_input_byte += (size_t) num_bytes;
+ src->pub.bytes_in_buffer -= (size_t) num_bytes;
+ }
+}
+
+
+/*
+ * An additional method that can be provided by data source modules is the
+ * resync_to_restart method for error recovery in the presence of RST markers.
+ * For the moment, this source module just uses the default resync method
+ * provided by the JPEG library. That method assumes that no backtracking
+ * is possible.
+ */
+
+
+/*
+ * Terminate source --- called by jpeg_finish_decompress
+ * after all data has been read. Often a no-op.
+ *
+ * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
+ * application must deal with any cleanup that should happen even
+ * for error exit.
+ */
+
+static void
+term_source (j_decompress_ptr cinfo)
+{
+ /* no work necessary here */
+}
+
+
+/*
+ * Prepare for input from a memory buffer.
+ */
+
+GLOBAL(void)
+jpeg_memory_src (j_decompress_ptr cinfo, const JOCTET * buffer, size_t bufsize)
+{
+ my_src_ptr src;
+
+ /* The source object is made permanent so that a series of JPEG images
+ * can be read from a single buffer by calling jpeg_memory_src
+ * only before the first one.
+ * This makes it unsafe to use this manager and a different source
+ * manager serially with the same JPEG object. Caveat programmer.
+ */
+ if (cinfo->src == NULL) { /* first time for this JPEG object? */
+ cinfo->src = (struct jpeg_source_mgr *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ sizeof(my_source_mgr));
+ }
+
+ src = (my_src_ptr) cinfo->src;
+ src->pub.init_source = init_source;
+ src->pub.fill_input_buffer = fill_input_buffer;
+ src->pub.skip_input_data = skip_input_data;
+ src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
+ src->pub.term_source = term_source;
+
+ src->pub.next_input_byte = buffer;
+ src->pub.bytes_in_buffer = bufsize;
+}
diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc
index c58306e48..674d66e2b 100644
--- a/rtengine/procparams.cc
+++ b/rtengine/procparams.cc
@@ -46,13 +46,13 @@ void ProcParams::destroy (ProcParams* pp) {
void ProcParams::setDefaults () {
toneCurve.autoexp = false;
- toneCurve.clip = 0.002;
+ toneCurve.clip = 0.001;
toneCurve.expcomp = 0;
toneCurve.brightness = 0;
toneCurve.contrast = 0;
toneCurve.black = 0;
toneCurve.hlcompr = 70;
- toneCurve.shcompr = 85;
+ toneCurve.shcompr = 25;
toneCurve.curve.clear ();
labCurve.brightness = 0;
@@ -147,6 +147,9 @@ void ProcParams::setDefaults () {
vignetting.amount = 0;
vignetting.radius = 50;
+ vignetting.strength = 1;
+ vignetting.centerX = 0;
+ vignetting.centerY = 0;
chmixer.red[0] = 100;
chmixer.red[1] = 0;
@@ -326,6 +329,9 @@ int ProcParams::save (Glib::ustring fname) const {
// save vignetting correction
keyFile.set_integer ("Vignetting Correction", "Amount", vignetting.amount);
keyFile.set_integer ("Vignetting Correction", "Radius", vignetting.radius);
+ keyFile.set_integer ("Vignetting Correction", "Strength", vignetting.strength);
+ keyFile.set_integer ("Vignetting Correction", "CenterX", vignetting.centerX);
+ keyFile.set_integer ("Vignetting Correction", "CenterY", vignetting.centerY);
// save highlight recovery settings
keyFile.set_boolean ("HLRecovery", "Enabled", hlrecovery.enabled);
@@ -580,6 +586,9 @@ if (keyFile.has_group ("CACorrection")) {
if (keyFile.has_group ("Vignetting Correction")) {
if (keyFile.has_key ("Vignetting Correction", "Amount")) vignetting.amount = keyFile.get_integer ("Vignetting Correction", "Amount");
if (keyFile.has_key ("Vignetting Correction", "Radius")) vignetting.radius = keyFile.get_integer ("Vignetting Correction", "Radius");
+ if (keyFile.has_key ("Vignetting Correction", "Strength")) vignetting.strength = keyFile.get_integer ("Vignetting Correction", "Strength");
+ if (keyFile.has_key ("Vignetting Correction", "CenterX")) vignetting.centerX = keyFile.get_integer ("Vignetting Correction", "CenterX");
+ if (keyFile.has_key ("Vignetting Correction", "CenterY")) vignetting.centerY = keyFile.get_integer ("Vignetting Correction", "CenterY");
}
// load highlight recovery settings
@@ -775,6 +784,9 @@ bool ProcParams::operator== (const ProcParams& other) {
&& cacorrection.blue == other.cacorrection.blue
&& vignetting.amount == other.vignetting.amount
&& vignetting.radius == other.vignetting.radius
+ && vignetting.strength == other.vignetting.strength
+ && vignetting.centerX == other.vignetting.centerX
+ && vignetting.centerY == other.vignetting.centerY
&& !memcmp (&chmixer.red, &other.chmixer.red, 3*sizeof(int))
&& !memcmp (&chmixer.green, &other.chmixer.green, 3*sizeof(int))
&& !memcmp (&chmixer.blue, &other.chmixer.blue, 3*sizeof(int))
diff --git a/rtengine/procparams.h b/rtengine/procparams.h
index cb7d0253c..884fc4468 100644
--- a/rtengine/procparams.h
+++ b/rtengine/procparams.h
@@ -249,6 +249,9 @@ class VignettingParams {
public:
int amount;
int radius;
+ int strength;
+ int centerX;
+ int centerY;
};
/**
diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc
index ffbae35f2..cacb52b60 100644
--- a/rtengine/rawimagesource.cc
+++ b/rtengine/rawimagesource.cc
@@ -782,7 +782,7 @@ int RawImageSource::load (Glib::ustring fname, bool batch) {
for (int j=0; j<3; j++)
for (int k=0; k<3; k++)
cam[i][j] += coeff[k][i] * sRGB_d50[k][j];
- camProfile = iccStore.createFromMatrix (cam, false, "Camera");
+ camProfile = iccStore->createFromMatrix (cam, false, "Camera");
inverse33 (cam, icam);
if (ri->profile_data)
@@ -1165,7 +1165,7 @@ void RawImageSource::colorSpaceConversion (Image16* im, ColorManagementParams cm
else if (inProfile=="(camera)" || inProfile=="")
in = camprofile;
else {
- in = iccStore.getProfile (inProfile);
+ in = iccStore->getProfile (inProfile);
if (in==NULL)
inProfile = "(camera)";
}
@@ -1174,11 +1174,11 @@ void RawImageSource::colorSpaceConversion (Image16* im, ColorManagementParams cm
if (inProfile=="(camera)" || inProfile=="" || (inProfile=="(embedded)" && !embedded)) {
// in this case we avoid using the slllllooooooowwww lcms
-// out = iccStore.workingSpace (wProfile);
+// out = iccStore->workingSpace (wProfile);
// hTransform = cmsCreateTransform (in, TYPE_RGB_16_PLANAR, out, TYPE_RGB_16_PLANAR, settings->colorimetricIntent, cmsFLAGS_MATRIXINPUT | cmsFLAGS_MATRIXOUTPUT);//cmsFLAGS_MATRIXINPUT | cmsFLAGS_MATRIXOUTPUT);
// cmsDoTransform (hTransform, im->data, im->data, im->planestride/2);
// cmsDeleteTransform(hTransform);
- TMatrix work = iccStore.workingSpaceInverseMatrix (cmp.working);
+ TMatrix work = iccStore->workingSpaceInverseMatrix (cmp.working);
double mat[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
for (int i=0; i<3; i++)
for (int j=0; j<3; j++)
@@ -1199,8 +1199,8 @@ void RawImageSource::colorSpaceConversion (Image16* im, ColorManagementParams cm
}
}
else {
- out = iccStore.workingSpace (cmp.working);
-// out = iccStore.workingSpaceGamma (wProfile);
+ out = iccStore->workingSpace (cmp.working);
+// out = iccStore->workingSpaceGamma (wProfile);
lcmsMutex->lock ();
cmsHTRANSFORM hTransform = cmsCreateTransform (in, TYPE_RGB_16_PLANAR, out, TYPE_RGB_16_PLANAR, settings->colorimetricIntent, 0);
lcmsMutex->unlock ();
@@ -1834,14 +1834,14 @@ int RawImageSource::getAEHistogram (unsigned int* histogram, int& histcompr) {
}
if (ri->filters)
for (int j=start; jdata[i][j]>>histcompr]+=2;
- else
+ else*/
histogram[ri->data[i][j]>>histcompr]+=4;
else
for (int j=start; j<3*end; j++) {
histogram[ri->data[i][j+0]>>histcompr]++;
- histogram[ri->data[i][j+1]>>histcompr]++;
+ histogram[ri->data[i][j+1]>>histcompr]+=2;
histogram[ri->data[i][j+2]>>histcompr]++;
}
}
diff --git a/rtengine/rtthumbnail.cc b/rtengine/rtthumbnail.cc
index 3ee47d5a5..43f64539c 100644
--- a/rtengine/rtthumbnail.cc
+++ b/rtengine/rtthumbnail.cc
@@ -48,6 +48,62 @@ my_jpeg_stdio_src (j_decompress_ptr cinfo, FILE * infile);
namespace rtengine {
+Thumbnail* Thumbnail::loadFromMemory (const char* image, int length, int &w, int &h, int fixwh) {
+ Image16* img = new Image16 ();
+ int err = img->loadJPEGFromMemory(image,length);
+ if (err) {
+ printf("loadfromMemory: error\n");
+ delete img;
+ return NULL;
+ }
+
+ Thumbnail* tpp = new Thumbnail ();
+
+ tpp->camwbRed = 1.0;
+ tpp->camwbGreen = 1.0;
+ tpp->camwbBlue = 1.0;
+
+ tpp->embProfileLength = 0;
+ unsigned char* data;
+ img->getEmbeddedProfileData (tpp->embProfileLength, data);
+ if (data && tpp->embProfileLength) {
+ tpp->embProfileData = new unsigned char [tpp->embProfileLength];
+ memcpy (tpp->embProfileData, data, tpp->embProfileLength);
+ }
+ else {
+ tpp->embProfileLength = 0;
+ tpp->embProfileData = NULL;
+ }
+
+ tpp->redMultiplier = 1.0;
+ tpp->greenMultiplier = 1.0;
+ tpp->blueMultiplier = 1.0;
+
+ tpp->scaleForSave = 8192;
+ tpp->defGain = 1.0;
+ tpp->gammaCorrected = false;
+ tpp->isRaw = 1;
+ memset (tpp->colorMatrix, 0, sizeof(tpp->colorMatrix));
+ tpp->colorMatrix[0][0] = 1.0;
+ tpp->colorMatrix[1][1] = 1.0;
+ tpp->colorMatrix[2][2] = 1.0;
+
+ if (fixwh==1) {
+ w = h * img->width / img->height;
+ tpp->scale = (double)img->height / h;
+ }
+ else {
+ h = w * img->height / img->width;
+ tpp->scale = (double)img->width / w;
+ }
+
+ tpp->thumbImg = img->resize (w, h, TI_Nearest);
+ delete img;
+
+ tpp->init ();
+ return tpp;
+}
+
Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, int fixwh) {
Image16* img = new Image16 ();
@@ -143,7 +199,7 @@ void Thumbnail::init () {
for (int j=0; j<3; j++)
for (int k=0; k<3; k++)
camToD50[i][j] += colorMatrix[k][i] * sRGB_d50[k][j];
- camProfile = iccStore.createFromMatrix (camToD50, false, "Camera");
+ camProfile = iccStore->createFromMatrix (camToD50, false, "Camera");
}
bool Thumbnail::igammacomputed = false;
@@ -173,6 +229,39 @@ Thumbnail::~Thumbnail () {
cmsCloseProfile(camProfile);
}
+IImage8* Thumbnail::quickProcessImage (const procparams::ProcParams& params, int rheight, TypeInterpolation interp, double& myscale) {
+
+ int rwidth;
+ if (params.coarse.rotate==90 || params.coarse.rotate==270) {
+ rwidth = rheight;
+ rheight = thumbImg->height * rwidth / thumbImg->width;
+ }
+ else
+ rwidth = thumbImg->width * rheight / thumbImg->height;
+ Image16* baseImg = thumbImg->resize (rwidth, rheight, interp);
+
+ if (params.coarse.rotate) {
+ Image16* tmp = baseImg->rotate (params.coarse.rotate);
+ rwidth = tmp->width;
+ rheight = tmp->height;
+ delete baseImg;
+ baseImg = tmp;
+ }
+ if (params.coarse.hflip) {
+ Image16* tmp = baseImg->hflip ();
+ delete baseImg;
+ baseImg = tmp;
+ }
+ if (params.coarse.vflip) {
+ Image16* tmp = baseImg->vflip ();
+ delete baseImg;
+ baseImg = tmp;
+ }
+ Image8* img8 = baseImg->to8();
+ delete baseImg;
+ return img8;
+}
+
IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rheight, TypeInterpolation interp, double& myscale) {
// compute WB multipliers
diff --git a/rtengine/rtthumbnail.h b/rtengine/rtthumbnail.h
index f9b1c9914..438fe2e04 100644
--- a/rtengine/rtthumbnail.h
+++ b/rtengine/rtthumbnail.h
@@ -70,9 +70,12 @@ namespace rtengine {
void init ();
IImage8* processImage (const procparams::ProcParams& pparams, int rheight, TypeInterpolation interp, double& scale);
+ IImage8* quickProcessImage (const procparams::ProcParams& pparams, int rheight, TypeInterpolation interp, double& scale);
int getImageWidth (const procparams::ProcParams& pparams, int rheight);
void getFinalSize (const rtengine::procparams::ProcParams& pparams, int& w, int& h);
+ static Thumbnail* loadQuickFromRaw (const Glib::ustring& fname, rtengine::RawMetaDataLocation& rml, int &w, int &h, int fixwh);
+ static Thumbnail* loadFromMemory (const char* image, int length, int &w, int &h, int fixwh);
static Thumbnail* loadFromRaw (const Glib::ustring& fname, RawMetaDataLocation& rml, int &w, int &h, int fixwh);
static Thumbnail* loadFromImage (const Glib::ustring& fname, int &w, int &h, int fixwh);
diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc
index 37f46ebab..169b7954c 100644
--- a/rtengine/simpleprocess.cc
+++ b/rtengine/simpleprocess.cc
@@ -199,7 +199,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p
ProfileContent pc;
if (params.icm.output.compare (0, 6, "No ICM") && params.icm.output!="")
- pc = iccStore.getContent (params.icm.output);
+ pc = iccStore->getContent (params.icm.output);
readyImg->setOutputProfile (pc.data, pc.length);
diff --git a/rtengine/stdimagesource.cc b/rtengine/stdimagesource.cc
index 3ef593ead..cbffc3597 100644
--- a/rtengine/stdimagesource.cc
+++ b/rtengine/stdimagesource.cc
@@ -256,19 +256,19 @@ void StdImageSource::getImage (ColorTemp ctemp, int tran, Image16* image, Previe
void StdImageSource::colorSpaceConversion (Image16* im, ColorManagementParams cmp, cmsHPROFILE embedded) {
cmsHPROFILE in;
- cmsHPROFILE out = iccStore.workingSpace (cmp.working);
+ cmsHPROFILE out = iccStore->workingSpace (cmp.working);
if (cmp.input=="(embedded)" || cmp.input=="" || cmp.input=="(camera)") {
if (embedded)
in = embedded;
else
- in = iccStore.getsRGBProfile ();
+ in = iccStore->getsRGBProfile ();
}
else if (cmp.input!="(none)") {
- in = iccStore.getProfile (cmp.input);
+ in = iccStore->getProfile (cmp.input);
if (in==NULL && embedded)
in = embedded;
else if (in==NULL)
- in = iccStore.getsRGBProfile ();
+ in = iccStore->getsRGBProfile ();
else if (cmp.gammaOnInput)
for (int i=0; iheight; i++)
for (int j=0; jwidth; j++) {
diff --git a/rtgui/CMakeLists.txt b/rtgui/CMakeLists.txt
index 221521cb1..adf2eaf88 100644
--- a/rtgui/CMakeLists.txt
+++ b/rtgui/CMakeLists.txt
@@ -14,6 +14,7 @@ set (BASESOURCEFILES
whitebalance.cc vignetting.cc rotate.cc distortion.cc
crophandler.cc curveeditor.cc dirbrowser.cc
filecatalog.cc
+ previewloader.cc
histogrampanel.cc history.cc imagearea.cc
imageareapanel.cc iptcpanel.cc labcurve.cc lumadenoise.cc main.cc
multilangmgr.cc mycurve.cc options.cc
diff --git a/rtgui/cachemanager.cc b/rtgui/cachemanager.cc
index a7029951a..f44fcb165 100644
--- a/rtgui/cachemanager.cc
+++ b/rtgui/cachemanager.cc
@@ -24,10 +24,26 @@
#include
#include
-CacheManager cacheMgr;
+CacheManager*
+CacheManager::getInstance(void)
+{
+ static CacheManager* instance_ = 0;
+ if ( instance_ == 0 )
+ {
+ static Glib::Mutex smutex_;
+ Glib::Mutex::Lock lock(smutex_);
+ if ( instance_ == 0 )
+ {
+ instance_ = new CacheManager();
+ }
+ }
+ return instance_;
+}
void CacheManager::init () {
+ Glib::Mutex::Lock lock(mutex_);
+
openEntries.clear ();
baseDir = options.cacheBaseDir;
@@ -49,12 +65,18 @@ Thumbnail* CacheManager::getEntry (const Glib::ustring& fname) {
Thumbnail* res = NULL;
- std::map::iterator r = openEntries.find (fname);
- // if it is open, return it
- if (r!=openEntries.end()) {
- r->second->increaseRef ();
- return r->second;
- }
+ // take manager lock and search for entry, if found return it else release
+ // lock and create it
+ {
+ Glib::Mutex::Lock lock(mutex_);
+
+ string_thumb_map::iterator r = openEntries.find (fname);
+ // if it is open, return it
+ if (r!=openEntries.end()) {
+ r->second->increaseRef ();
+ return r->second;
+ }
+ }
// compute the md5
std::string md5 = getMD5 (fname);
@@ -78,6 +100,7 @@ Thumbnail* CacheManager::getEntry (const Glib::ustring& fname) {
}
// if not, create a new one
if (!res) {
+
res = new Thumbnail (this, fname, md5);
if (!res->isSupported ()) {
delete res;
@@ -85,20 +108,45 @@ Thumbnail* CacheManager::getEntry (const Glib::ustring& fname) {
}
}
+ // retake the lock and see if it was added while we we're unlocked, if it
+ // was use it over our version. if not added we create the cache entry
if (res)
- openEntries[fname] = res;
+ {
+ Glib::Mutex::Lock lock(mutex_);
+
+ string_thumb_map::iterator r = openEntries.find (fname);
+ if (r!=openEntries.end()) {
+ delete res;
+ r->second->increaseRef ();
+ return r->second;
+ }
+
+ // it wasn't, create a new entry
+ openEntries[fname] = res;
+ }
+
return res;
}
void CacheManager::deleteEntry (const Glib::ustring& fname) {
+ Glib::Mutex::Lock lock(mutex_);
+
// check if it is opened
- std::map::iterator r = openEntries.find (fname);
+ string_thumb_map::iterator r = openEntries.find (fname);
// if it is open, dont delete it
if (r!=openEntries.end()) {
std::string md5 = r->second->getMD5 ();
- r->second->decreaseRef ();
+
+ // decrease reference count; this will call back into CacheManager so
+ // we release the lock for it.
+ {
+ lock.release();
+ r->second->decreaseRef ();
+ lock.acquire();
+ }
+
// if in the editor, the thumbnail still exists. If not, delete it:
r = openEntries.find (fname);
if (r==openEntries.end() && md5!="") {
@@ -126,6 +174,8 @@ void CacheManager::deleteEntry (const Glib::ustring& fname) {
void CacheManager::renameEntry (const std::string& oldfilename, const std::string& oldmd5, const std::string& newfilename) {
+ Glib::Mutex::Lock lock(mutex_);
+
std::string newmd5 = getMD5 (newfilename);
::g_rename ((getCacheFileName ("profiles", oldfilename, oldmd5) + paramFileExtension).c_str(), (getCacheFileName ("profiles", newfilename, newmd5) + paramFileExtension).c_str());
@@ -136,7 +186,7 @@ void CacheManager::renameEntry (const std::string& oldfilename, const std::strin
::g_rename ((getCacheFileName ("data", oldfilename, oldmd5) + ".txt").c_str(), (getCacheFileName ("data", newfilename, newmd5) + ".txt").c_str());
// check if it is opened
- std::map::iterator r = openEntries.find (oldfilename);
+ string_thumb_map::iterator r = openEntries.find (oldfilename);
// if it is open, update md5
if (r!=openEntries.end()) {
Thumbnail* t = r->second;
@@ -144,14 +194,16 @@ void CacheManager::renameEntry (const std::string& oldfilename, const std::strin
t->setFileName (newfilename);
openEntries[newfilename] = t;
t->updateCache ();
- t->reSaveThumbnail ();
+ t->saveThumbnail ();
}
}
void CacheManager::closeThumbnail (Thumbnail* t) {
+ Glib::Mutex::Lock lock(mutex_);
+
t->updateCache ();
- std::map::iterator r = openEntries.find (t->getFileName());
+ string_thumb_map::iterator r = openEntries.find (t->getFileName());
if (r!=openEntries.end())
openEntries.erase (r);
delete t;
@@ -159,11 +211,15 @@ void CacheManager::closeThumbnail (Thumbnail* t) {
void CacheManager::closeCache () {
+ Glib::Mutex::Lock lock(mutex_);
+
applyCacheSizeLimitation ();
}
void CacheManager::clearAll () {
+ Glib::Mutex::Lock lock(mutex_);
+
deleteDir ("images");
deleteDir ("aehistograms");
deleteDir ("embprofiles");
@@ -171,30 +227,34 @@ void CacheManager::clearAll () {
deleteDir ("data");
// re-generate thumbnail images and clear profiles of open thumbnails
- std::map::iterator i;
- for (i=openEntries.begin(); i!=openEntries.end(); i++) {
- i->second->clearProcParams (CACHEMGR);
- i->second->generateThumbnailImage ();
- i->second->updateCache ();
- }
+ //string_thumb_map::iterator i;
+ //for (i=openEntries.begin(); i!=openEntries.end(); i++) {
+ // i->second->clearProcParams (CACHEMGR);
+ // i->second->generateThumbnailImage ();
+ // i->second->updateCache ();
+ //}
}
void CacheManager::clearThumbImages () {
+ Glib::Mutex::Lock lock(mutex_);
+
deleteDir ("images");
deleteDir ("aehistograms");
deleteDir ("embprofiles");
// re-generate thumbnail images of open thumbnails
- std::map::iterator i;
- for (i=openEntries.begin(); i!=openEntries.end(); i++)
- i->second->generateThumbnailImage ();
+ //string_thumb_map::iterator i;
+ //for (i=openEntries.begin(); i!=openEntries.end(); i++)
+ // i->second->generateThumbnailImage ();
}
void CacheManager::clearProfiles () {
+ Glib::Mutex::Lock lock(mutex_);
+
deleteDir ("profiles");
// clear profiles of open thumbnails
- std::map::iterator i;
+ string_thumb_map::iterator i;
for (i=openEntries.begin(); i!=openEntries.end(); i++)
i->second->clearProcParams (CACHEMGR);
}
@@ -234,9 +294,9 @@ void CacheManager::applyCacheSizeLimitation () {
std::vector flist;
Glib::ustring dataDir = Glib::build_filename (baseDir, "data");
Glib::RefPtr dir = Gio::File::create_for_path (dataDir);
-
- safe_build_file_list (dir, flist);
-
+
+ safe_build_file_list (dir, flist);
+
if (flist.size() > options.maxCacheEntries) {
std::sort (flist.begin(), flist.end());
while (flist.size() > options.maxCacheEntries) {
@@ -245,7 +305,7 @@ void CacheManager::applyCacheSizeLimitation () {
::g_remove ((Glib::build_filename (Glib::build_filename (baseDir, "images"), flist.front().fname) + ".jpg").c_str());
::g_remove ((Glib::build_filename (Glib::build_filename (baseDir, "aehistograms"), flist.front().fname)).c_str());
::g_remove ((Glib::build_filename (Glib::build_filename (baseDir, "embprofiles"), flist.front().fname) + ".icc").c_str());
-// ::g_remove ((Glib::build_filename (Glib::build_filename (baseDir, "profiles"), flist.front().fname) + paramFileExtension).c_str());
+ // ::g_remove ((Glib::build_filename (Glib::build_filename (baseDir, "profiles"), flist.front().fname) + paramFileExtension).c_str());
flist.erase (flist.begin());
}
}
diff --git a/rtgui/cachemanager.h b/rtgui/cachemanager.h
index f2f15c59d..983c2acbd 100644
--- a/rtgui/cachemanager.h
+++ b/rtgui/cachemanager.h
@@ -29,14 +29,21 @@ class Thumbnail;
class CacheManager {
- std::map openEntries;
- Glib::ustring baseDir;
+ typedef std::pair string_thumb_pair;
+ typedef std::map string_thumb_map;
+
+ string_thumb_map openEntries;
+ Glib::ustring baseDir;
+ Glib::Mutex mutex_;
void deleteDir (const Glib::ustring& dirName);
- public:
CacheManager () {}
+ public:
+
+ static CacheManager* getInstance(void);
+
void init ();
Thumbnail* getEntry (const Glib::ustring& fname);
void deleteEntry (const Glib::ustring& fname);
@@ -44,7 +51,7 @@ class CacheManager {
void closeThumbnail (Thumbnail* t);
- const Glib::ustring& getBaseDir () { return baseDir; }
+ const Glib::ustring& getBaseDir () { Glib::Mutex::Lock lock(mutex_); return baseDir; }
void closeCache ();
static std::string getMD5 (const Glib::ustring& fname);
@@ -58,7 +65,7 @@ class CacheManager {
Glib::ustring getCacheFileName (const Glib::ustring& subdir, const Glib::ustring& fname, const Glib::ustring& md5);
};
-extern CacheManager cacheMgr;
+#define cacheMgr CacheManager::getInstance()
#endif
diff --git a/rtgui/filebrowserentry.cc b/rtgui/filebrowserentry.cc
index ef813410e..b31d6b454 100644
--- a/rtgui/filebrowserentry.cc
+++ b/rtgui/filebrowserentry.cc
@@ -56,14 +56,20 @@ FileBrowserEntry::FileBrowserEntry (Thumbnail* thm, const Glib::ustring& fname)
FileBrowserEntry::~FileBrowserEntry () {
- thumbImageUpdater.removeJobs (this);
+ // so jobs arriving now do nothing
+ if (feih->pending)
+ {
+ feih->destroyed = true;
+ }
+ else
+ {
+ delete feih;
+ feih = 0;
+ }
+
+ thumbImageUpdater->removeJobs (this);
if (thumbnail)
thumbnail->removeThumbnailListener (this);
-
- if (feih->pending)
- feih->destroyed = true;
- else
- delete feih;
}
void FileBrowserEntry::refreshThumbnailImage () {
@@ -71,8 +77,16 @@ void FileBrowserEntry::refreshThumbnailImage () {
if (!thumbnail)
return;
- thumbImageUpdater.add (thumbnail, thumbnail->getProcParams(), preh, &updatepriority, this);
- thumbImageUpdater.process ();
+ thumbImageUpdater->add (thumbnail, thumbnail->getProcParams(), preh, &updatepriority, false, this);
+}
+
+void FileBrowserEntry::refreshQuickThumbnailImage () {
+ // Only make a (slow) processed preview if the picture has been edited at all
+ if ( thumbnail &&
+ thumbnail->isQuick() && (!options.internalThumbIfUntouched || thumbnail->isPParamsValid()) )
+ {
+ thumbImageUpdater->add(thumbnail, thumbnail->getProcParams(), preh, &updatepriority, true, this);
+ }
}
void FileBrowserEntry::calcThumbnailSize () {
@@ -134,10 +148,11 @@ struct tiupdate {
int fbeupdate (void* data) {
- gdk_threads_enter ();
tiupdate* params = (tiupdate*)data;
FileBrowserEntryIdleHelper* feih = params->feih;
+ GThreadLock lock;
+
if (feih->destroyed) {
if (feih->pending == 1)
delete feih;
@@ -145,14 +160,12 @@ int fbeupdate (void* data) {
feih->pending--;
params->img->free ();
delete params;
- gdk_threads_leave ();
return 0;
}
feih->fbentry->_updateImage (params->img, params->scale, params->cropParams);
feih->pending--;
- gdk_threads_leave ();
delete params;
return 0;
@@ -160,8 +173,19 @@ int fbeupdate (void* data) {
void FileBrowserEntry::updateImage (rtengine::IImage8* img, double scale, rtengine::procparams::CropParams cropParams) {
- redrawRequests++;
- feih->pending++;
+ {
+ GThreadLock lock;
+
+ if ( feih == 0 ||
+ feih->destroyed )
+ {
+ return;
+ }
+
+ redrawRequests++;
+ feih->pending++;
+ }
+
tiupdate* param = new tiupdate ();
param->feih = feih;
param->img = img;
diff --git a/rtgui/filebrowserentry.h b/rtgui/filebrowserentry.h
index 53a1fcf16..490e0d100 100644
--- a/rtgui/filebrowserentry.h
+++ b/rtgui/filebrowserentry.h
@@ -76,6 +76,7 @@ public:
FileThumbnailButtonSet* getThumbButtonSet ();
void refreshThumbnailImage ();
+ void refreshQuickThumbnailImage ();
void calcThumbnailSize ();
std::vector > getIconsOnImageArea ();
diff --git a/rtgui/filecatalog.cc b/rtgui/filecatalog.cc
index 36cd269c2..26866cee4 100644
--- a/rtgui/filecatalog.cc
+++ b/rtgui/filecatalog.cc
@@ -44,10 +44,8 @@ int _directoryUpdater (void* cat) {
}
#endif
-FileCatalog::FileCatalog (CoarsePanel* cp, ToolBar* tb) : listener(NULL), fslistener(NULL), hasValidCurrentEFS(false), filterPanel(NULL), coarsePanel(cp), toolBar(tb) {
+FileCatalog::FileCatalog (CoarsePanel* cp, ToolBar* tb) : selectedDirectoryId(1), listener(NULL), fslistener(NULL), hasValidCurrentEFS(false), filterPanel(NULL), coarsePanel(cp), toolBar(tb) {
- previewLoader.setPreviewLoaderListener (this);
-
// construct and initialize thumbnail browsers
fileBrowser = new FileBrowser();
fileBrowser->setFileBrowserListener (this);
@@ -220,19 +218,23 @@ void FileCatalog::closeDir () {
wdMonitor = NULL;
}
#endif
+
+ // ignore old requests
+ ++selectedDirectoryId;
+
// terminate thumbnail preview loading
- previewLoader.terminate ();
+ previewLoader->removeAllJobs ();
// terminate thumbnail updater
- thumbImageUpdater.terminate ();
+ thumbImageUpdater->removeAllJobs ();
// remove entries
+ selectedDirectory = "";
fileBrowser->close ();
fileNameList.clear ();
dirEFS.clear ();
hasValidCurrentEFS = false;
- selectedDirectory = "";
redrawAll ();
}
@@ -268,7 +270,6 @@ void FileCatalog::dirSelected (const Glib::ustring& dirname, const Glib::ustring
}
_refreshProgressBar ();
- previewLoader.process ();
#ifdef _WIN32
wdMonitor = new WinDirMonitor (selectedDirectory, this);
@@ -310,7 +311,14 @@ int refreshpb (void* data) {
return 0;
}
-void FileCatalog::previewReady (FileBrowserEntry* fdn) {
+void FileCatalog::previewReady (int dir_id, FileBrowserEntry* fdn) {
+
+ GThreadLock lock;
+
+ if ( dir_id != selectedDirectoryId )
+ {
+ return;
+ }
// put it into the "full directory" browser
fdn->setImageAreaToolListener (iatlistener);
@@ -366,44 +374,24 @@ void FileCatalog::_previewsFinished () {
filterPanel->setFilter ( currentEFS,false );
}
}
+ // restart anything that might have been loaded low quality
+ fileBrowser->refreshQuickThumbImages();
}
-void FileCatalog::previewsFinished () {
+void FileCatalog::previewsFinished (int dir_id) {
+
+ GThreadLock lock;
+
+ if ( dir_id != selectedDirectoryId )
+ {
+ return;
+ }
if (!hasValidCurrentEFS)
currentEFS = dirEFS;
g_idle_add (prevfinished, this);
}
-void PreviewLoader::remove (Glib::ustring fname) {
- std::list::iterator i;
- for (i=jqueue.begin(); i!=jqueue.end(); i++)
- if (i->fullName==fname)
- break;
- if (i!=jqueue.end())
- jqueue.erase (i);
-}
-
-void PreviewLoader::start () {
-
- jqueue.sort ();
-}
-
-void PreviewLoader::process (DirEntry& current) {
-
- if (Glib::file_test (current.fullName, Glib::FILE_TEST_EXISTS)) {
- Thumbnail* tmb = cacheMgr.getEntry (current.fullName);
- if (tmb && pl)
- pl->previewReady (new FileBrowserEntry (tmb, current.fullName));
- }
-}
-
-void PreviewLoader::end () {
-
- if (pl)
- pl->previewsFinished ();
-}
-
void FileCatalog::setEnabled (bool e) {
enabled = e;
@@ -422,15 +410,11 @@ void FileCatalog::refreshAll () {
void FileCatalog::_openImage (std::vector tmb) {
if (enabled && listener!=NULL) {
- previewLoader.stop ();
- thumbImageUpdater.stop ();
for (size_t i=0; igetFileName())==editedFiles.end())
listener->fileSelected (tmb[i]);
tmb[i]->decreaseRef ();
}
- previewLoader.process ();
- thumbImageUpdater.process ();
}
}
@@ -475,7 +459,7 @@ void FileCatalog::deleteRequested (std::vector tbe) {
// t->thumbnail->decreaseRef ();
delete t;
// remove from cache
- cacheMgr.deleteEntry (fname);
+ cacheMgr->deleteEntry (fname);
// delete from file system
::g_remove (fname.c_str());
// delete paramfile if found
@@ -492,7 +476,6 @@ void FileCatalog::deleteRequested (std::vector tbe) {
void FileCatalog::developRequested (std::vector tbe) {
if (listener) {
- thumbImageUpdater.stop ();
for (size_t i=0; ithumbnail->getProcParams();
rtengine::ProcessingJob* pjob = rtengine::ProcessingJob::create (tbe[i]->filename, tbe[i]->thumbnail->getType()==FT_Raw, params);
@@ -512,7 +495,6 @@ void FileCatalog::developRequested (std::vector tbe) {
listener->addBatchQueueJob (new BatchQueueEntry (pjob, params, tbe[i]->filename, NULL, pw, ph, tbe[i]->thumbnail));
}
}
- thumbImageUpdater.process ();
}
}
@@ -538,7 +520,7 @@ void FileCatalog::renameRequested (std::vector tbe) {
nBaseName += "." + getExtension (baseName);
Glib::ustring nfname = Glib::build_filename (dirName, nBaseName);
if (!::g_rename (ofname.c_str(), nfname.c_str())) {
- cacheMgr.renameEntry (ofname, tbe[i]->thumbnail->getMD5(), nfname);
+ cacheMgr->renameEntry (ofname, tbe[i]->thumbnail->getMD5(), nfname);
reparseDirectory ();
}
renameDlg->hide ();
@@ -584,7 +566,7 @@ void FileCatalog::renameRequested (std::vector tbe) {
}
Glib::ustring nfname = Glib::build_filename (dirName, nBaseName);
if (!::g_rename (ofname.c_str(), nfname.c_str())) {
- cacheMgr.renameEntry (ofname, tbe[i]->thumbnail->getMD5(), nfname);
+ cacheMgr->renameEntry (ofname, tbe[i]->thumbnail->getMD5(), nfname);
// the remaining part (removing old and adding new entry) is done by the directory monitor
reparseDirectory ();
// on_dir_changed (Gio::File::create_for_path (nfname), Gio::File::create_for_path (nfname), Gio::FILE_MONITOR_EVENT_CHANGED, true);
@@ -749,7 +731,7 @@ int FileCatalog::reparseDirectory () {
fileNamesToDel.push_back (t[i]->filename);
for (size_t i=0; idelEntry (fileNamesToDel[i]);
- cacheMgr.deleteEntry (fileNamesToDel[i]);
+ cacheMgr->deleteEntry (fileNamesToDel[i]);
}
// check if a new file has been added
@@ -761,10 +743,8 @@ int FileCatalog::reparseDirectory () {
break;
}
if (!found) {
- previewLoader.stop ();
checkAndAddFile (Gio::File::create_for_parse_name (nfileNameList[i]));
_refreshProgressBar ();
- previewLoader.process ();
}
}
@@ -801,7 +781,7 @@ void FileCatalog::checkAndAddFile (Glib::RefPtr file) {
if (info && info->get_file_type() != Gio::FILE_TYPE_DIRECTORY && (!info->is_hidden() || !options.fbShowHidden)) {
int lastdot = info->get_name().find_last_of ('.');
if (options.is_extention_enabled(lastdot!=(int)Glib::ustring::npos ? info->get_name().substr (lastdot+1) : "")){
- previewLoader.add (DirEntry (file->get_parse_name()));
+ previewLoader->add (selectedDirectoryId,file->get_parse_name(),this);
previewsToLoad++;
}
}
@@ -820,10 +800,10 @@ void FileCatalog::addAndOpenFile (const Glib::ustring& fname) {
int lastdot = info->get_name().find_last_of ('.');
if (options.is_extention_enabled(lastdot!=(int)Glib::ustring::npos ? info->get_name().substr (lastdot+1) : "")){
// if supported, load thumbnail first
- Thumbnail* tmb = cacheMgr.getEntry (file->get_parse_name());
+ Thumbnail* tmb = cacheMgr->getEntry (file->get_parse_name());
if (tmb) {
FileBrowserEntry* entry = new FileBrowserEntry (tmb, file->get_parse_name());
- previewReady (entry);
+ previewReady (selectedDirectoryId,entry);
// open the file
FCOIParams* params = new FCOIParams;
params->catalog = this;
@@ -856,25 +836,15 @@ bool FileCatalog::trashIsEmpty () {
void FileCatalog::zoomIn () {
- bool pLoad = previewLoader.runs();
- if (pLoad)
- previewLoader.stop ();
fileBrowser->zoomIn ();
- if (pLoad)
- previewLoader.process ();
}
void FileCatalog::zoomOut () {
- bool pLoad = previewLoader.runs();
- if (pLoad)
- previewLoader.stop ();
fileBrowser->zoomOut ();
- if (pLoad)
- previewLoader.process ();
}
void FileCatalog::refreshEditedState (const std::set& efiles) {
@@ -969,4 +939,3 @@ bool FileCatalog::handleShortcutKey (GdkEventKey* event) {
return false;
}
-
diff --git a/rtgui/filecatalog.h b/rtgui/filecatalog.h
index f7e95ac4f..85e669c23 100644
--- a/rtgui/filecatalog.h
+++ b/rtgui/filecatalog.h
@@ -33,12 +33,7 @@
#include
#include
#include
-
-class PreviewLoaderListener {
- public:
- virtual void previewReady (FileBrowserEntry* fd) {}
- virtual void previewsFinished () {}
-};
+#include
class DirEntry {
@@ -52,21 +47,6 @@ class DirEntry {
}
};
-class PreviewLoader : public ProcessingThread {
-
- protected:
- PreviewLoaderListener* pl;
-
- public:
- PreviewLoader () : pl(NULL) { ProcessingThread(); }
- void setPreviewLoaderListener (PreviewLoaderListener* p) { pl = p; }
- void start ();
- void process () { ProcessingThread::process (); }
- void process (DirEntry& current);
- void remove (Glib::ustring fname);
- void end ();
-};
-
class FileCatalog : public Gtk::VBox,
public DirSelectionListener,
public PreviewLoaderListener,
@@ -80,9 +60,12 @@ class FileCatalog : public Gtk::VBox,
Gtk::HBox* hBox;
Glib::ustring selectedDirectory;
+ int selectedDirectoryId;
bool enabled;
- PreviewLoader previewLoader;
+ // Restore PreviewLoader if the new threadsafe is not that threadsafe ;-)
+ //PreviewLoader previewLoader;
+ //PreviewMultiLoader previewLoader;
FileSelectionListener* listener;
FileSelectionChangeListener* fslistener;
ImageAreaToolListener* iatlistener;
@@ -151,8 +134,8 @@ class FileCatalog : public Gtk::VBox,
void refreshEditedState (const std::set& efiles);
// previewloaderlistener interface
- void previewReady (FileBrowserEntry* fdn);
- void previewsFinished ();
+ void previewReady (int dir_id, FileBrowserEntry* fdn);
+ void previewsFinished (int dir_id);
void _previewsFinished ();
void _refreshProgressBar ();
diff --git a/rtgui/guiutils.h b/rtgui/guiutils.h
index 6c4a9423c..126733a64 100644
--- a/rtgui/guiutils.h
+++ b/rtgui/guiutils.h
@@ -16,8 +16,8 @@
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see .
*/
-#ifndef __UTILS_
-#define __UTILS_
+#ifndef __GUI_UTILS_
+#define __GUI_UTILS_
#include
#include
@@ -28,4 +28,47 @@ Glib::ustring removeExtension (const Glib::ustring& filename);
Glib::ustring getExtension (const Glib::ustring& filename);
void drawCrop (Cairo::RefPtr cr, int imx, int imy, int imw, int imh, int startx, int starty, double scale, const rtengine::procparams::CropParams& cparams);
+/**
+ * @brief Lock GTK for critical section.
+ *
+ * Will unlock on destruction. To use:
+ *
+ *
+ * {
+ * GThreadLock lock;
+ * // critical code
+ * }
+ *
+ */
+class GThreadLock
+{
+public:
+ GThreadLock()
+ {
+ gdk_threads_enter();
+ }
+ ~GThreadLock()
+ {
+ gdk_threads_leave();
+ }
+};
+
+/**
+ * @brief Unlock GTK critical section.
+ *
+ * Will relock on destruction.
+ */
+class GThreadUnLock
+{
+public:
+ GThreadUnLock()
+ {
+ gdk_threads_leave();
+ }
+ ~GThreadUnLock()
+ {
+ gdk_threads_enter();
+ }
+};
+
#endif
diff --git a/rtgui/options.cc b/rtgui/options.cc
index 9a52d6d45..18ca9af0f 100644
--- a/rtgui/options.cc
+++ b/rtgui/options.cc
@@ -241,6 +241,7 @@ if (keyFile.has_group ("File Browser")) {
if (keyFile.has_key ("File Browser", "ThumbnailZoomRatios"))thumbnailZoomRatios= keyFile.get_double_list ("File Browser", "ThumbnailZoomRatios");
if (keyFile.has_key ("File Browser", "OverlayedFileNames")) overlayedFileNames = keyFile.get_boolean ("File Browser", "OverlayedFileNames");
if (keyFile.has_key ("File Browser", "ShowFileNames")) showFileNames = keyFile.get_boolean ("File Browser", "ShowFileNames");
+ if (keyFile.has_key ("File Browser", "InternalThumbIfUntouched")) internalThumbIfUntouched = keyFile.get_boolean ("File Browser", "InternalThumbIfUntouched");
}
if (keyFile.has_group ("Clipping Indication")) {
@@ -359,7 +360,8 @@ int Options::saveToFile (Glib::ustring fname) {
keyFile.set_double_list ("File Browser", "ThumbnailZoomRatios", ptzoom);
keyFile.set_boolean ("File Browser", "OverlayedFileNames", overlayedFileNames);
keyFile.set_boolean ("File Browser", "ShowFileNames", showFileNames );
-
+ keyFile.set_boolean ("File Browser", "InternalThumbIfUntouched", internalThumbIfUntouched );
+
keyFile.set_integer ("Clipping Indication", "HighlightThreshold", highlightThreshold);
keyFile.set_integer ("Clipping Indication", "ShadowThreshold", shadowThreshold);
keyFile.set_boolean ("Clipping Indication", "BlinkClipped", blinkClipped);
diff --git a/rtgui/options.h b/rtgui/options.h
index 3b313c6f9..c56475948 100644
--- a/rtgui/options.h
+++ b/rtgui/options.h
@@ -123,8 +123,9 @@ class Options {
std::vector favoriteDirs;
std::vector renameTemplates;
bool renameUseTemplates;
- bool overwriteOutputFile;
-
+ bool internalThumbIfUntouched;
+ bool overwriteOutputFile;
+
std::vector thumbnailZoomRatios;
bool overlayedFileNames;
bool showFileNames;
diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc
index 41ddd4a68..ced7e0dde 100644
--- a/rtgui/paramsedited.cc
+++ b/rtgui/paramsedited.cc
@@ -107,6 +107,9 @@ void ParamsEdited::set (bool v) {
cacorrection.blue = v;
vignetting.amount = v;
vignetting.radius = v;
+ vignetting.strength = v;
+ vignetting.centerX = v;
+ vignetting.centerY = v;
chmixer.red[0] = v;
chmixer.red[1] = v;
chmixer.red[2] = v;
@@ -234,6 +237,9 @@ void ParamsEdited::initFrom (const std::vector
cacorrection.blue = cacorrection.blue && p.cacorrection.blue == other.cacorrection.blue;
vignetting.amount = vignetting.amount && p.vignetting.amount == other.vignetting.amount;
vignetting.radius = vignetting.radius && p.vignetting.radius == other.vignetting.radius;
+ vignetting.strength = vignetting.strength && p.vignetting.strength == other.vignetting.strength;
+ vignetting.centerX = vignetting.centerX && p.vignetting.centerX == other.vignetting.centerX;
+ vignetting.centerY = vignetting.centerY && p.vignetting.centerY == other.vignetting.centerY;
chmixer.red[0] = chmixer.red[0] && p.chmixer.red[0] == other.chmixer.red[0];
chmixer.red[1] = chmixer.red[1] && p.chmixer.red[1] == other.chmixer.red[1];
chmixer.red[2] = chmixer.red[2] && p.chmixer.red[2] == other.chmixer.red[2];
@@ -352,6 +358,9 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten
if (cacorrection.blue) toEdit.cacorrection.blue = options.baBehav[ADDSET_CA] ? toEdit.cacorrection.blue + mods.cacorrection.blue : mods.cacorrection.blue;
if (vignetting.amount) toEdit.vignetting.amount = options.baBehav[ADDSET_VIGN_AMOUNT] ? toEdit.vignetting.amount + mods.vignetting.amount : mods.vignetting.amount;
if (vignetting.radius) toEdit.vignetting.radius = mods.vignetting.radius;
+ if (vignetting.strength) toEdit.vignetting.strength = mods.vignetting.strength;
+ if (vignetting.centerX) toEdit.vignetting.centerX = mods.vignetting.centerX;
+ if (vignetting.centerY) toEdit.vignetting.centerY = mods.vignetting.centerY;
if (chmixer.red[0]) toEdit.chmixer.red[0] = mods.chmixer.red[0];
if (chmixer.red[1]) toEdit.chmixer.red[1] = mods.chmixer.red[1];
if (chmixer.red[2]) toEdit.chmixer.red[2] = mods.chmixer.red[2];
diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h
index 11f060d0f..affa2166a 100644
--- a/rtgui/paramsedited.h
+++ b/rtgui/paramsedited.h
@@ -191,6 +191,9 @@ class VignettingParamsEdited {
public:
bool amount;
bool radius;
+ bool strength;
+ bool centerX;
+ bool centerY;
};
class ChannelMixerParamsEdited {
diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc
index 62a1b970d..b6483285d 100644
--- a/rtgui/preferences.cc
+++ b/rtgui/preferences.cc
@@ -1185,34 +1185,16 @@ void Preferences::delExtPressed () {
void Preferences::clearProfilesPressed () {
- Gtk::MessageDialog md (*this, M("PREFERENCES_CLEARDLG_LINE1"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_NONE, true);
- md.set_secondary_text (M("PREFERENCES_CLEARDLG_LINE2"));
- md.set_title (M("PREFERENCES_CLEARDLG_TITLE"));
- md.show_all ();
- while (gtk_events_pending ()) gtk_main_iteration ();
- cacheMgr.clearProfiles ();
- md.hide ();
+ cacheMgr->clearProfiles ();
}
void Preferences::clearThumbImagesPressed () {
- Gtk::MessageDialog md (*this, M("PREFERENCES_CLEARDLG_LINE1"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_NONE, true);
- md.set_secondary_text (M("PREFERENCES_CLEARDLG_LINE2"));
- md.set_title (M("PREFERENCES_CLEARDLG_TITLE"));
- md.show_all ();
- while (gtk_events_pending ()) gtk_main_iteration ();
- cacheMgr.clearThumbImages ();
- md.hide ();
+ cacheMgr->clearThumbImages ();
}
void Preferences::clearAllPressed () {
- Gtk::MessageDialog md (*this, M("PREFERENCES_CLEARDLG_LINE1"), false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_NONE, true);
- md.set_secondary_text (M("PREFERENCES_CLEARDLG_LINE2"));
- md.set_title (M("PREFERENCES_CLEARDLG_TITLE"));
- md.show_all ();
- while (gtk_events_pending ()) gtk_main_iteration ();
- cacheMgr.clearAll ();
- md.hide ();
+ cacheMgr->clearAll ();
}
diff --git a/rtgui/previewloader.cc b/rtgui/previewloader.cc
new file mode 100644
index 000000000..c8a5fa337
--- /dev/null
+++ b/rtgui/previewloader.cc
@@ -0,0 +1,170 @@
+/*
+ * This file is part of RawTherapee.
+ *
+ * Copyright (c) 2004-2010 Gabor Horvath
+ *
+ * RawTherapee is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RawTherapee is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RawTherapee. If not, see .
+ */
+
+#include
+#include
+#include
+
+#ifdef _OPENMP
+#include
+#endif
+
+#define DEBUG(format,args...)
+//#define DEBUG(format,args...) printf("PreviewLoader::%s: " format "\n", __FUNCTION__, ## args)
+
+class PreviewLoader::Impl
+{
+public:
+ struct Job
+ {
+ Job(int dir_id, const Glib::ustring& dir_entry, PreviewLoaderListener* listener):
+ dir_id_(dir_id),
+ dir_entry_(dir_entry),
+ listener_(listener)
+ {}
+
+ Job():
+ dir_id_(0),
+ listener_(0)
+ {}
+
+ int dir_id_;
+ Glib::ustring dir_entry_;
+ PreviewLoaderListener* listener_;
+ };
+
+ struct JobCompare
+ {
+ bool operator()(const Job& lhs, const Job& rhs)
+ {
+ if ( lhs.dir_id_ == rhs.dir_id_ )
+ {
+ return lhs.dir_entry_ < rhs.dir_entry_;
+ }
+ return lhs.dir_id_ < rhs.dir_id_;
+ }
+ };
+
+ typedef std::set JobSet;
+
+ Impl()
+ {
+ int threadCount=1;
+ #ifdef _OPENMP
+ threadCount=omp_get_num_procs();
+ #endif
+
+ threadPool_=new Glib::ThreadPool(threadCount,0);
+ }
+
+ Glib::ThreadPool* threadPool_;
+
+ Glib::Mutex mutex_;
+
+ JobSet jobs_;
+
+ void
+ processNextJob(void)
+ {
+ Job j;
+ {
+ Glib::Mutex::Lock lock(mutex_);
+
+ // nothing to do; could be jobs have been removed
+ if ( jobs_.empty() )
+ {
+ DEBUG("processing: nothing to do");
+ return;
+ }
+
+ // copy and remove front job
+ j = *jobs_.begin();
+ jobs_.erase(jobs_.begin());
+ DEBUG("processing %s",j.dir_entry_.c_str());
+ DEBUG("%d job(s) remaining",jobs_.size());
+ }
+
+ // unlock and do processing; will relock on block exit, then call listener
+ // if something got
+ Thumbnail* tmb = 0;
+ {
+ if (Glib::file_test(j.dir_entry_, Glib::FILE_TEST_EXISTS))
+ {
+ tmb = cacheMgr->getEntry(j.dir_entry_);
+ }
+ }
+
+ // we got something so notify listener
+ if ( tmb )
+ {
+ j.listener_->previewReady(j.dir_id_,new FileBrowserEntry(tmb,j.dir_entry_));
+ }
+
+ // signal at end
+ if ( jobs_.empty() )
+ {
+ j.listener_->previewsFinished(j.dir_id_);
+ }
+ }
+};
+
+PreviewLoader::PreviewLoader():
+ impl_(new Impl())
+{
+}
+
+PreviewLoader*
+PreviewLoader::getInstance(void)
+{
+ // this will not be deleted...
+ static PreviewLoader* instance_ = 0;
+ if ( instance_ == 0 )
+ {
+ instance_ = new PreviewLoader();
+ }
+ return instance_;
+}
+
+void
+PreviewLoader::add(int dir_id, const Glib::ustring& dir_entry, PreviewLoaderListener* l)
+{
+ // somebody listening?
+ if ( l != 0 )
+ {
+ Glib::Mutex::Lock lock(impl_->mutex_);
+
+ // create a new job and append to queue
+ DEBUG("saving job %s",dir_entry.c_str());
+ impl_->jobs_.insert(Impl::Job(dir_id,dir_entry,l));
+
+ // queue a run request
+ DEBUG("adding run request %s",dir_entry.c_str());
+ impl_->threadPool_->push(sigc::mem_fun(*impl_, &PreviewLoader::Impl::processNextJob));
+ }
+}
+
+void
+PreviewLoader::removeAllJobs(void)
+{
+ DEBUG("stop");
+
+ impl_->jobs_.clear();
+}
+
+
diff --git a/rtgui/previewloader.h b/rtgui/previewloader.h
new file mode 100644
index 000000000..b113d590d
--- /dev/null
+++ b/rtgui/previewloader.h
@@ -0,0 +1,93 @@
+/*
+ * This file is part of RawTherapee.
+ *
+ * Copyright (c) 2004-2010 Gabor Horvath
+ *
+ * RawTherapee is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * RawTherapee is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RawTherapee. If not, see .
+ */
+#ifndef _PREVIEWLOADER_
+#define _PREVIEWLOADER_
+
+#include
+#include
+#include
+
+class PreviewLoaderListener
+{
+public:
+
+ /**
+ * @brief a preview is ready
+ *
+ * @param dir_id directory ID this is for
+ * @param fd entry
+ */
+ virtual void previewReady (int dir_id, FileBrowserEntry* fd) {}
+
+ /**
+ * @brief all previews have finished loading
+ */
+ virtual void previewsFinished (int dir_id_) {}
+};
+
+class PreviewLoader
+{
+ public:
+
+ /**
+ * @brief Singleton entry point.
+ *
+ * @note expects to be called inside gtk thread lock
+ *
+ * @return Pointer to thumbnail image updater.
+ */
+ static PreviewLoader* getInstance(void);
+
+ /**
+ * @brief Add an thumbnail image update request.
+ *
+ * Code will add the request to the queue and, if needed, start a pool
+ * thread to process it.
+ *
+ * @param dir_id directory we're looking at
+ * @param dir_entry entry in it
+ * @param l listener
+ */
+ void add(int dir_id, const Glib::ustring& dir_entry, PreviewLoaderListener* l);
+
+ /**
+ * @brief Stop processing and remove all jobs.
+ *
+ * Will not return till all jobs have completed.
+ *
+ * @note expects to be called inside gtk thread lock
+ */
+ void removeAllJobs(void);
+
+ private:
+
+ PreviewLoader();
+
+ class Impl;
+ Impl* impl_;
+};
+
+/**
+ * @brief Singleton boiler plate.
+ *
+ * To use: \c previewLoader->start() ,
+ */
+#define previewLoader PreviewLoader::getInstance()
+
+#endif
diff --git a/rtgui/rtwindow.cc b/rtgui/rtwindow.cc
index b3c4f0e2f..6dd3cfe40 100644
--- a/rtgui/rtwindow.cc
+++ b/rtgui/rtwindow.cc
@@ -23,7 +23,7 @@
RTWindow::RTWindow () {
- cacheMgr.init ();
+ cacheMgr->init ();
#ifdef GLIBMM_EXCEPTIONS_ENABLED
try { set_default_icon_from_file (argv0+"/images/logoicon16.png");
@@ -248,7 +248,7 @@ bool RTWindow::on_delete_event(GdkEventAny* event) {
if (options.startupDir==STARTUPDIR_LAST && fileBrowser->lastSelectedDir ()!="")
options.startupPath = fileBrowser->lastSelectedDir ();
fileBrowser->close ();
- cacheMgr.closeCache ();
+ cacheMgr->closeCache ();
options.lastScale = editorPanel->zoomBar->getScale ();
diff --git a/rtgui/thumbbrowserbase.cc b/rtgui/thumbbrowserbase.cc
index ad464c3a7..cea0bbc83 100644
--- a/rtgui/thumbbrowserbase.cc
+++ b/rtgui/thumbbrowserbase.cc
@@ -498,6 +498,12 @@ void ThumbBrowserBase::refreshThumbImages () {
redraw ();
}
+void ThumbBrowserBase::refreshQuickThumbImages () {
+ for (int i=0; irefreshQuickThumbnailImage ();
+ }
+}
+
void ThumbBrowserBase::refreshEditedState (const std::set& efiles) {
editedFiles = efiles;
diff --git a/rtgui/thumbbrowserbase.h b/rtgui/thumbbrowserbase.h
index e8ffe4b53..801a96756 100644
--- a/rtgui/thumbbrowserbase.h
+++ b/rtgui/thumbbrowserbase.h
@@ -95,6 +95,7 @@ class ThumbBrowserBase : public Gtk::VBox {
void styleChanged (const Glib::RefPtr& style);
void redraw (); // arrange files and draw area
void refreshThumbImages (); // refresh thumbnail sizes, re-generate thumbnail images, arrange and draw
+ void refreshQuickThumbImages (); // refresh thumbnail sizes, re-generate thumbnail images, arrange and draw
void refreshEditedState (const std::set& efiles);
void initEntry (ThumbBrowserEntryBase* entry);
diff --git a/rtgui/thumbbrowserentrybase.h b/rtgui/thumbbrowserentrybase.h
index 20f8dda77..6562633d0 100644
--- a/rtgui/thumbbrowserentrybase.h
+++ b/rtgui/thumbbrowserentrybase.h
@@ -109,6 +109,7 @@ protected:
bool operator< (ThumbBrowserEntryBase& other) { return shortname.casefold()>other.shortname.casefold(); }
virtual void refreshThumbnailImage () {}
+ virtual void refreshQuickThumbnailImage () {}
virtual void calcThumbnailSize () {}
virtual void drawProgressBar (Glib::RefPtr win, Glib::RefPtr gc, const Gdk::Color& foregr, const Gdk::Color& backgr, int x, int w, int y, int h) {}
diff --git a/rtgui/thumbimageupdater.cc b/rtgui/thumbimageupdater.cc
index cbdc6313b..38720095f 100644
--- a/rtgui/thumbimageupdater.cc
+++ b/rtgui/thumbimageupdater.cc
@@ -16,150 +16,270 @@
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see .
*/
+
+#include
#include
#include
+#include
-#define threadNum 1
-ThumbImageUpdater thumbImageUpdater;
+#ifdef _OPENMP
+#include
+#endif
-ThumbImageUpdater::ThumbImageUpdater ()
- : tostop(false), stopped(true), qMutex(NULL), startMutex(NULL), threadPool(NULL) {
-
-}
+#define DEBUG(format,args...)
+//#define DEBUG(format,args...) printf("ThumbImageUpdate::%s: " format "\n", __FUNCTION__, ## args)
-ThumbImageUpdater::~ThumbImageUpdater ()
+class
+ThumbImageUpdater::Impl
{
- delete threadPool;
+public:
+
+ struct Job
+ {
+ Job(Thumbnail* thumbnail, const rtengine::procparams::ProcParams& pparams,
+ int height, bool* priority, bool upgrade,
+ ThumbImageUpdateListener* listener):
+ thumbnail_(thumbnail),
+ pparams_(pparams),
+ height_(height),
+ priority_(priority),
+ upgrade_(upgrade),
+ listener_(listener)
+ {}
+
+ Job():
+ thumbnail_(0),
+ listener_(0)
+ {}
+
+ Thumbnail* thumbnail_;
+ rtengine::procparams::ProcParams pparams_;
+ int height_;
+ bool* priority_;
+ bool upgrade_;
+ ThumbImageUpdateListener* listener_;
+ };
+
+ typedef std::list JobList;
+
+ Impl():
+ active_(0),
+ inactive_waiting_(false)
+ {
+ int threadCount=1;
+ #ifdef _OPENMP
+ threadCount=omp_get_num_procs();
+ #endif
+
+ threadPool_=new Glib::ThreadPool(threadCount,0);
+ }
+
+ Glib::ThreadPool* threadPool_;
+
+ Glib::Mutex mutex_;
+
+ JobList jobs_;
+
+ unsigned int active_;
+
+ bool inactive_waiting_;
+
+ Glib::Cond inactive_;
+
+ void
+ processNextJob(void)
+ {
+ Job j;
+
+ {
+ Glib::Mutex::Lock lock(mutex_);
+
+ // nothing to do; could be jobs have been removed
+ if ( jobs_.empty() )
+ {
+ DEBUG("processing: nothing to do (%d,%d)",paused_,jobs_.empty());
+ return;
+ }
+
+ JobList::iterator i;
+
+ // see if any priority jobs exist
+ for ( i = jobs_.begin(); i != jobs_.end(); ++i)
+ {
+ if ( *(i->priority_) )
+ {
+ DEBUG("processing(priority) %s",i->thumbnail_->getFileName().c_str());
+ break;
+ }
+ }
+
+ // see if any none upgrade jobs exist
+ for ( i = jobs_.begin(); i != jobs_.end(); ++i)
+ {
+ if ( !i->upgrade_ )
+ {
+ DEBUG("processing(not-upgrade) %s",i->thumbnail_->getFileName().c_str());
+ break;
+ }
+ }
+
+ // if none, then use first
+ if ( i == jobs_.end() )
+ {
+ i = jobs_.begin();
+ DEBUG("processing(first) %s",i->thumbnail_->getFileName().c_str());
+ }
+
+ // copy found job
+ j = *i;
+
+ // remove so not run again
+ jobs_.erase(i);
+ DEBUG("%d job(s) remaining",jobs_.size());
+
+ ++active_;
+ }
+
+ // unlock and do processing; will relock on block exit, then call listener
+ double scale = 1.0;
+ rtengine::IImage8* img = 0;
+
+ if ( j.upgrade_ )
+ {
+ if ( j.thumbnail_->isQuick() )
+ {
+ img = j.thumbnail_->upgradeThumbImage(j.pparams_, j.height_, scale);
+ }
+ }
+ else
+ {
+ img = j.thumbnail_->processThumbImage(j.pparams_, j.height_, scale);
+ }
+
+ if (img)
+ {
+ DEBUG("pushing image %s",j.thumbnail_->getFileName().c_str());
+ j.listener_->updateImage(img, scale, j.pparams_.crop);
+ }
+
+ {
+ Glib::Mutex::Lock lock(mutex_);
+
+ if ( --active_ == 0 &&
+ inactive_waiting_ )
+ {
+ inactive_waiting_ = false;
+ inactive_.signal();
+ }
+ }
+ }
+};
+
+ThumbImageUpdater*
+ThumbImageUpdater::getInstance(void)
+{
+ // this will not be deleted...
+ static ThumbImageUpdater* instance_ = 0;
+ if ( instance_ == 0 )
+ {
+ instance_ = new ThumbImageUpdater();
+ }
+ return instance_;
}
-void ThumbImageUpdater::add (Thumbnail* t, const rtengine::procparams::ProcParams& params, int height, bool* priority, ThumbImageUpdateListener* l) {
+ThumbImageUpdater::ThumbImageUpdater():
+ impl_(new Impl())
+{
+}
- if (!qMutex)
- qMutex = new Glib::Mutex ();
- if (!startMutex)
- startMutex = new Glib::Mutex ();
+void
+ThumbImageUpdater::add(Thumbnail* t, const rtengine::procparams::ProcParams& params,
+ int height, bool* priority, bool upgrade, ThumbImageUpdateListener* l)
+{
+ // nobody listening?
+ if ( l == 0 )
+ {
+ return;
+ }
+
+ Glib::Mutex::Lock lock(impl_->mutex_);
- qMutex->lock ();
// look up if an older version is in the queue
- std::list::iterator i;
- for (i=jqueue.begin(); i!=jqueue.end(); i++)
- if (i->thumbnail==t && i->listener==l) {
- i->pparams = params;
- i->height = height;
- i->priority = priority;
- break;
- }
- // not found, create and append new job
- if (i==jqueue.end ()) {
- Job j;
- j.thumbnail = t;
- j.pparams = params;
- j.height = height;
- j.listener = l;
- j.priority = priority;
- jqueue.push_back (j);
- }
- qMutex->unlock ();
-}
+ Impl::JobList::iterator i(impl_->jobs_.begin());
+ for ( ; i != impl_->jobs_.end(); ++i )
+ {
+ if ( i->thumbnail_ == t &&
+ i->listener_ == l &&
+ i->upgrade_ == upgrade )
+ {
+ DEBUG("updating job %s",t->getFileName().c_str());
+ // we have one, update queue entry, will be picked up by thread when processed
+ i->pparams_ = params;
+ i->height_ = height;
+ i->priority_ = priority;
+ return;
+ }
+ }
-void ThumbImageUpdater::process () {
+ // create a new job and append to queue
+ DEBUG("queing job %s",t->getFileName().c_str());
+ impl_->jobs_.push_back(Impl::Job(t,params,height,priority,upgrade,l));
- if (stopped) {
- stopped = false;
-
- if(!threadPool)
- threadPool = new Glib::ThreadPool(threadNum,1);
-
- //thread = Glib::Thread::create (sigc::mem_fun(*this, &ThumbImageUpdater::process_), (unsigned long int)0, true, true, Glib::THREAD_PRIORITY_NORMAL);
- process_();
- }
-}
-
-void ThumbImageUpdater::process_ () {
-
- stopped = false;
- tostop = false;
-
- while (!tostop && !jqueue.empty ()) {
-
- std::list::iterator i;
- for (i=jqueue.begin (); i!=jqueue.end(); i++)
- if (*(i->priority))
- break;
-
- if (i==jqueue.end())
- i = jqueue.begin();
-
- Job current = *i;
- if (current.listener)
- threadPool->push(sigc::bind(sigc::mem_fun(*this, &ThumbImageUpdater::processJob), current));
-
- jqueue.erase (i);
- }
-
- stopped = true;
- //printf("Threads # %d \n", threadPool->get_num_threads());
-
-}
-
-void ThumbImageUpdater::processJob (Job current) {
-
- if (current.listener) {
- double scale = 1.0;
- rtengine::IImage8* img = current.thumbnail->processThumbImage (current.pparams, current.height, scale);
- if (img)
- current.listener->updateImage (img, scale, current.pparams.crop);
- }
-
-}
-
-void ThumbImageUpdater::stop () {
-
- gdk_threads_leave();
- tostop = true;
-
- if (threadPool) {
- threadPool->shutdown(TRUE);
- threadPool = NULL;
- }
- gdk_threads_enter();
-}
-
-void ThumbImageUpdater::removeJobs () {
-
- if (!qMutex)
- return;
-
- qMutex->lock ();
- while (!jqueue.empty())
- jqueue.pop_front ();
- qMutex->unlock ();
-}
-
-void ThumbImageUpdater::removeJobs (ThumbImageUpdateListener* listener) {
-
- if (!qMutex)
- return;
-
- qMutex->lock ();
- bool ready = false;
- while (!ready) {
- ready = true;
- std::list::iterator i;
- for (i=jqueue.begin(); i!=jqueue.end(); i++)
- if (i->listener == listener) {
- jqueue.erase (i);
- ready = false;
- break;
- }
- }
- qMutex->unlock ();
-}
-
-void ThumbImageUpdater::terminate () {
-
- stop ();
- removeJobs ();
+ DEBUG("adding run request %s",t->getFileName().c_str());
+ impl_->threadPool_->push(sigc::mem_fun(*impl_, &ThumbImageUpdater::Impl::processNextJob));
}
+void
+ThumbImageUpdater::removeJobs(ThumbImageUpdateListener* listener)
+{
+ DEBUG("removeJobs(%p)",listener);
+
+ Glib::Mutex::Lock lock(impl_->mutex_);
+
+ for( Impl::JobList::iterator i(impl_->jobs_.begin()); i != impl_->jobs_.end(); )
+ {
+ if (i->listener_ == listener)
+ {
+ DEBUG("erasing specific job");
+ Impl::JobList::iterator e(i++);
+ impl_->jobs_.erase(e);
+ }
+ else
+ {
+ ++i;
+ }
+ }
+
+ while ( impl_->active_ != 0 )
+ {
+ // XXX this is nasty... it would be nicer if we weren't called with
+ // this lock held
+ GThreadUnLock unlock;
+ DEBUG("waiting for running jobs1");
+ impl_->inactive_waiting_ = true;
+ impl_->inactive_.wait(impl_->mutex_);
+ }
+}
+
+void
+ThumbImageUpdater::removeAllJobs(void)
+{
+ DEBUG("stop");
+
+
+ Glib::Mutex::Lock lock(impl_->mutex_);
+
+ impl_->jobs_.clear();
+
+ while ( impl_->active_ != 0 )
+ {
+ // XXX this is nasty... it would be nicer if we weren't called with
+ // this lock held
+ GThreadUnLock unlock;
+ DEBUG("waiting for running jobs2");
+ impl_->inactive_waiting_ = true;
+ impl_->inactive_.wait(impl_->mutex_);
+ }
+}
+
diff --git a/rtgui/thumbimageupdater.h b/rtgui/thumbimageupdater.h
index 909b90754..6fdce5bc1 100644
--- a/rtgui/thumbimageupdater.h
+++ b/rtgui/thumbimageupdater.h
@@ -26,45 +26,76 @@
class ThumbImageUpdateListener {
- public:
- virtual void updateImage (rtengine::IImage8* img, double scale, rtengine::procparams::CropParams cropParams) {}
+public:
+
+ /**
+ * @brief Called when thumbnail image is update
+ *
+ * @param img new thumbnail image
+ * @param scale scale (??)
+ * @param cropParams how it was cropped (??)
+ *
+ * @note no locks are held when called back
+ */
+ virtual void updateImage (rtengine::IImage8* img, double scale, rtengine::procparams::CropParams cropParams) {}
};
class ThumbImageUpdater {
- struct Job {
- Thumbnail* thumbnail;
- rtengine::procparams::ProcParams pparams;
- int height;
- bool* priority;
- ThumbImageUpdateListener* listener;
- };
-
- protected:
- bool tostop;
- bool stopped;
- std::list jqueue;
- Glib::Thread* thread;
- Glib::Mutex* qMutex;
- Glib::Mutex* startMutex;
- //Glib::Thread **threadPool;
- Glib::ThreadPool * threadPool;
-
public:
- ThumbImageUpdater ();
- ~ThumbImageUpdater ();
- void add (Thumbnail* t, const rtengine::procparams::ProcParams& params, int height, bool* priority, ThumbImageUpdateListener* l);
- void process ();
- void stop ();
- void removeJobs ();
- void removeJobs (ThumbImageUpdateListener* listener);
- void terminate ();
+ /**
+ * @brief Singleton entry point.
+ *
+ * @return Pointer to thumbnail image updater.
+ */
+ static ThumbImageUpdater* getInstance(void);
- void process_ ();
- void processJob (Job current);
+ /**
+ * @brief Add an thumbnail image update request.
+ *
+ * Code will add the request to the queue and, if needed, start a pool
+ * thread to process it.
+ *
+ * @param t thumbnail
+ * @param params processing params (?)
+ * @param height how big
+ * @param priority if \c true then run as soon as possible
+ * @param l listener waiting on update
+ */
+ void add(Thumbnail* t, const rtengine::procparams::ProcParams& params,
+ int height, bool* priority, bool upgrade, ThumbImageUpdateListener* l);
+
+ /**
+ * @brief Remove jobs associated with listener \c l.
+ *
+ * Jobs being processed will be finished. Will not return till all jobs for
+ * \c l have been completed.
+ *
+ * @param listener jobs associated with this will be stopped
+ */
+ void removeJobs(ThumbImageUpdateListener* listener);
+
+ /**
+ * @brief Stop processing and remove all jobs.
+ *
+ * Will not return till all running jobs have completed.
+ */
+ void removeAllJobs(void);
+
+ private:
+
+ ThumbImageUpdater();
+
+ class Impl;
+ Impl* impl_;
};
-extern ThumbImageUpdater thumbImageUpdater;
+/**
+ * @brief Singleton boiler plate.
+ *
+ * To use: \c thumbImageUpdater->start() ,
+ */
+#define thumbImageUpdater ThumbImageUpdater::getInstance()
#endif
diff --git a/rtgui/thumbnail.cc b/rtgui/thumbnail.cc
index 3f9cd2e72..0ffe641de 100644
--- a/rtgui/thumbnail.cc
+++ b/rtgui/thumbnail.cc
@@ -34,86 +34,106 @@ using namespace rtengine::procparams;
Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, CacheImageData* cf)
: fname(fname), cfs(*cf), cachemgr(cm), ref(1), enqueueNumber(0), tpp(NULL),
- pparamsValid(false), needsReProcessing(true), lastImg(NULL) {
+ pparamsValid(false), needsReProcessing(true), lastImg(NULL),
+ quick_(false), initial_(false) {
- mutex = new Glib::Mutex ();
cfs.load (getCacheFileName ("data")+".txt");
loadProcParams ();
- loadThumbnail ();
+ _loadThumbnail ();
generateExifDateTimeStrings ();
}
Thumbnail::Thumbnail (CacheManager* cm, const Glib::ustring& fname, const std::string& md5)
: fname(fname), cachemgr(cm), ref(1), enqueueNumber(0), tpp(NULL), pparamsValid(false),
- needsReProcessing(true), lastImg(NULL) {
+ needsReProcessing(true), lastImg(NULL),
+ quick_(false), initial_(true) {
- mutex = new Glib::Mutex ();
cfs.md5 = md5;
- generateThumbnailImage ();
+ _generateThumbnailImage ();
loadProcParams ();
cfs.recentlySaved = false;
+
+ initial_ = false;
}
-void Thumbnail::generateThumbnailImage (bool internal) {
+void Thumbnail::_generateThumbnailImage () {
- if (!internal)
- mutex->lock ();
+ // delete everything loaded into memory
+ delete tpp;
+ tpp = NULL;
+ delete [] lastImg;
+ lastImg = NULL;
+ tw = -1;
+ th = options.maxThumbnailHeight;
-// delete everything loaded into memory
- delete tpp;
- tpp = NULL;
- delete [] lastImg;
- lastImg = NULL;
- tw = -1;
- th = options.maxThumbnailHeight;
+ // generate thumbnail image
-// generate thumbnail image
+ Glib::ustring ext = getExtension (fname);
+ if (ext=="")
+ return;
+ cfs.supported = false;
+ cfs.exifValid = false;
+ cfs.timeValid = false;
- Glib::ustring ext = getExtension (fname);
- if (ext=="")
- return;
- cfs.supported = false;
- cfs.exifValid = false;
- cfs.timeValid = false;
-
- delete tpp;
- tpp = NULL;
- if (ext.lowercase()=="jpg" || ext.lowercase()=="png" || ext.lowercase()=="tif" || ext.lowercase()=="tiff")
- tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, 1);
- if (tpp) {
- if (ext.lowercase()=="jpg") {
- cfs.format = FT_Jpeg;
- infoFromImage (fname);
- }
- else if (ext.lowercase()=="png")
- cfs.format = FT_Png;
- else if (ext.lowercase()=="tif" || ext.lowercase()=="tiff") {
- cfs.format = FT_Tiff;
- infoFromImage (fname);
- }
- }
- else {
- rtengine::RawMetaDataLocation ri;
- tpp = rtengine::Thumbnail::loadFromRaw (fname, ri, tw, th, 1);
- if (tpp) {
- cfs.format = FT_Raw;
- infoFromImage (fname, &ri);
- }
- }
- if (tpp) {
- // save thumbnail image to cache
- saveThumbnail ();
- cfs.supported = true;
- }
- needsReProcessing = true;
+ delete tpp;
+ tpp = NULL;
+ if (ext.lowercase()=="jpg" || ext.lowercase()=="png" || ext.lowercase()=="tif" || ext.lowercase()=="tiff")
+ tpp = rtengine::Thumbnail::loadFromImage (fname, tw, th, 1);
+ if (tpp) {
+ if (ext.lowercase()=="jpg") {
+ cfs.format = FT_Jpeg;
+ infoFromImage (fname);
+ }
+ else if (ext.lowercase()=="png")
+ cfs.format = FT_Png;
+ else if (ext.lowercase()=="tif" || ext.lowercase()=="tiff") {
+ cfs.format = FT_Tiff;
+ infoFromImage (fname);
+ }
+ }
+ else {
+ // RAW works like this:
+ // 1. if we are here it's because we aren't in the cache so load the JPG
+ // image out of the RAW. Mark as "quick".
+ // 2. if we don't find that then just grab the real image.
+ rtengine::RawMetaDataLocation ri;
+ if ( initial_ )
+ {
+ quick_ = true;
+ tpp = rtengine::Thumbnail::loadQuickFromRaw (fname, ri, tw, th, 1);
+ }
+ if ( tpp == 0 )
+ {
+ quick_ = false;
+ tpp = rtengine::Thumbnail::loadFromRaw (fname, ri, tw, th, 1);
+ }
+ if (tpp) {
+ cfs.format = FT_Raw;
+ infoFromImage (fname, &ri);
+ }
+ }
+ if (tpp )
+ {
+ if ( !quick_ )
+ {
+ _saveThumbnail ();
+ }
+ cfs.supported = true;
+ }
+ needsReProcessing = true;
- cfs.save (getCacheFileName ("data")+".txt");
+ if ( !quick_ )
+ {
+ cfs.save (getCacheFileName ("data")+".txt");
+ }
- generateExifDateTimeStrings ();
-
- if (!internal)
- mutex->unlock ();
+ generateExifDateTimeStrings ();
+}
+
+void Thumbnail::generateThumbnailImage () {
+ Glib::Mutex::Lock lock(mutex);
+ _generateThumbnailImage();
}
bool Thumbnail::isSupported () {
@@ -231,8 +251,24 @@ bool Thumbnail::isEnqueued () {
return enqueueNumber > 0;
}
-void Thumbnail::increaseRef () { ref++; }
-void Thumbnail::decreaseRef () { ref--; if (!ref) cachemgr->closeThumbnail (this); }
+void Thumbnail::increaseRef ()
+{
+ Glib::Mutex::Lock lock(mutex);
+ ++ref;
+}
+
+void Thumbnail::decreaseRef ()
+{
+ Glib::Mutex::Lock lock(mutex);
+ if ( ref != 0 )
+ {
+ --ref;
+ if ( ref == 0 )
+ {
+ cachemgr->closeThumbnail (this);
+ }
+ }
+}
void Thumbnail::getThumbnailSize (int &w, int &h) {
@@ -244,15 +280,33 @@ void Thumbnail::getThumbnailSize (int &w, int &h) {
rtengine::IImage8* Thumbnail::processThumbImage (const rtengine::procparams::ProcParams& pparams, int h, double& scale) {
- mutex->lock ();
+ Glib::Mutex::Lock lock(mutex);
if (!tpp)
return NULL;
- rtengine::IImage8* res = tpp->processImage (pparams, h, rtengine::TI_Bilinear, scale);
+ if ( quick_ )
+ {
+ return tpp->quickProcessImage (pparams, h, rtengine::TI_Nearest, scale);
+ }
+ else
+ {
+ return tpp->processImage (pparams, h, rtengine::TI_Bilinear, scale);
+ }
+}
- mutex->unlock ();
- return res;
+rtengine::IImage8* Thumbnail::upgradeThumbImage (const rtengine::procparams::ProcParams& pparams, int h, double& scale) {
+
+ Glib::Mutex::Lock lock(mutex);
+
+ if ( !quick_ )
+ {
+ return 0;
+ }
+
+ quick_ = false;
+ _generateThumbnailImage();
+ return tpp->processImage (pparams, h, rtengine::TI_Bilinear, scale);
}
void Thumbnail::generateExifDateTimeStrings () {
@@ -340,10 +394,7 @@ void Thumbnail::infoFromImage (const Glib::ustring& fname, rtengine::RawMetaData
delete idata;
}
-void Thumbnail::loadThumbnail (bool internal, bool firstTrial) {
-
- if (!internal)
- mutex->lock ();
+void Thumbnail::_loadThumbnail(bool firstTrial) {
needsReProcessing = true;
delete tpp;
@@ -357,9 +408,9 @@ void Thumbnail::loadThumbnail (bool internal, bool firstTrial) {
succ = succ && tpp->readImage (getCacheFileName ("images"));
if (!succ && firstTrial) {
- generateThumbnailImage (true);
+ _generateThumbnailImage ();
if (cfs.supported && firstTrial)
- loadThumbnail (true, false);
+ _loadThumbnail (false);
}
else if (!succ) {
delete tpp;
@@ -375,11 +426,14 @@ void Thumbnail::loadThumbnail (bool internal, bool firstTrial) {
tpp->init ();
}
- if (!internal)
- mutex->unlock ();
}
-void Thumbnail::saveThumbnail () {
+void Thumbnail::loadThumbnail (bool firstTrial) {
+ Glib::Mutex::Lock lock(mutex);
+ _loadThumbnail(firstTrial);
+}
+
+void Thumbnail::_saveThumbnail () {
if (!tpp)
return;
@@ -406,6 +460,12 @@ void Thumbnail::saveThumbnail () {
tpp->writeData (getCacheFileName ("data")+".txt");
}
+void Thumbnail::saveThumbnail ()
+{
+ Glib::Mutex::Lock lock(mutex);
+ _saveThumbnail();
+}
+
void Thumbnail::updateCache () {
if (pparamsValid) {
diff --git a/rtgui/thumbnail.h b/rtgui/thumbnail.h
index fc57d3b6a..0373f4f3d 100644
--- a/rtgui/thumbnail.h
+++ b/rtgui/thumbnail.h
@@ -31,7 +31,7 @@
class CacheManager;
class Thumbnail {
- Glib::Mutex* mutex;
+ Glib::Mutex mutex;
Glib::ustring fname; // file name corresponding to the thumbnail
CacheImageData cfs; // cache entry corresponding to the thumbnail
@@ -58,12 +58,17 @@ class Thumbnail {
Glib::ustring exifString;
Glib::ustring dateTimeString;
+ bool initial_;
+ bool quick_;
+
// vector of listeners
std::vector listeners;
+ void _loadThumbnail (bool firstTrial=true);
+ void _saveThumbnail ();
+ void _generateThumbnailImage ();
void infoFromImage (const Glib::ustring& fname, rtengine::RawMetaDataLocation* rml=NULL);
- void loadThumbnail (bool internal=false, bool firstTrial=true);
- void saveThumbnail ();
+ void loadThumbnail (bool firstTrial=true);
void generateExifDateTimeStrings ();
Glib::ustring getCacheFileName (Glib::ustring subdir);
@@ -79,6 +84,8 @@ class Thumbnail {
void clearProcParams (int whoClearedIt=-1);
void loadProcParams ();
+ bool isQuick() { return quick_; }
+ bool isPParamsValid() { return pparamsValid; }
bool isRecentlySaved ();
void imageDeveloped ();
void imageEnqueued ();
@@ -87,11 +94,11 @@ class Thumbnail {
// unsigned char* getThumbnailImage (int &w, int &h, int fixwh=1); // fixwh = 0: fix w and calculate h, =1: fix h and calculate w
rtengine::IImage8* processThumbImage (const rtengine::procparams::ProcParams& pparams, int h, double& scale);
- void processThumbImage2 (const rtengine::procparams::ProcParams& pparams, int h, rtengine::IImage8*& img, double& scale) { img = processThumbImage(pparams, h, scale); }
+ rtengine::IImage8* upgradeThumbImage (const rtengine::procparams::ProcParams& pparams, int h, double& scale);
void getThumbnailSize (int &w, int &h);
void getFinalSize (const rtengine::procparams::ProcParams& pparams, int& w, int& h) { if (tpp) tpp->getFinalSize (pparams, w, h); }
- void generateThumbnailImage (bool internal=false);
+ void generateThumbnailImage ();
const Glib::ustring& getExifString ();
const Glib::ustring& getDateTimeString ();
@@ -122,7 +129,7 @@ class Thumbnail {
void decreaseRef ();
void updateCache ();
- void reSaveThumbnail () { mutex->lock (); saveThumbnail(); mutex->unlock(); }
+ void saveThumbnail ();
};
diff --git a/rtgui/tonecurve.cc b/rtgui/tonecurve.cc
index fed471bb1..f0f194844 100644
--- a/rtgui/tonecurve.cc
+++ b/rtgui/tonecurve.cc
@@ -57,7 +57,7 @@ ToneCurve::ToneCurve () : ToolPanel(), expAdd(false), blackAdd(false), brAdd(fal
//----------- Black Level ----------------------------------
black = Gtk::manage (new Adjuster (M("TP_EXPOSURE_BLACKLEVEL"), 0, 16384, 1, 0));
pack_start (*black);
- shcompr = Gtk::manage (new Adjuster (M("TP_EXPOSURE_COMPRSHADOWS"), -100, 100, 1, 0));
+ shcompr = Gtk::manage (new Adjuster (M("TP_EXPOSURE_COMPRSHADOWS"), 0, 100, 1, 25));
pack_start (*shcompr);
pack_start (*Gtk::manage (new Gtk::HSeparator()));
diff --git a/rtgui/vignetting.cc b/rtgui/vignetting.cc
index 622885f19..3839326c9 100644
--- a/rtgui/vignetting.cc
+++ b/rtgui/vignetting.cc
@@ -30,8 +30,20 @@ Vignetting::Vignetting () : vigAdd(false) {
radius = Gtk::manage (new Adjuster (M("TP_VIGNETTING_RADIUS"), 0, 100, 1, 50));
radius->setAdjusterListener (this);
+ strength = Gtk::manage (new Adjuster (M("TP_VIGNETTING_STRENGTH"), 1, 100, 1, 1));
+ strength->setAdjusterListener (this);
+
+ centerX = Gtk::manage (new Adjuster (M("TP_VIGNETTING_CENTER_X"), -100, 100, 1, 0));
+ centerX->setAdjusterListener (this);
+
+ centerY = Gtk::manage (new Adjuster (M("TP_VIGNETTING_CENTER_Y"), -100, 100, 1, 0));
+ centerY->setAdjusterListener (this);
+
pack_start (*amount);
pack_start (*radius);
+ pack_start (*strength);
+ pack_start (*centerX);
+ pack_start (*centerY);
show_all();
}
@@ -45,6 +57,9 @@ void Vignetting::read (const ProcParams* pp, const ParamsEdited* pedited) {
amount->setValue (pp->vignetting.amount);
radius->setValue (pp->vignetting.radius);
+ strength->setValue (pp->vignetting.strength);
+ centerX->setValue (pp->vignetting.centerX);
+ centerY->setValue (pp->vignetting.centerY);
enableListener ();
}
@@ -53,6 +68,9 @@ void Vignetting::write (ProcParams* pp, ParamsEdited* pedited) {
pp->vignetting.amount = (int)amount->getValue ();
pp->vignetting.radius = (int)radius->getValue ();
+ pp->vignetting.strength = (int)strength->getValue ();
+ pp->vignetting.centerX = (int)centerX->getValue ();
+ pp->vignetting.centerY = (int)centerY->getValue ();
if (pedited)
pedited->vignetting.amount = amount->getEditedState ();
@@ -62,6 +80,9 @@ void Vignetting::setDefaults (const ProcParams* defParams, const ParamsEdited* p
amount->setDefault (defParams->vignetting.amount);
radius->setDefault (defParams->vignetting.radius);
+ strength->setDefault (defParams->vignetting.strength);
+ centerX->setDefault (defParams->vignetting.centerX);
+ centerY->setDefault (defParams->vignetting.centerY);
if (pedited)
amount->setDefaultEditedState (pedited->vignetting.amount ? Edited : UnEdited);
@@ -72,7 +93,7 @@ void Vignetting::setDefaults (const ProcParams* defParams, const ParamsEdited* p
void Vignetting::adjusterChanged (Adjuster* a, double newval) {
if (listener)
- listener->panelChanged (EvVignetting, Glib::ustring::compose ("%1=%3\n%2=%4", M("TP_VIGNETTING_AMOUNT"), M("TP_VIGNETTING_RADIUS"), (int)amount->getValue(), (int)radius->getValue()));
+ listener->panelChanged (EvVignetting, Glib::ustring::compose ("%1=%5\n%2=%6\n%3=%7\n%4=%8 %9", M("TP_VIGNETTING_AMOUNT"), M("TP_VIGNETTING_RADIUS"), M("TP_VIGNETTING_STRENGTH"), M("TP_VIGNETTING_CENTER"), (int)amount->getValue(), (int)radius->getValue(), (int)strength->getValue(), (int)centerX->getValue(), (int)centerY->getValue()));
}
void Vignetting::setAdjusterBehavior (bool bvadd) {
diff --git a/rtgui/vignetting.h b/rtgui/vignetting.h
index a4fc0dcd3..64d51c75d 100644
--- a/rtgui/vignetting.h
+++ b/rtgui/vignetting.h
@@ -28,6 +28,9 @@ class Vignetting : public Gtk::VBox, public AdjusterListener, public ToolPanel {
protected:
Adjuster* amount;
Adjuster* radius;
+ Adjuster* strength;
+ Adjuster* centerX;
+ Adjuster* centerY;
bool vigAdd;
public: