diff --git a/rtdata/languages/Deutsch b/rtdata/languages/Deutsch
index 1daaa9119..f502e61cc 100644
--- a/rtdata/languages/Deutsch
+++ b/rtdata/languages/Deutsch
@@ -48,6 +48,7 @@
#47 19.11.2017 HDR-Dynamikkompression (TooWaBoo) RT 5.3
#48 13.12.2017 Erweiterung (TooWaBoo) RT 5.3
#49 21.12.2017 Lokaler Kontrast (TooWaBoo) RT 5.3
+#50 07.01.2018 Crop Settings (TooWaBoo) RT 5.3
ABOUT_TAB_BUILD;Version
ABOUT_TAB_CREDITS;Danksagungen
@@ -572,9 +573,9 @@ HISTORY_MSG_281;(Farbanpassungen)\nSättigung schützen\nIntensität
HISTORY_MSG_282;(Farbanpassungen)\nSättigung schützen\nSchwelle
HISTORY_MSG_283;(Farbanpassungen)\nIntensität
HISTORY_MSG_284;(Farbanpassungen)\nSättigung schützen\nAutomatisch
-HISTORY_MSG_285;(Rauschreduzierung)\nMedianmethode
+HISTORY_MSG_285;(Rauschreduzierung)\nMedianfilter - Methode
HISTORY_MSG_286;(Rauschreduzierung)\nMediantyp
-HISTORY_MSG_287;(Rauschreduzierung)\nMedianiterationen
+HISTORY_MSG_287;(Rauschreduzierung)\nMedianfilter - Iterationen
HISTORY_MSG_288;(Weißbild)\nKontrolle zu heller Bereiche
HISTORY_MSG_289;(Weißbild)\nAuto-Kontrolle zu\nheller Bereiche
HISTORY_MSG_290;(Sensor-Matrix)\nSchwarzpunkt - Rot
@@ -1151,7 +1152,7 @@ PREFERENCES_REMEMBERZOOMPAN;Zoom und Bildposition merken
PREFERENCES_REMEMBERZOOMPAN_TOOLTIP;Öffnen eines neuen Bildes mit den Zoom- und Positionswerten\ndes vorangegangenen Bildes.\n\nFunktioniert nur unter folgenden Bedingungen:\nEin-Reitermodus aktiv\n“Demosaikmethode für 100%-Ansicht“ muss auf “Wie im Bild-\nverarbeitungsprofil vorgegeben“ eingestellt sein.
PREFERENCES_RGBDTL_LABEL;Maximale Anzahl Threads für Rauschreduzierung
PREFERENCES_RGBDTL_TOOLTIP;Die Rauschreduzierung benötigt mindestens 128MB RAM für ein 10 Megapixel-Bild oder 512MB für ein 40 Megapixel-Bild, und zusätzlich 128MB RAM pro Thread. Je mehr Threads parallel ablaufen, desto schneller ist die Berechnung. Bei Einstellung "0" werden so viele Threads wie möglich benutzt.
-PREFERENCES_SAVE_TP_OPEN_NOW;Werkzeugstatus jetzt sichern
+PREFERENCES_SAVE_TP_OPEN_NOW;Werkzeugstatus jetzt speichern
PREFERENCES_SELECTFONT;Schriftart
PREFERENCES_SELECTFONT_COLPICKER;Schriftart für die Farbwähler
PREFERENCES_SELECTLANG;Sprache
@@ -1513,7 +1514,7 @@ TP_DIRPYRDENOISE_LUMINANCE_CURVE;Luminanzkurve
TP_DIRPYRDENOISE_LUMINANCE_DETAIL;Luminanzdetails
TP_DIRPYRDENOISE_LUMINANCE_FRAME;Luminanz
TP_DIRPYRDENOISE_LUMINANCE_SMOOTHING;Luminanz
-TP_DIRPYRDENOISE_MAIN_COLORSPACE;Methode
+TP_DIRPYRDENOISE_MAIN_COLORSPACE;Farbraum
TP_DIRPYRDENOISE_MAIN_COLORSPACE_LAB;L*a*b*
TP_DIRPYRDENOISE_MAIN_COLORSPACE_LABEL;Rauschreduzierung
TP_DIRPYRDENOISE_MAIN_COLORSPACE_RGB;RGB
@@ -1524,7 +1525,7 @@ TP_DIRPYRDENOISE_MAIN_MODE;Qualität
TP_DIRPYRDENOISE_MAIN_MODE_AGGRESSIVE;Hoch
TP_DIRPYRDENOISE_MAIN_MODE_CONSERVATIVE;Standard
TP_DIRPYRDENOISE_MAIN_MODE_TOOLTIP;Einstellung der Qualität der Rauschreduzierung.\nDie Einstellung “Hoch“ verbessert die Rausch-\nreduzierung auf Kosten der Verarbeitungszeit.
-TP_DIRPYRDENOISE_MEDIAN_METHOD;Medianmethode
+TP_DIRPYRDENOISE_MEDIAN_METHOD;Methode
TP_DIRPYRDENOISE_MEDIAN_METHOD_CHROMINANCE;Nur Farbe
TP_DIRPYRDENOISE_MEDIAN_METHOD_LAB;L*a*b*
TP_DIRPYRDENOISE_MEDIAN_METHOD_LABEL;Medianfilter
@@ -1532,7 +1533,7 @@ TP_DIRPYRDENOISE_MEDIAN_METHOD_LUMINANCE;Nur Luminanz
TP_DIRPYRDENOISE_MEDIAN_METHOD_RGB;RGB
TP_DIRPYRDENOISE_MEDIAN_METHOD_TOOLTIP;Bei der Methode “Nur Luminanz“ und “L*a*b*“,\nwird der Medianfilter nach den Waveletschritten\nverarbeitet.\nBei RGB wird der Medianfilter am Ende der\nRauschreduzierung verarbeitet.
TP_DIRPYRDENOISE_MEDIAN_METHOD_WEIGHTED;Gewichtet L* (wenig) + a*b* (normal)
-TP_DIRPYRDENOISE_MEDIAN_PASSES;Medianiterationen
+TP_DIRPYRDENOISE_MEDIAN_PASSES;Iterationen
TP_DIRPYRDENOISE_MEDIAN_PASSES_TOOLTIP;Manchmal führt ein kleines 3×3-Fenster mit\nmehreren Iterationen zu besseren Ergebnissen\nals ein 7×7-Fenster mit nur einer Iteration.
TP_DIRPYRDENOISE_MEDIAN_TYPE;Mediantyp
TP_DIRPYRDENOISE_MEDIAN_TYPE_TOOLTIP;Einen Medianfilter mit der gewünschten Fenstergröße auswählen.\nJe größer das Fenster, umso länger dauert die Verarbeitungszeit.\n\n3×3 weich: Nutzt 5 Pixel in einem 3×3-Pixelfenster.\n3×3: Nutzt 9 Pixel in einem 3×3-Pixelfenster.\n5×5 weich: Nutzt 13 Pixel in einem 5×5-Pixelfenster.\n5×5: Nutzt 25 Pixel in einem 5×5-Pixelfenster.\n7×7: Nutzt 49 Pixel in einem 7×7-Pixelfenster.\n9×9: Nutzt 81 Pixel in einem 9×9-Pixelfenster.\n\nManchmal ist das Ergebnis mit einem kleineren Fenster und mehreren Iterationen besser, als mit einem größeren und nur einer Iteration.
@@ -2226,25 +2227,25 @@ ZOOMPANEL_ZOOMOUT;Herauszoomen\nTaste: -
! Untranslated keys follow; remove the ! prefix after an entry is translated.
!!!!!!!!!!!!!!!!!!!!!!!!!
-!BATCHQUEUE_STARTSTOPHINT;Start or stop processing the images in the queue.\n\nShortcut: Ctrl+s
-!GENERAL_SLIDER;Slider
-!HISTORY_MSG_173;NR - Detail recovery
-!HISTORY_MSG_203;NR - Color space
-!HISTORY_MSG_256;NR - Median - Type
-!HISTORY_MSG_297;NR - Mode
-!HISTORY_MSG_METADATA_MODE;Metadata copy mode
-!PREFERENCES_CROP;Crop editing
-!PREFERENCES_CROP_AUTO_FIT;Automatically zoom to fit the crop area
-!PREFERENCES_CROP_GUIDES;Guides shown when not editing the crop
-!PREFERENCES_CROP_GUIDES_FRAME;Frame
-!PREFERENCES_CROP_GUIDES_FULL;Original
-!PREFERENCES_CROP_GUIDES_NONE;None
-!PREFERENCES_EDITORCMDLINE;Custom command line
-!TP_DIRPYRDENOISE_CHROMINANCE_CURVE_TOOLTIP;Increase (multiply) the value of all chrominance sliders.\nThis curve lets you adjust the strength of chromatic noise reduction as a function of chromaticity, for instance to increase the action in areas of low saturation and to decrease it in those of high saturation.
-!TP_DIRPYRDENOISE_LABEL;Noise Reduction
-!TP_METADATA_EDIT;Apply modifications
-!TP_METADATA_MODE;Metadata copy mode
-!TP_METADATA_STRIP;Strip all metadata
-!TP_METADATA_TUNNEL;Copy unchanged
-!TP_RAW_PIXELSHIFTONEGREEN;Use one green instead of average
-!TP_RAW_PIXELSHIFTONEGREEN_TOOLTIP;Use one green instead of averaging two greens for regions without motion.
+BATCHQUEUE_STARTSTOPHINT;Startet / Stoppt die Verarbeitung\nder Warteschlange.\n\nTaste: Strg + s
+GENERAL_SLIDER;Regler
+HISTORY_MSG_173;(Rauschreduzierung)\nLuminanzdetails
+HISTORY_MSG_203;(Rauschreduzierung)\nFarbraum
+HISTORY_MSG_256;(Rauschreduzierung)\nMedianfilter - Mediantyp
+HISTORY_MSG_297;(Rauschreduzierung)\nQualität
+HISTORY_MSG_METADATA_MODE;(Metadaten)\nKopiermodus
+PREFERENCES_CROP;Einstellung des Ausschnittswerkzeuges
+PREFERENCES_CROP_AUTO_FIT;Automatischer Zoom des Ausschnitts
+PREFERENCES_CROP_GUIDES;Hilfslinien anzeigen wenn Ausschnitt nicht verändert wird
+PREFERENCES_CROP_GUIDES_FRAME;Rahmen
+PREFERENCES_CROP_GUIDES_FULL;Vorgabe des Ausschnittswerkzeuges
+PREFERENCES_CROP_GUIDES_NONE;Keine
+PREFERENCES_EDITORCMDLINE;Benutzerdefinierte Befehlszeile
+TP_DIRPYRDENOISE_CHROMINANCE_CURVE_TOOLTIP;Erhöht / Reduziert die Intensität der\nChrominanz-Rauschreduzierung in\nAbhängigkeit der Farbsättigung.
+TP_DIRPYRDENOISE_LABEL;Rauschreduzierung
+TP_METADATA_EDIT;Veränderte Daten
+TP_METADATA_MODE;Kopiermodus
+TP_METADATA_STRIP;Keine
+TP_METADATA_TUNNEL;Unveränderte Daten
+TP_RAW_PIXELSHIFTONEGREEN;Benutze ein Grün
+TP_RAW_PIXELSHIFTONEGREEN_TOOLTIP;Benutze ein Grün anstelle des\nDurchschnitts beider Grüns für\nBereiche ohne Bewegung.
diff --git a/rtdata/themes/TooWaBlue-GTK3-20_.css b/rtdata/themes/TooWaBlue-GTK3-20_.css
index 1e196bff8..af7fb00af 100644
--- a/rtdata/themes/TooWaBlue-GTK3-20_.css
+++ b/rtdata/themes/TooWaBlue-GTK3-20_.css
@@ -2,7 +2,7 @@
This file is part of RawTherapee.
Copyright (c) 2016-2017 TooWaBoo
- Version 2.60
+ Version 2.61
RawTherapee is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -213,10 +213,6 @@ dialog frame > label {
padding-left: 0.91667em;
}
-#BatchQueueButtons {
- margin-top: 0.66667em;
-}
-
frame > label {
margin: 0;
padding: 0.5em 0;
@@ -637,6 +633,11 @@ scale:disabled trough {
background-image: none;
}
+#BatchQueueButtonsMainContainer scale:disabled slider,
+#BatchQueueButtonsMainContainer scale:disabled trough {
+ background-color: shade(@bg-light-grey,.85);
+}
+
/*** end ***************************************************************************************/
/*** Progressbar *******************************************************************************/
@@ -1225,6 +1226,51 @@ popover.background modelbutton:hover {
}
/** end ****************************************************************************************/
+/*** Switch ***********************************************************************************/
+switch {
+ min-height: 2.16667em;
+ min-width: 11em;
+ margin: 0;
+ padding: 0;
+ border-radius: 0.2em;
+ background-image: none;
+ box-shadow: inset 0.08334em 0.08334em rgba(0, 0, 0, 0.08), 0 0.08334em rgba(242, 242, 242, 0.1);
+ border: 0.08334em solid @bg-entry-border;
+ background-color: @bg-scale-entry;
+ margin-bottom: 0.5em;
+}
+
+switch slider {
+ border: 0.08334em solid @bg-entry-border;
+ background-image: linear-gradient(to bottom, shade (@accent-color2,1.15), shade (@accent-color2,.85));
+ border: 0.08334em solid @bg-entry-border;
+ box-shadow: inset 0 0.08334em rgba(242, 242, 242, 0.1);
+ border-radius: 0.2em 0 0 0.2em;
+}
+switch:checked slider{
+ border-radius: 0 0.2em 0.2em 0;
+}
+
+switch:hover slider {
+ background-image: linear-gradient(to bottom, shade (@accent-color2,1.20), shade (@accent-color2,.90));
+}
+
+switch:checked {
+ background-color: rgb(140,0,20);
+ color: @headline-big;
+}
+
+switch:disabled:not(:checked) {
+ box-shadow: none;
+ background-image: none;
+ background-color: shade (@bg-light-grey, .85);
+}
+switch:disabled slider {
+ background-image: linear-gradient(to bottom, rgba(125,125,125,.4), rgba(60,60,60,.4));
+ background-color: shade (@bg-light-grey, .85);
+}
+/** end ****************************************************************************************/
+
/*** Buttons ***********************************************************************************/
button {
min-height: 2.16667em;
@@ -1355,6 +1401,7 @@ button.MiddleH {
/**/
/* Button base format for Toolbox and dialogs */
+#ToolPanelNotebook > stack > box > box > combobox .combo,
dialog button,
#MyExpander button,
#BatchQueueButtonsMainContainer button {
@@ -1371,7 +1418,7 @@ combobox .combo,
dialog combobox .combo,
#ToolPanelNotebook combobox .combo,
#BatchQueueButtonsMainContainer combobox .combo {
- padding: 0 0.208334em;
+ padding: 0 0.26667em;
}
/**/
@@ -1386,6 +1433,7 @@ dialog combobox .combo,
#MyExpander combobox + label */ {
margin-left: 0.16667em;
}
+
#MyExpander label + * > button:not(.flat).Left,
#MyExpander label + combobox:not(:first-child):not(:only-child),
#MyExpander label + button:not(.flat):not(spinbutton) {
@@ -1455,13 +1503,6 @@ messagedialog .dialog-action-area button:not(:only-child):nth-child(2) {
}
/**/
-/* Queue */
-#BatchQueueButtons button {
- min-height: 2.16667em;
- min-width: 10em;
-}
-/**/
-
/* View & Filechooser Buttons */
dialog .view button,
window .view button {
diff --git a/rtengine/alignedbuffer.h b/rtengine/alignedbuffer.h
index 560f0884f..27a376c57 100644
--- a/rtengine/alignedbuffer.h
+++ b/rtengine/alignedbuffer.h
@@ -18,6 +18,8 @@
*/
#ifndef _ALIGNEDBUFFER_
#define _ALIGNEDBUFFER_
+
+#include
#include
#include
diff --git a/rtengine/cJSON.c b/rtengine/cJSON.c
index 8e9cdcccf..263a45113 100644
--- a/rtengine/cJSON.c
+++ b/rtengine/cJSON.c
@@ -38,7 +38,8 @@ const char *cJSON_GetErrorPtr(void) {return ep;}
static int cJSON_strcasecmp(const char *s1,const char *s2)
{
- if (!s1) return (s1==s2)?0:1;if (!s2) return 1;
+ if (!s1) return (s1==s2)?0:1;
+ if (!s2) return 1;
for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0;
return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
}
@@ -107,7 +108,7 @@ static const char *parse_number(cJSON *item,const char *num)
}
n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */
-
+
item->valuedouble=n;
item->valueint=(int)n;
item->type=cJSON_Number;
@@ -156,12 +157,12 @@ static const char *parse_string(cJSON *item,const char *str)
{
const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2;
if (*str!='\"') {ep=str;return 0;} /* not a string! */
-
+
while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */
-
+
out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */
if (!out) return 0;
-
+
ptr=str+1;ptr2=out;
while (*ptr!='\"' && *ptr)
{
@@ -190,7 +191,7 @@ static const char *parse_string(cJSON *item,const char *str)
}
len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;
-
+
#if defined( __GNUC__ ) && __GNUC__ >= 7// silence warning
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
@@ -224,10 +225,10 @@ static const char *parse_string(cJSON *item,const char *str)
static char *print_string_ptr(const char *str)
{
const char *ptr;char *ptr2,*out;int len=0;unsigned char token;
-
+
if (!str) return cJSON_strdup("");
ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;}
-
+
out=(char*)cJSON_malloc(len+3);
if (!out) return 0;
@@ -360,7 +361,7 @@ static char *print_array(cJSON *item,int depth,int fmt)
char *out=0,*ptr,*ret;int len=5;
cJSON *child=item->child;
int numentries=0,i=0,fail=0;
-
+
/* How many entries in the array? */
while (child) numentries++,child=child->next;
/* Explicitly handle numentries==0 */
@@ -383,7 +384,7 @@ static char *print_array(cJSON *item,int depth,int fmt)
if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1;
child=child->next;
}
-
+
/* If we didn't fail, try to malloc the output string */
if (!fail) out=(char*)cJSON_malloc(len);
/* If that fails, we fail. */
@@ -396,7 +397,7 @@ static char *print_array(cJSON *item,int depth,int fmt)
cJSON_free(entries);
return 0;
}
-
+
/* Compose the output array. */
*out='[';
ptr=out+1;*ptr=0;
@@ -408,7 +409,7 @@ static char *print_array(cJSON *item,int depth,int fmt)
}
cJSON_free(entries);
*ptr++=']';*ptr++=0;
- return out;
+ return out;
}
/* Build an object from the text. */
@@ -416,11 +417,11 @@ static const char *parse_object(cJSON *item,const char *value)
{
cJSON *child;
if (*value!='{') {ep=value;return 0;} /* not an object! */
-
+
item->type=cJSON_Object;
value=skip(value+1);
if (*value=='}') return value+1; /* empty array. */
-
+
item->child=child=cJSON_New_Item();
if (!item->child) return 0;
value=skip(parse_string(child,skip(value)));
@@ -429,7 +430,7 @@ static const char *parse_object(cJSON *item,const char *value)
if (*value!=':') {ep=value;return 0;} /* fail! */
value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
if (!value) return 0;
-
+
while (*value==',')
{
cJSON *new_item;
@@ -442,7 +443,7 @@ static const char *parse_object(cJSON *item,const char *value)
value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */
if (!value) return 0;
}
-
+
if (*value=='}') return value+1; /* end of array */
ep=value;return 0; /* malformed. */
}
@@ -483,7 +484,7 @@ static char *print_object(cJSON *item,int depth,int fmt)
if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1;
child=child->next;
}
-
+
/* Try to allocate the output string */
if (!fail) out=(char*)cJSON_malloc(len);
if (!out) fail=1;
@@ -495,7 +496,7 @@ static char *print_object(cJSON *item,int depth,int fmt)
cJSON_free(names);cJSON_free(entries);
return 0;
}
-
+
/* Compose the output: */
*out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0;
for (i=0;ichild;while (c && which>0) c=c->next,which--;if (!c) return 0;
- if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;}
+cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {
+ cJSON *c=array->child;
+ while (c && which>0) c=c->next,which--;
+ if (!c) return 0;
+ if (c->prev) c->prev->next=c->next;
+ if (c->next) c->next->prev=c->prev;
+ if (c==array->child) array->child=c->next;c->prev=c->next=0;
+ return c;
+}
void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));}
cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;}
void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));}
@@ -602,4 +611,4 @@ void cJSON_Minify(char *json)
else *into++=*json++; // All other characters.
}
*into=0; // and null-terminate.
-}
\ No newline at end of file
+}
diff --git a/rtengine/color.cc b/rtengine/color.cc
index dbabb217b..706d0f36d 100644
--- a/rtengine/color.cc
+++ b/rtengine/color.cc
@@ -1786,7 +1786,7 @@ void Color::Lab2XYZ(vfloat L, vfloat a, vfloat b, vfloat &x, vfloat &y, vfloat &
void Color::RGB2Lab(float *R, float *G, float *B, float *L, float *a, float *b, const float wp[3][3], int width)
{
-#ifdef __SSE2__
+#if defined( __SSE2__ ) && defined( __x86_64__ )
vfloat maxvalfv = F2V(MAXVALF);
vfloat c116v = F2V(116.f);
vfloat c5242d88v = F2V(5242.88f);
@@ -1794,7 +1794,7 @@ void Color::RGB2Lab(float *R, float *G, float *B, float *L, float *a, float *b,
vfloat c200v = F2V(200.f);
#endif
int i = 0;
-#ifdef __SSE2__
+#if defined( __SSE2__ ) && defined( __x86_64__ )
for(;i < width - 3; i+=4) {
const vfloat rv = LVFU(R[i]);
const vfloat gv = LVFU(G[i]);
diff --git a/rtengine/dcraw.cc b/rtengine/dcraw.cc
index 75891c589..eee4f34c0 100644
--- a/rtengine/dcraw.cc
+++ b/rtengine/dcraw.cc
@@ -3851,7 +3851,7 @@ float CLASS foveon_avg (short *pix, int range[2], float cfilt)
short * CLASS foveon_make_curve (double max, double mul, double filt)
{
short *curve;
- unsigned i, size;
+ size_t i, size;
double x;
if (!filt) filt = 0.8;
diff --git a/rtengine/image16.cc b/rtengine/image16.cc
index 426fc289c..1c023d181 100644
--- a/rtengine/image16.cc
+++ b/rtengine/image16.cc
@@ -330,50 +330,50 @@ Image16::tofloat()
return imgfloat;
}
-// Parallized transformation; create transform with cmsFLAGS_NOCACHE!
-void Image16::ExecCMSTransform(cmsHTRANSFORM hTransform, const LabImage &labImage, int cx, int cy)
-{
- // LittleCMS cannot parallelize planar Lab float images
- // so build temporary buffers to allow multi processor execution
-#ifdef _OPENMP
- #pragma omp parallel
-#endif
- {
- AlignedBuffer bufferLab(width * 3);
- AlignedBuffer bufferRGB(width * 3);
+// // Parallized transformation; create transform with cmsFLAGS_NOCACHE!
+// void Image16::ExecCMSTransform(cmsHTRANSFORM hTransform, const LabImage &labImage, int cx, int cy)
+// {
+// // LittleCMS cannot parallelize planar Lab float images
+// // so build temporary buffers to allow multi processor execution
+// #ifdef _OPENMP
+// #pragma omp parallel
+// #endif
+// {
+// AlignedBuffer bufferLab(width * 3);
+// AlignedBuffer bufferRGB(width * 3);
-#ifdef _OPENMP
- #pragma omp for schedule(static)
-#endif
+// #ifdef _OPENMP
+// #pragma omp for schedule(static)
+// #endif
- for (int y = cy; y < cy + height; y++)
- {
- unsigned short *pRGB, *pR, *pG, *pB;
- float *pLab, *pL, *pa, *pb;
+// for (int y = cy; y < cy + height; y++)
+// {
+// unsigned short *pRGB, *pR, *pG, *pB;
+// float *pLab, *pL, *pa, *pb;
- pLab= bufferLab.data;
- pL = labImage.L[y] + cx;
- pa = labImage.a[y] + cx;
- pb = labImage.b[y] + cx;
+// pLab= bufferLab.data;
+// pL = labImage.L[y] + cx;
+// pa = labImage.a[y] + cx;
+// pb = labImage.b[y] + cx;
- for (int x = 0; x < width; x++) {
- *(pLab++) = *(pL++) / 327.68f;
- *(pLab++) = *(pa++) / 327.68f;
- *(pLab++) = *(pb++) / 327.68f;
- }
+// for (int x = 0; x < width; x++) {
+// *(pLab++) = *(pL++) / 327.68f;
+// *(pLab++) = *(pa++) / 327.68f;
+// *(pLab++) = *(pb++) / 327.68f;
+// }
- cmsDoTransform (hTransform, bufferLab.data, bufferRGB.data, width);
+// cmsDoTransform (hTransform, bufferLab.data, bufferRGB.data, width);
- pRGB = bufferRGB.data;
- pR = r(y - cy);
- pG = g(y - cy);
- pB = b(y - cy);
+// pRGB = bufferRGB.data;
+// pR = r(y - cy);
+// pG = g(y - cy);
+// pB = b(y - cy);
- for (int x = 0; x < width; x++) {
- *(pR++) = *(pRGB++);
- *(pG++) = *(pRGB++);
- *(pB++) = *(pRGB++);
- }
- } // End of parallelization
- }
-}
+// for (int x = 0; x < width; x++) {
+// *(pR++) = *(pRGB++);
+// *(pG++) = *(pRGB++);
+// *(pB++) = *(pRGB++);
+// }
+// } // End of parallelization
+// }
+// }
diff --git a/rtengine/image16.h b/rtengine/image16.h
index 4d74dfbc4..ee402d556 100644
--- a/rtengine/image16.h
+++ b/rtengine/image16.h
@@ -96,7 +96,7 @@ public:
delete this;
}
- void ExecCMSTransform(cmsHTRANSFORM hTransform, const LabImage &labImage, int cx, int cy);
+ /* void ExecCMSTransform(cmsHTRANSFORM hTransform, const LabImage &labImage, int cx, int cy); */
};
}
diff --git a/rtengine/imagefloat.cc b/rtengine/imagefloat.cc
index d5b17ed80..bfeb85534 100644
--- a/rtengine/imagefloat.cc
+++ b/rtengine/imagefloat.cc
@@ -154,11 +154,25 @@ void Imagefloat::getScanline (int row, unsigned char* buffer, int bps)
int ix = 0;
float* sbuffer = (float*) buffer;
+ // agriggio -- assume the image is normalized to [0, 65535]
for (int i = 0; i < width; i++) {
+ sbuffer[ix++] = r(row, i) / 65535.f;
+ sbuffer[ix++] = g(row, i) / 65535.f;
+ sbuffer[ix++] = b(row, i) / 65535.f;
+ }
+ } else if (bps == 16) {
+ unsigned short *sbuffer = (unsigned short *)buffer;
+ for (int i = 0, ix = 0; i < width; i++) {
sbuffer[ix++] = r(row, i);
sbuffer[ix++] = g(row, i);
sbuffer[ix++] = b(row, i);
}
+ } else if (bps == 8) {
+ for (int i = 0, ix = 0; i < width; i++) {
+ buffer[ix++] = rtengine::uint16ToUint8Rounded(r(row, i));
+ buffer[ix++] = rtengine::uint16ToUint8Rounded(g(row, i));
+ buffer[ix++] = rtengine::uint16ToUint8Rounded(b(row, i));
+ }
}
}
@@ -516,3 +530,51 @@ void Imagefloat::ExecCMSTransform(cmsHTRANSFORM hTransform)
} // End of parallelization
}
}
+
+// Parallized transformation; create transform with cmsFLAGS_NOCACHE!
+void Imagefloat::ExecCMSTransform(cmsHTRANSFORM hTransform, const LabImage &labImage, int cx, int cy)
+{
+ // LittleCMS cannot parallelize planar Lab float images
+ // so build temporary buffers to allow multi processor execution
+#ifdef _OPENMP
+ #pragma omp parallel
+#endif
+ {
+ AlignedBuffer bufferLab(width * 3);
+ AlignedBuffer bufferRGB(width * 3);
+
+#ifdef _OPENMP
+ #pragma omp for schedule(static)
+#endif
+
+ for (int y = cy; y < cy + height; y++)
+ {
+ float *pRGB, *pR, *pG, *pB;
+ float *pLab, *pL, *pa, *pb;
+
+ pLab= bufferLab.data;
+ pL = labImage.L[y] + cx;
+ pa = labImage.a[y] + cx;
+ pb = labImage.b[y] + cx;
+
+ for (int x = 0; x < width; x++) {
+ *(pLab++) = *(pL++) / 327.68f;
+ *(pLab++) = *(pa++) / 327.68f;
+ *(pLab++) = *(pb++) / 327.68f;
+ }
+
+ cmsDoTransform (hTransform, bufferLab.data, bufferRGB.data, width);
+
+ pRGB = bufferRGB.data;
+ pR = r(y - cy);
+ pG = g(y - cy);
+ pB = b(y - cy);
+
+ for (int x = 0; x < width; x++) {
+ *(pR++) = *(pRGB++);
+ *(pG++) = *(pRGB++);
+ *(pB++) = *(pRGB++);
+ }
+ } // End of parallelization
+ }
+}
diff --git a/rtengine/imagefloat.h b/rtengine/imagefloat.h
index 7348588df..753406d25 100644
--- a/rtengine/imagefloat.h
+++ b/rtengine/imagefloat.h
@@ -106,6 +106,7 @@ public:
void calcCroppedHistogram(const ProcParams ¶ms, float scale, LUTu & hist);
void ExecCMSTransform(cmsHTRANSFORM hTransform);
+ void ExecCMSTransform(cmsHTRANSFORM hTransform, const LabImage &labImage, int cx, int cy);
};
}
diff --git a/rtengine/imageio.cc b/rtengine/imageio.cc
index a8fe9d0da..88274cdb4 100644
--- a/rtengine/imageio.cc
+++ b/rtengine/imageio.cc
@@ -75,15 +75,6 @@ FILE* g_fopen_withBinaryAndLock(const Glib::ustring& fname)
return f;
}
-Glib::ustring to_utf8 (const std::string& str)
-{
- try {
- return Glib::locale_to_utf8 (str);
- } catch (Glib::Error&) {
- return Glib::convert_with_fallback (str, "UTF-8", "ISO-8859-1", "?");
- }
-}
-
}
Glib::ustring ImageIO::errorMsg[6] = {"Success", "Cannot read file.", "Invalid header.", "Error while reading header.", "File reading error", "Image format not supported."};
@@ -136,13 +127,19 @@ void ImageIO::setMetadata (const rtexif::TagDirectory* eroot, const rtengine::pr
iptc = iptc_data_new ();
+ const unsigned char utf8Esc[] = {0x1B, '%', 'G'};
+ IptcDataSet * ds = iptc_dataset_new ();
+ iptc_dataset_set_tag (ds, IPTC_RECORD_OBJECT_ENV, IPTC_TAG_CHARACTER_SET);
+ iptc_dataset_set_data (ds, utf8Esc, 3, IPTC_DONT_VALIDATE);
+ iptc_data_add_dataset (iptc, ds);
+ iptc_dataset_unref (ds);
+
for (rtengine::procparams::IPTCPairs::const_iterator i = iptcc.begin(); i != iptcc.end(); ++i) {
if (i->first == "Keywords" && !(i->second.empty())) {
for (unsigned int j = 0; j < i->second.size(); j++) {
IptcDataSet * ds = iptc_dataset_new ();
iptc_dataset_set_tag (ds, IPTC_RECORD_APP_2, IPTC_TAG_KEYWORDS);
- std::string loc = to_utf8(i->second.at(j));
- iptc_dataset_set_data (ds, (unsigned char*)loc.c_str(), min(static_cast(64), loc.size()), IPTC_DONT_VALIDATE);
+ iptc_dataset_set_data (ds, (unsigned char*)i->second.at(j).c_str(), min(static_cast(64), i->second.at(j).bytes()), IPTC_DONT_VALIDATE);
iptc_data_add_dataset (iptc, ds);
iptc_dataset_unref (ds);
}
@@ -152,8 +149,7 @@ void ImageIO::setMetadata (const rtexif::TagDirectory* eroot, const rtengine::pr
for (unsigned int j = 0; j < i->second.size(); j++) {
IptcDataSet * ds = iptc_dataset_new ();
iptc_dataset_set_tag (ds, IPTC_RECORD_APP_2, IPTC_TAG_SUPPL_CATEGORY);
- std::string loc = to_utf8(i->second.at(j));
- iptc_dataset_set_data (ds, (unsigned char*)loc.c_str(), min(static_cast(32), loc.size()), IPTC_DONT_VALIDATE);
+ iptc_dataset_set_data (ds, (unsigned char*)i->second.at(j).c_str(), min(static_cast(32), i->second.at(j).bytes()), IPTC_DONT_VALIDATE);
iptc_data_add_dataset (iptc, ds);
iptc_dataset_unref (ds);
}
@@ -165,8 +161,7 @@ void ImageIO::setMetadata (const rtexif::TagDirectory* eroot, const rtengine::pr
if (i->first == strTags[j].field && !(i->second.empty())) {
IptcDataSet * ds = iptc_dataset_new ();
iptc_dataset_set_tag (ds, IPTC_RECORD_APP_2, strTags[j].tag);
- std::string loc = to_utf8(i->second.at(0));
- iptc_dataset_set_data (ds, (unsigned char*)loc.c_str(), min(strTags[j].size, loc.size()), IPTC_DONT_VALIDATE);
+ iptc_dataset_set_data (ds, (unsigned char*)i->second.at(0).c_str(), min(strTags[j].size, i->second.at(0).bytes()), IPTC_DONT_VALIDATE);
iptc_data_add_dataset (iptc, ds);
iptc_dataset_unref (ds);
}
@@ -1250,13 +1245,13 @@ int ImageIO::saveJPEG (Glib::ustring fname, int quality, int subSamp)
int bytes = 0;
if (!error && (bytes = iptc_jpeg_ps3_save_iptc (nullptr, 0, iptcdata, size, buffer, 65532)) < 0) {
- if (iptcdata) {
- iptc_data_free_buf (iptc, iptcdata);
- }
-
error = true;
}
+ if (iptcdata) {
+ iptc_data_free_buf (iptc, iptcdata);
+ }
+
if (!error) {
jpeg_write_marker(&cinfo, JPEG_APP0 + 13, buffer, bytes);
}
@@ -1341,189 +1336,198 @@ int ImageIO::saveTIFF (Glib::ustring fname, int bps, bool uncompressed)
int lineWidth = width * 3 * bps / 8;
unsigned char* linebuffer = new unsigned char[lineWidth];
-// TODO the following needs to be looked into - do we really need two ways to write a Tiff file ?
- if (exifRoot && uncompressed) {
- FILE *file = g_fopen_withBinaryAndLock (fname);
+ // little hack to get libTiff to use proper byte order (see TIFFClienOpen()):
+ const char *mode = !exifRoot ? "w" : (exifRoot->getOrder() == rtexif::INTEL ? "wl" : "wb");
+#ifdef WIN32
+ FILE *file = g_fopen_withBinaryAndLock (fname);
+ int fileno = _fileno(file);
+ int osfileno = _get_osfhandle(fileno);
+ TIFF* out = TIFFFdOpen (osfileno, fname.c_str(), mode);
+#else
+ TIFF* out = TIFFOpen(fname.c_str(), mode);
+ int fileno = TIFFFileno (out);
+#endif
- if (!file) {
- delete [] linebuffer;
- return IMIO_CANNOTWRITEFILE;
+ if (!out) {
+ delete [] linebuffer;
+ return IMIO_CANNOTWRITEFILE;
+ }
+
+ if (pl) {
+ pl->setProgressStr ("PROGRESSBAR_SAVETIFF");
+ pl->setProgress (0.0);
+ }
+
+ if (exifRoot) {
+ rtexif::TagDirectory* cl = (const_cast (exifRoot))->clone (nullptr);
+
+ // ------------------ remove some unknown top level tags which produce warnings when opening a tiff (might be useless) -----------------
+
+ rtexif::Tag *removeTag = cl->getTag (0x9003);
+
+ if (removeTag) {
+ removeTag->setKeep (false);
}
- if (pl) {
- pl->setProgressStr ("PROGRESSBAR_SAVETIFF");
- pl->setProgress (0.0);
+ removeTag = cl->getTag (0x9211);
+
+ if (removeTag) {
+ removeTag->setKeep (false);
}
- // buffer for the exif and iptc
- unsigned int bufferSize;
- unsigned char* buffer = nullptr; // buffer will be allocated in createTIFFHeader
- unsigned char* iptcdata = nullptr;
- unsigned int iptclen = 0;
+ // ------------------ Apply list of change -----------------
- if (iptc && iptc_data_save (iptc, &iptcdata, &iptclen) && iptcdata) {
+ for (auto currExifChange : exifChange) {
+ cl->applyChange (currExifChange.first, currExifChange.second);
+ }
+
+ rtexif::Tag *tag = cl->getTag (TIFFTAG_EXIFIFD);
+
+ if (tag && tag->isDirectory()) {
+ rtexif::TagDirectory *exif = tag->getDirectory();
+
+ if (exif) {
+ int exif_size = exif->calculateSize();
+ unsigned char *buffer = new unsigned char[exif_size + 8];
+ // TIFFOpen writes out the header and sets file pointer at position 8
+
+ exif->write (8, buffer);
+
+ write (fileno, buffer + 8, exif_size);
+
+ delete [] buffer;
+ // let libtiff know that scanlines or any other following stuff should go
+ // at a different offset:
+ TIFFSetWriteOffset (out, exif_size + 8);
+ TIFFSetField (out, TIFFTAG_EXIFIFD, 8);
+ }
+ }
+
+ //TODO Even though we are saving EXIF IFD - MakerNote still comes out screwed.
+
+ if ((tag = cl->getTag (TIFFTAG_MODEL)) != nullptr) {
+ TIFFSetField (out, TIFFTAG_MODEL, tag->getValue());
+ }
+
+ if ((tag = cl->getTag (TIFFTAG_MAKE)) != nullptr) {
+ TIFFSetField (out, TIFFTAG_MAKE, tag->getValue());
+ }
+
+ if ((tag = cl->getTag (TIFFTAG_DATETIME)) != nullptr) {
+ TIFFSetField (out, TIFFTAG_DATETIME, tag->getValue());
+ }
+
+ if ((tag = cl->getTag (TIFFTAG_ARTIST)) != nullptr) {
+ TIFFSetField (out, TIFFTAG_ARTIST, tag->getValue());
+ }
+
+ if ((tag = cl->getTag (TIFFTAG_COPYRIGHT)) != nullptr) {
+ TIFFSetField (out, TIFFTAG_COPYRIGHT, tag->getValue());
+ }
+
+ delete cl;
+ }
+
+ unsigned char* iptcdata = nullptr;
+ unsigned int iptclen = 0;
+
+ if (iptc && iptc_data_save (iptc, &iptcdata, &iptclen)) {
+ if (iptcdata) {
iptc_data_free_buf (iptc, iptcdata);
iptcdata = nullptr;
}
+ }
- int size = rtexif::ExifManager::createTIFFHeader (exifRoot, exifChange, width, height, bps, profileData, profileLength, (char*)iptcdata, iptclen, buffer, bufferSize);
-
- if (iptcdata) {
- iptc_data_free_buf (iptc, iptcdata);
+ if (iptcdata) {
+ rtexif::Tag* iptcTag = new rtexif::Tag (nullptr, rtexif::lookupAttrib (rtexif::ifdAttribs, "IPTCData"));
+ iptcTag->initLongArray((char*)iptcdata, iptclen);
+#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
+ bool needsReverse = exifRoot && exifRoot->getOrder() == rtexif::MOTOROLA;
+#else
+ bool needsReverse = exifRoot && exifRoot->getOrder() == rtexif::INTEL;
+#endif
+ if (needsReverse) {
+ unsigned char *ptr = iptcTag->getValue();
+ for (int a = 0; a < iptcTag->getCount(); ++a) {
+ unsigned char cc;
+ cc = ptr[3];
+ ptr[3] = ptr[0];
+ ptr[0] = cc;
+ cc = ptr[2];
+ ptr[2] = ptr[1];
+ ptr[1] = cc;
+ ptr += 4;
+ }
}
+ TIFFSetField (out, TIFFTAG_RICHTIFFIPTC, iptcTag->getCount(), (long*)iptcTag->getValue());
+ iptc_data_free_buf (iptc, iptcdata);
+ }
- // The maximum lenght is strangely not the same than for the JPEG file...
- // Which maximum length is the good one ?
- if (size > 0 && size <= static_cast(bufferSize)) {
- fwrite (buffer, size, 1, file);
- }
+ TIFFSetField (out, TIFFTAG_SOFTWARE, "RawTherapee " RTVERSION);
+ TIFFSetField (out, TIFFTAG_IMAGEWIDTH, width);
+ TIFFSetField (out, TIFFTAG_IMAGELENGTH, height);
+ TIFFSetField (out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
+ TIFFSetField (out, TIFFTAG_SAMPLESPERPIXEL, 3);
+ TIFFSetField (out, TIFFTAG_ROWSPERSTRIP, height);
+ TIFFSetField (out, TIFFTAG_BITSPERSAMPLE, bps);
+ TIFFSetField (out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+ TIFFSetField (out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
+ TIFFSetField (out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
+ TIFFSetField (out, TIFFTAG_COMPRESSION, uncompressed ? COMPRESSION_NONE : COMPRESSION_DEFLATE);
+ TIFFSetField (out, TIFFTAG_SAMPLEFORMAT, bps == 32 ? SAMPLEFORMAT_IEEEFP : SAMPLEFORMAT_UINT);
+
+ if (!uncompressed) {
+ TIFFSetField (out, TIFFTAG_PREDICTOR, bps == 32 ? PREDICTOR_FLOATINGPOINT : PREDICTOR_HORIZONTAL);
+ }
+
+ if (profileData) {
+ TIFFSetField (out, TIFFTAG_ICCPROFILE, profileLength, profileData);
+ }
#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
- bool needsReverse = bps == 16 && exifRoot->getOrder() == rtexif::MOTOROLA;
+ bool needsReverse = (bps == 16 || bps == 32) && exifRoot->getOrder() == rtexif::MOTOROLA;
#else
- bool needsReverse = bps == 16 && exifRoot->getOrder() == rtexif::INTEL;
+ bool needsReverse = (bps == 16 || bps == 32) && exifRoot->getOrder() == rtexif::INTEL;
#endif
- for (int i = 0; i < height; i++) {
- getScanline (i, linebuffer, bps);
+ for (int row = 0; row < height; row++) {
+ getScanline (row, linebuffer, bps);
- if (needsReverse)
+ if (needsReverse) {
+ if (bps == 16) {
for (int i = 0; i < lineWidth; i += 2) {
char c = linebuffer[i];
linebuffer[i] = linebuffer[i + 1];
linebuffer[i + 1] = c;
}
-
- fwrite (linebuffer, lineWidth, 1, file);
-
- if (pl && !(i % 100)) {
- pl->setProgress ((double)(i + 1) / height);
+ } else {
+ for (int i = 0; i < lineWidth; i += 4) {
+ std::swap(linebuffer[i], linebuffer[i+3]);
+ std::swap(linebuffer[i+1], linebuffer[i+2]);
+ }
}
}
- if(buffer) {
- delete [] buffer;
- }
-
- if (ferror(file)) {
- writeOk = false;
- }
-
- fclose (file);
- } else {
- // little hack to get libTiff to use proper byte order (see TIFFClienOpen()):
- const char *mode = !exifRoot ? "w" : (exifRoot->getOrder() == rtexif::INTEL ? "wl" : "wb");
-#ifdef WIN32
- FILE *file = g_fopen_withBinaryAndLock (fname);
- int fileno = _fileno(file);
- int osfileno = _get_osfhandle(fileno);
- TIFF* out = TIFFFdOpen (osfileno, fname.c_str(), mode);
-#else
- TIFF* out = TIFFOpen(fname.c_str(), mode);
- int fileno = TIFFFileno (out);
-#endif
-
- if (!out) {
+ if (TIFFWriteScanline (out, linebuffer, row, 0) < 0) {
+ TIFFClose (out);
delete [] linebuffer;
return IMIO_CANNOTWRITEFILE;
}
- if (pl) {
- pl->setProgressStr ("PROGRESSBAR_SAVETIFF");
- pl->setProgress (0.0);
+ if (pl && !(row % 100)) {
+ pl->setProgress ((double)(row + 1) / height);
}
-
- if (exifRoot) {
- rtexif::Tag *tag = exifRoot->getTag (TIFFTAG_EXIFIFD);
-
- if (tag && tag->isDirectory()) {
- rtexif::TagDirectory *exif = tag->getDirectory();
-
- if (exif) {
- int exif_size = exif->calculateSize();
- unsigned char *buffer = new unsigned char[exif_size + 8];
- // TIFFOpen writes out the header and sets file pointer at position 8
-
- exif->write (8, buffer);
-
- write (fileno, buffer + 8, exif_size);
-
- delete [] buffer;
- // let libtiff know that scanlines or any other following stuff should go
- // at a different offset:
- TIFFSetWriteOffset (out, exif_size + 8);
- TIFFSetField (out, TIFFTAG_EXIFIFD, 8);
- }
- }
-
-//TODO Even though we are saving EXIF IFD - MakerNote still comes out screwed.
-
- if ((tag = exifRoot->getTag (TIFFTAG_MODEL)) != nullptr) {
- TIFFSetField (out, TIFFTAG_MODEL, tag->getValue());
- }
-
- if ((tag = exifRoot->getTag (TIFFTAG_MAKE)) != nullptr) {
- TIFFSetField (out, TIFFTAG_MAKE, tag->getValue());
- }
-
- if ((tag = exifRoot->getTag (TIFFTAG_DATETIME)) != nullptr) {
- TIFFSetField (out, TIFFTAG_DATETIME, tag->getValue());
- }
-
- if ((tag = exifRoot->getTag (TIFFTAG_ARTIST)) != nullptr) {
- TIFFSetField (out, TIFFTAG_ARTIST, tag->getValue());
- }
-
- if ((tag = exifRoot->getTag (TIFFTAG_COPYRIGHT)) != nullptr) {
- TIFFSetField (out, TIFFTAG_COPYRIGHT, tag->getValue());
- }
-
- }
-
- TIFFSetField (out, TIFFTAG_SOFTWARE, "RawTherapee " RTVERSION);
- TIFFSetField (out, TIFFTAG_IMAGEWIDTH, width);
- TIFFSetField (out, TIFFTAG_IMAGELENGTH, height);
- TIFFSetField (out, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
- TIFFSetField (out, TIFFTAG_SAMPLESPERPIXEL, 3);
- TIFFSetField (out, TIFFTAG_ROWSPERSTRIP, height);
- TIFFSetField (out, TIFFTAG_BITSPERSAMPLE, bps);
- TIFFSetField (out, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
- TIFFSetField (out, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
- TIFFSetField (out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
- TIFFSetField (out, TIFFTAG_COMPRESSION, uncompressed ? COMPRESSION_NONE : COMPRESSION_DEFLATE);
-
- if (!uncompressed) {
- TIFFSetField (out, TIFFTAG_PREDICTOR, PREDICTOR_NONE);
- }
-
- if (profileData) {
- TIFFSetField (out, TIFFTAG_ICCPROFILE, profileLength, profileData);
- }
-
- for (int row = 0; row < height; row++) {
- getScanline (row, linebuffer, bps);
-
- if (TIFFWriteScanline (out, linebuffer, row, 0) < 0) {
- TIFFClose (out);
- delete [] linebuffer;
- return IMIO_CANNOTWRITEFILE;
- }
-
- if (pl && !(row % 100)) {
- pl->setProgress ((double)(row + 1) / height);
- }
- }
-
- if (TIFFFlush(out) != 1) {
- writeOk = false;
- }
-
- TIFFClose (out);
-#ifdef WIN32
- fclose (file);
-#endif
}
+ if (TIFFFlush(out) != 1) {
+ writeOk = false;
+ }
+
+ TIFFClose (out);
+#ifdef WIN32
+ fclose (file);
+#endif
+
delete [] linebuffer;
if (pl) {
diff --git a/rtengine/improccoordinator.cc b/rtengine/improccoordinator.cc
index 6403612d6..97e356f18 100644
--- a/rtengine/improccoordinator.cc
+++ b/rtengine/improccoordinator.cc
@@ -1274,21 +1274,18 @@ void ImProcCoordinator::saveInputICCReference (const Glib::ustring& fname, bool
}
}
- Image16* im16 = im->to16();
- delete im;
-
int imw, imh;
double tmpScale = ipf.resizeScale (¶ms, fW, fH, imw, imh);
if (tmpScale != 1.0) {
- Image16* tempImage = new Image16 (imw, imh);
- ipf.resize (im16, tempImage, tmpScale);
- delete im16;
- im16 = tempImage;
+ Imagefloat* tempImage = new Imagefloat (imw, imh);
+ ipf.resize (im, tempImage, tmpScale);
+ delete im;
+ im = tempImage;
}
- im16->saveTIFF (fname, 16, true);
- delete im16;
+ im->saveTIFF (fname, 16, true);
+ delete im;
if (plistener) {
plistener->setProgressState (false);
diff --git a/rtengine/improcfun.cc b/rtengine/improcfun.cc
index 052f13d08..00c349323 100644
--- a/rtengine/improcfun.cc
+++ b/rtengine/improcfun.cc
@@ -54,7 +54,7 @@ using namespace rtengine;
// begin of helper function for rgbProc()
void shadowToneCurve(const LUTf &shtonecurve, float *rtemp, float *gtemp, float *btemp, int istart, int tH, int jstart, int tW, int tileSize) {
-#ifdef __SSE2__
+#if defined( __SSE2__ ) && defined( __x86_64__ )
vfloat cr = F2V(0.299f);
vfloat cg = F2V(0.587f);
vfloat cb = F2V(0.114f);
@@ -62,7 +62,7 @@ void shadowToneCurve(const LUTf &shtonecurve, float *rtemp, float *gtemp, float
for (int i = istart, ti = 0; i < tH; i++, ti++) {
int j = jstart, tj = 0;
-#ifdef __SSE2__
+#if defined( __SSE2__ ) && defined( __x86_64__ )
for (; j < tW - 3; j+=4, tj+=4) {
vfloat rv = LVF(rtemp[ti * tileSize + tj]);
@@ -95,14 +95,14 @@ void shadowToneCurve(const LUTf &shtonecurve, float *rtemp, float *gtemp, float
void highlightToneCurve(const LUTf &hltonecurve, float *rtemp, float *gtemp, float *btemp, int istart, int tH, int jstart, int tW, int tileSize, float exp_scale, float comp, float hlrange) {
-#ifdef __SSE2__
+#if defined( __SSE2__ ) && defined( __x86_64__ )
vfloat threev = F2V(3.f);
vfloat maxvalfv = F2V(MAXVALF);
#endif
for (int i = istart, ti = 0; i < tH; i++, ti++) {
int j = jstart, tj = 0;
-#ifdef __SSE2__
+#if defined( __SSE2__ ) && defined( __x86_64__ )
for (; j < tW - 3; j+=4, tj+=4) {
vfloat rv = LVF(rtemp[ti * tileSize + tj]);
@@ -159,7 +159,7 @@ void proPhotoBlue(float *rtemp, float *gtemp, float *btemp, int istart, int tH,
// this is a hack to avoid the blue=>black bug (Issue 2141)
for (int i = istart, ti = 0; i < tH; i++, ti++) {
int j = jstart, tj = 0;
-#ifdef __SSE2__
+#if defined( __SSE2__ ) && defined( __x86_64__ )
for (; j < tW - 3; j+=4, tj+=4) {
vfloat rv = LVF(rtemp[ti * tileSize + tj]);
vfloat gv = LVF(gtemp[ti * tileSize + tj]);
@@ -2170,7 +2170,9 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw
const float pow1 = pow_F ( 1.64f - pow_F ( 0.29f, n ), 0.73f );
float nj, nbbj, ncbj, czj, awj, flj;
Ciecam02::initcam2float (gamu, yb2, pilotout, f2, la2, xw2, yw2, zw2, nj, dj, nbbj, ncbj, czj, awj, flj);
+#ifdef __SSE2__
const float reccmcz = 1.f / (c2 * czj);
+#endif
const float pow1n = pow_F ( 1.64f - pow_F ( 0.29f, nj ), 0.73f );
const float epsil = 0.0001f;
@@ -2735,7 +2737,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw
Ciecam02::jch2xyz_ciecam02float ( xx, yy, zz,
J, C, h,
xw2, yw2, zw2,
- f2, c2, nc2, gamu, pow1n, nbbj, ncbj, flj, czj, dj, awj);
+ c2, nc2, gamu, pow1n, nbbj, ncbj, flj, czj, dj, awj);
float x, y, z;
x = xx * 655.35f;
y = yy * 655.35f;
@@ -2746,10 +2748,9 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw
// gamut control in Lab mode; I must study how to do with cIECAM only
if (gamu == 1) {
- float HH, Lprov1, Chprov1;
+ float Lprov1, Chprov1;
Lprov1 = Ll / 327.68f;
Chprov1 = sqrtf (SQR (aa) + SQR (bb)) / 327.68f;
- HH = xatan2f (bb, aa);
float2 sincosval;
if (Chprov1 == 0.0f) {
@@ -3079,7 +3080,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int pW, int pw
Ciecam02::jch2xyz_ciecam02float ( xx, yy, zz,
ncie->J_p[i][j], ncie_C_p, ncie->h_p[i][j],
xw2, yw2, zw2,
- f2, c2, nc2, gamu, pow1n, nbbj, ncbj, flj, czj, dj, awj);
+ c2, nc2, gamu, pow1n, nbbj, ncbj, flj, czj, dj, awj);
float x = (float)xx * 655.35f;
float y = (float)yy * 655.35f;
float z = (float)zz * 655.35f;
@@ -3762,7 +3763,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer
} else {
for (int i = istart, ti = 0; i < tH; i++, ti++) {
int j = jstart, tj = 0;
-#ifdef __SSE2__
+#if defined( __SSE2__ ) && defined( __x86_64__ )
for (; j < tW - 3; j+=4, tj+=4) {
//brightness/contrast
STVF(rtemp[ti * TS + tj], tonecurve(LVF(rtemp[ti * TS + tj])));
diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h
index 1adc2fc5f..c1b175ab6 100644
--- a/rtengine/improcfun.h
+++ b/rtengine/improcfun.h
@@ -239,9 +239,9 @@ public:
void transform (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const FramesMetaData *metadata, int rawRotationDeg, bool fullImage);
float resizeScale (const ProcParams* params, int fw, int fh, int &imw, int &imh);
void lab2monitorRgb (LabImage* lab, Image8* image);
- void resize (Image16* src, Image16* dst, float dScale);
+ void resize (Imagefloat* src, Imagefloat* dst, float dScale);
void Lanczos (const LabImage* src, LabImage* dst, float scale);
- void Lanczos (const Image16* src, Image16* dst, float scale);
+ void Lanczos (const Imagefloat* src, Imagefloat* dst, float scale);
void deconvsharpening (float** luminance, float** buffer, int W, int H, const SharpeningParams &sharpenParam);
void MLsharpen (LabImage* lab);// Manuel's clarity / sharpening
@@ -349,7 +349,7 @@ public:
void colorToningLabGrid(LabImage *lab);
Image8* lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm);
- Image16* lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, GammaValues *ga = nullptr);
+ Imagefloat* lab2rgbOut (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, GammaValues *ga = nullptr);
// CieImage *ciec;
bool transCoord (int W, int H, int x, int y, int w, int h, int& xv, int& yv, int& wv, int& hv, double ascaleDef = -1, const LensCorrection *pLCPMap = nullptr);
diff --git a/rtengine/iplab2rgb.cc b/rtengine/iplab2rgb.cc
index abef0a878..ba2fe6ffb 100644
--- a/rtengine/iplab2rgb.cc
+++ b/rtengine/iplab2rgb.cc
@@ -262,7 +262,7 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch,
* If a custom gamma profile can be created, divide by 327.68, convert to xyz and apply the custom gamma transform
* otherwise divide by 327.68, convert to xyz and apply the sRGB transform, before converting with gamma2curve
*/
-Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, GammaValues *ga)
+Imagefloat* ImProcFunctions::lab2rgbOut (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, GammaValues *ga)
{
if (cx < 0) {
@@ -281,7 +281,7 @@ Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int
ch = lab->H - cy;
}
- Image16* image = new Image16 (cw, ch);
+ Imagefloat* image = new Imagefloat (cw, ch);
cmsHPROFILE oprof = nullptr;
if (ga) {
@@ -300,11 +300,12 @@ Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int
}
lcmsMutex->lock ();
cmsHPROFILE iprof = cmsCreateLab4Profile(nullptr);
- cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_Lab_FLT, oprof, TYPE_RGB_16, icm.outputIntent, flags);
+ cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_Lab_FLT, oprof, TYPE_RGB_FLT, icm.outputIntent, flags);
lcmsMutex->unlock ();
image->ExecCMSTransform(hTransform, *lab, cx, cy);
cmsDeleteTransform(hTransform);
+ image->normalizeFloatTo65535();
} else {
#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic,16) if (multiThread)
@@ -329,9 +330,9 @@ Image16* ImProcFunctions::lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int
Color::xyz2srgb(x_, y_, z_, R, G, B);
- image->r(i - cy, j - cx) = (int)Color::gamma2curve[CLIP(R)];
- image->g(i - cy, j - cx) = (int)Color::gamma2curve[CLIP(G)];
- image->b(i - cy, j - cx) = (int)Color::gamma2curve[CLIP(B)];
+ image->r(i - cy, j - cx) = Color::gamma2curve[CLIP(R)];
+ image->g(i - cy, j - cx) = Color::gamma2curve[CLIP(G)];
+ image->b(i - cy, j - cx) = Color::gamma2curve[CLIP(B)];
}
}
}
diff --git a/rtengine/ipresize.cc b/rtengine/ipresize.cc
index 644e180c7..1a48e5c43 100644
--- a/rtengine/ipresize.cc
+++ b/rtengine/ipresize.cc
@@ -46,7 +46,7 @@ static inline float Lanc (float x, float a)
}
}
-void ImProcFunctions::Lanczos (const Image16* src, Image16* dst, float scale)
+void ImProcFunctions::Lanczos (const Imagefloat* src, Imagefloat* dst, float scale)
{
const float delta = 1.0f / scale;
@@ -159,9 +159,9 @@ void ImProcFunctions::Lanczos (const Image16* src, Image16* dst, float scale)
b += wh[k] * lb[jj];
}
- dst->r (i, j) = CLIP (static_cast (r));
- dst->g (i, j) = CLIP (static_cast (g));
- dst->b (i, j) = CLIP (static_cast (b));
+ dst->r (i, j) = CLIP (r);//static_cast (r));
+ dst->g (i, j) = CLIP (g);//static_cast (g));
+ dst->b (i, j) = CLIP (b);//static_cast (b));
}
}
@@ -396,7 +396,7 @@ float ImProcFunctions::resizeScale (const ProcParams* params, int fw, int fh, in
return (float)dScale;
}
-void ImProcFunctions::resize (Image16* src, Image16* dst, float dScale)
+void ImProcFunctions::resize (Imagefloat* src, Imagefloat* dst, float dScale)
{
#ifdef PROFILE
time_t t1 = clock();
diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc
index 4b8ccf71a..80041e706 100644
--- a/rtengine/procparams.cc
+++ b/rtengine/procparams.cc
@@ -1478,7 +1478,7 @@ bool EPDParams::operator !=(const EPDParams& other) const
FattalToneMappingParams::FattalToneMappingParams() :
enabled(false),
threshold(0),
- amount(1)
+ amount(30)
{
}
diff --git a/rtengine/rt_math.h b/rtengine/rt_math.h
index 4bdfe6f06..787e2e63f 100644
--- a/rtengine/rt_math.h
+++ b/rtengine/rt_math.h
@@ -25,6 +25,8 @@ constexpr double RT_NAN = std::numeric_limits::quiet_NaN();
constexpr float RT_PI_F = RT_PI;
constexpr float RT_PI_F_2 = RT_PI_2;
constexpr float RT_PI_F_180 = RT_PI_180;
+constexpr float RT_1_PI_F = RT_1_PI;
+constexpr float RT_2_PI_F = RT_2_PI;
constexpr float RT_INFINITY_F = std::numeric_limits::infinity();
constexpr float RT_NAN_F = std::numeric_limits::quiet_NaN();
diff --git a/rtengine/rtengine.h b/rtengine/rtengine.h
index 8e24b7bb9..873cfd9bc 100644
--- a/rtengine/rtengine.h
+++ b/rtengine/rtengine.h
@@ -534,7 +534,7 @@ public:
* @param errorCode is the error code if an error occured (e.g. the input image could not be loaded etc.)
* @param pl is an optional ProgressListener if you want to keep track of the progress
* @return the resulting image, with the output profile applied, exif and iptc data set. You have to save it or you can access the pixel data directly. */
-IImage16* processImage (ProcessingJob* job, int& errorCode, ProgressListener* pl = nullptr, bool flush = false);
+IImagefloat* processImage (ProcessingJob* job, int& errorCode, ProgressListener* pl = nullptr, bool flush = false);
/** This class is used to control the batch processing. The class implementing this interface will be called when the full processing of an
* image is ready and the next job to process is needed. */
@@ -545,7 +545,7 @@ public:
* there is no jobs left.
* @param img is the result of the last ProcessingJob
* @return the next ProcessingJob to process */
- virtual ProcessingJob* imageReady (IImage16* img) = 0;
+ virtual ProcessingJob* imageReady (IImagefloat* img) = 0;
virtual void error (Glib::ustring message) = 0;
};
/** This function performs all the image processinf steps corresponding to the given ProcessingJob. It runs in the background, thus it returns immediately,
diff --git a/rtengine/simpleprocess.cc b/rtengine/simpleprocess.cc
index 9f79153f7..e74c32a35 100644
--- a/rtengine/simpleprocess.cc
+++ b/rtengine/simpleprocess.cc
@@ -65,7 +65,7 @@ public:
{
}
- Image16 *operator()()
+ Imagefloat *operator()()
{
if (!job->fast) {
return normal_pipeline();
@@ -75,7 +75,7 @@ public:
}
private:
- Image16 *normal_pipeline()
+ Imagefloat *normal_pipeline()
{
if (!stage_init()) {
return nullptr;
@@ -86,7 +86,7 @@ private:
return stage_finish();
}
- Image16 *fast_pipeline()
+ Imagefloat *fast_pipeline()
{
if (!job->pparams.resize.enabled) {
return normal_pipeline();
@@ -832,7 +832,7 @@ private:
}
}
- Image16 *stage_finish()
+ Imagefloat *stage_finish()
{
procparams::ProcParams& params = job->pparams;
//ImProcFunctions ipf (¶ms, true);
@@ -1228,7 +1228,7 @@ private:
}
}
- Image16* readyImg = nullptr;
+ Imagefloat* readyImg = nullptr;
cmsHPROFILE jprof = nullptr;
bool customGamma = false;
bool useLCMS = false;
@@ -1238,7 +1238,7 @@ private:
GammaValues ga;
// if(params.blackwhite.enabled) params.toneCurve.hrenabled=false;
- readyImg = ipf.lab2rgb16 (labView, cx, cy, cw, ch, params.icm, &ga);
+ readyImg = ipf.lab2rgbOut (labView, cx, cy, cw, ch, params.icm, &ga);
customGamma = true;
//or selected Free gamma
@@ -1252,7 +1252,7 @@ private:
// if Default gamma mode: we use the profile selected in the "Output profile" combobox;
// gamma come from the selected profile, otherwise it comes from "Free gamma" tool
- readyImg = ipf.lab2rgb16 (labView, cx, cy, cw, ch, params.icm);
+ readyImg = ipf.lab2rgbOut (labView, cx, cy, cw, ch, params.icm);
if (settings->verbose) {
printf ("Output profile_: \"%s\"\n", params.icm.output.c_str());
@@ -1282,7 +1282,7 @@ private:
}
if (tmpScale != 1.0 && params.resize.method == "Nearest") { // resize rgb data (gamma applied)
- Image16* tempImage = new Image16 (imw, imh);
+ Imagefloat* tempImage = new Imagefloat (imw, imh);
ipf.resize (readyImg, tempImage, tmpScale);
delete readyImg;
readyImg = tempImage;
@@ -1568,7 +1568,7 @@ private:
} // namespace
-IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* pl, bool flush)
+IImagefloat* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* pl, bool flush)
{
ImageProcessor proc (pjob, errorCode, pl, flush);
return proc();
@@ -1581,7 +1581,7 @@ void batchProcessingThread (ProcessingJob* job, BatchProcessingListener* bpl)
while (currentJob) {
int errorCode;
- IImage16* img = processImage (currentJob, errorCode, bpl, true);
+ IImagefloat* img = processImage (currentJob, errorCode, bpl, true);
if (errorCode) {
bpl->error (M ("MAIN_MSG_CANNOTLOAD"));
diff --git a/rtengine/sleef.c b/rtengine/sleef.c
index 17dfccc0f..f03c9f1b3 100644
--- a/rtengine/sleef.c
+++ b/rtengine/sleef.c
@@ -923,9 +923,8 @@ __inline float mulsignf(float x, float y) {
return intBitsToFloat(floatToRawIntBits(x) ^ (floatToRawIntBits(y) & (1 << 31)));
}
-__inline float signf(float d) { return mulsignf(1, d); }
+__inline float signf(float d) { return copysign(1, d); }
__inline float mlaf(float x, float y, float z) { return x * y + z; }
-__inline float xrintf(float x) { return x < 0 ? (int)(x - 0.5f) : (int)(x + 0.5f); }
__inline int xisnanf(float x) { return x != x; }
__inline int xisinff(float x) { return x == rtengine::RT_INFINITY_F || x == -rtengine::RT_INFINITY_F; }
@@ -984,7 +983,7 @@ __inline float xsinf(float d) {
int q;
float u, s;
- q = (int)xrintf(d * (float)rtengine::RT_1_PI);
+ q = rint(d * rtengine::RT_1_PI_F);
d = mlaf(q, -PI4_Af*4, d);
d = mlaf(q, -PI4_Bf*4, d);
@@ -1009,7 +1008,7 @@ __inline float xcosf(float d) {
int q;
float u, s;
- q = 1 + 2*(int)xrintf(d * (float)rtengine::RT_1_PI - 0.5f);
+ q = 1 + 2*rint(d * rtengine::RT_1_PI_F - 0.5f);
d = mlaf(q, -PI4_Af*2, d);
d = mlaf(q, -PI4_Bf*2, d);
@@ -1035,7 +1034,7 @@ __inline float2 xsincosf(float d) {
float u, s, t;
float2 r;
- q = (int)rint(d * ((float)(2 * rtengine::RT_1_PI)));
+ q = rint(d * rtengine::RT_2_PI_F);
s = d;
@@ -1076,7 +1075,7 @@ __inline float xtanf(float d) {
int q;
float u, s, x;
- q = (int)xrintf(d * (float)(2 * rtengine::RT_1_PI));
+ q = rint(d * (float)(2 * rtengine::RT_1_PI));
x = d;
@@ -1202,7 +1201,7 @@ __inline float xlogf(float d) {
__inline float xexpf(float d) {
if(d<=-104.0f) return 0.0f;
- int q = (int)xrintf(d * R_LN2f);
+ int q = rint(d * R_LN2f);
float s, u;
s = mlaf(q, -L2Uf, d);
diff --git a/rtengine/tmo_fattal02.cc b/rtengine/tmo_fattal02.cc
index 645451905..7ef490807 100644
--- a/rtengine/tmo_fattal02.cc
+++ b/rtengine/tmo_fattal02.cc
@@ -1121,15 +1121,37 @@ void ImProcFunctions::ToneMapFattal02 (Imagefloat *rgb)
const float min_luminance = 1.f;
TMatrix ws = ICCStore::getInstance()->workingSpaceMatrix (params->icm.working);
-#ifdef _OPENMP
- #pragma omp parallel for if (multiThread)
-#endif
+ float max_Y = 0.f;
+ int max_x = 0, max_y = 0;
+#ifdef _OPENMP
+ #pragma omp parallel if (multiThread)
+#endif
+{
+ float max_YThr = 0.f;
+ int max_xThr = 0, max_yThr = 0;
+#ifdef _OPENMP
+ #pragma omp for schedule(dynamic,16) nowait
+#endif
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
Yr (x, y) = std::max (luminance (rgb->r (y, x), rgb->g (y, x), rgb->b (y, x), ws), min_luminance); // clip really black pixels
+ if (Yr(x, y) > max_YThr) {
+ max_YThr = Yr(x, y);
+ max_xThr = x;
+ max_yThr = y;
+ }
}
}
+#ifdef _OPENMP
+#pragma omp critical
+#endif
+ if (max_YThr > max_Y) {
+ max_Y = max_YThr;
+ max_x = max_xThr;
+ max_y = max_yThr;
+ }
+}
// median filter on the deep shadows, to avoid boosting noise
// because w2 >= w and h2 >= h, we can use the L buffer as temporary buffer for Median_Denoise()
@@ -1170,9 +1192,11 @@ void ImProcFunctions::ToneMapFattal02 (Imagefloat *rgb)
const float hr = float(h2) / float(h);
const float wr = float(w2) / float(w);
+
+ const float scale = 65535.f / std::max(L(max_x * wr + 1, max_y * hr + 1), epsilon) * (65535.f / Yr(max_x, max_y));
#ifdef _OPENMP
- #pragma omp parallel for if(multiThread)
+ #pragma omp parallel for schedule(dynamic,16) if(multiThread)
#endif
for (int y = 0; y < h; y++) {
int yy = y * hr + 1;
@@ -1181,7 +1205,7 @@ void ImProcFunctions::ToneMapFattal02 (Imagefloat *rgb)
int xx = x * wr + 1;
float Y = Yr (x, y);
- float l = std::max (L (xx, yy), epsilon) * (65535.f / Y);
+ float l = std::max (L (xx, yy), epsilon) * (scale / Y);
rgb->r (y, x) = std::max (rgb->r (y, x), 0.f) * l;
rgb->g (y, x) = std::max (rgb->g (y, x), 0.f) * l;
rgb->b (y, x) = std::max (rgb->b (y, x), 0.f) * l;
diff --git a/rtexif/rtexif.cc b/rtexif/rtexif.cc
index a90ec18b5..6cb1e7ff8 100644
--- a/rtexif/rtexif.cc
+++ b/rtexif/rtexif.cc
@@ -739,11 +739,12 @@ void TagDirectory::applyChange (std::string name, Glib::ustring value)
} else {
const TagAttrib* attrib = nullptr;
- for (int i = 0; attribs[i].ignore != -1; i++)
+ for (int i = 0; attribs[i].ignore != -1; i++) {
if (!strcmp (attribs[i].name, fseg.c_str())) {
attrib = &attribs[i];
break;
}
+ }
if (attrib) {
Tag* nt = new Tag (this, attrib);
@@ -1663,15 +1664,11 @@ void Tag::toString (char* buffer, int ofs) const
return;
}
- size_t maxcount = 4;
-
- if (count < 4) {
- maxcount = count;
- }
+ size_t maxcount = rtengine::min(count, 10);
strcpy (buffer, "");
- for (ssize_t i = 0; i < std::min(maxcount, valuesize - ofs); i++) {
+ for (ssize_t i = 0; i < rtengine::min(maxcount, valuesize - ofs); i++) {
if (i > 0) {
strcat (buffer, ", ");
}
@@ -1931,22 +1928,48 @@ void Tag::initInt (int data, TagType t, int cnt)
setInt (data, 0, t);
}
+void Tag::swapByteOrder2(char *buffer, int count)
+{
+ char* ptr = buffer;
+ for (int i = 0; i < count; i+=2) {
+ unsigned char c = ptr[0];
+ ptr[0] = ptr[1];
+ ptr[1] = c;
+ ptr += 2;
+ }
+}
void Tag::initUserComment (const Glib::ustring &text)
{
+ const bool useBOM = false; // set it to true if you want to output BOM in UCS-2/UTF-8 UserComments ; this could be turned to an options entry
type = UNDEFINED;
if (text.is_ascii()) {
- count = 8 + strlen (text.c_str());
- valuesize = count;
+ valuesize = count = 8 + strlen (text.c_str());
value = new unsigned char[valuesize];
- memcpy((char*)value, "ASCII\0\0\0", 8);
- memcpy((char*)value + 8, text.c_str(), valuesize - 8);
+ memcpy(value, "ASCII\0\0\0", 8);
+ memcpy(value + 8, text.c_str(), valuesize - 8);
} else {
- wchar_t *commentStr = (wchar_t*)g_utf8_to_utf16 (text.c_str(), -1, NULL, NULL, NULL);
- count = 8 + wcslen(commentStr)*2;
- valuesize = count;
- value = (unsigned char*)new char[valuesize];
- memcpy((char*)value, "UNICODE\0", 8);
- memcpy((char*)value + 8, (char*)commentStr, valuesize - 8);
+ wchar_t *commentStr = (wchar_t*)g_utf8_to_utf16 (text.c_str(), -1, nullptr, nullptr, nullptr);
+ size_t wcStrSize = wcslen(commentStr);
+ valuesize = count = wcStrSize * 2 + 8 + (useBOM ? 2 : 0);
+ value = new unsigned char[valuesize];
+ memcpy(value, "UNICODE\0", 8);
+
+ if (useBOM) {
+ if (getOrder() == INTEL) { //Little Endian
+ value[8] = 0xFF;
+ value[9] = 0xFE;
+ } else {
+ value[8] = 0xFE;
+ value[9] = 0xFF;
+ }
+ }
+
+ // Swapping byte order to match the Exif's byte order
+ if (getOrder() != HOSTORDER) {
+ swapByteOrder2((char*)commentStr, wcStrSize * 2);
+ }
+
+ memcpy(value + 8 + (useBOM ? 2 : 0), (char*)commentStr, wcStrSize * 2);
g_free(commentStr);
}
}
@@ -3197,120 +3220,6 @@ int ExifManager::createJPEGMarker (const TagDirectory* root, const rtengine::pro
return size + 6;
}
-int ExifManager::createTIFFHeader (const TagDirectory* root, const rtengine::procparams::ExifPairs& changeList, int W, int H, int bps, const char* profiledata, int profilelen, const char* iptcdata, int iptclen, unsigned char *&buffer, unsigned &bufferSize)
-{
-
-// write tiff header
- int offs = 0;
- ByteOrder order = HOSTORDER;
-
- if (root) {
- order = root->getOrder ();
- }
-
- TagDirectory* cl;
-
- if (root) {
- cl = (const_cast (root))->clone (nullptr);
- // remove some unknown top level tags which produce warnings when opening a tiff
- Tag *removeTag = cl->getTag (0x9003);
-
- if (removeTag) {
- removeTag->setKeep (false);
- }
-
- removeTag = cl->getTag (0x9211);
-
- if (removeTag) {
- removeTag->setKeep (false);
- }
- } else {
- cl = new TagDirectory (nullptr, ifdAttribs, HOSTORDER);
- }
-
-// add tiff strip data
- int rps = 8;
- int strips = ceil ((double)H / rps);
- cl->replaceTag (new Tag (cl, lookupAttrib (ifdAttribs, "RowsPerStrip"), rps, LONG));
- Tag* stripBC = new Tag (cl, lookupAttrib (ifdAttribs, "StripByteCounts"));
- stripBC->initInt (0, LONG, strips);
- cl->replaceTag (stripBC);
- Tag* stripOffs = new Tag (cl, lookupAttrib (ifdAttribs, "StripOffsets"));
- stripOffs->initInt (0, LONG, strips);
- cl->replaceTag (stripOffs);
-
- for (int i = 0; i < strips - 1; i++) {
- stripBC->setInt (rps * W * 3 * bps / 8, i * 4);
- }
-
- int remaining = (H - rps * floor ((double)H / rps)) * W * 3 * bps / 8;
-
- if (remaining) {
- stripBC->setInt (remaining, (strips - 1) * 4);
- } else {
- stripBC->setInt (rps * W * 3 * bps / 8, (strips - 1) * 4);
- }
-
- if (profiledata) {
- Tag* icc = new Tag (cl, lookupAttrib (ifdAttribs, "ICCProfile"));
- icc->initUndefArray (profiledata, profilelen);
- cl->replaceTag (icc);
- }
-
- if (iptcdata) {
- Tag* iptc = new Tag (cl, lookupAttrib (ifdAttribs, "IPTCData"));
- iptc->initLongArray (iptcdata, iptclen);
- cl->replaceTag (iptc);
- }
-
-// apply list of changes
- for (rtengine::procparams::ExifPairs::const_iterator i = changeList.begin(); i != changeList.end(); ++i) {
- cl->applyChange (i->first, i->second);
- }
-
- // append default properties
- const std::vector defTags = getDefaultTIFFTags (cl);
-
- defTags[0]->setInt (W, 0, LONG);
- defTags[1]->setInt (H, 0, LONG);
- defTags[8]->initInt (0, SHORT, 3);
-
- for (int i = 0; i < 3; i++) {
- defTags[8]->setInt (bps, i * 2, SHORT);
- }
-
- for (int i = defTags.size() - 1; i >= 0; i--) {
- Tag* defTag = defTags[i];
- cl->replaceTag (defTag->clone (cl));
- delete defTag;
- }
-
-// calculate strip offsets
- int size = cl->calculateSize ();
- int byps = bps / 8;
-
- for (int i = 0; i < strips; i++) {
- stripOffs->setInt (size + 8 + i * rps * W * 3 * byps, i * 4);
- }
-
- cl->sort ();
- bufferSize = cl->calculateSize() + 8;
- buffer = new unsigned char[bufferSize]; // this has to be deleted in caller
- sset2 ((unsigned short)order, buffer + offs, order);
- offs += 2;
- sset2 (42, buffer + offs, order);
- offs += 2;
- sset4 (8, buffer + offs, order);
-
- int endOffs = cl->write (8, buffer);
-
-// cl->printAll();
- delete cl;
-
- return endOffs;
-}
-
-
int ExifManager::createPNGMarker(const TagDirectory* root, const rtengine::procparams::ExifPairs &changeList, int W, int H, int bps, const char* iptcdata, int iptclen, unsigned char *&buffer, unsigned &bufferSize)
{
// write tiff header
diff --git a/rtexif/rtexif.h b/rtexif/rtexif.h
index 822407389..33419fe71 100644
--- a/rtexif/rtexif.h
+++ b/rtexif/rtexif.h
@@ -236,6 +236,8 @@ public:
void initLongArray (const char* data, int len);
void initRational (int num, int den);
+ static void swapByteOrder2 (char *buffer, int count);
+
// get basic tag properties
int getID () const
{
diff --git a/rtexif/stdattribs.cc b/rtexif/stdattribs.cc
index a7e3fe00f..ca19b7f1c 100644
--- a/rtexif/stdattribs.cc
+++ b/rtexif/stdattribs.cc
@@ -452,12 +452,109 @@ public:
}
count = std::min (count, 65535); // limit to 65535 chars to avoid crashes in case of corrupted metadata
- char *buffer = new char[count - 7];
+ char *buffer = new char[count - 6]; // include 2 ending null chars for UCS-2 string (possibly)
+ char *value = (char*)t->getValue();
- if (!memcmp ((char*)t->getValue(), "ASCII\0\0\0", 8)) {
- strncpy (buffer, (char*)t->getValue() + 8, count - 8);
+ if (!memcmp(value, "ASCII\0\0\0", 8)) {
+ memcpy(buffer, value + 8, count - 8);
buffer[count - 8] = '\0';
+ } else if (!memcmp(value, "UNICODE\0", 8)) {
+ memcpy(buffer, value + 8, count - 8);
+ buffer[count - 7] = buffer[count - 8] = '\0';
+ Glib::ustring tmp1(buffer);
+
+
+ bool hasBOM = false;
+ enum ByteOrder bo = UNKNOWN;
+ if (count % 2 || (count >= 11 && (buffer[0] == 0xEF && buffer[1] == 0xBB && buffer[2] == 0xBF))) {
+ // odd string length can only be UTF-8, don't change anything
+ std::string retVal (buffer + 3);
+ delete [] buffer;
+ return retVal;
+ } else if (count >= 10) {
+ if (buffer[0] == 0xFF && buffer[1] == 0xFE) {
+ bo = INTEL; // little endian
+ hasBOM = true;
+ } else if (buffer[0] == 0xFE && buffer[1] == 0xFF) {
+ bo = MOTOROLA; // big endian
+ hasBOM = true;
+ }
+ }
+ if (bo == UNKNOWN) {
+ // auto-detecting byte order; we still don't know if it's UCS-2 or UTF-8
+ int a = 0, b = 0, c = 0, d = 0;
+ for (int j = 8; j < count; j++) {
+ char cc = value[j];
+ if (!(j%2)) {
+ // counting zeros for first byte
+ if (!cc) {
+ ++a;
+ }
+ } else {
+ // counting zeros for second byte
+ if (!cc) {
+ ++b;
+ }
+ }
+ if (!(cc & 0x80) || ((cc & 0xC0) == 0xC0) || ((cc & 0xC0) == 0x80)) {
+ ++c;
+ }
+ if ((cc & 0xC0) == 0x80) {
+ ++d;
+ }
+ }
+ if (c == (count - 8) && d) {
+ // this is an UTF-8 string
+ std::string retVal (buffer);
+ delete [] buffer;
+ return retVal;
+ }
+ if ((a || b) && a != b) {
+ bo = a > b ? MOTOROLA : INTEL;
+ }
+ }
+ if (bo == UNKNOWN) {
+ // assuming platform's byte order
+#if __BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__
+ bo = INTEL;
+#else
+ bo = MOTOROLA;
+#endif
+ }
+
+ // now swapping if necessary
+ if (!hasBOM && bo != HOSTORDER) {
+ if (t->getOrder() != HOSTORDER) {
+ Tag::swapByteOrder2(buffer, count - 8);
+ }
+ }
+
+ glong written;
+ char* utf8Str = g_utf16_to_utf8((unsigned short int*)buffer, -1, nullptr, &written, nullptr);
+ delete [] buffer;
+ buffer = new char[written + 1];
+ memcpy(buffer, utf8Str, written);
+ buffer[written] = 0;
+ } else if (!memcmp(value, "\0\0\0\0\0\0\0\0", 8)) {
+ // local charset string, whatever it is
+ memcpy(buffer, value + 8, count - 8);
+ buffer[count - 7] = buffer[count - 8] = '\0';
+
+ gsize written = 0;
+ char *utf8Str = g_locale_to_utf8(buffer, count - 8, nullptr, &written, nullptr);
+ if (utf8Str && written) {
+ delete [] buffer;
+ size_t length = strlen(utf8Str);
+ buffer = new char[length + 1];
+ strcpy(buffer, utf8Str);
+ } else {
+ buffer[0] = 0;
+ }
+ if (utf8Str) {
+ g_free(utf8Str);
+ }
} else {
+ // JIS: unsupported
buffer[0] = 0;
}
@@ -467,11 +564,8 @@ public:
}
virtual void fromString (Tag* t, const std::string& value)
{
- char *buffer = new char[t->getCount()];
- memcpy (buffer, "ASCII\0\0\0", 8);
- strcpy (buffer + 8, value.c_str());
- t->fromString (buffer, value.size() + 9);
- delete [] buffer;
+ Glib::ustring tmpStr(value);
+ t->userCommentFromString (tmpStr);
}
};
UserCommentInterpreter userCommentInterpreter;
@@ -809,10 +903,10 @@ const TagAttrib ifdAttribs[] = {
{0, AC_WRITE, 0, nullptr, 0x828e, AUTO, "CFAPattern", &cfaInterpreter},
{0, AC_WRITE, 0, kodakIfdAttribs, 0x8290, AUTO, "KodakIFD", &stdInterpreter},
{0, AC_WRITE, 1, nullptr, 0x8298, AUTO, "Copyright", &stdInterpreter},
+ {0, AC_SYSTEM, 0, nullptr, 0x83BB, AUTO, "IPTCData", &stdInterpreter},
{0, AC_DONTWRITE, 0, nullptr, 0x8606, AUTO, "LeafData", &stdInterpreter}, // is actually a subdir, but a proprietary format
{0, AC_WRITE, 0, exifAttribs, 0x8769, AUTO, "Exif", &stdInterpreter},
{0, AC_SYSTEM, 0, nullptr, 0x8773, AUTO, "ICCProfile", &stdInterpreter},
- {0, AC_SYSTEM, 0, nullptr, 0x83BB, AUTO, "IPTCData", &stdInterpreter},
{0, AC_WRITE, 0, gpsAttribs, 0x8825, AUTO, "GPSInfo", &stdInterpreter},
{0, AC_WRITE, 0, nullptr, 0x9003, AUTO, "DateTimeOriginal", &stdInterpreter},
{0, AC_WRITE, 0, nullptr, 0x9004, AUTO, "DateTimeDigitized", &stdInterpreter},
diff --git a/rtgui/batchqueue.cc b/rtgui/batchqueue.cc
index 6b04ed0ae..2f3505a08 100644
--- a/rtgui/batchqueue.cc
+++ b/rtgui/batchqueue.cc
@@ -373,7 +373,7 @@ Glib::ustring BatchQueue::getTempFilenameForParams( const Glib::ustring &filenam
{
timeval tv;
gettimeofday(&tv, nullptr);
- char mseconds[4];
+ char mseconds[11];
sprintf(mseconds, "%d", (int)(tv.tv_usec / 1000));
time_t rawtime;
struct tm *timeinfo;
@@ -578,7 +578,7 @@ void BatchQueue::startProcessing ()
}
}
-rtengine::ProcessingJob* BatchQueue::imageReady (rtengine::IImage16* img)
+rtengine::ProcessingJob* BatchQueue::imageReady (rtengine::IImagefloat* img)
{
// save image img
diff --git a/rtgui/batchqueue.h b/rtgui/batchqueue.h
index 68373838e..0d91542b6 100644
--- a/rtgui/batchqueue.h
+++ b/rtgui/batchqueue.h
@@ -62,7 +62,7 @@ public:
return (!fd.empty());
}
- rtengine::ProcessingJob* imageReady (rtengine::IImage16* img);
+ rtengine::ProcessingJob* imageReady (rtengine::IImagefloat* img);
void error (Glib::ustring msg);
void setProgress (double p);
void rightClicked (ThumbBrowserEntryBase* entry);
diff --git a/rtgui/editorpanel.cc b/rtgui/editorpanel.cc
index e9964073a..6e13cd2a5 100644
--- a/rtgui/editorpanel.cc
+++ b/rtgui/editorpanel.cc
@@ -1772,9 +1772,9 @@ void EditorPanel::procParamsChanged (Thumbnail* thm, int whoChangedIt)
}
}
-bool EditorPanel::idle_saveImage (ProgressConnector *pc, Glib::ustring fname, SaveFormat sf, rtengine::procparams::ProcParams &pparams)
+bool EditorPanel::idle_saveImage (ProgressConnector *pc, Glib::ustring fname, SaveFormat sf, rtengine::procparams::ProcParams &pparams)
{
- rtengine::IImage16* img = pc->returnValue();
+ rtengine::IImagefloat* img = pc->returnValue();
delete pc;
if ( img ) {
@@ -1785,13 +1785,13 @@ bool EditorPanel::idle_saveImage (ProgressConnector *pc, Gl
img->setSaveProgressListener (parent->getProgressListener());
if (sf.format == "tif")
- ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImage16::saveAsTIFF), fname, sf.tiffBits, sf.tiffUncompressed),
+ ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImagefloat::saveAsTIFF), fname, sf.tiffBits, sf.tiffUncompressed),
sigc::bind (sigc::mem_fun (*this, &EditorPanel::idle_imageSaved), ld, img, fname, sf, pparams));
else if (sf.format == "png")
- ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImage16::saveAsPNG), fname, sf.pngBits),
+ ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImagefloat::saveAsPNG), fname, sf.pngBits),
sigc::bind (sigc::mem_fun (*this, &EditorPanel::idle_imageSaved), ld, img, fname, sf, pparams));
else if (sf.format == "jpg")
- ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImage16::saveAsJPEG), fname, sf.jpegQuality, sf.jpegSubSamp),
+ ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImagefloat::saveAsJPEG), fname, sf.jpegQuality, sf.jpegSubSamp),
sigc::bind (sigc::mem_fun (*this, &EditorPanel::idle_imageSaved), ld, img, fname, sf, pparams));
else {
delete ld;
@@ -1812,7 +1812,7 @@ bool EditorPanel::idle_saveImage (ProgressConnector *pc, Gl
return false;
}
-bool EditorPanel::idle_imageSaved (ProgressConnector *pc, rtengine::IImage16* img, Glib::ustring fname, SaveFormat sf, rtengine::procparams::ProcParams &pparams)
+bool EditorPanel::idle_imageSaved (ProgressConnector *pc, rtengine::IImagefloat* img, Glib::ustring fname, SaveFormat sf, rtengine::procparams::ProcParams &pparams)
{
img->free ();
@@ -1937,7 +1937,7 @@ void EditorPanel::saveAsPressed ()
ipc->getParams (&pparams);
rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams);
- ProgressConnector *ld = new ProgressConnector();
+ ProgressConnector *ld = new ProgressConnector();
ld->startFunc (sigc::bind (sigc::ptr_fun (&rtengine::processImage), job, err, parent->getProgressListener(), false ),
sigc::bind (sigc::mem_fun ( *this, &EditorPanel::idle_saveImage ), ld, fnameOut, sf, pparams));
saveimgas->set_sensitive (false);
@@ -1981,7 +1981,7 @@ void EditorPanel::sendToGimpPressed ()
rtengine::procparams::ProcParams pparams;
ipc->getParams (&pparams);
rtengine::ProcessingJob* job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams);
- ProgressConnector *ld = new ProgressConnector();
+ ProgressConnector *ld = new ProgressConnector();
ld->startFunc (sigc::bind (sigc::ptr_fun (&rtengine::processImage), job, err, parent->getProgressListener(), false ),
sigc::bind (sigc::mem_fun ( *this, &EditorPanel::idle_sendToGimp ), ld, openThm->getFileName() ));
saveimgas->set_sensitive (false);
@@ -1996,7 +1996,7 @@ bool EditorPanel::saveImmediately (const Glib::ustring &filename, const SaveForm
rtengine::ProcessingJob *job = rtengine::ProcessingJob::create (ipc->getInitialImage(), pparams);
// save immediately
- rtengine::IImage16 *img = rtengine::processImage (job, err, nullptr, false);
+ rtengine::IImagefloat *img = rtengine::processImage (job, err, nullptr, false);
int err = 0;
@@ -2042,10 +2042,10 @@ void EditorPanel::histogramProfile_toggled()
colorMgmtToolBar->updateHistogram();
}
-bool EditorPanel::idle_sendToGimp ( ProgressConnector *pc, Glib::ustring fname)
+bool EditorPanel::idle_sendToGimp ( ProgressConnector *pc, Glib::ustring fname)
{
- rtengine::IImage16* img = pc->returnValue();
+ rtengine::IImagefloat* img = pc->returnValue();
delete pc;
if (img) {
@@ -2077,7 +2077,7 @@ bool EditorPanel::idle_sendToGimp ( ProgressConnector *pc,
ProgressConnector *ld = new ProgressConnector();
img->setSaveProgressListener (parent->getProgressListener());
- ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImage16::saveAsTIFF), fileName, sf.tiffBits, sf.tiffUncompressed),
+ ld->startFunc (sigc::bind (sigc::mem_fun (img, &rtengine::IImagefloat::saveAsTIFF), fileName, sf.tiffBits, sf.tiffUncompressed),
sigc::bind (sigc::mem_fun (*this, &EditorPanel::idle_sentToGimp), ld, img, fileName));
} else {
Glib::ustring msg_ = Glib::ustring (" Error during image processing\n");
@@ -2090,7 +2090,7 @@ bool EditorPanel::idle_sendToGimp ( ProgressConnector *pc,
return false;
}
-bool EditorPanel::idle_sentToGimp (ProgressConnector *pc, rtengine::IImage16* img, Glib::ustring filename)
+bool EditorPanel::idle_sentToGimp (ProgressConnector *pc, rtengine::IImagefloat* img, Glib::ustring filename)
{
img->free ();
int errore = pc->returnValue();
diff --git a/rtgui/editorpanel.h b/rtgui/editorpanel.h
index 0249e77ca..7876d18e1 100644
--- a/rtgui/editorpanel.h
+++ b/rtgui/editorpanel.h
@@ -146,10 +146,10 @@ private:
void close ();
BatchQueueEntry* createBatchQueueEntry ();
- bool idle_imageSaved (ProgressConnector *pc, rtengine::IImage16* img, Glib::ustring fname, SaveFormat sf, rtengine::procparams::ProcParams &pparams);
- bool idle_saveImage (ProgressConnector *pc, Glib::ustring fname, SaveFormat sf, rtengine::procparams::ProcParams &pparams);
- bool idle_sendToGimp ( ProgressConnector *pc, Glib::ustring fname);
- bool idle_sentToGimp (ProgressConnector *pc, rtengine::IImage16* img, Glib::ustring filename);
+ bool idle_imageSaved (ProgressConnector *pc, rtengine::IImagefloat* img, Glib::ustring fname, SaveFormat sf, rtengine::procparams::ProcParams &pparams);
+ bool idle_saveImage (ProgressConnector *pc, Glib::ustring fname, SaveFormat sf, rtengine::procparams::ProcParams &pparams);
+ bool idle_sendToGimp ( ProgressConnector *pc, Glib::ustring fname);
+ bool idle_sentToGimp (ProgressConnector *pc, rtengine::IImagefloat* img, Glib::ustring filename);
void histogramProfile_toggled ();
diff --git a/rtgui/fattaltonemap.cc b/rtgui/fattaltonemap.cc
index 10dba51cf..a6f4c5190 100644
--- a/rtgui/fattaltonemap.cc
+++ b/rtgui/fattaltonemap.cc
@@ -26,10 +26,7 @@ using namespace rtengine::procparams;
FattalToneMapping::FattalToneMapping(): FoldableToolPanel(this, "fattal", M("TP_TM_FATTAL_LABEL"), true, true)
{
-
-// setEnabledTooltipMarkup(M("TP_EPD_TOOLTIP"));
-
- amount = Gtk::manage(new Adjuster (M("TP_TM_FATTAL_AMOUNT"), 1., 100., 1., 0.0));
+ amount = Gtk::manage(new Adjuster (M("TP_TM_FATTAL_AMOUNT"), 1., 100., 30., 0.0));
threshold = Gtk::manage(new Adjuster (M("TP_TM_FATTAL_THRESHOLD"), -100., 100., 1., 0.0));
amount->setAdjusterListener(this);
diff --git a/rtgui/main-cli.cc b/rtgui/main-cli.cc
index 870f90940..fdfee64ab 100644
--- a/rtgui/main-cli.cc
+++ b/rtgui/main-cli.cc
@@ -822,7 +822,7 @@ int processLineParams ( int argc, char **argv )
}
// Process image
- rtengine::IImage16* resultImage = rtengine::processImage (job, errorCode, nullptr);
+ rtengine::IImagefloat* resultImage = rtengine::processImage (job, errorCode, nullptr);
if ( !resultImage ) {
errors++;
diff --git a/rtgui/saveformatpanel.cc b/rtgui/saveformatpanel.cc
index 13e687595..fef05de23 100644
--- a/rtgui/saveformatpanel.cc
+++ b/rtgui/saveformatpanel.cc
@@ -40,14 +40,16 @@ SaveFormatPanel::SaveFormatPanel () : listener (nullptr)
format->append ("JPEG (8 bit)");
format->append ("TIFF (8 bit)");
format->append ("TIFF (16 bit)");
+ format->append ("TIFF (32 bit float)");
format->append ("PNG (8 bit)");
format->append ("PNG (16 bit)");
fstr[0] = "jpg";
fstr[1] = "tif";
fstr[2] = "tif";
- fstr[3] = "png";
+ fstr[3] = "tif";
fstr[4] = "png";
+ fstr[5] = "png";
hb1->attach (*flab, 0, 0, 1, 1);
hb1->attach (*format, 1, 0, 1, 1);
@@ -121,8 +123,10 @@ void SaveFormatPanel::init (SaveFormat &sf)
if (sf.format == "jpg") {
format->set_active (0);
} else if (sf.format == "png" && sf.pngBits == 16) {
- format->set_active (4);
+ format->set_active (5);
} else if (sf.format == "png" && sf.pngBits == 8) {
+ format->set_active (4);
+ } else if (sf.format == "tif" && sf.tiffBits == 32) {
format->set_active (3);
} else if (sf.format == "tif" && sf.tiffBits == 16) {
format->set_active (2);
@@ -146,7 +150,7 @@ SaveFormat SaveFormatPanel::getFormat ()
int sel = format->get_active_row_number();
sf.format = fstr[sel];
- if (sel == 4) {
+ if (sel == 5) {
sf.pngBits = 16;
} else {
sf.pngBits = 8;
@@ -154,6 +158,8 @@ SaveFormat SaveFormatPanel::getFormat ()
if (sel == 2) {
sf.tiffBits = 16;
+ } else if (sel == 3) {
+ sf.tiffBits = 32;
} else {
sf.tiffBits = 8;
}
diff --git a/rtgui/saveformatpanel.h b/rtgui/saveformatpanel.h
index 76ae7055d..8dc493051 100644
--- a/rtgui/saveformatpanel.h
+++ b/rtgui/saveformatpanel.h
@@ -44,7 +44,7 @@ protected:
Gtk::Grid* jpegOpts;
Gtk::Label* jpegSubSampLabel;
FormatChangeListener* listener;
- Glib::ustring fstr[5];
+ Glib::ustring fstr[6];
Gtk::CheckButton* savesPP;