Merge branch 'master' into softproofing
This commit is contained in:
commit
50165dab20
41
.travis.yml
Normal file
41
.travis.yml
Normal file
@ -0,0 +1,41 @@
|
||||
sudo: required
|
||||
dist: trusty
|
||||
|
||||
language: cpp
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
|
||||
os:
|
||||
- linux
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
notifications:
|
||||
irc:
|
||||
channels:
|
||||
- "chat.freenode.net#rawtherapee"
|
||||
template:
|
||||
- "%{repository}/%{branch} (%{commit} - %{author}): %{build_url}: %{message}"
|
||||
email:
|
||||
on_success: change
|
||||
on_failure: always
|
||||
|
||||
env:
|
||||
global:
|
||||
- OMP_NUM_THREADS=4
|
||||
|
||||
before_install:
|
||||
- sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
|
||||
- sudo apt-get -qq update
|
||||
- sudo apt-get install build-essential cmake curl g++-6 gcc-6 git libbz2-dev libcanberra-gtk-dev libexiv2-dev libexpat-dev libfftw3-dev libglibmm-2.4-dev libgtk2.0-dev libgtkmm-2.4-dev libiptcdata0-dev libjpeg8-dev liblcms2-dev libpng12-dev libsigc++-2.0-dev libtiff5-dev zlib1g-dev
|
||||
- sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-6 60 --slave /usr/bin/g++ g++ /usr/bin/g++-6
|
||||
|
||||
before_script:
|
||||
- mkdir build
|
||||
- cd build
|
||||
- cmake -DCMAKE_CXX_FLAGS="-Wno-deprecated-declarations" -DWITH_LTO="OFF" -DPROC_TARGET_NUMBER="2" ..
|
||||
|
||||
script: make
|
28
clean.sh
28
clean.sh
@ -1,28 +0,0 @@
|
||||
#!/bin/sh
|
||||
find -name CMakeCache.txt -delete
|
||||
rm install_manifest.txt
|
||||
|
||||
rm -r ./CMakeFiles
|
||||
rm -r ./rtengine/CMakeFiles
|
||||
rm -r ./rtexif/CMakeFiles
|
||||
rm -r ./rtgui/CMakeFiles
|
||||
rm -r ./rtdata/CMakeFiles
|
||||
|
||||
rm ./cmake*
|
||||
rm ./rtengine/cmake*
|
||||
rm ./rtexif/cmake*
|
||||
rm ./rtgui/cmake*
|
||||
rm ./rtdata/cmake*
|
||||
|
||||
rm ./Makefile
|
||||
rm ./rtengine/Makefile
|
||||
rm ./rtexif/Makefile
|
||||
rm ./rtgui/Makefile
|
||||
rm ./rtdata/Makefile
|
||||
|
||||
rm ./rtengine/librtengine.so
|
||||
rm ./rtengine/librtengine.a
|
||||
rm ./rtgui/rawtherapee
|
||||
rm ./rtexif/librtexif.so
|
||||
rm ./rtexif/librtexif.a
|
||||
exit 0
|
BIN
rtdata/images/Dark/actions/colorPickers-hide.png
Normal file
BIN
rtdata/images/Dark/actions/colorPickers-hide.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 685 B |
BIN
rtdata/images/Dark/actions/colorPickers-show.png
Normal file
BIN
rtdata/images/Dark/actions/colorPickers-show.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 833 B |
BIN
rtdata/images/Dark/actions/gtk-color-picker-add.png
Normal file
BIN
rtdata/images/Dark/actions/gtk-color-picker-add.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 851 B |
BIN
rtdata/images/Light/actions/colorPickers-hide.png
Normal file
BIN
rtdata/images/Light/actions/colorPickers-hide.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 645 B |
BIN
rtdata/images/Light/actions/colorPickers-show.png
Normal file
BIN
rtdata/images/Light/actions/colorPickers-show.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 796 B |
BIN
rtdata/images/Light/actions/gtk-color-picker-add.png
Normal file
BIN
rtdata/images/Light/actions/gtk-color-picker-add.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 810 B |
@ -990,7 +990,8 @@ PREFERENCES_REMEMBERZOOMPAN;Se souvenir de niveau de zoom et de la position de l
|
||||
PREFERENCES_REMEMBERZOOMPAN_TOOLTIP;Retient le niveau de zoom et la position de l'image courante lors de l'ouverture d'une nouvelle image.\n\nCette option ne fonctionne que dans le mode "Éditeur unique" et quand "Méthode de dématriçage utilisé pour l'aperçu à un zoom <100%" is set to "Idem PP3".
|
||||
PREFERENCES_RGBDTL_LABEL;Nombre maximum d'unités de calcul pour la Réduction du bruit
|
||||
PREFERENCES_RGBDTL_TOOLTIP;La réduction du bruit nécessite un minimum d'à peu près 128Mo de RAM pour une image de 10MPix ou 512Mo pour une image de 40MPix, ainsi que 128Mo de RAM supplémentaire par unité de calcul. Plus il y aura d'unités de calcul travaillant en parallèle, plus ce sera rapide. Laissez la valeur à "0" pour utiliser automatiquement autant d'unités de calcul que possible.
|
||||
PREFERENCES_SELECTFONT;Police de caractère
|
||||
PREFERENCES_SELECTFONT;Police générale
|
||||
PREFERENCES_SELECTFONT_COLPICKER;Police des pipette à couleur
|
||||
PREFERENCES_SELECTLANG;Choix de la langue
|
||||
PREFERENCES_SELECTTHEME;Choisissez un thème
|
||||
PREFERENCES_SERIALIZE_TIFF_READ;Réglage de lecture des images TIFF
|
||||
@ -1093,6 +1094,7 @@ THRESHOLDSELECTOR_HINT;Maintenez la touche <b>Shift</b> appuyée pour déplacer
|
||||
THRESHOLDSELECTOR_T;Haut
|
||||
THRESHOLDSELECTOR_TL;Haut-Gauche
|
||||
THRESHOLDSELECTOR_TR;Haut-droite
|
||||
TOOLBAR_TOOLTIP_COLORPICKER;Ancre de Vérification Couleur\n\nLorque activé:\nCliquez la zone d'image avec le bouton gauche de la souris pour ajouter une ancre\nDéplacez-le en le "tirant" avec le bouton gauche de la souris\nSupprimez une ancre en cliquant dessus avec le bouton droit de la souris\nSupprimez toutes les ancres avec Shift + click avec le bouton droit\nCliquez avec le bouton droit de la souris en dehors de toute ancre pour revenir au mode Déplacement
|
||||
TOOLBAR_TOOLTIP_CROP;Sélection du recadrage\nRaccourci: <b>c</b>\nDéplacez le recadrage en utilisant Shift + Glisser
|
||||
TOOLBAR_TOOLTIP_HAND;Outil de navigation\nRaccourci: <b>h</b>
|
||||
TOOLBAR_TOOLTIP_STRAIGHTEN;Sélection de la ligne d'horizon\nRaccourci: <b>s</b>\n\nIndiquez la verticale ou l'horizontale en dessinant une ligne à travers l'image de prévisualisation. L'angle de rotation sera affiché près de la ligne guide. Le centre de rotation est le centre géométrique de l'image.
|
||||
|
@ -1041,7 +1041,8 @@ PREFERENCES_REMEMBERZOOMPAN;Remember zoom % and pan offset
|
||||
PREFERENCES_REMEMBERZOOMPAN_TOOLTIP;Remember the zoom % and pan offset of the current image when opening a new image.\n\nThis option only works in "Single Editor Tab Mode" and when "Demosaicing method used for the preview at <100% zoom" is set to "As in PP3".
|
||||
PREFERENCES_RGBDTL_LABEL;Max number of threads for Noise Reduction and Wavelet Levels
|
||||
PREFERENCES_RGBDTL_TOOLTIP;Leave the setting at "0" to automatically use as many threads as possible. The more threads run in parallel, the faster the computation. Refer to RawPedia for memory requirements.
|
||||
PREFERENCES_SELECTFONT;Select font
|
||||
PREFERENCES_SELECTFONT;Select global font
|
||||
PREFERENCES_SELECTFONT_COLPICKER;Select Color Picker's font
|
||||
PREFERENCES_SELECTLANG;Select language
|
||||
PREFERENCES_SELECTTHEME;Select theme
|
||||
PREFERENCES_SERIALIZE_TIFF_READ;Tiff Read Settings
|
||||
@ -1146,6 +1147,7 @@ THRESHOLDSELECTOR_HINT;Hold the <b>Shift</b> key to move individual control poin
|
||||
THRESHOLDSELECTOR_T;Top
|
||||
THRESHOLDSELECTOR_TL;Top-left
|
||||
THRESHOLDSELECTOR_TR;Top-right
|
||||
TOOLBAR_TOOLTIP_COLORPICKER;Lockable Color Picker\n\nWhen enabled:\nClick in the preview with left mouse button to add a color picker\nDrag it around while pressing the left mouse button\nDelete the color picker with a right mouse button click\nDelete all color pickers with Shift + Right mouse button click\nRight click away from any color picker to go back to the Hand tool
|
||||
TOOLBAR_TOOLTIP_CROP;<b>Crop</b> selection.\nShortcut: <b>c</b>\nMove the crop area using <b>Shift-mouse drag</b>
|
||||
TOOLBAR_TOOLTIP_HAND;Hand tool.\nShortcut: <b>h</b>
|
||||
TOOLBAR_TOOLTIP_STRAIGHTEN;<b>Straighten</b> / <b>fine rotation</b>.\nShortcut: <b>s</b>\n\nIndicate the vertical or horizontal by drawing a guide line over the image preview. Angle of rotation will be shown next to the guide line. Center of rotation is the geometrical center of the image.
|
||||
|
@ -1,264 +0,0 @@
|
||||
#include "EdgePreserveLab.h"
|
||||
#include "boxblur.h"
|
||||
#include <cstdlib>
|
||||
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
//#define MAX(a,b) ((a)<(b)?(b):(a))
|
||||
//#define MIN(a,b) ((a)>(b)?(b):(a))
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
EdgePreserveLab::EdgePreserveLab(unsigned int width, unsigned int height)
|
||||
{
|
||||
w = width;
|
||||
h = height;
|
||||
n = w * h;
|
||||
|
||||
//Initialize the matrix just once at construction.
|
||||
A = new MultiDiagonalSymmetricMatrix(n, 5);
|
||||
|
||||
if(!(
|
||||
A->CreateDiagonal(0, 0) &&
|
||||
A->CreateDiagonal(1, 1) &&
|
||||
A->CreateDiagonal(2, w - 1) &&
|
||||
A->CreateDiagonal(3, w) &&
|
||||
A->CreateDiagonal(4, w + 1))) {
|
||||
delete A;
|
||||
A = NULL;
|
||||
printf("Error in EdgePreserveLab construction: out of memory.\n");
|
||||
} else {
|
||||
a0 = A->Diagonals[0];
|
||||
a_1 = A->Diagonals[1];
|
||||
a_w1 = A->Diagonals[2];
|
||||
a_w = A->Diagonals[3];
|
||||
a_w_1 = A->Diagonals[4];
|
||||
}
|
||||
}
|
||||
|
||||
EdgePreserveLab::~EdgePreserveLab()
|
||||
{
|
||||
delete A;
|
||||
}
|
||||
|
||||
float *EdgePreserveLab::CreateBlur(float *Source, float LScale, float abScale, float EdgeStoppingLuma, float EdgeStoppingChroma, unsigned int Iterates, float *Blur, bool UseBlurForEdgeStop)
|
||||
{
|
||||
if(Blur == NULL)
|
||||
UseBlurForEdgeStop = false, //Use source if there's no supplied Blur.
|
||||
Blur = new float[3 * n];
|
||||
|
||||
if(LScale == 0.0f) {
|
||||
memcpy(Blur, Source, 3 * n * sizeof(float));
|
||||
return Blur;
|
||||
}
|
||||
|
||||
//Create the edge stopping function a, rotationally symmetric and just one instead of (ax, ay). Maybe don't need Blur yet, so use its memory.
|
||||
float *a, *b, *g;
|
||||
|
||||
if(UseBlurForEdgeStop) {
|
||||
a = new float[n], g = Blur;
|
||||
} else {
|
||||
a = Blur, g = Source;
|
||||
}
|
||||
|
||||
//b = new float[n];
|
||||
|
||||
unsigned int x, y, i;
|
||||
unsigned int w1 = w - 1, h1 = h - 1;
|
||||
float eps = 0.0001f;
|
||||
float scL = powf(100.0f, LScale);
|
||||
float scab = powf(200.0f, abScale);
|
||||
|
||||
float * var = new float[w * h];
|
||||
rtengine::boxvar(g, var, 1, 1, w, h);
|
||||
|
||||
#ifdef _OPENMP
|
||||
#pragma omp parallel for
|
||||
#endif
|
||||
|
||||
for(y = 0; y < h1; y++) {
|
||||
float *rg = &g[w * y];
|
||||
|
||||
for(x = 0; x < w1; x++) {
|
||||
//Estimate the central difference gradient in the center of a four pixel square. (gx, gy) is actually 2*gradient.
|
||||
/*float gx = (fabs((rg[x + 1] - rg[x]) + (rg[x + w + 1] - rg[x + w])));
|
||||
float gy = (fabs((rg[x + w] - rg[x]) + (rg[x + w + 1] - rg[x + 1])));
|
||||
|
||||
//TODO: combine this with gx, gy if not needing separate quantities
|
||||
float hx = (fabs((rg[x + 1 + n] - rg[x + n]) + (rg[x + w + 1 + n] - rg[x + w + n])) + \
|
||||
fabs((rg[x + 1 + 2*n] - rg[x + 2*n]) + (rg[x + w + 1 + 2*n] - rg[x + w + 2*n])));
|
||||
float hy = (fabs((rg[x + w + n] - rg[x + n]) + (rg[x + w + 1 + n] - rg[x + 1 + n])) + \
|
||||
fabs((rg[x + w + 2*n] - rg[x + 2*n]) + (rg[x + w + 1 + 2*n] - rg[x + 1 + 2*n])));
|
||||
*/
|
||||
//float gradtot = (gx+gy+hx+hy);
|
||||
//gradhisto[MAX(0,MIN(32767,(int)gradtot))] ++;
|
||||
|
||||
//Apply power to the magnitude of the gradient to get the edge stopping function.
|
||||
//a[x + w*y] = scL*expf(-100.0f*(gx + gy + hx + hy)/(EdgeStoppingLuma));
|
||||
//a[x + w*y] = scL*expf(-var[y*w+x]/SQR(0.02*EdgeStoppingLuma));///(0.1+rg[x]);
|
||||
a[x + w * y] = scL * expf(-50.0f * sqrt(var[y * w + x]) / (EdgeStoppingLuma + eps)); ///(0.1+rg[x]);
|
||||
|
||||
//b[x + w*y] = (scab)*expf(-20.0f*(gx + gy + Lave*(hx + hy))/(EdgeStoppingChroma));
|
||||
//b[x + w*y] = (scab)*expf(-400.0f*SQR(gx + gy + Lave*(hx + hy))/SQR(EdgeStoppingChroma));;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Now setup the linear problem. I use the Maxima CAS, here's code for making an FEM formulation for the smoothness term:
|
||||
p(x, y) := (1 - x)*(1 - y);
|
||||
P(m, n) := A[m][n]*p(x, y) + A[m + 1][n]*p(1 - x, y) + A[m + 1][n + 1]*p(1 - x, 1 - y) + A[m][n + 1]*p(x, 1 - y);
|
||||
Integrate(f) := integrate(integrate(f, x, 0, 1), y, 0, 1);
|
||||
|
||||
Integrate(diff(P(u, v), x)*diff(p(x, y), x) + diff(P(u, v), y)*diff(p(x, y), y));
|
||||
Integrate(diff(P(u - 1, v), x)*diff(p(1 - x, y), x) + diff(P(u - 1, v), y)*diff(p(1 - x, y), y));
|
||||
Integrate(diff(P(u - 1, v - 1), x)*diff(p(1 - x, 1 - y), x) + diff(P(u - 1, v - 1), y)*diff(p(1 - x, 1 - y), y));
|
||||
Integrate(diff(P(u, v - 1), x)*diff(p(x, 1 - y), x) + diff(P(u, v - 1), y)*diff(p(x, 1 - y), y));
|
||||
So yeah. Use the numeric results of that to fill the matrix A.*/
|
||||
memset(a_1, 0, A->DiagonalLength(1)*sizeof(float));
|
||||
memset(a_w1, 0, A->DiagonalLength(w - 1)*sizeof(float));
|
||||
memset(a_w, 0, A->DiagonalLength(w)*sizeof(float));
|
||||
memset(a_w_1, 0, A->DiagonalLength(w + 1)*sizeof(float));
|
||||
|
||||
//TODO: OMP here?
|
||||
for(i = y = 0; y != h; y++) {
|
||||
for(x = 0; x != w; x++, i++) {
|
||||
float ac;
|
||||
a0[i] = 1.0;
|
||||
|
||||
//Remember, only fill the lower triangle. Memory for upper is never made. It's symmetric. Trust.
|
||||
if(x > 0 && y > 0)
|
||||
ac = a[i - w - 1] / 6.0f,
|
||||
a_w_1[i - w - 1] -= 2.0f * ac, a_w[i - w] -= ac,
|
||||
a_1[i - 1] -= ac, a0[i] += 4.0f * ac;
|
||||
|
||||
if(x < w1 && y > 0)
|
||||
ac = a[i - w] / 6.0f,
|
||||
a_w[i - w] -= ac, a_w1[i - w + 1] -= 2.0f * ac,
|
||||
a0[i] += 4.0f * ac;
|
||||
|
||||
if(x > 0 && y < h1)
|
||||
ac = a[i - 1] / 6.0f,
|
||||
a_1[i - 1] -= ac, a0[i] += 4.0f * ac;
|
||||
|
||||
if(x < w1 && y < h1) {
|
||||
a0[i] += 4.0f * a[i] / 6.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(UseBlurForEdgeStop) {
|
||||
delete[] a;
|
||||
}
|
||||
|
||||
|
||||
//Solve & return.
|
||||
A->CreateIncompleteCholeskyFactorization(1); //Fill-in of 1 seems to work really good. More doesn't really help and less hurts (slightly).
|
||||
|
||||
if(!UseBlurForEdgeStop) {
|
||||
memcpy(Blur, Source, 3 * n * sizeof(float));
|
||||
}
|
||||
|
||||
// blur L channel
|
||||
SparseConjugateGradient(A->PassThroughVectorProduct, Source, n, false, Blur, 0.0f, (void *)A, Iterates, A->PassThroughCholeskyBackSolve);
|
||||
|
||||
//reset A for ab channels
|
||||
/*memset(a_1, 0, A->DiagonalLength(1)*sizeof(float));
|
||||
memset(a_w1, 0, A->DiagonalLength(w - 1)*sizeof(float));
|
||||
memset(a_w, 0, A->DiagonalLength(w)*sizeof(float));
|
||||
memset(a_w_1, 0, A->DiagonalLength(w + 1)*sizeof(float));
|
||||
for(i = y = 0; y != h; y++){
|
||||
for(x = 0; x != w; x++, i++){
|
||||
float ac;
|
||||
a0[i] = 1.0;
|
||||
|
||||
//Remember, only fill the lower triangle. Memory for upper is never made. It's symmetric. Trust.
|
||||
if(x > 0 && y > 0)
|
||||
ac = b[i - w - 1]/6.0f,
|
||||
a_w_1[i - w - 1] -= 2.0f*ac, a_w[i - w] -= ac,
|
||||
a_1[i - 1] -= ac, a0[i] += 4.0f*ac;
|
||||
|
||||
if(x < w1 && y > 0)
|
||||
ac = b[i - w]/6.0f,
|
||||
a_w[i - w] -= ac, a_w1[i - w + 1] -= 2.0f*ac,
|
||||
a0[i] += 4.0f*ac;
|
||||
|
||||
if(x > 0 && y < h1)
|
||||
ac = b[i - 1]/6.0f,
|
||||
a_1[i - 1] -= ac, a0[i] += 4.0f*ac;
|
||||
|
||||
if(x < w1 && y < h1)
|
||||
a0[i] += 4.0f*b[i]/6.0f;
|
||||
}
|
||||
}*/
|
||||
/*if(UseBlurForEdgeStop)*/ //delete[] b;
|
||||
|
||||
// blur ab channels
|
||||
//A->CreateIncompleteCholeskyFactorization(1); //Fill-in of 1 seems to work really good. More doesn't really help and less hurts (slightly).
|
||||
//SparseConjugateGradient(A->PassThroughVectorProduct, Source+n, n, false, Blur+n, 0.0f, (void *)A, Iterates, A->PassThroughCholeskyBackSolve);
|
||||
//SparseConjugateGradient(A->PassThroughVectorProduct, Source+2*n, n, false, Blur+2*n, 0.0f, (void *)A, Iterates, A->PassThroughCholeskyBackSolve);
|
||||
|
||||
A->KillIncompleteCholeskyFactorization();
|
||||
return Blur;
|
||||
}
|
||||
|
||||
float *EdgePreserveLab::CreateIteratedBlur(float *Source, float LScale, float abScale, float EdgeStoppingLuma, float EdgeStoppingChroma, unsigned int Iterates, unsigned int Reweightings, float *Blur)
|
||||
{
|
||||
//Simpler outcome?
|
||||
if(Reweightings == 0) {
|
||||
return CreateBlur(Source, LScale, abScale, EdgeStoppingLuma, EdgeStoppingChroma, Iterates, Blur);
|
||||
}
|
||||
|
||||
//Create a blur here, initialize.
|
||||
if(Blur == NULL) {
|
||||
Blur = new float[3 * n];
|
||||
}
|
||||
|
||||
memcpy(Blur, Source, 3 * n * sizeof(float));
|
||||
|
||||
//Iteratively improve the blur.
|
||||
Reweightings++;
|
||||
|
||||
for(unsigned int i = 0; i != Reweightings; i++) {
|
||||
CreateBlur(Source, LScale, abScale, EdgeStoppingLuma, EdgeStoppingChroma, Iterates, Blur, true);
|
||||
}
|
||||
|
||||
return Blur;
|
||||
}
|
||||
|
||||
float *EdgePreserveLab::CompressDynamicRange(float *Source, float LScale, float abScale, float EdgeStoppingLuma, float EdgeStoppingChroma, float CompressionExponent, float DetailBoost, unsigned int Iterates, unsigned int Reweightings, float *Compressed)
|
||||
{
|
||||
//We're working with luminance, which does better logarithmic.
|
||||
unsigned int i;
|
||||
//for(i = 0; i != n; i++)
|
||||
// Source[i] = logf(Source[i] + 0.0001f);
|
||||
|
||||
//Blur. Also setup memory for Compressed (we can just use u since each element of u is used in one calculation).
|
||||
float *u = CreateIteratedBlur(Source, LScale, abScale, EdgeStoppingLuma, EdgeStoppingChroma, Iterates, Reweightings);
|
||||
|
||||
if(Compressed == NULL) {
|
||||
Compressed = u;
|
||||
}
|
||||
|
||||
//Apply compression, detail boost, unlogging. Compression is done on the logged data and detail boost on unlogged.
|
||||
for(i = 0; i != n; i++) {
|
||||
//float ce = expf(Source[i] + u[i]*(CompressionExponent - 1.0f)) - 0.0001f;
|
||||
//float ue = expf(u[i]) - 0.0001f;
|
||||
//Source[i] = expf(Source[i]) - 0.0001f;
|
||||
//Compressed[i] = ce + DetailBoost*(Source[i] - ue);
|
||||
Compressed[i] = u[i];//ue;//for testing, to display blur
|
||||
}
|
||||
|
||||
if(Compressed != u) {
|
||||
delete[] u;
|
||||
}
|
||||
|
||||
return Compressed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -1,77 +0,0 @@
|
||||
#pragma once
|
||||
/*
|
||||
The EdgePreserveLab files contain standard C++ (standard except the first line) code for creating and, to a
|
||||
limited extent (create your own uses!), messing with multi scale edge preserving decompositions of a 32 bit single channel
|
||||
image. As a byproduct it contains a lot of linear algebra which can be useful for optimization problems that
|
||||
you want to solve in rectangles on rectangular grids.
|
||||
|
||||
Anyway. Basically, this is an implementation of what's presented in the following papers:
|
||||
Edge-Preserving Decompositions for Multi-Scale Tone and Detail Manipulation
|
||||
An Iterative Solution Method for Linear Systems of Which the Coefficient Matrix is a Symetric M-Matrix
|
||||
Color correction for tone mapping
|
||||
Wikipedia, the free encyclopedia
|
||||
|
||||
First one is most of what matters, next two are details, last everything else. I did a few things differently, especially:
|
||||
Reformulated the minimization with finite elements instead of finite differences. This results in better conditioning,
|
||||
slightly better accuracy (less artifacts), the possibility of a better picked edge stopping function, but more memory consumption.
|
||||
|
||||
A single rotationally invariant edge stopping function is used instead of two non-invariant ones.
|
||||
|
||||
Incomplete Cholseky factorization instead of Szeliski's LAHBF. Slower, but not subject to any patents.
|
||||
|
||||
For tone mapping, original images are decomposed instead of their logarithms, and just one decomposition is made;
|
||||
I find that this way works plenty good (theirs isn't better or worse... just different) and is simpler.
|
||||
|
||||
Written by ben_pcc in Portland, Oregon, USA; code modified by Emil Martinec.
|
||||
|
||||
// EdgePreserveLab.h and EdgePreserveLab.cpp are 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.
|
||||
//
|
||||
// This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <cmath>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "EdgePreservingDecomposition.h"
|
||||
|
||||
class EdgePreserveLab
|
||||
{
|
||||
public:
|
||||
EdgePreserveLab(unsigned int width, unsigned int height);
|
||||
~EdgePreserveLab();
|
||||
|
||||
//Create an edge preserving blur of Source. Will create and return, or fill into Blur if not NULL. In place not ok.
|
||||
//If UseBlurForEdgeStop is true, supplied not NULL Blur is used to calculate the edge stopping function instead of Source.
|
||||
float *CreateBlur(float *Source, float LScale, float abScale, float EdgeStoppingLuma, float EdgeStoppingChroma, unsigned int Iterates, float *Blur = NULL, bool UseBlurForEdgeStop = false);
|
||||
|
||||
//Iterates CreateBlur such that the smoothness term approaches a specific norm via iteratively reweighted least squares. In place not ok.
|
||||
float *CreateIteratedBlur(float *Source, float LScale, float abScale, float EdgeStoppingLuma, float EdgeStoppingChroma, unsigned int Iterates, unsigned int Reweightings, float *Blur = NULL);
|
||||
|
||||
/*Lowers global contrast while preserving or boosting local contrast. Can fill into Compressed. The smaller Compression
|
||||
the more compression is applied, with Compression = 1 giving no effect and above 1 the opposite effect. You can totally
|
||||
use Compression = 1 and play with DetailBoost for some really sweet unsharp masking. If working on luma/grey, consider giving it a logarithm.
|
||||
In place calculation to save memory (Source == Compressed) is totally ok. Reweightings > 0 invokes CreateIteratedBlur instead of CreateBlur. */
|
||||
float *CompressDynamicRange(float *Source, float LScale = 1.0f, float abScale = 5.0f, float EdgeStoppingLuma = 1.0f, float EdgeStoppingChroma = 1.0f,
|
||||
float CompressionExponent = 0.8f, float DetailBoost = 0.1f, unsigned int Iterates = 20,
|
||||
unsigned int Reweightings = 0, float *Compressed = NULL);
|
||||
|
||||
private:
|
||||
MultiDiagonalSymmetricMatrix *A; //The equations are simple enough to not mandate a matrix class, but fast solution NEEDS a complicated preconditioner.
|
||||
unsigned int w, h, n;
|
||||
|
||||
//Convenient access to the data in A.
|
||||
float *a0, *a_1, *a_w, *a_w_1, *a_w1;
|
||||
};
|
@ -67,13 +67,16 @@ ben_s or nonbasketless. Enjoy!
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "opthelper.h"
|
||||
#include "noncopyable.h"
|
||||
|
||||
//This is for solving big symmetric positive definite linear problems.
|
||||
float *SparseConjugateGradient(void Ax(float *Product, float *x, void *Pass), float *b, int n, bool OkToModify_b = true, float *x = NULL, float RMSResidual = 0.0f, void *Pass = NULL, int MaximumIterates = 0, void Preconditioner(float *Product, float *x, void *Pass) = NULL);
|
||||
|
||||
//Storage and use class for symmetric matrices, the nonzero contents of which are confined to diagonals.
|
||||
class MultiDiagonalSymmetricMatrix
|
||||
class MultiDiagonalSymmetricMatrix :
|
||||
public rtengine::NonCopyable
|
||||
{
|
||||
public:
|
||||
MultiDiagonalSymmetricMatrix(int Dimension, int NumberOfDiagonalsInLowerTriangle);
|
||||
@ -131,7 +134,8 @@ public:
|
||||
|
||||
};
|
||||
|
||||
class EdgePreservingDecomposition
|
||||
class EdgePreservingDecomposition :
|
||||
public rtengine::NonCopyable
|
||||
{
|
||||
public:
|
||||
EdgePreservingDecomposition(int width, int height);
|
||||
|
@ -109,7 +109,7 @@ void ImProcFunctions::Median_Denoise(float **src, float **dst, const int width,
|
||||
medBuffer[0] = src;
|
||||
|
||||
// we need a buffer if src == dst or if (src != dst && iterations > 1)
|
||||
if (src == dst || (src != dst && iterations > 1)) {
|
||||
if (src == dst || iterations > 1) {
|
||||
if (buffer == nullptr) { // we didn't get a buufer => create one
|
||||
allocBuffer = new float*[height];
|
||||
|
||||
@ -854,7 +854,7 @@ SSEFUNCTION void ImProcFunctions::RGB_denoise(int kall, Imagefloat * src, Imagef
|
||||
const float noisevarab_b = SQR(realblue);
|
||||
|
||||
//input L channel
|
||||
array2D<float> *Lin;
|
||||
array2D<float> *Lin = nullptr;
|
||||
//wavelet denoised image
|
||||
LabImage * labdn = new LabImage(width, height);
|
||||
|
||||
@ -1678,10 +1678,7 @@ SSEFUNCTION void ImProcFunctions::RGB_denoise(int kall, Imagefloat * src, Imagef
|
||||
}
|
||||
|
||||
delete labdn;
|
||||
|
||||
if (denoiseLuminance) {
|
||||
delete Lin;
|
||||
}
|
||||
delete Lin;
|
||||
|
||||
}//end of tile row
|
||||
}//end of tile loop
|
||||
@ -2251,7 +2248,6 @@ SSEFUNCTION bool ImProcFunctions::WaveletDenoiseAll_BiShrinkL(wavelet_decomposit
|
||||
float ** WavCoeffs_L = WaveletCoeffs_L.level_coeffs(lvl);
|
||||
|
||||
if (lvl == maxlvl - 1) {
|
||||
float vari[4];
|
||||
int edge = 0;
|
||||
ShrinkAllL(WaveletCoeffs_L, buffer, lvl, dir, noisevarlum, madL[lvl], nullptr, edge);
|
||||
} else {
|
||||
@ -2614,7 +2610,7 @@ SSEFUNCTION void ImProcFunctions::ShrinkAllL(wavelet_decomposition &WaveletCoeff
|
||||
// printf("OK lev=%d\n",level);
|
||||
float mad_L = madL[dir - 1] ;
|
||||
|
||||
if (edge == 1) {
|
||||
if (edge == 1 && vari) {
|
||||
noisevarlum = blurBuffer; // we need one buffer, but fortunately we don't have to allocate a new one because we can use blurBuffer
|
||||
|
||||
for (int i = 0; i < W_L * H_L; ++i) {
|
||||
@ -3045,7 +3041,7 @@ void ImProcFunctions::calcautodn_info (float &chaut, float &delta, int Nb, int l
|
||||
delta *= 0.15f;
|
||||
} else if (chaut < 650.f) {
|
||||
delta *= 0.1f;
|
||||
} else if (chaut >= 650.f) {
|
||||
} else /*if (chaut >= 650.f)*/ {
|
||||
delta *= 0.07f;
|
||||
}
|
||||
|
||||
@ -3083,7 +3079,7 @@ void ImProcFunctions::calcautodn_info (float &chaut, float &delta, int Nb, int l
|
||||
delta *= 0.3f;
|
||||
} else if (chaut < 650.f) {
|
||||
delta *= 0.2f;
|
||||
} else if (chaut >= 650.f) {
|
||||
} else /*if (chaut >= 650.f)*/ {
|
||||
delta *= 0.15f;
|
||||
}
|
||||
|
||||
@ -3108,7 +3104,7 @@ void ImProcFunctions::calcautodn_info (float &chaut, float &delta, int Nb, int l
|
||||
|
||||
}
|
||||
|
||||
SSEFUNCTION void ImProcFunctions::RGB_denoise_info(Imagefloat * src, Imagefloat * provicalc, const bool isRAW, LUTf &gamcurve, float gam, float gamthresh, float gamslope, const procparams::DirPyrDenoiseParams & dnparams, const double expcomp, float &chaut, int &Nb, float &redaut, float &blueaut, float &maxredaut, float &maxblueaut, float &minredaut, float &minblueaut, float &nresi, float &highresi, float &chromina, float &sigma, float &lumema, float &sigma_L, float &redyel, float &skinc, float &nsknc, bool multiThread)
|
||||
SSEFUNCTION void ImProcFunctions::RGB_denoise_info(Imagefloat * src, Imagefloat * provicalc, const bool isRAW, LUTf &gamcurve, float gam, float gamthresh, float gamslope, const procparams::DirPyrDenoiseParams & dnparams, const double expcomp, float &chaut, int &Nb, float &redaut, float &blueaut, float &maxredaut, float &maxblueaut, float &minredaut, float &minblueaut, float &chromina, float &sigma, float &lumema, float &sigma_L, float &redyel, float &skinc, float &nsknc, bool multiThread)
|
||||
{
|
||||
if ((settings->leveldnautsimpl == 1 && dnparams.Cmethod == "MAN") || (settings->leveldnautsimpl == 0 && dnparams.C2method == "MANU")) {
|
||||
//nothing to do
|
||||
@ -3547,9 +3543,6 @@ SSEFUNCTION void ImProcFunctions::RGB_denoise_info(Imagefloat * src, Imagefloat
|
||||
}
|
||||
|
||||
comptlevel += 1;
|
||||
float chresid, chmaxredresid, chmaxblueresid;
|
||||
nresi = chresid;
|
||||
highresi = chresid + 0.66f * (max(chmaxredresid, chmaxblueresid) - chresid); //evaluate sigma
|
||||
delete adecomp;
|
||||
delete bdecomp;
|
||||
delete labdn;
|
||||
|
@ -61,13 +61,16 @@
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
#include <cassert>
|
||||
|
||||
#ifndef NDEBUG
|
||||
#include <glibmm.h>
|
||||
#include <fstream>
|
||||
#endif
|
||||
|
||||
#include "opthelper.h"
|
||||
#include <assert.h>
|
||||
#include "rt_math.h"
|
||||
#include "noncopyable.h"
|
||||
|
||||
// Bit representations of flags
|
||||
enum {
|
||||
@ -85,7 +88,8 @@ using LUTd = LUT<double>;
|
||||
using LUTuc = LUT<uint8_t>;
|
||||
|
||||
template<typename T>
|
||||
class LUT
|
||||
class LUT :
|
||||
public rtengine::NonCopyable
|
||||
{
|
||||
protected:
|
||||
// list of variables ordered to improve cache speed
|
||||
|
@ -26,18 +26,17 @@
|
||||
|
||||
#ifdef BENCHMARK
|
||||
#define BENCHFUN StopWatch StopFun(__func__);
|
||||
#define BENCHFUNMICRO StopWatch StopFun(__func__, true);
|
||||
#else
|
||||
#define BENCHFUN
|
||||
#define BENCHFUNMICRO
|
||||
#endif
|
||||
|
||||
class StopWatch
|
||||
{
|
||||
public:
|
||||
StopWatch( )
|
||||
{
|
||||
stopped = false;
|
||||
}
|
||||
StopWatch( const char* msg)
|
||||
|
||||
explicit StopWatch( const char* msg, bool microseconds = false ) : microseconds(microseconds)
|
||||
{
|
||||
message = msg;
|
||||
start();
|
||||
@ -56,8 +55,13 @@ public:
|
||||
void stop()
|
||||
{
|
||||
stopTime.set();
|
||||
long elapsedTime = stopTime.etime(startTime) / 1000;
|
||||
std::cout << message << " took " << elapsedTime << " ms" << std::endl;
|
||||
if(!microseconds) {
|
||||
long elapsedTime = stopTime.etime(startTime) / 1000;
|
||||
std::cout << message << " took " << elapsedTime << " ms" << std::endl;
|
||||
} else {
|
||||
long elapsedTime = stopTime.etime(startTime);
|
||||
std::cout << message << " took " << elapsedTime << " us" << std::endl;
|
||||
}
|
||||
stopped = true;
|
||||
}
|
||||
void stop(const char *msg)
|
||||
@ -66,6 +70,7 @@ public:
|
||||
stop();
|
||||
};
|
||||
private:
|
||||
bool microseconds;
|
||||
MyTime startTime;
|
||||
MyTime stopTime;
|
||||
const char *message;
|
||||
|
@ -93,7 +93,15 @@ public:
|
||||
// we're freeing the memory and allocate it again if the new size is bigger.
|
||||
|
||||
if (allocatedSize < oldAllocatedSize) {
|
||||
real = realloc(real, allocatedSize + alignment);
|
||||
void *temp = realloc(real, allocatedSize + alignment);
|
||||
if (temp) { // realloc succeeded
|
||||
real = temp;
|
||||
} else { // realloc failed => free old buffer and allocate new one
|
||||
if (real) {
|
||||
free (real);
|
||||
}
|
||||
real = malloc(allocatedSize + alignment);
|
||||
}
|
||||
} else {
|
||||
if (real) {
|
||||
free (real);
|
||||
@ -143,7 +151,7 @@ private:
|
||||
size_t size;
|
||||
|
||||
public:
|
||||
AlignedBufferMP(size_t sizeP)
|
||||
explicit AlignedBufferMP(size_t sizeP)
|
||||
{
|
||||
size = sizeP;
|
||||
}
|
||||
|
@ -66,8 +66,11 @@
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
|
||||
#include "noncopyable.h"
|
||||
|
||||
template<typename T>
|
||||
class array2D
|
||||
class array2D :
|
||||
public rtengine::NonCopyable
|
||||
{
|
||||
|
||||
private:
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file is part of RawTherapee.
|
||||
*
|
||||
* Copyright (C) 2016 Floessie <floessie.mail@gmail.com>
|
||||
* Copyright (C) 2016 Flössie <floessie.mail@gmail.com>
|
||||
*
|
||||
* RawTherapee is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -20,11 +20,13 @@
|
||||
#define _CIEIMAGE_H_
|
||||
|
||||
#include "image16.h"
|
||||
#include "noncopyable.h"
|
||||
|
||||
namespace rtengine
|
||||
{
|
||||
|
||||
class CieImage
|
||||
class CieImage :
|
||||
public NonCopyable
|
||||
{
|
||||
private:
|
||||
bool fromImage;
|
||||
|
@ -7,16 +7,16 @@
|
||||
|
||||
#include "cache.h"
|
||||
#include "alignedbuffer.h"
|
||||
#include "noncopyable.h"
|
||||
|
||||
namespace rtengine
|
||||
{
|
||||
|
||||
class HaldCLUT
|
||||
class HaldCLUT final :
|
||||
public NonCopyable
|
||||
{
|
||||
public:
|
||||
HaldCLUT();
|
||||
HaldCLUT(const HaldCLUT& other) = delete;
|
||||
HaldCLUT& operator =(const HaldCLUT& other) = delete;
|
||||
~HaldCLUT();
|
||||
|
||||
bool load(const Glib::ustring& filename);
|
||||
@ -51,14 +51,12 @@ private:
|
||||
Glib::ustring clut_profile;
|
||||
};
|
||||
|
||||
class CLUTStore
|
||||
class CLUTStore final :
|
||||
public NonCopyable
|
||||
{
|
||||
public:
|
||||
static CLUTStore& getInstance();
|
||||
|
||||
CLUTStore(const CLUTStore& other) = delete;
|
||||
CLUTStore& operator =(const CLUTStore& other) = delete;
|
||||
|
||||
std::shared_ptr<HaldCLUT> getClut(const Glib::ustring& filename);
|
||||
|
||||
void clearCache();
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "mytime.h"
|
||||
#include "sleef.c"
|
||||
#include "opthelper.h"
|
||||
#include "iccstore.h"
|
||||
|
||||
#define pow_F(a,b) (xexpf(b*xlogf(a)))
|
||||
|
||||
@ -361,6 +362,153 @@ void Color::cleanup ()
|
||||
}
|
||||
}
|
||||
|
||||
void Color::rgb2lab (Glib::ustring profile, Glib::ustring profileW, int r, int g, int b, float &LAB_l, float &LAB_a, float &LAB_b, bool workingSpace)
|
||||
{
|
||||
double xyz_rgb[3][3];
|
||||
const double ep = 216.0 / 24389.0;
|
||||
const double ka = 24389.0 / 27.0;
|
||||
|
||||
double var_R = r / 65535.0;
|
||||
double var_G = g / 65535.0;
|
||||
double var_B = b / 65535.0;
|
||||
|
||||
Glib::ustring profileCalc;
|
||||
profileCalc = "sRGB"; //default
|
||||
|
||||
if (workingSpace) {
|
||||
profileCalc = profileW; //display working
|
||||
}
|
||||
|
||||
else {// if you want display = output space
|
||||
if (profile == "RT_sRGB" || profile == "RT_sRGB_gBT709" || profile == "RT_sRGB_g10") {
|
||||
profileCalc = "sRGB";
|
||||
}
|
||||
|
||||
if (profile == "ProPhoto" || profile == "RT_Large_gBT709" || profile == "RT_Large_g10" || profile == "RT_Large_gsRGB") {
|
||||
profileCalc = "ProPhoto";
|
||||
}
|
||||
|
||||
if (profile == "AdobeRGB1998" || profile == "RT_Medium_gsRGB") {
|
||||
profileCalc = "Adobe RGB";
|
||||
}
|
||||
|
||||
if (profile == "WideGamutRGB") {
|
||||
profileCalc = "WideGamut";
|
||||
}
|
||||
}
|
||||
|
||||
if (workingSpace) {//display working
|
||||
if (profileW == "sRGB") { //apply sRGB inverse gamma
|
||||
|
||||
if ( var_R > 0.04045 ) {
|
||||
var_R = pow ( ( ( var_R + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve);
|
||||
} else {
|
||||
var_R = var_R / 12.92;
|
||||
}
|
||||
|
||||
if ( var_G > 0.04045 ) {
|
||||
var_G = pow ( ( ( var_G + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve);
|
||||
} else {
|
||||
var_G = var_G / 12.92;
|
||||
}
|
||||
|
||||
if ( var_B > 0.04045 ) {
|
||||
var_B = pow ( ( ( var_B + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve);
|
||||
} else {
|
||||
var_B = var_B / 12.92;
|
||||
}
|
||||
} else if (profileW == "ProPhoto") { // apply inverse gamma 1.8
|
||||
var_R = pow ( var_R, 1.8);
|
||||
var_G = pow ( var_G, 1.8);
|
||||
var_B = pow ( var_B, 1.8);
|
||||
} else { // apply inverse gamma 2.2
|
||||
var_R = pow ( var_R, 2.2);
|
||||
var_G = pow ( var_G, 2.2);
|
||||
var_B = pow ( var_B, 2.2);
|
||||
}
|
||||
} else { //display outout profile
|
||||
|
||||
if (profile == "RT_sRGB" || profile == "RT_Large_gsRGB" || profile == "RT_Medium_gsRGB") { //apply sRGB inverse gamma
|
||||
if ( var_R > 0.04045 ) {
|
||||
var_R = pow ( ( ( var_R + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve);
|
||||
} else {
|
||||
var_R = var_R / 12.92;
|
||||
}
|
||||
|
||||
if ( var_G > 0.04045 ) {
|
||||
var_G = pow ( ( ( var_G + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve);
|
||||
} else {
|
||||
var_G = var_G / 12.92;
|
||||
}
|
||||
|
||||
if ( var_B > 0.04045 ) {
|
||||
var_B = pow ( ( ( var_B + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve);
|
||||
} else {
|
||||
var_B = var_B / 12.92;
|
||||
}
|
||||
}
|
||||
|
||||
else if (profile == "RT_sRGB_gBT709" || profile == "RT_Large_gBT709") { //
|
||||
if ( var_R > 0.0795 ) {
|
||||
var_R = pow ( ( ( var_R + 0.0954 ) / 1.0954 ), 2.2);
|
||||
} else {
|
||||
var_R = var_R / 4.5;
|
||||
}
|
||||
|
||||
if ( var_G > 0.0795 ) {
|
||||
var_G = pow ( ( ( var_G + 0.0954 ) / 1.0954 ), 2.2);
|
||||
} else {
|
||||
var_G = var_G / 4.5;
|
||||
}
|
||||
|
||||
if ( var_B > 0.0795 ) {
|
||||
var_B = pow ( ( ( var_B + 0.0954 ) / 1.0954 ), 2.2);
|
||||
} else {
|
||||
var_B = var_B / 4.5;
|
||||
}
|
||||
|
||||
} else if (profile == "ProPhoto") { // apply inverse gamma 1.8
|
||||
|
||||
var_R = pow ( var_R, 1.8);
|
||||
var_G = pow ( var_G, 1.8);
|
||||
var_B = pow ( var_B, 1.8);
|
||||
} else if (profile == "RT_sRGB_g10" || profile == "RT_Large_g10") { // apply inverse gamma 1.8
|
||||
|
||||
var_R = pow ( var_R, 1.);
|
||||
var_G = pow ( var_G, 1.);
|
||||
var_B = pow ( var_B, 1.);
|
||||
}
|
||||
|
||||
else {// apply inverse gamma 2.2
|
||||
var_R = pow ( var_R, 2.2);
|
||||
var_G = pow ( var_G, 2.2);
|
||||
var_B = pow ( var_B, 2.2);
|
||||
}
|
||||
}
|
||||
|
||||
// TMatrix wprof = rtengine::ICCStore::getInstance()->workingSpaceMatrix (profileW);
|
||||
|
||||
TMatrix wprof = rtengine::ICCStore::getInstance()->workingSpaceMatrix (profileCalc);
|
||||
|
||||
for (int m = 0; m < 3; m++)
|
||||
for (int n = 0; n < 3; n++) {
|
||||
xyz_rgb[m][n] = wprof[m][n];
|
||||
}
|
||||
|
||||
double varxx, varyy, varzz;
|
||||
double var_X = ( xyz_rgb[0][0] * var_R + xyz_rgb[0][1] * var_G + xyz_rgb[0][2] * var_B ) / Color::D50x;
|
||||
double var_Y = ( xyz_rgb[1][0] * var_R + xyz_rgb[1][1] * var_G + xyz_rgb[1][2] * var_B ) ;
|
||||
double var_Z = ( xyz_rgb[2][0] * var_R + xyz_rgb[2][1] * var_G + xyz_rgb[2][2] * var_B ) / Color::D50z;
|
||||
|
||||
varxx = var_X > ep ? cbrt(var_X) : ( ka * var_X + 16.0) / 116.0 ;
|
||||
varyy = var_Y > ep ? cbrt(var_Y) : ( ka * var_Y + 16.0) / 116.0 ;
|
||||
varzz = var_Z > ep ? cbrt(var_Z) : ( ka * var_Z + 16.0) / 116.0 ;
|
||||
LAB_l = ( 116 * varyy ) - 16;
|
||||
LAB_a = 500 * ( varxx - varyy );
|
||||
LAB_b = 200 * ( varyy - varzz );
|
||||
|
||||
}
|
||||
|
||||
void Color::rgb2hsl(float r, float g, float b, float &h, float &s, float &l)
|
||||
{
|
||||
|
||||
|
@ -177,6 +177,22 @@ public:
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convert red/green/blue to L*a*b
|
||||
* @brief Convert red/green/blue to hue/saturation/luminance
|
||||
* @param profile output profile name
|
||||
* @param profileW working profile name
|
||||
* @param r red channel [0 ; 65535]
|
||||
* @param g green channel [0 ; 65535]
|
||||
* @param b blue channel [0 ; 65535]
|
||||
* @param L Lab L channel [0 ; 1] (return value)
|
||||
* @param a Lab a channel [0 ; 1] (return value)
|
||||
* @param b Lab b channel [0; 1] (return value)
|
||||
* @param workingSpace true: compute the Lab value using the Working color space ; false: use the Output color space
|
||||
*/
|
||||
static void rgb2lab (Glib::ustring profile, Glib::ustring profileW, int r, int g, int b, float &LAB_l, float &LAB_a, float &LAB_b, bool workingSpace);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convert red/green/blue to hue/saturation/luminance
|
||||
* @param r red channel [0 ; 65535]
|
||||
|
@ -34,7 +34,7 @@ namespace rtengine
|
||||
|
||||
extern const Settings* settings;
|
||||
|
||||
static const double cie_colour_match_jd[97][3] = {//350nm to 830nm 5 nm J.Desmis 2 degree Standard Observer.
|
||||
static const double cie_colour_match_jd[97][3] = {//350nm to 830nm 5 nm J.Desmis 2° Standard Observer.
|
||||
{0.0000000, 0.000000, 0.000000}, {0.0000000, 0.000000, 0.000000}, {0.0001299, 0.0003917, 0.0006061},
|
||||
{0.0002321, 0.000006965, 0.001086}, {0.0004149, 0.00001239, 0.001946}, {0.0007416, 0.00002202, 0.003846},
|
||||
{0.001368, 0.000039, 0.006450001}, {0.002236, 0.000064, 0.01054999}, {0.004243, 0.000120, 0.02005001},
|
||||
@ -295,7 +295,7 @@ const double ColorTemp::Solux4100_spect[97] = {
|
||||
62.40, 61.373, 59.75, 58.1810, 56.25, 54.395, 51.90, 49.496, 47.05, 44.620
|
||||
};
|
||||
|
||||
//spectral data for Solux lamp : near Daylight (for example "Musee d'Orsay") - 4700K
|
||||
//spectral data for Solux lamp : near Daylight (for example "Musée d'Orsay") - 4700K
|
||||
const double ColorTemp::Solux4700_spect[97] = {
|
||||
0.4590, 0.83, 1.2011, 1.53, 1.8647, 2.15, 2.5338, 3.06, 3.5809, 3.99, 4.4137, 4.82, 5.2228, 5.63, 6.0387, 6.53, 6.9944, 7.55, 8.0266, 8.475, 8.9276, 8.90, 9.7840, 10.20, 10.6390, 11.00, 11.3600, 11.75, 12.1340, 12.36, 12.5880, 12.74, 12.8790,
|
||||
13.07, 13.2560, 13.38, 13.5220, 13.41, 13.3070, 13.35, 13.3990, 13.37, 13.3420, 13.39, 13.4220, 13.65, 13.2710, 13.25, 13.2330, 13.12, 13.0110, 12.93, 12.8470, 12.805, 12.7630, 12.66, 12.5760, 12.563, 12.5490,
|
||||
@ -1025,7 +1025,7 @@ void ColorTemp::cieCAT02(double Xw, double Yw, double Zw, double &CAM02BB00, dou
|
||||
|
||||
}
|
||||
|
||||
void ColorTemp::temp2mulxyz (double tem, double gree, std::string method , double &Xxyz, double &Zxyz)
|
||||
void ColorTemp::temp2mulxyz (double tem, double gree, const std::string &method, double &Xxyz, double &Zxyz)
|
||||
{
|
||||
double xD, yD, x_D, y_D, interm;
|
||||
double x, y, z;
|
||||
@ -1100,7 +1100,7 @@ void ColorTemp::temp2mulxyz (double tem, double gree, std::string method , doubl
|
||||
x_D = -4.6070e9 / (tem * tem * tem) + 2.9678e6 / (tem * tem) + 0.09911e3 / tem + 0.244063;
|
||||
} else if (tem <= 25000) {
|
||||
x_D = -2.0064e9 / (tem * tem * tem) + 1.9018e6 / (tem * tem) + 0.24748e3 / tem + 0.237040;
|
||||
} else if (tem > 25000) {
|
||||
} else /*if (tem > 25000)*/ {
|
||||
x_D = -2.0064e9 / (tem * tem * tem) + 1.9018e6 / (tem * tem) + 0.24748e3 / tem + 0.237040 - ((tem - 25000) / 25000) * 0.025; //Jacques empirical adjustemnt for very high temp (underwater !)
|
||||
}
|
||||
|
||||
@ -1135,12 +1135,10 @@ void ColorTemp::temp2mul (double temp, double green, double equal, double& rmul,
|
||||
//printf("temp=%d green=%.3f equal=%.3f\n", (int)temp, (float) green, (float) equal);
|
||||
|
||||
//variables for CRI and display Lab, and palette
|
||||
bool CRI_type = false;
|
||||
double xD, yD, x_D, y_D, interm;
|
||||
double m1, m2;
|
||||
double xp, yp;
|
||||
|
||||
double x, y, z, xx, yy, zz;
|
||||
double x, y, z;
|
||||
double Xchk[50], Ychk[50], Zchk[50]; //50 : I think it's a good limit for number of color : for CRI and Palette
|
||||
double Xcam02[50], Ycam02[50], Zcam02[50];
|
||||
double Xcam02pal[50], Ycam02pal[50], Zcam02pal[50];
|
||||
@ -1148,16 +1146,12 @@ void ColorTemp::temp2mul (double temp, double green, double equal, double& rmul,
|
||||
double XchkLamp[50], YchkLamp[50], ZchkLamp[50];
|
||||
double Xcam02Lamp[50], Ycam02Lamp[50], Zcam02Lamp[50];
|
||||
double Xpal[50], Ypal[50], Zpal[50];
|
||||
double tempw;
|
||||
const double epsilon = 0.008856; //Lab
|
||||
const double whiteD50[3] = {0.9646019585, 1.0, 0.8244507152}; //calculate with this tool : spect 5nm
|
||||
double CAM02BB00, CAM02BB01, CAM02BB02, CAM02BB10, CAM02BB11, CAM02BB12, CAM02BB20, CAM02BB21, CAM02BB22; //for CIECAT02
|
||||
|
||||
double xr[50], yr[50], zr[50];
|
||||
double fx[50], fy[50], fz[50];
|
||||
double Llamp[50], alamp[50], blamp[50];
|
||||
double Lbb[50], abb[50], bbb[50];
|
||||
double Lpal[50], apal[50], bpal[50];
|
||||
|
||||
int palet = -1;
|
||||
bool palette = false;
|
||||
@ -1263,7 +1257,7 @@ void ColorTemp::temp2mul (double temp, double green, double equal, double& rmul,
|
||||
x_D = -4.6070e9 / (temp * temp * temp) + 2.9678e6 / (temp * temp) + 0.09911e3 / temp + 0.244063;
|
||||
} else if (temp <= 25000) {
|
||||
x_D = -2.0064e9 / (temp * temp * temp) + 1.9018e6 / (temp * temp) + 0.24748e3 / temp + 0.237040;
|
||||
} else if (temp > 25000) { // above 25000 it's unknown..then I have modified to adjust for underwater
|
||||
} else /*if (temp > 25000)*/ { // above 25000 it's unknown..then I have modified to adjust for underwater
|
||||
x_D = -2.0064e9 / (temp * temp * temp) + 1.9018e6 / (temp * temp) + 0.24748e3 / temp + 0.237040 - ((temp - 25000) / 25000) * 0.025; //Jacques empirical adjustemnt for very high temp (underwater !)
|
||||
}
|
||||
|
||||
@ -1291,8 +1285,6 @@ void ColorTemp::temp2mul (double temp, double green, double equal, double& rmul,
|
||||
double Xwb = xD / yD;
|
||||
double Ywb = 1.0;
|
||||
double Zwb = (1.0 - xD - yD) / yD;
|
||||
double correl_temp;
|
||||
|
||||
|
||||
if (settings->verbose) {
|
||||
// double u=4*xD/(-2*xD+12*yD+3);
|
||||
@ -1335,11 +1327,6 @@ void ColorTemp::temp2mul (double temp, double green, double equal, double& rmul,
|
||||
{
|
||||
double x_x, y_y, z_z;
|
||||
// illuminants
|
||||
const double* spect_illummax[] = {
|
||||
Daylight5300_spect, Cloudy6200_spect, Shade7600_spect, A2856_spect, FluoF1_spect, FluoF2_spect, FluoF3_spect, FluoF4_spect, FluoF5_spect, FluoF6_spect, FluoF7_spect,
|
||||
FluoF8_spect, FluoF9_spect, FluoF10_spect, FluoF11_spect, FluoF12_spect, HMI_spect, GTI_spect, JudgeIII_spect, Solux3500_spect, Solux4100_spect, Solux4700_spect, NG_Solux4700_spect, NG_CRSSP12WWMR16_spect, NG_CRSSP12WWMR16_spect,
|
||||
Flash5500_spect, Flash6000_spect, Flash6500_spect
|
||||
};
|
||||
// color
|
||||
const double* spec_colorpalet[] = {
|
||||
ColabSkin98_m2_10_spect, ColabSkin95_0_4_spect, ColabSkin91_4_14_spect, ColabSkin90_m1_20_spect,
|
||||
@ -1359,13 +1346,18 @@ void ColorTemp::temp2mul (double temp, double green, double equal, double& rmul,
|
||||
int N_col = sizeof(spec_colorpalet) / sizeof(spec_colorpalet[0]); //number of color
|
||||
|
||||
if(palet < 28) {
|
||||
const double* spect_illummax[] = {
|
||||
Daylight5300_spect, Cloudy6200_spect, Shade7600_spect, A2856_spect, FluoF1_spect, FluoF2_spect, FluoF3_spect, FluoF4_spect, FluoF5_spect, FluoF6_spect, FluoF7_spect,
|
||||
FluoF8_spect, FluoF9_spect, FluoF10_spect, FluoF11_spect, FluoF12_spect, HMI_spect, GTI_spect, JudgeIII_spect, Solux3500_spect, Solux4100_spect, Solux4700_spect, NG_Solux4700_spect, NG_CRSSP12WWMR16_spect, NG_CRSSP12WWMR16_spect,
|
||||
Flash5500_spect, Flash6000_spect, Flash6500_spect
|
||||
};
|
||||
for(int i = 0; i < N_col; i++) {
|
||||
spectrum_to_color_xyz_preset(spec_colorpalet[i], spect_illummax[palet], x_x, y_y, z_z);
|
||||
Xpal[i] = x_x;
|
||||
Ypal[i] = y_y;
|
||||
Zpal[i] = z_z;
|
||||
}
|
||||
} else if(palet >= 28) {
|
||||
} else /*if(palet >= 28)*/ {
|
||||
if(temp < INITIALBLACKBODY) {
|
||||
for(int i = 0; i < N_col; i++) {
|
||||
spectrum_to_color_xyz_blackbody(spec_colorpalet[i], temp, x_x, y_y, z_z);
|
||||
@ -1387,8 +1379,8 @@ void ColorTemp::temp2mul (double temp, double green, double equal, double& rmul,
|
||||
}
|
||||
}
|
||||
|
||||
xp = xD;
|
||||
yp = yD;
|
||||
double xp = xD;
|
||||
double yp = yD;
|
||||
double Xwbpal = xp / yp; //white balance
|
||||
double Ywbpal = 1.0;
|
||||
double Zwbpal = (1.0 - xp - yp) / yp;
|
||||
@ -1433,6 +1425,8 @@ void ColorTemp::temp2mul (double temp, double green, double equal, double& rmul,
|
||||
|
||||
//Lab values in function of color and illuminant
|
||||
//these values can be compared to preview values when using white-balance (skin / sky / BW)
|
||||
double Lpal[50], apal[50], bpal[50];
|
||||
|
||||
for(int i = 0; i < N_col; i++) {
|
||||
Lpal[i] = 116.0 * fy[i] - 16.0;
|
||||
apal[i] = 500.0 * (fx[i] - fy[i]);
|
||||
@ -1464,12 +1458,6 @@ void ColorTemp::temp2mul (double temp, double green, double equal, double& rmul,
|
||||
int numero_color = settings->CRI_color - 1;
|
||||
|
||||
//spectral data illuminant (actually 21): only those necessary (lamp, fluorescent, LED) others CRI=100 (not Flash...)
|
||||
const double* spect_illum[] = {
|
||||
Daylight5300_spect, Cloudy6200_spect, Shade7600_spect, A2856_spect, FluoF1_spect, FluoF2_spect, FluoF3_spect,
|
||||
FluoF4_spect, FluoF5_spect, FluoF6_spect, FluoF7_spect, FluoF8_spect, FluoF9_spect, FluoF10_spect, FluoF11_spect,
|
||||
FluoF12_spect, HMI_spect, GTI_spect, JudgeIII_spect, Solux3500_spect, Solux4100_spect, Solux4700_spect,
|
||||
NG_Solux4700_spect, NG_CRSSP12WWMR16_spect, NG_CRSSP12WWMR16_spect
|
||||
};
|
||||
const double* spec_color[] = {
|
||||
ColorchechredC3_spect, ColorchechOraA2_spect, ColorchechYelD3_spect, ColorchechGreE2_spect, ColorchechGreB3_spect,
|
||||
ColorchechCyaF3_spect, ColorchechPurD2_spect, ColorchechMagE3_spect, ColorchechSkiA138_13_14_spect, ColorchechGraC4_67_spect,
|
||||
@ -1480,6 +1468,9 @@ void ColorTemp::temp2mul (double temp, double green, double equal, double& rmul,
|
||||
|
||||
int N_c = sizeof(spec_color) / sizeof(spec_color[0]); //number of color
|
||||
|
||||
bool CRI_type = false;
|
||||
double tempw;
|
||||
|
||||
if (method == "Fluo F1") {
|
||||
CRI_type = true;
|
||||
tempw = 6430;
|
||||
@ -1569,25 +1560,26 @@ void ColorTemp::temp2mul (double temp, double green, double equal, double& rmul,
|
||||
}
|
||||
|
||||
if (CRI_type) {
|
||||
const double* spect_illum[] = {
|
||||
Daylight5300_spect, Cloudy6200_spect, Shade7600_spect, A2856_spect, FluoF1_spect, FluoF2_spect, FluoF3_spect,
|
||||
FluoF4_spect, FluoF5_spect, FluoF6_spect, FluoF7_spect, FluoF8_spect, FluoF9_spect, FluoF10_spect, FluoF11_spect,
|
||||
FluoF12_spect, HMI_spect, GTI_spect, JudgeIII_spect, Solux3500_spect, Solux4100_spect, Solux4700_spect,
|
||||
NG_Solux4700_spect, NG_CRSSP12WWMR16_spect, NG_CRSSP12WWMR16_spect
|
||||
};
|
||||
|
||||
float DeltaE[50], DeltaEs[8];
|
||||
float quadCRI = 0.0f, quadCRIs = 0.0f;
|
||||
float CRI_RT = 0.0, CRI[50];
|
||||
float CRI_RTs = 0.0, CRIs[8];
|
||||
|
||||
for(int i = 0; i < N_c; i++) {
|
||||
spectrum_to_color_xyz_preset(spec_color[i], spect_illum[illum + 3], xx, yy, zz);
|
||||
XchkLamp[i] = xx;
|
||||
YchkLamp[i] = yy;
|
||||
ZchkLamp[i] = zz;
|
||||
spectrum_to_color_xyz_preset(spec_color[i], spect_illum[illum + 3], XchkLamp[i], YchkLamp[i], ZchkLamp[i]);
|
||||
}
|
||||
|
||||
//calculate XYZ for each color : for Blackbody and Daylight at tempw
|
||||
if(tempw <= INITIALBLACKBODY) {
|
||||
for(int i = 0; i < N_c; i++) {
|
||||
spectrum_to_color_xyz_blackbody(spec_color[i], tempw, xx, yy, zz);
|
||||
Xchk[i] = xx;
|
||||
Ychk[i] = yy;
|
||||
Zchk[i] = zz;
|
||||
spectrum_to_color_xyz_blackbody(spec_color[i], tempw, Xchk[i], Ychk[i], Zchk[i]);
|
||||
}
|
||||
|
||||
spectrum_to_xyz_blackbody(tempw, x, y, z);//for white point
|
||||
@ -1608,18 +1600,15 @@ void ColorTemp::temp2mul (double temp, double green, double equal, double& rmul,
|
||||
m22 = (0.03 - 31.4424 * x_DD + 30.0717 * y_DD) / interm2;
|
||||
|
||||
for(int i = 0; i < N_c; i++) {
|
||||
spectrum_to_color_xyz_daylight(spec_color[i], m11, m22, xx, yy, zz);
|
||||
Xchk[i] = xx;
|
||||
Ychk[i] = yy;
|
||||
Zchk[i] = zz;
|
||||
spectrum_to_color_xyz_daylight(spec_color[i], m11, m22, Xchk[i], Ychk[i], Zchk[i]);
|
||||
}
|
||||
|
||||
spectrum_to_xyz_daylight(m11, m22, x, y, z);
|
||||
}
|
||||
|
||||
XYZtoCorColorTemp(Xwb, Ywb, Zwb, correl_temp);
|
||||
|
||||
if (settings->verbose) {
|
||||
double correl_temp;
|
||||
XYZtoCorColorTemp(Xwb, Ywb, Zwb, correl_temp);
|
||||
printf("Correlated temperature (lamp)=%i\n", (int) correl_temp); //use only for lamp...otherwise It give an information!!
|
||||
}
|
||||
|
||||
@ -1680,6 +1669,7 @@ void ColorTemp::temp2mul (double temp, double green, double equal, double& rmul,
|
||||
}
|
||||
}
|
||||
|
||||
double Llamp[50], alamp[50], blamp[50];
|
||||
for(int i = 0; i < N_c; i++) {
|
||||
Llamp[i] = 116.0 * fy[i] - 16.0;
|
||||
alamp[i] = 500.0 * (fx[i] - fy[i]);
|
||||
@ -1712,6 +1702,8 @@ void ColorTemp::temp2mul (double temp, double green, double equal, double& rmul,
|
||||
}
|
||||
}
|
||||
|
||||
double Lbb[50], abb[50], bbb[50];
|
||||
|
||||
for(int i = 0; i < N_c; i++) {
|
||||
Lbb[i] = 116.*fy[i] - 16.;
|
||||
abb[i] = 500.*(fx[i] - fy[i]);
|
||||
@ -1797,7 +1789,7 @@ The next 3 methods are inspired from:
|
||||
|
||||
this values are often called xBar yBar zBar and are characteristics of a color / illuminant
|
||||
|
||||
values cie_colour_match[][3] = Observer 2 degree Standard Observer x2, y2, z2
|
||||
values cie_colour_match[][3] = 2° Standard Observer x2, y2, z2
|
||||
E.g. for 380nm: x2=0.001368 y2=0.000039 z2=0.006451 round in J.Walker to 0.0014 0.0000 0.0065 above
|
||||
I have increase precision used by J.Walker and pass to 350nm to 830nm
|
||||
*/
|
||||
@ -1855,7 +1847,7 @@ void ColorTemp::spectrum_to_xyz_preset(const double* spec_intens, double &x, dou
|
||||
|
||||
this values are often called xBar yBar zBar and are characteristics of a color / illuminant
|
||||
|
||||
values cie_colour_match[][3] = 2 degree Standard Observer x2, y2, z2
|
||||
values cie_colour_match[][3] = 2° Standard Observer x2, y2, z2
|
||||
E.g. for 380nm: x2=0.001368 y2=0.000039 z2=0.006451 round in J.Walker to 0.0014 0.0000 0.0065 above
|
||||
I have increased the precision used by J.Walker and pass from 350nm to 830nm
|
||||
*/
|
||||
|
@ -53,7 +53,7 @@ private:
|
||||
public:
|
||||
|
||||
ColorTemp () : temp(-1.), green(-1.), equal (1.), method("Custom") {}
|
||||
ColorTemp (double e) : temp(-1.), green(-1.), equal (e), method("Custom") {}
|
||||
explicit ColorTemp (double e) : temp(-1.), green(-1.), equal (e), method("Custom") {}
|
||||
ColorTemp (double t, double g, double e, const Glib::ustring &m);
|
||||
ColorTemp (double mulr, double mulg, double mulb, double e);
|
||||
|
||||
@ -92,7 +92,7 @@ public:
|
||||
}
|
||||
|
||||
void mul2temp (const double rmul, const double gmul, const double bmul, const double equal, double& temp, double& green) const;
|
||||
static void temp2mulxyz (double tem, double gree, std::string method, double &Xxyz, double &Zxyz);
|
||||
static void temp2mulxyz (double tem, double gree, const std::string &method, double &Xxyz, double &Zxyz);
|
||||
|
||||
static void cieCAT02(double Xw, double Yw, double Zw, double &CAM02BB00, double &CAM02BB01, double &CAM02BB02, double &CAM02BB10, double &CAM02BB11, double &CAM02BB12, double &CAM02BB20, double &CAM02BB21, double &CAM02BB22, double adap );
|
||||
//static void CAT02 (Imagefloat* baseImg, const ProcParams* params);
|
||||
|
@ -35,7 +35,7 @@ struct Coord
|
||||
Coord () = default;
|
||||
Coord (const int x, const int y);
|
||||
Coord (const Coord& other) = default;
|
||||
Coord (const PolarCoord& other);
|
||||
explicit Coord (const PolarCoord& other);
|
||||
|
||||
Coord& operator= (const Coord& other) = default;
|
||||
Coord& operator= (const PolarCoord& other);
|
||||
@ -48,7 +48,10 @@ struct Coord
|
||||
Coord& operator+= (const Coord& other);
|
||||
Coord& operator-= (const Coord& other);
|
||||
Coord& operator*= (const double scale);
|
||||
|
||||
bool operator< (const Coord& rhs) const;
|
||||
bool operator> (const Coord& rhs) const;
|
||||
bool operator<=(const Coord& rhs) const;
|
||||
bool operator>=(const Coord& rhs) const;
|
||||
};
|
||||
|
||||
bool operator== (const Coord& lhs, const Coord& rhs);
|
||||
@ -66,7 +69,7 @@ struct PolarCoord
|
||||
PolarCoord () = default;
|
||||
PolarCoord (const double radius, const double angle);
|
||||
PolarCoord (const PolarCoord& other) = default;
|
||||
PolarCoord (const Coord& other);
|
||||
explicit PolarCoord (const Coord& other);
|
||||
|
||||
PolarCoord& operator= (const PolarCoord& other) = default;
|
||||
PolarCoord& operator= (const Coord& other);
|
||||
@ -130,6 +133,26 @@ inline Coord& Coord::operator*= (const double scale)
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bool Coord::operator< (const Coord& rhs) const
|
||||
{
|
||||
return x < rhs.x && y < rhs.y;
|
||||
}
|
||||
|
||||
inline bool Coord::operator> (const Coord& rhs) const
|
||||
{
|
||||
return x > rhs.x && y > rhs.y;
|
||||
}
|
||||
|
||||
inline bool Coord::operator<=(const Coord& rhs) const
|
||||
{
|
||||
return x <= rhs.x && y <= rhs.y;
|
||||
}
|
||||
|
||||
inline bool Coord::operator>=(const Coord& rhs) const
|
||||
{
|
||||
return x >= rhs.x && y >= rhs.y;
|
||||
}
|
||||
|
||||
inline bool operator== (const Coord& lhs, const Coord& rhs)
|
||||
{
|
||||
return lhs.x == rhs.x && lhs.y == rhs.y;
|
||||
|
@ -22,15 +22,17 @@
|
||||
#define CPLX_WAVELET_DEC_H_INCLUDED
|
||||
|
||||
#include <cstddef>
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
|
||||
#include "cplx_wavelet_level.h"
|
||||
#include "cplx_wavelet_filter_coeffs.h"
|
||||
#include "noncopyable.h"
|
||||
|
||||
namespace rtengine
|
||||
{
|
||||
|
||||
class wavelet_decomposition
|
||||
class wavelet_decomposition :
|
||||
public NonCopyable
|
||||
{
|
||||
public:
|
||||
|
||||
|
@ -26,11 +26,12 @@
|
||||
|
||||
#include <glibmm.h>
|
||||
|
||||
#include "../rtgui/threadutils.h"
|
||||
|
||||
#include "imagefloat.h"
|
||||
#include "curves.h"
|
||||
#include "colortemp.h"
|
||||
|
||||
#include "../rtgui/threadutils.h"
|
||||
#include "noncopyable.h"
|
||||
|
||||
namespace rtengine
|
||||
{
|
||||
@ -63,7 +64,7 @@ public:
|
||||
using Triple = std::array<double, 3>;
|
||||
using Matrix = std::array<Triple, 3>;
|
||||
|
||||
DCPProfile(const Glib::ustring& filename);
|
||||
explicit DCPProfile(const Glib::ustring& filename);
|
||||
~DCPProfile();
|
||||
|
||||
explicit operator bool() const;
|
||||
@ -145,14 +146,12 @@ private:
|
||||
AdobeToneCurve tone_curve;
|
||||
};
|
||||
|
||||
class DCPStore final
|
||||
class DCPStore final :
|
||||
public NonCopyable
|
||||
{
|
||||
public:
|
||||
static DCPStore* getInstance();
|
||||
|
||||
DCPStore(const DCPStore& other) = delete;
|
||||
DCPStore& operator =(const DCPStore& other) = delete;
|
||||
|
||||
void init(const Glib::ustring& rt_profile_dir);
|
||||
|
||||
bool isValidDCPFileName(const Glib::ustring& filename) const;
|
||||
|
@ -33,7 +33,7 @@ extern const Settings* settings;
|
||||
Crop::Crop (ImProcCoordinator* parent, EditDataProvider *editDataProvider, bool isDetailWindow)
|
||||
: PipetteBuffer(editDataProvider), origCrop(NULL), laboCrop(NULL), labnCrop(NULL),
|
||||
cropImg(NULL), cbuf_real(NULL), cshmap(NULL), transCrop(NULL), cieCrop(NULL), cbuffer(NULL),
|
||||
updating(false), newUpdatePending(false), skip(10),
|
||||
updating(false), newUpdatePending(false), skip(10), padding(0),
|
||||
cropx(0), cropy(0), cropw(-1), croph(-1),
|
||||
trafx(0), trafy(0), trafw(-1), trafh(-1),
|
||||
rqcropx(0), rqcropy(0), rqcropw(-1), rqcroph(-1),
|
||||
@ -321,7 +321,7 @@ void Crop::update (int todo)
|
||||
|
||||
float maxr = 0.f;
|
||||
float maxb = 0.f;
|
||||
float chaut, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, nresi, highresi, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc;
|
||||
float chaut, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc;
|
||||
int Nb;
|
||||
|
||||
chaut = 0.f;
|
||||
@ -334,7 +334,7 @@ void Crop::update (int todo)
|
||||
LUTf gamcurve(65536, 0);
|
||||
float gam, gamthresh, gamslope;
|
||||
parent->ipf.RGB_denoise_infoGamCurve(params.dirpyrDenoise, parent->imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope);
|
||||
parent->ipf.RGB_denoise_info(origCrop, provicalc, parent->imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope, params.dirpyrDenoise, parent->imgsrc->getDirPyrDenoiseExpComp(), chaut, Nb, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, nresi, highresi, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc, true);
|
||||
parent->ipf.RGB_denoise_info(origCrop, provicalc, parent->imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope, params.dirpyrDenoise, parent->imgsrc->getDirPyrDenoiseExpComp(), chaut, Nb, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc, true);
|
||||
// printf("redy=%f skin=%f pcskin=%f\n",redyel, skinc,nsknc);
|
||||
// printf("DCROP skip=%d cha=%4.0f Nb=%d red=%4.0f bl=%4.0f redM=%4.0f bluM=%4.0f L=%4.0f sigL=%4.0f Ch=%4.0f Si=%4.0f\n",skip, chaut,Nb, redaut,blueaut, maxredaut, maxblueaut, lumema, sigma_L, chromina, sigma);
|
||||
float multip = 1.f;
|
||||
@ -453,9 +453,9 @@ void Crop::update (int todo)
|
||||
parent->imgsrc->convertColorSpace(provicalc, params.icm, parent->currWB);//for denoise luminance curve
|
||||
|
||||
float pondcorrec = 1.0f;
|
||||
float chaut = 0.f, redaut = 0.f, blueaut = 0.f, maxredaut = 0.f, maxblueaut = 0.f, minredaut = 0.f, minblueaut = 0.f, nresi = 0.f, highresi = 0.f, chromina = 0.f, sigma = 0.f, lumema = 0.f, sigma_L = 0.f, redyel = 0.f, skinc = 0.f, nsknc = 0.f;
|
||||
float chaut = 0.f, redaut = 0.f, blueaut = 0.f, maxredaut = 0.f, maxblueaut = 0.f, minredaut = 0.f, minblueaut = 0.f, chromina = 0.f, sigma = 0.f, lumema = 0.f, sigma_L = 0.f, redyel = 0.f, skinc = 0.f, nsknc = 0.f;
|
||||
int nb = 0;
|
||||
parent->ipf.RGB_denoise_info(origCropPart, provicalc, parent->imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope, params.dirpyrDenoise, parent->imgsrc->getDirPyrDenoiseExpComp(), chaut, nb, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, nresi, highresi, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc);
|
||||
parent->ipf.RGB_denoise_info(origCropPart, provicalc, parent->imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope, params.dirpyrDenoise, parent->imgsrc->getDirPyrDenoiseExpComp(), chaut, nb, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc);
|
||||
|
||||
//printf("DCROP skip=%d cha=%f red=%f bl=%f redM=%f bluM=%f chrom=%f sigm=%f lum=%f\n",skip, chaut,redaut,blueaut, maxredaut, maxblueaut, chromina, sigma, lumema);
|
||||
Nb[hcr * 3 + wcr] = nb;
|
||||
|
@ -1,521 +0,0 @@
|
||||
/*
|
||||
* This file is part of RawTherapee.
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* (C) 2010 Emil Martinec <ejmartin@uchicago.edu>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <cmath>
|
||||
#include "curves.h"
|
||||
#include "labimage.h"
|
||||
#include "improcfun.h"
|
||||
#include "rawimagesource.h"
|
||||
#include "rt_math.h"
|
||||
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
#define CLIPC(a) ((a)>-32000?((a)<32000?(a):32000):-32000)
|
||||
|
||||
#define DIRWT(i1,j1,i,j) (rangefn[abs((int)data_fine->L[i1][j1]-data_fine->L[i][j])+abs((int)data_fine->a[i1][j1]-data_fine->a[i][j])+abs((int)data_fine->b[i1][j1]-data_fine->b[i][j])] )
|
||||
|
||||
namespace rtengine
|
||||
{
|
||||
|
||||
static const int maxlevel = 4;
|
||||
|
||||
//sequence of scales
|
||||
static const int scales[8] = {1, 2, 4, 8, 16, 32, 64, 128};
|
||||
//sequence of pitches
|
||||
static const int pitches[8] = {1, 1, 1, 1, 1, 1, 1, 1};
|
||||
|
||||
//sequence of scales
|
||||
//static const int scales[8] = {1,1,1,1,1,1,1,1};
|
||||
//sequence of pitches
|
||||
//static const int pitches[8] = {2,2,2,2,2,2,2,2};
|
||||
|
||||
//sequence of scales
|
||||
//static const int scales[8] = {1,3,6,10,15,21,28,36};
|
||||
//sequence of pitches
|
||||
//static const int pitches[8] = {1,1,1,1,1,1,1,1};
|
||||
|
||||
//sequence of scales
|
||||
//static const int scales[8] = {1,1,2,4,8,16,32,64};
|
||||
//sequence of pitches
|
||||
//static const int pitches[8] = {2,1,1,1,1,1,1,1};
|
||||
|
||||
//pitch is spacing of subsampling
|
||||
//scale is spacing of directional averaging weights
|
||||
//example 1: no subsampling at any level -- pitch=1, scale=2^n
|
||||
//example 2: subsampling by 2 every level -- pitch=2, scale=1 at each level
|
||||
//example 3: no subsampling at first level, subsampling by 2 thereafter --
|
||||
// pitch =1, scale=1 at first level; pitch=2, scale=2 thereafter
|
||||
|
||||
|
||||
|
||||
|
||||
void ImProcFunctions :: dirpyrLab_equalizer(LabImage * src, LabImage * dst, /*float luma, float chroma, float gamma*/ const double * mult )
|
||||
{
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
LUTf rangefn(0x20000);
|
||||
|
||||
|
||||
//set up weights
|
||||
float noise = 1500;
|
||||
|
||||
|
||||
//set up range functions
|
||||
|
||||
for (int i = 0; i < 0x20000; i++) {
|
||||
rangefn[i] = (int)((noise / ((double)i + noise)));
|
||||
}
|
||||
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
|
||||
int level;
|
||||
int ** buffer[3];
|
||||
|
||||
|
||||
LabImage * dirpyrLablo[maxlevel];
|
||||
|
||||
int w = src->W;
|
||||
int h = src->H;
|
||||
|
||||
buffer[0] = allocArray<int> (w + 128, h + 128);
|
||||
buffer[1] = allocArray<int> (w + 128, h + 128);
|
||||
buffer[2] = allocArray<int> (w + 128, h + 128);
|
||||
|
||||
for (int i = 0; i < h + 128; i++)
|
||||
for (int j = 0; j < w + 128; j++) {
|
||||
for (int c = 0; c < 3; c++) {
|
||||
buffer[c][i][j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
w = (int)((w - 1) / pitches[0]) + 1;
|
||||
h = (int)((h - 1) / pitches[0]) + 1;
|
||||
|
||||
dirpyrLablo[0] = new LabImage(w, h);
|
||||
|
||||
for (level = 1; level < maxlevel; level++) {
|
||||
w = (int)((w - 1) / pitches[level]) + 1;
|
||||
h = (int)((h - 1) / pitches[level]) + 1;
|
||||
dirpyrLablo[level] = new LabImage(w, h);
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// c[0] = luma = noise_L
|
||||
// c[1] = chroma = noise_ab
|
||||
// c[2] decrease of noise var with scale
|
||||
// c[3] radius of domain blur at each level
|
||||
// c[4] shadow smoothing
|
||||
// c[5] edge preservation
|
||||
|
||||
level = 0;
|
||||
|
||||
int scale = scales[level];
|
||||
|
||||
int pitch = pitches[level];
|
||||
|
||||
//int thresh = 10 * c[8];
|
||||
//impulse_nr (src, src, m_w1, m_h1, thresh, noisevar);
|
||||
|
||||
dirpyr_eq(src, dirpyrLablo[0], rangefn, 0, pitch, scale, mult );
|
||||
|
||||
level = 1;
|
||||
|
||||
int totalpitch = pitches[0];
|
||||
|
||||
while(level < maxlevel) {
|
||||
scale = scales[level];
|
||||
pitch = pitches[level];
|
||||
|
||||
dirpyr_eq(dirpyrLablo[level - 1], dirpyrLablo[level], rangefn, level, pitch, scale, mult );
|
||||
|
||||
level ++;
|
||||
totalpitch *= pitch;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
//initiate buffer for final image
|
||||
for(int i = 0, i1 = 0; i < src->H; i += totalpitch, i1++)
|
||||
for(int j = 0, j1 = 0; j < src->W; j += totalpitch, j1++) {
|
||||
|
||||
//copy pixels
|
||||
buffer[0][i][j] = dirpyrLablo[maxlevel - 1]->L[i1][j1];
|
||||
buffer[1][i][j] = dirpyrLablo[maxlevel - 1]->a[i1][j1];
|
||||
buffer[2][i][j] = dirpyrLablo[maxlevel - 1]->b[i1][j1];
|
||||
|
||||
}
|
||||
|
||||
//if we are not subsampling, this is lots faster but does the typecasting work???
|
||||
//memcpy(buffer[0],dirpyrLablo[maxlevel-1]->L,sizeof(buffer[0]));
|
||||
//memcpy(buffer[1],dirpyrLablo[maxlevel-1]->a,sizeof(buffer[1]));
|
||||
//memcpy(buffer[2],dirpyrLablo[maxlevel-1]->b,sizeof(buffer[2]));
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
|
||||
for(int level = maxlevel - 1; level > 0; level--) {
|
||||
|
||||
//int scale = scales[level];
|
||||
int pitch = pitches[level];
|
||||
|
||||
totalpitch /= pitch;
|
||||
|
||||
idirpyr_eq(dirpyrLablo[level], dirpyrLablo[level - 1], buffer, level, pitch, totalpitch, mult );
|
||||
|
||||
}
|
||||
|
||||
|
||||
scale = scales[0];
|
||||
pitch = pitches[0];
|
||||
totalpitch /= pitch;
|
||||
|
||||
idirpyr_eq(dirpyrLablo[0], dst, buffer, 0, pitch, totalpitch, mult );
|
||||
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
for (int i = 0; i < dst->H; i++)
|
||||
for (int j = 0; j < dst->W; j++) {
|
||||
|
||||
// TODO: Is integer cast necessary here?
|
||||
dst->L[i][j] = CLIP((int)( buffer[0][i][j] ));
|
||||
dst->a[i][j] = CLIPC((int)( buffer[1][i][j] ));
|
||||
dst->b[i][j] = CLIPC((int)( buffer[2][i][j] ));
|
||||
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
for(int i = 0; i < maxlevel; i++) {
|
||||
delete dirpyrLablo[i];
|
||||
}
|
||||
|
||||
for (int c = 0; c < 3; c++) {
|
||||
freeArray<int>(buffer[c], h + 128);
|
||||
}
|
||||
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
}
|
||||
|
||||
void ImProcFunctions::dirpyr_eq(LabImage* data_fine, LabImage* data_coarse, LUTf & rangefn, int level, int pitch, int scale, const double * mult )
|
||||
{
|
||||
|
||||
//pitch is spacing of subsampling
|
||||
//scale is spacing of directional averaging weights
|
||||
//example 1: no subsampling at any level -- pitch=1, scale=2^n
|
||||
//example 2: subsampling by 2 every level -- pitch=2, scale=1 at each level
|
||||
//example 3: no subsampling at first level, subsampling by 2 thereafter --
|
||||
// pitch =1, scale=1 at first level; pitch=2, scale=2 thereafter
|
||||
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// calculate weights, compute directionally weighted average
|
||||
|
||||
int width = data_fine->W;
|
||||
int height = data_fine->H;
|
||||
|
||||
|
||||
|
||||
//generate domain kernel
|
||||
int halfwin = 1;//min(ceil(2*sig),3);
|
||||
int scalewin = halfwin * scale;
|
||||
|
||||
|
||||
#ifdef _OPENMP
|
||||
#pragma omp parallel for
|
||||
#endif
|
||||
|
||||
for(int i = 0; i < height; i += pitch) {
|
||||
int i1 = i / pitch;
|
||||
|
||||
for(int j = 0, j1 = 0; j < width; j += pitch, j1++) {
|
||||
float Lout, aout, bout;
|
||||
float norm;
|
||||
norm = 0;//if we do want to include the input pixel in the sum
|
||||
Lout = 0;
|
||||
aout = 0;
|
||||
bout = 0;
|
||||
|
||||
for(int inbr = max(0, i - scalewin); inbr <= min(height - 1, i + scalewin); inbr += scale) {
|
||||
for (int jnbr = max(0, j - scalewin); jnbr <= min(width - 1, j + scalewin); jnbr += scale) {
|
||||
float dirwt = DIRWT(inbr, jnbr, i, j);
|
||||
Lout += dirwt * data_fine->L[inbr][jnbr];
|
||||
aout += dirwt * data_fine->a[inbr][jnbr];
|
||||
bout += dirwt * data_fine->b[inbr][jnbr];
|
||||
norm += dirwt;
|
||||
}
|
||||
}
|
||||
|
||||
data_coarse->L[i1][j1] = Lout / norm; //low pass filter
|
||||
data_coarse->a[i1][j1] = aout / norm;
|
||||
data_coarse->b[i1][j1] = bout / norm;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void ImProcFunctions::idirpyr_eq(LabImage* data_coarse, LabImage* data_fine, int *** buffer, int level, int pitch, int scale, const double * mult )
|
||||
{
|
||||
|
||||
int width = data_fine->W;
|
||||
int height = data_fine->H;
|
||||
|
||||
float lumamult[4], chromamult[4];
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
lumamult[i] = mult[i];
|
||||
chromamult[i] = mult[i + 4];
|
||||
}
|
||||
|
||||
float wtdsum[6], norm, dirwt;
|
||||
float hipass[3];
|
||||
int i1, j1;
|
||||
|
||||
|
||||
// for coarsest level, take non-subsampled lopass image and subtract from lopass_fine to generate hipass image
|
||||
|
||||
// denoise hipass image, add back into lopass_fine to generate denoised image at fine scale
|
||||
|
||||
// now iterate:
|
||||
// (1) take denoised image at level n, expand and smooth using gradient weights from lopass image at level n-1
|
||||
// the result is the smoothed image at level n-1
|
||||
// (2) subtract smoothed image at level n-1 from lopass image at level n-1 to make hipass image at level n-1
|
||||
// (3) denoise the hipass image at level n-1
|
||||
// (4) add the denoised image at level n-1 to the smoothed image at level n-1 to make the denoised image at level n-1
|
||||
|
||||
// note that the coarsest level amounts to skipping step (1) and doing (2,3,4).
|
||||
// in other words, skip step one if pitch=1
|
||||
|
||||
|
||||
|
||||
if (pitch == 1) {
|
||||
// step (1-2-3-4)
|
||||
#ifdef _OPENMP
|
||||
#pragma omp parallel for
|
||||
#endif
|
||||
|
||||
for(int i = 0; i < height; i++)
|
||||
for(int j = 0; j < width; j++) {
|
||||
|
||||
//luma
|
||||
float hipass0 = (float)data_fine->L[i][j] - data_coarse->L[i][j];
|
||||
buffer[0][i * scale][j * scale] += hipass0 * lumamult[level]; //*luma;
|
||||
|
||||
//chroma
|
||||
float hipass1 = data_fine->a[i][j] - data_coarse->a[i][j];
|
||||
float hipass2 = data_fine->b[i][j] - data_coarse->b[i][j];
|
||||
buffer[1][i * scale][j * scale] += hipass1 * chromamult[level]; //*chroma;
|
||||
buffer[2][i * scale][j * scale] += hipass2 * chromamult[level]; //*chroma;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// step (1)
|
||||
//if (pitch>1), pitch=2; expand coarse image, fill in missing data
|
||||
|
||||
LabImage* smooth;
|
||||
smooth = new LabImage(width, height);
|
||||
#ifdef _OPENMP
|
||||
#pragma omp parallel
|
||||
#endif
|
||||
|
||||
{
|
||||
#ifdef _OPENMP
|
||||
#pragma omp for
|
||||
#endif
|
||||
|
||||
for(int i = 0; i < height; i += pitch) {
|
||||
int i2 = i / pitch;
|
||||
|
||||
for(int j = 0, j2 = 0; j < width; j += pitch, j2++) {
|
||||
|
||||
//copy common pixels
|
||||
smooth->L[i][j] = data_coarse->L[i2][j2];
|
||||
smooth->a[i][j] = data_coarse->a[i2][j2];
|
||||
smooth->b[i][j] = data_coarse->b[i2][j2];
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _OPENMP
|
||||
#pragma omp for
|
||||
#endif
|
||||
|
||||
for(int i = 0; i < height - 1; i += 2)
|
||||
for(int j = 0; j < width - 1; j += 2) {
|
||||
//do midpoint first
|
||||
norm = dirwt = 0;
|
||||
wtdsum[0] = wtdsum[1] = wtdsum[2] = wtdsum[3] = wtdsum[4] = wtdsum[5] = 0.0;
|
||||
|
||||
for(i1 = i; i1 < min(height, i + 3); i1 += 2)
|
||||
for (j1 = j; j1 < min(width, j + 3); j1 += 2) {
|
||||
dirwt = 1;//IDIRWT(i1, j1, i, j);
|
||||
wtdsum[0] += dirwt * smooth->L[i1][j1];
|
||||
wtdsum[1] += dirwt * smooth->a[i1][j1];
|
||||
wtdsum[2] += dirwt * smooth->b[i1][j1];
|
||||
wtdsum[3] += dirwt * buffer[0][i1 * scale][j1 * scale]; // not completely right if j1*scale or i1*scale is out of bounds of original image ???
|
||||
wtdsum[4] += dirwt * buffer[1][i1 * scale][j1 * scale]; // also should we use directional average?
|
||||
wtdsum[5] += dirwt * buffer[2][i1 * scale][j1 * scale];
|
||||
norm += dirwt;
|
||||
}
|
||||
|
||||
norm = 1 / norm;
|
||||
smooth->L[i + 1][j + 1] = wtdsum[0] * norm;
|
||||
smooth->a[i + 1][j + 1] = wtdsum[1] * norm;
|
||||
smooth->b[i + 1][j + 1] = wtdsum[2] * norm;
|
||||
buffer[0][(i + 1)*scale][(j + 1)*scale] = wtdsum[3] * norm;
|
||||
buffer[1][(i + 1)*scale][(j + 1)*scale] = wtdsum[4] * norm;
|
||||
buffer[2][(i + 1)*scale][(j + 1)*scale] = wtdsum[5] * norm;
|
||||
}
|
||||
|
||||
#ifdef _OPENMP
|
||||
#pragma omp for
|
||||
#endif
|
||||
|
||||
for(int i = 0; i < height - 1; i += 2)
|
||||
for(int j = 0; j < width - 1; j += 2) {
|
||||
//now right neighbor
|
||||
if (j + 1 == width) {
|
||||
continue;
|
||||
}
|
||||
|
||||
norm = dirwt = 0;
|
||||
wtdsum[0] = wtdsum[1] = wtdsum[2] = wtdsum[3] = wtdsum[4] = wtdsum[5] = 0.0;
|
||||
|
||||
for (j1 = j; j1 < min(width, j + 3); j1 += 2) {
|
||||
dirwt = 1;//IDIRWT(i, j1, i, j);
|
||||
wtdsum[0] += dirwt * smooth->L[i][j1];
|
||||
wtdsum[1] += dirwt * smooth->a[i][j1];
|
||||
wtdsum[2] += dirwt * smooth->b[i][j1];
|
||||
wtdsum[3] += dirwt * buffer[0][i * scale][j1 * scale];
|
||||
wtdsum[4] += dirwt * buffer[1][i * scale][j1 * scale];
|
||||
wtdsum[5] += dirwt * buffer[2][i * scale][j1 * scale];
|
||||
norm += dirwt;
|
||||
}
|
||||
|
||||
for (i1 = max(0, i - 1); i1 < min(height, i + 2); i1 += 2) {
|
||||
dirwt = 1;//IDIRWT(i1, j+1, i, j);
|
||||
wtdsum[0] += dirwt * smooth->L[i1][j + 1];
|
||||
wtdsum[1] += dirwt * smooth->a[i1][j + 1];
|
||||
wtdsum[2] += dirwt * smooth->b[i1][j + 1];
|
||||
wtdsum[3] += dirwt * buffer[0][i1 * scale][(j + 1) * scale];
|
||||
wtdsum[4] += dirwt * buffer[1][i1 * scale][(j + 1) * scale];
|
||||
wtdsum[5] += dirwt * buffer[2][i1 * scale][(j + 1) * scale];
|
||||
norm += dirwt;
|
||||
}
|
||||
|
||||
norm = 1 / norm;
|
||||
smooth->L[i][j + 1] = wtdsum[0] * norm;
|
||||
smooth->a[i][j + 1] = wtdsum[1] * norm;
|
||||
smooth->b[i][j + 1] = wtdsum[2] * norm;
|
||||
buffer[0][i][(j + 1)*scale] = wtdsum[3] * norm;
|
||||
buffer[1][i][(j + 1)*scale] = wtdsum[4] * norm;
|
||||
buffer[2][i][(j + 1)*scale] = wtdsum[5] * norm;
|
||||
|
||||
//now down neighbor
|
||||
if (i + 1 == height) {
|
||||
continue;
|
||||
}
|
||||
|
||||
norm = 0;
|
||||
wtdsum[0] = wtdsum[1] = wtdsum[2] = wtdsum[3] = wtdsum[4] = wtdsum[5] = 0.0;
|
||||
|
||||
for (i1 = i; i1 < min(height, i + 3); i1 += 2) {
|
||||
dirwt = 1;//IDIRWT(i1, j, i, j);
|
||||
wtdsum[0] += dirwt * smooth->L[i1][j];
|
||||
wtdsum[1] += dirwt * smooth->a[i1][j];
|
||||
wtdsum[2] += dirwt * smooth->b[i1][j];
|
||||
wtdsum[3] += dirwt * buffer[0][i1 * scale][j * scale];
|
||||
wtdsum[4] += dirwt * buffer[1][i1 * scale][j * scale];
|
||||
wtdsum[5] += dirwt * buffer[2][i1 * scale][j * scale];
|
||||
norm += dirwt;
|
||||
}
|
||||
|
||||
for (j1 = max(0, j - 1); j1 < min(width, j + 2); j1 += 2) {
|
||||
dirwt = 1;//IDIRWT(i+1, j1, i, j);
|
||||
wtdsum[0] += dirwt * smooth->L[i + 1][j1];
|
||||
wtdsum[1] += dirwt * smooth->a[i + 1][j1];
|
||||
wtdsum[2] += dirwt * smooth->b[i + 1][j1];
|
||||
wtdsum[3] += dirwt * buffer[0][(i + 1) * scale][j1 * scale];
|
||||
wtdsum[4] += dirwt * buffer[1][(i + 1) * scale][j1 * scale];
|
||||
wtdsum[5] += dirwt * buffer[2][(i + 1) * scale][j1 * scale];
|
||||
norm += dirwt;
|
||||
}
|
||||
|
||||
norm = 1 / norm;
|
||||
smooth->L[i + 1][j] = wtdsum[0] * norm;
|
||||
smooth->a[i + 1][j] = wtdsum[1] * norm;
|
||||
smooth->b[i + 1][j] = wtdsum[2] * norm;
|
||||
buffer[0][(i + 1)*scale][j * scale] = wtdsum[3] * norm;
|
||||
buffer[1][(i + 1)*scale][j * scale] = wtdsum[4] * norm;
|
||||
buffer[2][(i + 1)*scale][j * scale] = wtdsum[5] * norm;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// step (2-3-4)
|
||||
#ifdef _OPENMP
|
||||
#pragma omp for
|
||||
#endif
|
||||
|
||||
for(int i = 0; i < height; i++)
|
||||
for(int j = 0; j < width; j++) {
|
||||
|
||||
//luma
|
||||
hipass[0] = (float)data_fine->L[i][j] - smooth->L[i][j];
|
||||
buffer[0][i * scale][j * scale] += hipass[0] * lumamult[level]; //*luma;
|
||||
|
||||
//chroma
|
||||
hipass[1] = data_fine->a[i][j] - smooth->a[i][j];
|
||||
hipass[2] = data_fine->b[i][j] - smooth->b[i][j];
|
||||
buffer[1][i * scale][j * scale] += hipass[1] * chromamult[level]; //*chroma;
|
||||
buffer[2][i * scale][j * scale] += hipass[2] * chromamult[level]; //*chroma;
|
||||
}
|
||||
} // end parallel
|
||||
delete smooth;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#undef DIRWT_L
|
||||
#undef DIRWT_AB
|
||||
|
||||
#undef NRWT_L
|
||||
#undef NRWT_AB
|
||||
|
||||
}
|
||||
|
@ -1,150 +0,0 @@
|
||||
/*
|
||||
* This file is part of RawTherapee.
|
||||
*
|
||||
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "rtengine.h"
|
||||
#include <iostream>
|
||||
//#include <giomm.h>
|
||||
#include <helpers.h>
|
||||
|
||||
class PListener : public rtengine::ProgressListener
|
||||
{
|
||||
|
||||
public:
|
||||
void setProgressStr (Glib::ustring str)
|
||||
{
|
||||
std::cout << str << std::endl;
|
||||
}
|
||||
void setProgress (double p)
|
||||
{
|
||||
std::cout << p << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
class MyPrevImgListener : public rtengine::PreviewImageListener
|
||||
{
|
||||
|
||||
IImage8* i;
|
||||
|
||||
public:
|
||||
// this method is called when the staged image processor creates a new image to store the resulting preview image (this does not happen too often)
|
||||
// usually you just have to store it
|
||||
void setImage (IImage8* img, double scale, procparams::CropParams cp)
|
||||
{
|
||||
i = img;
|
||||
}
|
||||
// if the staged image processor wants to delete the image that stores the preview image, it calls this method. You have to destroy the image.
|
||||
void delImage (IImage8* img)
|
||||
{
|
||||
if (img) {
|
||||
// make sure we dont use this image in an other thread
|
||||
IImage8* temp = i;
|
||||
i->getMutex().lock ();
|
||||
i = NULL;
|
||||
temp->getMutex().unlock ();
|
||||
// free it
|
||||
img->free ();
|
||||
}
|
||||
}
|
||||
// if the preview image changes, this method is called
|
||||
void imageReady (procparams::CropParams cp)
|
||||
{
|
||||
// initiate a redraw in the background and return as fast as possible
|
||||
}
|
||||
// a possible redraw function:
|
||||
//void redraw () {
|
||||
// if (i) {
|
||||
// i->lock ();
|
||||
// int w = i->getWidth ();
|
||||
// int h = i->getHeigt ();
|
||||
// const char* data = i->getData ();
|
||||
// ... draw it ...
|
||||
// i->unlock ();
|
||||
// }
|
||||
// }
|
||||
};
|
||||
|
||||
int main (int argc, char* argv[])
|
||||
{
|
||||
|
||||
if (argc < 4) {
|
||||
std::cout << "Usage: rtcmd <infile> <paramfile> <outfile>" << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Glib::thread_init ();
|
||||
|
||||
// create and fill settings
|
||||
rtengine::Settings* s = rtengine::Settings::create ();
|
||||
s->demosaicMethod = "hphd";
|
||||
s->colorCorrectionSteps = 2;
|
||||
s->iccDirectory = "";
|
||||
s->colorimetricIntent = 1;
|
||||
s->monitorProfile = "";
|
||||
// init rtengine
|
||||
rtengine::init (s);
|
||||
// the settings can be modified later through the "s" pointer without calling any api function
|
||||
|
||||
// Create a listener object. Any class is appropriate that inherits from rtengine::ProgressListener
|
||||
PListener pl;
|
||||
|
||||
// Load the image given in the first command line parameter
|
||||
rtengine::InitialImage* ii;
|
||||
int errorCode;
|
||||
ii = rtengine::InitialImage::load (argv[1], true, errorCode, &pl);
|
||||
|
||||
if (!ii) {
|
||||
ii = rtengine::InitialImage::load (argv[1], false, errorCode, &pl);
|
||||
}
|
||||
|
||||
if (!ii) {
|
||||
std::cout << "Input file not supported." << std::endl;
|
||||
exit(2);
|
||||
}
|
||||
|
||||
/* Second scenario. Create a stagedimageprocessor with a preview scale of 1:5 and change few things */
|
||||
MyPrevImgListener myPrevImgListener;
|
||||
|
||||
StagedImageProcessor* ipc = StagedImageProcessor::create (ii);
|
||||
ipc->setProgressListener (&pl);
|
||||
ipc->setPreviewImageListener (&myPrevImgListener);
|
||||
ipc->setPreviewScale (5); // preview scale = 1:5
|
||||
// you can add a histogram listener, too, that is notified when the histogram changes
|
||||
// ipc->setHistogramListener (...);
|
||||
// you can add autoexplistener that is notified about the exposure settings when the auto exp algorithm finishes
|
||||
// ipc->setAutoExpListener (curve);
|
||||
// you can add sizelistener if you want to be notified when the size of the final image changes (due to rotation/resize/etc)
|
||||
// ipc->setSizeListener (crop);
|
||||
|
||||
// if you want to change the settings you have to ask for the procparams structure of the staged image processor
|
||||
// you have to tell it what has changed. At the first time tell it EvPhotoLoaded so a full processing will be performed
|
||||
rtengine::procparams::ProcParams* params = ipc->beginUpdateParams ();
|
||||
// change this and that...
|
||||
params->toneCurve.brightness = 1.0;
|
||||
// you can load it, too, from a file: params->load (argv[2]);
|
||||
// finally you have to call this non-blocking method, and the image processing starts in the background. When finished, the preview image listener will be notified
|
||||
ipc->endUpdateParams (rtengine::EvPhotoLoaded);
|
||||
// you can go on with changing of the settings, following the gui actions
|
||||
// now we know that only the brightness has changed compared to the previous settings, to only a part of the processing has to be repeated
|
||||
params = ipc->beginUpdateParams ();
|
||||
params->toneCurve.brightness = 1.2;
|
||||
ipc->endUpdateParams (rtengine::EvBrightness);
|
||||
|
||||
// ... and so on. If you dont need it any more, you can destroy it (make sure that no processing is happening when you destroy it!)
|
||||
StagedImageProcessor::destroy (ipc);
|
||||
}
|
||||
|
@ -1,441 +0,0 @@
|
||||
/*
|
||||
* This file is part of RawTherapee.
|
||||
*
|
||||
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <climits>
|
||||
#include <cstdio>
|
||||
#include "rawimagesource.h"
|
||||
#include "rawimagesource_i.h"
|
||||
#include "jaggedarray.h"
|
||||
#include "../rtgui/options.h"
|
||||
|
||||
namespace rtengine
|
||||
{
|
||||
|
||||
// computes highlight recovery multipliers. Needs a possibly downscaled image where
|
||||
// the highlights are indicated by INT_MAX
|
||||
void hlmultipliers (int** rec[3], int max_3[3], int dh, int dw)
|
||||
{
|
||||
|
||||
// STEP I. recover color with two-color information
|
||||
int phase = -1;
|
||||
int k = 0;
|
||||
|
||||
for (k = 0; k < 1000; k++) {
|
||||
int changed = 0;
|
||||
|
||||
for (int i = 1; i < dh - 1; i++)
|
||||
for (int j = 1; j < dw - 1; j++) {
|
||||
int co, c1, c2;
|
||||
|
||||
// if (phase==2)
|
||||
// phase++;
|
||||
// if (phase>0)// && phase!=4)
|
||||
// continue;
|
||||
if (phase == -1 || phase == 0 || phase == 2) {
|
||||
if (rec[0][i][j] == INT_MAX && rec[1][i][j] != INT_MAX && rec[1][i][j] >= 0 && rec[2][i][j] != INT_MAX && rec[2][i][j] >= 0) {
|
||||
co = 0;
|
||||
c1 = 1;
|
||||
c2 = 2;
|
||||
} else if (rec[1][i][j] == INT_MAX && rec[0][i][j] != INT_MAX && rec[0][i][j] >= 0 && rec[2][i][j] != INT_MAX && rec[2][i][j] >= 0) {
|
||||
co = 1;
|
||||
c1 = 0;
|
||||
c2 = 2;
|
||||
} else if (rec[2][i][j] == INT_MAX && rec[1][i][j] != INT_MAX && rec[1][i][j] >= 0 && rec[0][i][j] != INT_MAX && rec[0][i][j] >= 0) {
|
||||
co = 2;
|
||||
c1 = 1;
|
||||
c2 = 0;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
double ratio[2] = {0.0, 0.0};
|
||||
int count = 0;
|
||||
double rato = (double)rec[c1][i][j] / rec[c2][i][j];
|
||||
double arato = 0.0;
|
||||
|
||||
if (phase == 2) {
|
||||
for (int x = -1; x <= 1; x++)
|
||||
for (int y = -1; y <= 1; y++) {
|
||||
// average m/c color ratios in the surrounding pixels
|
||||
if (rec[co][i + x][j + y] >= 0 && rec[co][i + x][j + y] != INT_MAX && rec[c1][i + x][j + y] >= 0 && rec[c1][i + x][j + y] != INT_MAX && rec[c2][i + x][j + y] > 0 && rec[c2][i + x][j + y] != INT_MAX) {
|
||||
double ratt = (double)rec[c1][i + x][j + y] / rec[c2][i + x][j + y];
|
||||
|
||||
if (ratt > rato * 1.2 || ratt < rato / 1.2 || rec[co][i + x][j + y] < max_3[co] * 1 / 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ratio[0] += (double)rec[c1][i + x][j + y] / rec[co][i + x][j + y];
|
||||
ratio[1] += (double)rec[c2][i + x][j + y] / rec[co][i + x][j + y];
|
||||
count++;
|
||||
}
|
||||
}
|
||||
} else if (phase == -1) {
|
||||
for (int x = -1; x <= 1; x++)
|
||||
for (int y = -1; y <= 1; y++) {
|
||||
// average m/c color ratios in the surrounding pixels
|
||||
if (rec[co][i + x][j + y] >= 0 && rec[co][i + x][j + y] != INT_MAX && rec[c1][i + x][j + y] >= 0 && rec[c1][i + x][j + y] != INT_MAX && rec[c2][i + x][j + y] > 0 && rec[c2][i + x][j + y] != INT_MAX) {
|
||||
double ratt = (double)rec[c1][i + x][j + y] / rec[c2][i + x][j + y];
|
||||
|
||||
if (ratt > rato * 1.05 || ratt < rato / 1.05 || rec[co][i + x][j + y] < max_3[co] * 4 / 5) {
|
||||
continue;
|
||||
}
|
||||
|
||||
arato += ratt;
|
||||
ratio[0] += (double)rec[c1][i + x][j + y] / rec[co][i + x][j + y];
|
||||
ratio[1] += (double)rec[c2][i + x][j + y] / rec[co][i + x][j + y];
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int x = -1; x <= 1; x++)
|
||||
for (int y = -1; y <= 1; y++) {
|
||||
// average m/c color ratios in the surrounding pixels
|
||||
if (rec[co][i + x][j + y] >= 0 && rec[co][i + x][j + y] != INT_MAX && rec[c1][i + x][j + y] >= 0 && rec[c1][i + x][j + y] != INT_MAX && rec[c2][i + x][j + y] > 0 && rec[c2][i + x][j + y] != INT_MAX) {
|
||||
double ratt = (double)rec[c1][i + x][j + y] / rec[c2][i + x][j + y];
|
||||
|
||||
if (ratt > rato * 1.1 || ratt < rato / 1.1 || rec[co][i + x][j + y] < max_3[co] * 3 / 4) {
|
||||
continue;
|
||||
}
|
||||
|
||||
arato += ratt;
|
||||
ratio[0] += (double)rec[c1][i + x][j + y] / rec[co][i + x][j + y];
|
||||
ratio[1] += (double)rec[c2][i + x][j + y] / rec[co][i + x][j + y];
|
||||
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// compute new pixel values from the surrounding color ratios
|
||||
if (count > 1) { //(phase==0 && count>1) || (phase==2 && count>1)) {
|
||||
rec[co][i][j] = -(int)((rec[c1][i][j] / ratio[0] * count + rec[c2][i][j] / ratio[1] * count) / 2);
|
||||
changed++;
|
||||
}
|
||||
} else if (phase == 1 || phase == 3) {
|
||||
if (rec[0][i][j] == INT_MAX && rec[1][i][j] == INT_MAX && rec[2][i][j] != INT_MAX && rec[2][i][j] >= 0) {
|
||||
co = 2;
|
||||
c1 = 0;
|
||||
c2 = 1;
|
||||
} else if (rec[0][i][j] == INT_MAX && rec[2][i][j] == INT_MAX && rec[1][i][j] != INT_MAX && rec[1][i][j] >= 0) {
|
||||
co = 1;
|
||||
c1 = 0;
|
||||
c2 = 2;
|
||||
} else if (rec[1][i][j] == INT_MAX && rec[2][i][j] == INT_MAX && rec[0][i][j] != INT_MAX && rec[0][i][j] >= 0) {
|
||||
co = 0;
|
||||
c1 = 1;
|
||||
c2 = 2;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
double ratio[2] = {0.0, 0.0};
|
||||
int count[2] = {0, 0};
|
||||
|
||||
for (int x = -1; x <= 1; x++)
|
||||
for (int y = -1; y <= 1; y++) {
|
||||
// average m/c color ratios in the surrounding pixels
|
||||
if (rec[co][i + x][j + y] >= 0 && rec[co][i + x][j + y] != INT_MAX && rec[c1][i + x][j + y] > 0 && rec[c1][i + x][j + y] != INT_MAX) {
|
||||
if ((phase == 1 && rec[c1][i + x][j + y] < max_3[c1] * 3 / 4) || (phase == 3 && rec[c1][i + x][j + y] < max_3[c1] * 1 / 2)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ratio[0] += (double)rec[co][i + x][j + y] / rec[c1][i + x][j + y];
|
||||
count[0] ++;
|
||||
}
|
||||
|
||||
if (rec[co][i + x][j + y] >= 0 && rec[co][i + x][j + y] != INT_MAX && rec[c2][i + x][j + y] > 0 && rec[c2][i + x][j + y] != INT_MAX) {
|
||||
if ((phase == 1 && rec[c2][i + x][j + y] < max_3[c2] * 3 / 4) || (phase == 3 && rec[c2][i + x][j + y] < max_3[c2] * 1 / 2))
|
||||
// if (/*phase!=3 && */rec[c2][i+x][j+y]<max[c2]*3/4)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ratio[1] += (double)rec[co][i + x][j + y] / rec[c2][i + x][j + y];
|
||||
count[1] ++;
|
||||
}
|
||||
}
|
||||
|
||||
// compute new pixel values from the surrounding color ratios
|
||||
if ((phase == 1 && count[0] > 2) || (phase == 3 && count[0] > 1)) {
|
||||
rec[c1][i][j] = - (int) ((double)rec[co][i][j] / ratio[0] * count[0]);
|
||||
changed++;
|
||||
}
|
||||
|
||||
if ((phase == 1 && count[1] > 2) || (phase == 3 && count[1] > 1)) {
|
||||
rec[c2][i][j] = - (int) ((double)rec[co][i][j] / ratio[1] * count[1]);
|
||||
changed++;
|
||||
}
|
||||
} else {
|
||||
int val = 0;
|
||||
int num = 0;
|
||||
|
||||
for (int c = 0; c < 3; c++)
|
||||
if (rec[c][i][j] != INT_MAX) {
|
||||
val += rec[c][i][j];
|
||||
num++;
|
||||
}
|
||||
|
||||
if (num < 3 && num > 0) {
|
||||
for (int c = 0; c < 3; c++) {
|
||||
rec[c][i][j] = val / num;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool change = false;
|
||||
|
||||
for (int i = 1; i < dh - 1; i++)
|
||||
for (int j = 1; j < dw - 1; j++)
|
||||
for (int c = 0; c < 3; c++) {
|
||||
if (rec[c][i][j] < 0) {
|
||||
rec[c][i][j] = -rec[c][i][j];
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!change && phase < 4) {
|
||||
phase++;
|
||||
|
||||
if( options.rtSettings.verbose ) {
|
||||
printf ("phc %d: %d\n", phase, k);
|
||||
}
|
||||
} else if (!change) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (k % 20 == 0 && options.rtSettings.verbose ) {
|
||||
printf ("changed %d\n", changed);
|
||||
}
|
||||
}
|
||||
|
||||
if( options.rtSettings.verbose ) {
|
||||
printf ("Highlight recovery ends in %d iterations\n", k);
|
||||
}
|
||||
|
||||
int maxval = max(max_3[0], max_3[1], max_3[2]);
|
||||
|
||||
for (int i = 0; i < dh; i++)
|
||||
for (int j = 0; j < dw; j++)
|
||||
if (rec[0][i][j] == INT_MAX || rec[1][i][j] == INT_MAX || rec[2][i][j] == INT_MAX) {
|
||||
rec[0][i][j] = maxval;
|
||||
rec[1][i][j] = maxval;
|
||||
rec[2][i][j] = maxval;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void RawImageSource::HLRecovery_ColorPropagation (float* red, float* green, float* blue, int i, int sx1, int width, int skip)
|
||||
{
|
||||
|
||||
int blr = (i + HR_SCALE / 2) / HR_SCALE - 1;
|
||||
|
||||
if (blr < 0 || blr >= H / HR_SCALE - 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
double mr1 = 1.0 - ((double)((i + HR_SCALE / 2) % HR_SCALE) / HR_SCALE + 0.5 / HR_SCALE);
|
||||
int maxcol = W / HR_SCALE - 2;
|
||||
|
||||
for (int j = sx1, jx = 0; jx < width; j += skip, jx++) {
|
||||
if (needhr[i][j]) {
|
||||
int blc = (j + HR_SCALE / 2) / HR_SCALE - 1;
|
||||
|
||||
if (blc < 0 || blc >= maxcol) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double mc1 = 1.0 - ((double)((j + HR_SCALE / 2) % HR_SCALE) / HR_SCALE + 0.5 / HR_SCALE);
|
||||
double mulr = mr1 * mc1 * hrmap[0][blr][blc] + mr1 * (1.0 - mc1) * hrmap[0][blr][blc + 1] + (1.0 - mr1) * mc1 * hrmap[0][blr + 1][blc] + (1.0 - mr1) * (1.0 - mc1) * hrmap[0][blr + 1][blc + 1];
|
||||
double mulg = mr1 * mc1 * hrmap[1][blr][blc] + mr1 * (1.0 - mc1) * hrmap[1][blr][blc + 1] + (1.0 - mr1) * mc1 * hrmap[1][blr + 1][blc] + (1.0 - mr1) * (1.0 - mc1) * hrmap[1][blr + 1][blc + 1];
|
||||
double mulb = mr1 * mc1 * hrmap[2][blr][blc] + mr1 * (1.0 - mc1) * hrmap[2][blr][blc + 1] + (1.0 - mr1) * mc1 * hrmap[2][blr + 1][blc] + (1.0 - mr1) * (1.0 - mc1) * hrmap[2][blr + 1][blc + 1];
|
||||
red[jx] = (red[jx] * mulr);
|
||||
green[jx] = (green[jx] * mulg);
|
||||
blue[jx] = (blue[jx] * mulb);
|
||||
} else {
|
||||
red[jx] = (red[jx]);
|
||||
green[jx] = (green[jx]);
|
||||
blue[jx] = (blue[jx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RawImageSource::updateHLRecoveryMap_ColorPropagation ()
|
||||
{
|
||||
|
||||
// detect maximal pixel values
|
||||
float* red = new float[W];
|
||||
float* blue = new float[W];
|
||||
int maxr = 0, maxg = 0, maxb = 0;
|
||||
|
||||
for (int i = 32; i < H - 32; i++) {
|
||||
interpolate_row_rb (red, blue, green[i - 1], green[i], green[i + 1], i);
|
||||
|
||||
for (int j = 32; j < W - 32; j++) {
|
||||
if ((ri->ISRED(i, j) || ri->getSensorType() != ST_BAYER) && red[j] > maxr) {
|
||||
maxr = red[j];
|
||||
}
|
||||
|
||||
if ((ri->ISGREEN(i, j) || ri->getSensorType() != ST_BAYER) && green[i][j] > maxg) {
|
||||
maxg = green[i][j];
|
||||
}
|
||||
|
||||
if ((ri->ISBLUE(i, j) || ri->getSensorType() != ST_BAYER) && blue[j] > maxb) {
|
||||
maxb = blue[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete [] red;
|
||||
delete [] blue;
|
||||
|
||||
maxr = maxr * 19 / 20;
|
||||
maxg = maxg * 19 / 20;
|
||||
maxb = maxb * 19 / 20;
|
||||
max_3[0] = maxr;
|
||||
max_3[1] = maxg;
|
||||
max_3[2] = maxb;
|
||||
|
||||
// downscale image
|
||||
int dw = W / HR_SCALE;
|
||||
int dh = H / HR_SCALE;
|
||||
Image16* ds = new Image16 (dw, dh);
|
||||
|
||||
// overburnt areas
|
||||
int** rec[3];
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
rec[i] = allocJaggedArray<int> (dw, dh);
|
||||
}
|
||||
|
||||
float* reds[HR_SCALE];
|
||||
float* blues[HR_SCALE];
|
||||
|
||||
for (int i = 0; i < HR_SCALE; i++) {
|
||||
reds[i] = new float[W];
|
||||
blues[i] = new float[W];
|
||||
}
|
||||
|
||||
if (needhr) {
|
||||
freeJaggedArray<char>(needhr);
|
||||
}
|
||||
|
||||
needhr = allocJaggedArray<char> (W, H);
|
||||
|
||||
for (int i = 0; i < dh; i++) {
|
||||
for (int j = 0; j < HR_SCALE; j++) {
|
||||
interpolate_row_rb (reds[j], blues[j], green[HR_SCALE * i + j - 1], green[HR_SCALE * i + j], green[HR_SCALE * i + j + 1], HR_SCALE * i + j);
|
||||
|
||||
for (int k = 0; k < W; k++)
|
||||
if (reds[j][k] >= max_3[0] || green[HR_SCALE * i + j][k] >= max_3[1] || blues[j][k] >= max_3[2]) {
|
||||
needhr[HR_SCALE * i + j][k] = 1;
|
||||
} else {
|
||||
needhr[HR_SCALE * i + j][k] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < dw; j++) {
|
||||
int sumr = 0;
|
||||
int cr = 0;
|
||||
int sumg = 0;
|
||||
int cg = 0;
|
||||
int sumb = 0;
|
||||
int cb = 0;
|
||||
|
||||
for (int x = 0; x < HR_SCALE; x++)
|
||||
for (int y = 0; y < HR_SCALE; y++) {
|
||||
int ix = HR_SCALE * i + x;
|
||||
int jy = HR_SCALE * j + y;
|
||||
sumr += reds[x][jy];
|
||||
|
||||
if (reds[x][jy] < maxr) {
|
||||
cr++;
|
||||
}
|
||||
|
||||
sumg += green[ix][jy];
|
||||
|
||||
if (green[ix][jy] < maxg) {
|
||||
cg++;
|
||||
}
|
||||
|
||||
sumb += blues[x][jy];
|
||||
|
||||
if (blues[x][jy] < maxb) {
|
||||
cb++;
|
||||
}
|
||||
}
|
||||
|
||||
if (cr < HR_SCALE * HR_SCALE) {
|
||||
rec[0][i][j] = INT_MAX;
|
||||
} else {
|
||||
rec[0][i][j] = sumr / HR_SCALE / HR_SCALE;
|
||||
}
|
||||
|
||||
if (cg < HR_SCALE * HR_SCALE) {
|
||||
rec[1][i][j] = INT_MAX;
|
||||
} else {
|
||||
rec[1][i][j] = sumg / HR_SCALE / HR_SCALE;
|
||||
}
|
||||
|
||||
if (cb < HR_SCALE * HR_SCALE) {
|
||||
rec[2][i][j] = INT_MAX;
|
||||
} else {
|
||||
rec[2][i][j] = sumb / HR_SCALE / HR_SCALE;
|
||||
}
|
||||
|
||||
ds->r(i, j) = sumr / HR_SCALE / HR_SCALE;
|
||||
ds->g(i, j) = sumg / HR_SCALE / HR_SCALE;
|
||||
ds->b(i, j) = sumb / HR_SCALE / HR_SCALE;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < HR_SCALE; i++) {
|
||||
delete [] reds[i];
|
||||
delete [] blues[i];
|
||||
}
|
||||
|
||||
hlmultipliers (rec, max_3, dh, dw);
|
||||
|
||||
if (hrmap[0] != NULL) {
|
||||
freeJaggedArray<float> (hrmap[0]);
|
||||
freeJaggedArray<float> (hrmap[1]);
|
||||
freeJaggedArray<float> (hrmap[2]);
|
||||
}
|
||||
|
||||
hrmap[0] = allocJaggedArray<float> (dw, dh);
|
||||
hrmap[1] = allocJaggedArray<float> (dw, dh);
|
||||
hrmap[2] = allocJaggedArray<float> (dw, dh);
|
||||
|
||||
for (int i = 0; i < dh; i++)
|
||||
for (int j = 0; j < dw; j++) {
|
||||
hrmap[0][i][j] = ds->r(i, j) > 0 ? (double)rec[0][i][j] / ds->r(i, j) : 1.0;
|
||||
hrmap[1][i][j] = ds->g(i, j) > 0 ? (double)rec[1][i][j] / ds->g(i, j) : 1.0;
|
||||
hrmap[2][i][j] = ds->b(i, j) > 0 ? (double)rec[2][i][j] / ds->b(i, j) : 1.0;
|
||||
}
|
||||
|
||||
delete ds;
|
||||
|
||||
freeJaggedArray<int> (rec[0]);
|
||||
freeJaggedArray<int> (rec[1]);
|
||||
freeJaggedArray<int> (rec[2]);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -46,8 +46,8 @@ public:
|
||||
ProfileContent (const ProfileContent& other);
|
||||
ProfileContent& operator= (const rtengine::ProfileContent& other);
|
||||
|
||||
ProfileContent (const Glib::ustring& fileName);
|
||||
ProfileContent (cmsHPROFILE hProfile);
|
||||
explicit ProfileContent (const Glib::ustring& fileName);
|
||||
explicit ProfileContent (cmsHPROFILE hProfile);
|
||||
cmsHPROFILE toProfile () const;
|
||||
};
|
||||
|
||||
|
@ -6394,7 +6394,7 @@ void ImProcFunctions::EPDToneMapCIE(CieImage *ncie, float a_w, float c_, float w
|
||||
Qpro = maxQ;
|
||||
}
|
||||
|
||||
EdgePreservingDecomposition epd = EdgePreservingDecomposition(Wid, Hei);
|
||||
EdgePreservingDecomposition epd(Wid, Hei);
|
||||
|
||||
#pragma omp parallel for
|
||||
|
||||
@ -6498,7 +6498,7 @@ void ImProcFunctions::EPDToneMap(LabImage *lab, unsigned int Iterates, int skip)
|
||||
float *a = lab->a[0];
|
||||
float *b = lab->b[0];
|
||||
unsigned int i, N = lab->W * lab->H;
|
||||
EdgePreservingDecomposition epd = EdgePreservingDecomposition(lab->W, lab->H);
|
||||
EdgePreservingDecomposition epd(lab->W, lab->H);
|
||||
|
||||
//Due to the taking of logarithms, L must be nonnegative. Further, scale to 0 to 1 using nominal range of L, 0 to 15 bit.
|
||||
float minL = FLT_MAX;
|
||||
|
@ -321,7 +321,7 @@ public:
|
||||
void Median_Denoise( float **src, float **dst, int width, int height, Median medianType, int iterations, int numThreads, float **buffer = NULL);
|
||||
void RGB_denoise(int kall, Imagefloat * src, Imagefloat * dst, Imagefloat * calclum, float * ch_M, float *max_r, float *max_b, bool isRAW, const procparams::DirPyrDenoiseParams & dnparams, const double expcomp, const NoiseCurve & noiseLCurve , const NoiseCurve & noiseCCurve , float &chaut, float &redaut, float &blueaut, float &maxredaut, float & maxblueaut, float &nresi, float &highresi);
|
||||
void RGB_denoise_infoGamCurve(const procparams::DirPyrDenoiseParams & dnparams, const bool isRAW, LUTf &gamcurve, float &gam, float &gamthresh, float &gamslope);
|
||||
void RGB_denoise_info(Imagefloat * src, Imagefloat * provicalc, bool isRAW, LUTf &gamcurve, float gam, float gamthresh, float gamslope, const procparams::DirPyrDenoiseParams & dnparams, const double expcomp, float &chaut, int &Nb, float &redaut, float &blueaut, float &maxredaut, float & maxblueaut, float &minredaut, float & minblueaut, float &nresi, float &highresi, float &chromina, float &sigma, float &lumema, float &sigma_L, float &redyel, float &skinc, float &nsknc, bool multiThread = false);
|
||||
void RGB_denoise_info(Imagefloat * src, Imagefloat * provicalc, bool isRAW, LUTf &gamcurve, float gam, float gamthresh, float gamslope, const procparams::DirPyrDenoiseParams & dnparams, const double expcomp, float &chaut, int &Nb, float &redaut, float &blueaut, float &maxredaut, float & maxblueaut, float &minredaut, float & minblueaut, float &chromina, float &sigma, float &lumema, float &sigma_L, float &redyel, float &skinc, float &nsknc, bool multiThread = false);
|
||||
void RGBtile_denoise (float * fLblox, int hblproc, float noisevar_Ldetail, float * nbrwt, float * blurbuffer ); //for DCT
|
||||
void RGBoutput_tile_row (float *bloxrow_L, float ** Ldetail, float ** tilemask_out, int height, int width, int top );
|
||||
bool WaveletDenoiseAllL(wavelet_decomposition &WaveletCoeffs_L, float *noisevarlum, float madL[8][3], float * vari, int edge);
|
||||
|
@ -103,7 +103,6 @@ struct cont_params {
|
||||
int backm;
|
||||
float eddet;
|
||||
float eddetthr;
|
||||
bool lips;
|
||||
float eddetthrHi;
|
||||
bool link;
|
||||
bool lip3;
|
||||
@ -218,19 +217,12 @@ SSEFUNCTION void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int
|
||||
|
||||
cp.tmstrength = params->wavelet.tmrs;
|
||||
//cp.tonemap = params->wavelet.tmr;
|
||||
cp.contena = true;
|
||||
cp.contena = params->wavelet.expcontrast;
|
||||
cp.chromena = true;
|
||||
cp.chromena = params->wavelet.expchroma;
|
||||
cp.edgeena = true;
|
||||
cp.edgeena = params->wavelet.expedge;
|
||||
cp.resena = true;
|
||||
cp.resena = params->wavelet.expresid;
|
||||
cp.finena = true;
|
||||
cp.finena = params->wavelet.expfinal;
|
||||
cp.toningena = true;
|
||||
cp.toningena = params->wavelet.exptoning;
|
||||
cp.noiseena = true;
|
||||
cp.noiseena = params->wavelet.expnoise;
|
||||
|
||||
if(params->wavelet.Backmethod == "black") {
|
||||
@ -491,7 +483,6 @@ SSEFUNCTION void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int
|
||||
cp.lev3s = static_cast<float>(params->wavelet.level3noise.value[0]);
|
||||
cp.lev3n = static_cast<float>(params->wavelet.level3noise.value[1]);
|
||||
|
||||
cp.detectedge = false;
|
||||
cp.detectedge = params->wavelet.medianlev;
|
||||
//printf("low=%f mean=%f sd=%f max=%f\n",cp.edg_low,cp.edg_mean,cp.edg_sd,cp.edg_max);
|
||||
int minwin = min(imwidth, imheight);
|
||||
@ -604,6 +595,7 @@ SSEFUNCTION void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int
|
||||
|
||||
//printf("levwav = %d\n",levwav);
|
||||
|
||||
#ifdef _OPENMP
|
||||
int numthreads = 1;
|
||||
int maxnumberofthreadsforwavelet = 0;
|
||||
|
||||
@ -641,7 +633,6 @@ SSEFUNCTION void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int
|
||||
|
||||
//printf("maxthre=%d\n",maxnumberofthreadsforwavelet);
|
||||
|
||||
#ifdef _OPENMP
|
||||
|
||||
// Calculate number of tiles. If less than omp_get_max_threads(), then limit num_threads to number of tiles
|
||||
if( options.rgbDenoiseThreadLimit > 0) {
|
||||
@ -675,10 +666,6 @@ SSEFUNCTION void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int
|
||||
printf("Ip Wavelet uses %d main thread(s) and up to %d nested thread(s) for each main thread\n", numthreads, wavNestedLevels);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _OPENMP
|
||||
#pragma omp parallel num_threads(numthreads)
|
||||
#endif
|
||||
{
|
||||
@ -881,7 +868,6 @@ SSEFUNCTION void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int
|
||||
if(!Ldecomp->memoryAllocationFailed) {
|
||||
|
||||
float madL[8][3];
|
||||
bool memoryAllocationFailed = false;
|
||||
#ifdef _RT_NESTED_OPENMP
|
||||
#pragma omp parallel for schedule(dynamic) collapse(2) num_threads(wavNestedLevels) if(wavNestedLevels>1)
|
||||
#endif
|
||||
@ -923,18 +909,16 @@ SSEFUNCTION void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int
|
||||
vari[1] = 8.f * SQR((cp.lev1n / 125.0) * (1.0 + cp.lev1n / 25.0));
|
||||
vari[2] = 8.f * SQR((cp.lev2n / 125.0) * (1.0 + cp.lev2n / 25.0));
|
||||
vari[3] = 8.f * SQR((cp.lev3n / 125.0) * (1.0 + cp.lev3n / 25.0));
|
||||
int edge = 1;
|
||||
|
||||
if((cp.lev0n > 0.1f || cp.lev1n > 0.1f || cp.lev2n > 0.1f || cp.lev3n > 0.1f) && cp.noiseena) {
|
||||
int edge = 1;
|
||||
vari[0] = max(0.0001f, vari[0]);
|
||||
vari[1] = max(0.0001f, vari[1]);
|
||||
vari[2] = max(0.0001f, vari[2]);
|
||||
vari[3] = max(0.0001f, vari[3]);
|
||||
float* noisevarlum = NULL; // we need a dummy to pass it to WaveletDenoiseAllL
|
||||
|
||||
if(!WaveletDenoiseAllL(*Ldecomp, noisevarlum, madL, vari, edge)) { //
|
||||
memoryAllocationFailed = true;
|
||||
}
|
||||
WaveletDenoiseAllL(*Ldecomp, noisevarlum, madL, vari, edge);
|
||||
}
|
||||
|
||||
ind = 1;
|
||||
@ -988,7 +972,7 @@ SSEFUNCTION void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int
|
||||
|
||||
// printf("Levwava before: %d\n",levwava);
|
||||
if(cp.chrores == 0.f && params->wavelet.CLmethod == "all" && !cp.cbena) { // no processing of residual ab => we probably can reduce the number of levels
|
||||
while(levwava > 0 && !cp.diag && (((cp.CHmet == 2 && (cp.chro == 0.f || cp.mul[levwava - 1] == 0.f )) || (cp.CHmet != 2 && (levwava == 10 || (!cp.curv || (cp.curv && cp.mulC[levwava - 1] == 0.f)))))) && (!cp.opaRG || levwava == 10 || (cp.opaRG && cp.mulopaRG[levwava - 1] == 0.f)) && ((levwava == 10 || (cp.CHSLmet == 1 && cp.mulC[levwava - 1] == 0.f)))) {
|
||||
while(levwava > 0 && !cp.diag && (((cp.CHmet == 2 && (cp.chro == 0.f || cp.mul[levwava - 1] == 0.f )) || (cp.CHmet != 2 && (levwava == 10 || (!cp.curv || cp.mulC[levwava - 1] == 0.f))))) && (!cp.opaRG || levwava == 10 || (cp.opaRG && cp.mulopaRG[levwava - 1] == 0.f)) && ((levwava == 10 || (cp.CHSLmet == 1 && cp.mulC[levwava - 1] == 0.f)))) {
|
||||
levwava--;
|
||||
}
|
||||
}
|
||||
@ -1009,7 +993,7 @@ SSEFUNCTION void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int
|
||||
|
||||
//printf("Levwavb before: %d\n",levwavb);
|
||||
if(cp.chrores == 0.f && params->wavelet.CLmethod == "all" && !cp.cbena) { // no processing of residual ab => we probably can reduce the number of levels
|
||||
while(levwavb > 0 && !cp.diag && (((cp.CHmet == 2 && (cp.chro == 0.f || cp.mul[levwavb - 1] == 0.f )) || (cp.CHmet != 2 && (levwavb == 10 || (!cp.curv || (cp.curv && cp.mulC[levwavb - 1] == 0.f)))))) && (!cp.opaBY || levwavb == 10 || (cp.opaBY && cp.mulopaBY[levwavb - 1] == 0.f)) && ((levwavb == 10 || (cp.CHSLmet == 1 && cp.mulC[levwavb - 1] == 0.f)))) {
|
||||
while(levwavb > 0 && !cp.diag && (((cp.CHmet == 2 && (cp.chro == 0.f || cp.mul[levwavb - 1] == 0.f )) || (cp.CHmet != 2 && (levwavb == 10 || (!cp.curv || cp.mulC[levwavb - 1] == 0.f))))) && (!cp.opaBY || levwavb == 10 || (cp.opaBY && cp.mulopaBY[levwavb - 1] == 0.f)) && ((levwavb == 10 || (cp.CHSLmet == 1 && cp.mulC[levwavb - 1] == 0.f)))) {
|
||||
levwavb--;
|
||||
}
|
||||
}
|
||||
@ -1030,7 +1014,7 @@ SSEFUNCTION void ImProcFunctions::ip_wavelet(LabImage * lab, LabImage * dst, int
|
||||
|
||||
// printf("Levwavab before: %d\n",levwavab);
|
||||
if(cp.chrores == 0.f && !hhutili && params->wavelet.CLmethod == "all") { // no processing of residual ab => we probably can reduce the number of levels
|
||||
while(levwavab > 0 && (((cp.CHmet == 2 && (cp.chro == 0.f || cp.mul[levwavab - 1] == 0.f )) || (cp.CHmet != 2 && (levwavab == 10 || (!cp.curv || (cp.curv && cp.mulC[levwavab - 1] == 0.f)))))) && (!cp.opaRG || levwavab == 10 || (cp.opaRG && cp.mulopaRG[levwavab - 1] == 0.f)) && ((levwavab == 10 || (cp.CHSLmet == 1 && cp.mulC[levwavab - 1] == 0.f)))) {
|
||||
while(levwavab > 0 && (((cp.CHmet == 2 && (cp.chro == 0.f || cp.mul[levwavab - 1] == 0.f )) || (cp.CHmet != 2 && (levwavab == 10 || (!cp.curv || cp.mulC[levwavab - 1] == 0.f))))) && (!cp.opaRG || levwavab == 10 || (cp.opaRG && cp.mulopaRG[levwavab - 1] == 0.f)) && ((levwavab == 10 || (cp.CHSLmet == 1 && cp.mulC[levwavab - 1] == 0.f)))) {
|
||||
levwavab--;
|
||||
}
|
||||
}
|
||||
@ -1406,14 +1390,11 @@ void ImProcFunctions::Evaluate2(wavelet_decomposition &WaveletCoeffs_L,
|
||||
void ImProcFunctions::Eval2 (float ** WavCoeffs_L, int level, const struct cont_params& cp,
|
||||
int W_L, int H_L, int skip_L, int ind, float *mean, float *meanN, float *sigma, float *sigmaN, float *MaxP, float *MaxN, float *madL)
|
||||
{
|
||||
const float eps = 0.01f;
|
||||
|
||||
float ava[4], avb[4], avLP[4], avLN[4];
|
||||
float maxL[4], minL[4], maxa[4], maxb[4];
|
||||
float avLP[4], avLN[4];
|
||||
float maxL[4], minL[4];
|
||||
float sigP[4], sigN[4];
|
||||
float AvL, AvN, SL, SN, maxLP, maxLN, MADL;
|
||||
float madLlev[10];
|
||||
float thr = params->wavelet.thres;
|
||||
float AvL, AvN, SL, SN, maxLP, maxLN;
|
||||
|
||||
for (int dir = 1; dir < 4; dir++) {
|
||||
Aver(WavCoeffs_L[dir], W_L * H_L, avLP[dir], avLN[dir], maxL[dir], minL[dir]);
|
||||
@ -1426,7 +1407,6 @@ void ImProcFunctions::Eval2 (float ** WavCoeffs_L, int level, const struct cont
|
||||
SN = 0.f;
|
||||
maxLP = 0.f;
|
||||
maxLN = 0.f;
|
||||
MADL = 0.f;
|
||||
|
||||
for (int dir = 1; dir < 4; dir++) {
|
||||
AvL += avLP[dir];
|
||||
@ -1435,7 +1415,6 @@ void ImProcFunctions::Eval2 (float ** WavCoeffs_L, int level, const struct cont
|
||||
SN += sigN[dir];
|
||||
maxLP += maxL[dir];
|
||||
maxLN += minL[dir];
|
||||
MADL += madL[dir];
|
||||
}
|
||||
|
||||
AvL /= 3;
|
||||
@ -1444,13 +1423,6 @@ void ImProcFunctions::Eval2 (float ** WavCoeffs_L, int level, const struct cont
|
||||
SN /= 3;
|
||||
maxLP /= 3;
|
||||
maxLN /= 3;
|
||||
MADL /= 3;
|
||||
|
||||
if(level < 4) {
|
||||
MADL = sqrt(MADL);
|
||||
} else {
|
||||
MADL = 0.f;
|
||||
}
|
||||
|
||||
mean[level] = AvL;
|
||||
meanN[level] = AvN;
|
||||
@ -1648,7 +1620,7 @@ void ImProcFunctions::EPDToneMapResid(float * WavCoeffs_L0, unsigned int Iterat
|
||||
float sca = params->epd.scale;
|
||||
float gamm = params->wavelet.gamma;
|
||||
float rew = params->epd.reweightingIterates;
|
||||
EdgePreservingDecomposition epd2 = EdgePreservingDecomposition(W_L, H_L);
|
||||
EdgePreservingDecomposition epd2(W_L, H_L);
|
||||
cp.TMmeth = 2; //default after testing
|
||||
|
||||
if(cp.TMmeth == 1) {
|
||||
@ -1801,25 +1773,22 @@ void ImProcFunctions::WaveletcontAllL(LabImage * labco, float ** varhue, float *
|
||||
float maxkoeLi[12];
|
||||
|
||||
float *koeLibuffer = NULL;
|
||||
bool lipschitz = true;
|
||||
|
||||
if(lipschitz == true) {
|
||||
for(int y = 0; y < 12; y++) {
|
||||
maxkoeLi[y] = 0.f; //9
|
||||
}
|
||||
|
||||
koeLibuffer = new float[12 * H_L * W_L]; //12
|
||||
|
||||
for (int i = 0; i < 12; i++) { //9
|
||||
koeLi[i] = &koeLibuffer[i * W_L * H_L];
|
||||
}
|
||||
|
||||
for(int j = 0; j < 12; j++) //9
|
||||
for (int i = 0; i < W_L * H_L; i++) {
|
||||
koeLi[j][i] = 0.f;
|
||||
}
|
||||
for(int y = 0; y < 12; y++) {
|
||||
maxkoeLi[y] = 0.f; //9
|
||||
}
|
||||
|
||||
koeLibuffer = new float[12 * H_L * W_L]; //12
|
||||
|
||||
for (int i = 0; i < 12; i++) { //9
|
||||
koeLi[i] = &koeLibuffer[i * W_L * H_L];
|
||||
}
|
||||
|
||||
for(int j = 0; j < 12; j++) //9
|
||||
for (int i = 0; i < W_L * H_L; i++) {
|
||||
koeLi[j][i] = 0.f;
|
||||
}
|
||||
|
||||
#ifdef _RT_NESTED_OPENMP
|
||||
#pragma omp parallel num_threads(wavNestedLevels) if(wavNestedLevels>1)
|
||||
#endif
|
||||
@ -1923,7 +1892,7 @@ void ImProcFunctions::WaveletcontAllL(LabImage * labco, float ** varhue, float *
|
||||
// float eddlow=5.f + cp.edgampl/2.f;//settings->ed_low;//5 to 40
|
||||
|
||||
|
||||
if(cp.detectedge && lipschitz == true) { //enabled Lipschitz control...more memory..more time...
|
||||
if(cp.detectedge) { //enabled Lipschitz control...more memory..more time...
|
||||
float *tmCBuffer = new float[H_L * W_L];
|
||||
float *tmC[H_L];
|
||||
|
||||
@ -2066,7 +2035,7 @@ void ImProcFunctions::WaveletcontAllL(LabImage * labco, float ** varhue, float *
|
||||
|
||||
float ** WavCoeffs_L = WaveletCoeffs_L.level_coeffs(lvl);
|
||||
|
||||
ContAllL (koeLi, maxkoeLi, lipschitz, maxlvl, labco, varhue, varchrom, WavCoeffs_L, WavCoeffs_L0, lvl, dir, cp, Wlvl_L, Hlvl_L, skip, mean, meanN, sigma, sigmaN, MaxP, MaxN, wavCLVCcurve, waOpacityCurveW, ChCurve, Chutili);
|
||||
ContAllL (koeLi, maxkoeLi, true, maxlvl, labco, varhue, varchrom, WavCoeffs_L, WavCoeffs_L0, lvl, dir, cp, Wlvl_L, Hlvl_L, skip, mean, meanN, sigma, sigmaN, MaxP, MaxN, wavCLVCcurve, waOpacityCurveW, ChCurve, Chutili);
|
||||
|
||||
|
||||
}
|
||||
@ -2281,9 +2250,6 @@ void ImProcFunctions::WaveletcontAllAB(LabImage * labco, float ** varhue, float
|
||||
int Wlvl_ab = WaveletCoeffs_ab.level_W(lvl);
|
||||
int Hlvl_ab = WaveletCoeffs_ab.level_H(lvl);
|
||||
|
||||
|
||||
int skip_ab = WaveletCoeffs_ab.level_stride(lvl);
|
||||
//printf("lev=%d skipL=%d skipab=%d\n",lvl, skip_L,skip_ab);
|
||||
float ** WavCoeffs_ab = WaveletCoeffs_ab.level_coeffs(lvl);
|
||||
ContAllAB (labco, maxlvl, varhue, varchrom, WavCoeffs_ab, WavCoeffs_ab0, lvl, dir, waOpacityCurveW, cp, Wlvl_ab, Hlvl_ab, useChannelA);
|
||||
}
|
||||
@ -2622,7 +2588,6 @@ void ImProcFunctions::ContAllL (float *koeLi[12], float *maxkoeLi, bool lipschit
|
||||
scaleskip[sc] = scales[sc] / skip;
|
||||
}
|
||||
|
||||
float atten01234 = 0.80f;
|
||||
float t_r = settings->top_right;
|
||||
float t_l = settings->top_left;
|
||||
float b_r = settings->bot_right;
|
||||
@ -2719,6 +2684,7 @@ void ImProcFunctions::ContAllL (float *koeLi[12], float *maxkoeLi, bool lipschit
|
||||
float value = ((float)cp.val) / 8.f; //strength
|
||||
|
||||
if (scaleskip[1] < 1.f) {
|
||||
float atten01234 = 0.80f;
|
||||
value *= (atten01234 * scaleskip[1]); //for zoom < 100% reduce strength...I choose level 1...but!!
|
||||
}
|
||||
|
||||
@ -2870,9 +2836,9 @@ void ImProcFunctions::ContAllL (float *koeLi[12], float *maxkoeLi, bool lipschit
|
||||
kinterm = 1.f;
|
||||
float kc = kmul * (wavCLVCcurve[absciss * 500.f] - 0.5f);
|
||||
float kcd = kmuld * (wavCLVCcurve[absciss * 500.f] - 0.5f);
|
||||
float reduceeffect = 0.6f;
|
||||
|
||||
if(kc >= 0.f) {
|
||||
float reduceeffect = 0.6f;
|
||||
kinterm = 1.f + reduceeffect * kmul * (wavCLVCcurve[absciss * 500.f] - 0.5f); //about 1 to 3 general and big amplification for max (under 0)
|
||||
} else {
|
||||
kinterm = 1.f - (SQR(kcd)) / 10.f;
|
||||
@ -3065,10 +3031,10 @@ void ImProcFunctions::ContAllL (float *koeLi[12], float *maxkoeLi, bool lipschit
|
||||
mea[8] = mean[level] + 2.5f * sigma[level]; //99%
|
||||
|
||||
bool useChromAndHue = (skinprot != 0.f || cp.HSmet);
|
||||
float modchro, kLlev;
|
||||
float modchro;
|
||||
|
||||
for (int i = 0; i < W_L * H_L; i++) {
|
||||
kLlev = 1.f;
|
||||
float kLlev = 1.f;
|
||||
|
||||
if(cpMul < 0.f) {
|
||||
beta = 1.f; // disabled for negatives values "less contrast"
|
||||
@ -3218,15 +3184,13 @@ void ImProcFunctions::ContAllL (float *koeLi[12], float *maxkoeLi, bool lipschit
|
||||
it = itmoins;
|
||||
} else if(level == med) {
|
||||
it = 7;
|
||||
} else if(level > med) {
|
||||
} else /*if(level > med)*/ {
|
||||
it = itplus;
|
||||
}
|
||||
|
||||
for(int j = 0; j < it; j++) {
|
||||
//float bal = cp.balan;//-100 +100
|
||||
float kba = 1.f;
|
||||
float k1;
|
||||
float k2;
|
||||
|
||||
// if(dir <3) kba= 1.f + bal/600.f;
|
||||
// if(dir==3) kba = 1.f - bal/300.f;
|
||||
@ -3234,8 +3198,8 @@ void ImProcFunctions::ContAllL (float *koeLi[12], float *maxkoeLi, bool lipschit
|
||||
int ii = i / W_L;
|
||||
int jj = i - ii * W_L;
|
||||
float LL100 = labco->L[ii * 2][jj * 2] / 327.68f;
|
||||
k1 = 0.3f * (waOpacityCurveW[6.f * LL100] - 0.5f); //k1 between 0 and 0.5 0.5==> 1/6=0.16
|
||||
k2 = k1 * 2.f;
|
||||
float k1 = 0.3f * (waOpacityCurveW[6.f * LL100] - 0.5f); //k1 between 0 and 0.5 0.5==> 1/6=0.16
|
||||
float k2 = k1 * 2.f;
|
||||
|
||||
if(dir < 3) {
|
||||
kba = 1.f + k1;
|
||||
@ -3261,23 +3225,21 @@ void ImProcFunctions::ContAllL (float *koeLi[12], float *maxkoeLi, bool lipschit
|
||||
it = itmoins;
|
||||
} else if(level == med) {
|
||||
it = 7;
|
||||
} else if(level > med) {
|
||||
} else /*if(level > med)*/ {
|
||||
it = itplus;
|
||||
}
|
||||
|
||||
for(int j = 0; j < it; j++) {
|
||||
float bal = cp.balan;//-100 +100
|
||||
float kba = 1.f;
|
||||
float k1;
|
||||
float k2;
|
||||
|
||||
// if(dir <3) kba= 1.f + bal/600.f;
|
||||
// if(dir==3) kba = 1.f - bal/300.f;
|
||||
for (int i = 0; i < W_L * H_L; i++) {
|
||||
int ii = i / W_L;
|
||||
int jj = i - ii * W_L;
|
||||
k1 = 600.f;
|
||||
k2 = 300.f;
|
||||
float k1 = 600.f;
|
||||
float k2 = 300.f;
|
||||
float LL100 = labco->L[ii * 2][jj * 2] / 327.68f;
|
||||
float aa = 4970.f;
|
||||
float bb = -397000.f;
|
||||
@ -3363,7 +3325,6 @@ void ImProcFunctions::ContAllAB (LabImage * labco, int maxlvl, float ** varhue,
|
||||
|
||||
// if( (cp.curv || cp.CHSLmet==1) && cp.CHmet!=2 && level < 9 && cpMulC != 0.f) { // cpMulC == 0.f means all will be multiplied by 1.f, so we can skip
|
||||
if( cp.CHmet != 2 && level < 9 && cpMulC != 0.f && cp.chromena) { // cpMulC == 0.f means all will be multiplied by 1.f, so we can skip
|
||||
float modchro, modhue, kClev;
|
||||
const float skinprot = params->wavelet.skinprotect;
|
||||
const float skinprotneg = -skinprot;
|
||||
const float factorHard = (1.f - skinprotneg / 100.f);
|
||||
@ -3373,15 +3334,13 @@ void ImProcFunctions::ContAllAB (LabImage * labco, int maxlvl, float ** varhue,
|
||||
int ii = i / W_ab;
|
||||
int jj = i - ii * W_ab;
|
||||
//WL and W_ab are identical
|
||||
float LL = labco->L[ii * 2][jj * 2];
|
||||
float LL100 = LL / 327.68f;
|
||||
float scale = 1.f;
|
||||
modchro = varchrom[ii * 2][jj * 2];
|
||||
float modchro = varchrom[ii * 2][jj * 2];
|
||||
|
||||
if(useSkinControl) {
|
||||
// hue chroma skin with initial lab datas
|
||||
modhue = varhue[ii][jj];
|
||||
scale = 1.f;
|
||||
float LL100 = labco->L[ii * 2][jj * 2] / 327.68f;
|
||||
float modhue = varhue[ii][jj];
|
||||
|
||||
if(skinprot > 0.f) {
|
||||
Color::SkinSatCbdl2 (LL100, modhue, modchro, skinprot, scale, true, cp.b_l, cp.t_l, cp.t_r, cp.b_r, 1); //1 for curve
|
||||
@ -3397,7 +3356,7 @@ void ImProcFunctions::ContAllAB (LabImage * labco, int maxlvl, float ** varhue,
|
||||
beta = 0.02f;
|
||||
}
|
||||
|
||||
kClev = beta;
|
||||
float kClev = beta;
|
||||
|
||||
if(cp.CHmet == 1) {
|
||||
if(level < cp.chrom) {
|
||||
@ -3479,15 +3438,13 @@ void ImProcFunctions::ContAllAB (LabImage * labco, int maxlvl, float ** varhue,
|
||||
it = itmoins;
|
||||
} else if(level == med) {
|
||||
it = 7;
|
||||
} else if(level > med) {
|
||||
} else /*if(level > med)*/ {
|
||||
it = itplus;
|
||||
}
|
||||
|
||||
for(int j = 0; j < it; j++) {
|
||||
//float bal = cp.balan;//-100 +100
|
||||
float kba = 1.f;
|
||||
float k1;
|
||||
float k2;
|
||||
|
||||
// if(dir <3) kba= 1.f + bal/600.f;
|
||||
// if(dir==3) kba = 1.f - bal/300.f;
|
||||
@ -3495,8 +3452,8 @@ void ImProcFunctions::ContAllAB (LabImage * labco, int maxlvl, float ** varhue,
|
||||
int ii = i / W_ab;
|
||||
int jj = i - ii * W_ab;
|
||||
float LL100 = labco->L[ii * 2][jj * 2] / 327.68f;
|
||||
k1 = 0.3f * (waOpacityCurveW[6.f * LL100] - 0.5f); //k1 between 0 and 0.5 0.5==> 1/6=0.16
|
||||
k2 = k1 * 2.f;
|
||||
float k1 = 0.3f * (waOpacityCurveW[6.f * LL100] - 0.5f); //k1 between 0 and 0.5 0.5==> 1/6=0.16
|
||||
float k2 = k1 * 2.f;
|
||||
|
||||
if(dir < 3) {
|
||||
kba = 1.f + k1;
|
||||
@ -3522,23 +3479,21 @@ void ImProcFunctions::ContAllAB (LabImage * labco, int maxlvl, float ** varhue,
|
||||
it = itmoins;
|
||||
} else if(level == med) {
|
||||
it = 7;
|
||||
} else if(level > med) {
|
||||
} else /*if(level > med)*/ {
|
||||
it = itplus;
|
||||
}
|
||||
|
||||
for(int j = 0; j < it; j++) {
|
||||
float bal = cp.balan;//-100 +100
|
||||
float kba = 1.f;
|
||||
float k1;
|
||||
float k2;
|
||||
|
||||
// if(dir <3) kba= 1.f + bal/600.f;
|
||||
// if(dir==3) kba = 1.f - bal/300.f;
|
||||
for (int i = 0; i < W_ab * H_ab; i++) {
|
||||
int ii = i / W_ab;
|
||||
int jj = i - ii * W_ab;
|
||||
k1 = 600.f;
|
||||
k2 = 300.f;
|
||||
float k1 = 600.f;
|
||||
float k2 = 300.f;
|
||||
float LL100 = labco->L[ii * 2][jj * 2] / 327.68f;
|
||||
float aa = 4970.f;
|
||||
float bb = -397000.f;
|
||||
@ -3607,10 +3562,8 @@ void ImProcFunctions::ContAllAB (LabImage * labco, int maxlvl, float ** varhue,
|
||||
if(choiceClevel < 3) { // not all levels visible, paint residual
|
||||
if(level == 0) {
|
||||
if(cp.backm != 2) { // nothing to change when residual is used as background
|
||||
float backGroundChroma = (cp.backm == 1) ? 0.f : 0.f; //we can change first to colorized...
|
||||
|
||||
for (int i = 0; i < W_ab * H_ab; i++) {
|
||||
WavCoeffs_ab0[i] = backGroundChroma;
|
||||
WavCoeffs_ab0[i] = 0.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,8 +17,9 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef JAGGEDARRAY_H
|
||||
#define JAGGEDARRAY_H
|
||||
#pragma once
|
||||
|
||||
#include "noncopyable.h"
|
||||
|
||||
namespace rtengine
|
||||
{
|
||||
@ -50,7 +51,8 @@ inline void freeJaggedArray (T** const a)
|
||||
}
|
||||
|
||||
template<class T>
|
||||
class JaggedArray
|
||||
class JaggedArray :
|
||||
public NonCopyable
|
||||
{
|
||||
public:
|
||||
JaggedArray (const int W, const int H, const bool initZero = false)
|
||||
@ -65,10 +67,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
JaggedArray (const JaggedArray&) = delete;
|
||||
JaggedArray& operator= (const JaggedArray&) = delete;
|
||||
|
||||
public:
|
||||
operator T** const () const
|
||||
{
|
||||
return a;
|
||||
@ -85,5 +83,3 @@ template<class T>
|
||||
void freeJaggedArray (JaggedArray<T>&);
|
||||
|
||||
} // rtengine
|
||||
|
||||
#endif // JAGGEDARRAY_H
|
||||
|
@ -250,8 +250,8 @@ static void _convolveImageVert(
|
||||
|
||||
static void _convolveSeparate(
|
||||
_KLT_FloatImage imgin,
|
||||
ConvolutionKernel horiz_kernel,
|
||||
ConvolutionKernel vert_kernel,
|
||||
const ConvolutionKernel &horiz_kernel,
|
||||
const ConvolutionKernel &vert_kernel,
|
||||
_KLT_FloatImage imgout)
|
||||
{
|
||||
/* Create temporary image */
|
||||
|
@ -276,7 +276,7 @@ float LCPMapper::calcVignetteFac(int x, int y) const
|
||||
+ 2.*aVig[0] * aVig[2] - 3.*param0Sqr * aVig[1]) * rsqr * rsqr));
|
||||
}
|
||||
|
||||
LCPProfile::LCPProfile(Glib::ustring fname)
|
||||
LCPProfile::LCPProfile(const Glib::ustring &fname)
|
||||
{
|
||||
const int BufferSize = 8192;
|
||||
char buf[BufferSize];
|
||||
|
@ -89,7 +89,7 @@ public:
|
||||
static const int MaxPersModelCount = 3000;
|
||||
LCPPersModel* aPersModel[MaxPersModelCount]; // Do NOT use std::list or something, it's buggy in GCC!
|
||||
|
||||
LCPProfile(Glib::ustring fname);
|
||||
explicit LCPProfile(const Glib::ustring &fname);
|
||||
|
||||
void calcParams(int mode, float focalLength, float focusDist, float aperture, LCPModelCommon *pCorr1, LCPModelCommon *pCorr2, LCPModelCommon *pCorr3) const; // Interpolates between the persModels frames
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* These median implementations from Floessie and Ingo Weyrich are inspired by this work:
|
||||
* These median implementations from Flössie and Ingo Weyrich are inspired by this work:
|
||||
*
|
||||
* http://ndevilla.free.fr/median/median.pdf
|
||||
* http://pages.ripco.net/~jgamble/nw.html
|
||||
@ -45,7 +45,7 @@ inline T median(std::array<T, N> array)
|
||||
std::nth_element(array.begin(), middle, array.end());
|
||||
|
||||
return
|
||||
N % 2
|
||||
(N % 2)
|
||||
? *middle
|
||||
: ((*middle + *std::max_element(array.begin(), middle)) / static_cast<T>(2));
|
||||
}
|
||||
|
34
rtengine/noncopyable.h
Normal file
34
rtengine/noncopyable.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* This file is part of RawTherapee.
|
||||
*
|
||||
* Copyright (c) 2016 Flössie <floessie.mail@gmail.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace rtengine
|
||||
{
|
||||
|
||||
class NonCopyable
|
||||
{
|
||||
public:
|
||||
NonCopyable() = default;
|
||||
|
||||
explicit NonCopyable(const NonCopyable&) = delete;
|
||||
NonCopyable& operator =(const NonCopyable&) = delete;
|
||||
};
|
||||
|
||||
}
|
@ -50,7 +50,7 @@ protected:
|
||||
void flush();
|
||||
|
||||
public:
|
||||
PipetteBuffer(::EditDataProvider *dataProvider);
|
||||
explicit PipetteBuffer(::EditDataProvider *dataProvider);
|
||||
~PipetteBuffer();
|
||||
|
||||
/** @brief Getter to know if the pipette buffer is correctly filled */
|
||||
|
@ -753,13 +753,13 @@ void WaveletParams::setDefaults()
|
||||
hhcurve.push_back(FCT_Linear);
|
||||
Chcurve.clear ();
|
||||
Chcurve.push_back(FCT_Linear);
|
||||
expcontrast = true;
|
||||
expchroma = true;
|
||||
expedge = true;
|
||||
expresid = true;
|
||||
expfinal = true;
|
||||
exptoning = true;
|
||||
expnoise = true;
|
||||
expcontrast = false;
|
||||
expchroma = false;
|
||||
expedge = false;
|
||||
expresid = false;
|
||||
expfinal = false;
|
||||
exptoning = false;
|
||||
expnoise = false;
|
||||
|
||||
for(int i = 0; i < 9; i ++) {
|
||||
c[i] = 0;
|
||||
|
@ -19,11 +19,13 @@
|
||||
#ifndef _PROCPARAMS_H_
|
||||
#define _PROCPARAMS_H_
|
||||
|
||||
#include <glibmm.h>
|
||||
#include <vector>
|
||||
#include <cstdio>
|
||||
#include <cmath>
|
||||
|
||||
#include <glibmm.h>
|
||||
#include <lcms2.h>
|
||||
|
||||
#include "LUT.h"
|
||||
#include "coord.h"
|
||||
|
||||
@ -1364,7 +1366,7 @@ class PartialProfile
|
||||
public:
|
||||
rtengine::procparams::ProcParams* pparams;
|
||||
ParamsEdited* pedited;
|
||||
PartialProfile& operator=(PartialProfile& rhs)
|
||||
PartialProfile& operator =(const PartialProfile& rhs)
|
||||
{
|
||||
pparams = rhs.pparams;
|
||||
pedited = rhs.pedited;
|
||||
|
@ -20,8 +20,10 @@
|
||||
#define __RAWIMAGE_H
|
||||
|
||||
#include <ctime>
|
||||
|
||||
#include "dcraw.h"
|
||||
#include "imageio.h"
|
||||
#include "noncopyable.h"
|
||||
|
||||
namespace rtengine
|
||||
{
|
||||
@ -32,7 +34,8 @@ struct badPix {
|
||||
badPix( uint16_t xc, uint16_t yc ): x(xc), y(yc) {}
|
||||
};
|
||||
|
||||
class PixelsMap
|
||||
class PixelsMap :
|
||||
public NonCopyable
|
||||
{
|
||||
int w; // line width in base_t units
|
||||
int h; // height
|
||||
@ -48,6 +51,7 @@ public:
|
||||
pm = new base_t [h * w ];
|
||||
memset(pm, 0, h * w * base_t_size );
|
||||
}
|
||||
|
||||
~PixelsMap()
|
||||
{
|
||||
delete [] pm;
|
||||
@ -99,7 +103,7 @@ class RawImage: public DCraw
|
||||
{
|
||||
public:
|
||||
|
||||
RawImage( const Glib::ustring &name );
|
||||
explicit RawImage( const Glib::ustring &name );
|
||||
~RawImage();
|
||||
|
||||
int loadRaw (bool loadData = true, bool closeFile = true, ProgressListener *plistener = 0, double progressRange = 1.0);
|
||||
|
@ -4395,7 +4395,7 @@ void RawImageSource::HLRecovery_CIELab (float* rin, float* gin, float* bin, floa
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void RawImageSource::hlRecovery (std::string method, float* red, float* green, float* blue, int width, float* hlmax )
|
||||
void RawImageSource::hlRecovery (const std::string &method, float* red, float* green, float* blue, int width, float* hlmax )
|
||||
{
|
||||
|
||||
if (method == "Luminance") {
|
||||
@ -4403,8 +4403,6 @@ void RawImageSource::hlRecovery (std::string method, float* red, float* green, f
|
||||
} else if (method == "CIELab blending") {
|
||||
HLRecovery_CIELab (red, green, blue, red, green, blue, width, 65535.0, imatrices.xyz_cam, imatrices.cam_xyz);
|
||||
}
|
||||
/*else if (method=="Color")
|
||||
HLRecovery_ColorPropagation (red, green, blue, i, sx1, width, skip);*/
|
||||
else if (method == "Blend") { // derived from Dcraw
|
||||
HLRecovery_blend(red, green, blue, width, 65535.0, hlmax);
|
||||
}
|
||||
|
@ -97,12 +97,10 @@ protected:
|
||||
void hphd_horizontal (float** hpmap, int row_from, int row_to);
|
||||
void hphd_green (float** hpmap);
|
||||
void processFalseColorCorrectionThread (Imagefloat* im, array2D<float> &rbconv_Y, array2D<float> &rbconv_I, array2D<float> &rbconv_Q, array2D<float> &rbout_I, array2D<float> &rbout_Q, const int row_from, const int row_to);
|
||||
void hlRecovery (std::string method, float* red, float* green, float* blue, int width, float* hlmax);
|
||||
void hlRecovery (const std::string &method, float* red, float* green, float* blue, int width, float* hlmax);
|
||||
void transformRect (PreviewProps pp, int tran, int &sx1, int &sy1, int &width, int &height, int &fw);
|
||||
void transformPosition (int x, int y, int tran, int& tx, int& ty);
|
||||
|
||||
void updateHLRecoveryMap_ColorPropagation ();
|
||||
void HLRecovery_ColorPropagation (float* red, float* green, float* blue, int i, int sx1, int width, int skip);
|
||||
unsigned FC(int row, int col)
|
||||
{
|
||||
return ri->FC(row, col);
|
||||
@ -188,7 +186,7 @@ public:
|
||||
|
||||
void convertColorSpace(Imagefloat* image, const ColorManagementParams &cmp, const ColorTemp &wb);
|
||||
static bool findInputProfile(Glib::ustring inProfile, cmsHPROFILE embedded, std::string camName, DCPProfile **dcpProf, cmsHPROFILE& in);
|
||||
static void colorSpaceConversion (Imagefloat* im, ColorManagementParams cmp, const ColorTemp &wb, double pre_mul[3], cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], std::string camName)
|
||||
static void colorSpaceConversion (Imagefloat* im, ColorManagementParams cmp, const ColorTemp &wb, double pre_mul[3], cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], const std::string &camName)
|
||||
{
|
||||
colorSpaceConversion_ (im, cmp, wb, pre_mul, embedded, camprofile, cam, camName);
|
||||
}
|
||||
|
@ -21,11 +21,13 @@
|
||||
|
||||
#include "imagefloat.h"
|
||||
#include "image16.h"
|
||||
#include "noncopyable.h"
|
||||
|
||||
namespace rtengine
|
||||
{
|
||||
|
||||
class SHMap
|
||||
class SHMap :
|
||||
public NonCopyable
|
||||
{
|
||||
|
||||
public:
|
||||
|
@ -273,7 +273,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p
|
||||
float maxr = 0.f;
|
||||
float maxb = 0.f;
|
||||
float pondcorrec = 1.0f;
|
||||
float chaut, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, nresi, highresi, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc;
|
||||
float chaut, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc;
|
||||
int Nb;
|
||||
chaut = 0.f;
|
||||
redaut = 0.f;
|
||||
@ -282,7 +282,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p
|
||||
maxblueaut = 0.f;
|
||||
chromina = 0.f;
|
||||
sigma = 0.f;
|
||||
ipf.RGB_denoise_info(origCropPart, provicalc, imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope, params.dirpyrDenoise, imgsrc->getDirPyrDenoiseExpComp(), chaut, Nb, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, nresi, highresi, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc);
|
||||
ipf.RGB_denoise_info(origCropPart, provicalc, imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope, params.dirpyrDenoise, imgsrc->getDirPyrDenoiseExpComp(), chaut, Nb, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc);
|
||||
float multip = 1.f;
|
||||
float adjustr = 1.f;
|
||||
|
||||
@ -490,8 +490,8 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p
|
||||
|
||||
imgsrc->convertColorSpace(provicalc, params.icm, currWB);//for denoise luminance curve
|
||||
int nb = 0;
|
||||
float chaut = 0.f, redaut = 0.f, blueaut = 0.f, maxredaut = 0.f, maxblueaut = 0.f, minredaut = 0.f, minblueaut = 0.f, nresi = 0.f, highresi = 0.f, chromina = 0.f, sigma = 0.f, lumema = 0.f, sigma_L = 0.f, redyel = 0.f, skinc = 0.f, nsknc = 0.f;
|
||||
ipf.RGB_denoise_info(origCropPart, provicalc, imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope, params.dirpyrDenoise, imgsrc->getDirPyrDenoiseExpComp(), chaut, nb, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, nresi, highresi, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc);
|
||||
float chaut = 0.f, redaut = 0.f, blueaut = 0.f, maxredaut = 0.f, maxblueaut = 0.f, minredaut = 0.f, minblueaut = 0.f, chromina = 0.f, sigma = 0.f, lumema = 0.f, sigma_L = 0.f, redyel = 0.f, skinc = 0.f, nsknc = 0.f;
|
||||
ipf.RGB_denoise_info(origCropPart, provicalc, imgsrc->isRAW(), gamcurve, gam, gamthresh, gamslope, params.dirpyrDenoise, imgsrc->getDirPyrDenoiseExpComp(), chaut, nb, redaut, blueaut, maxredaut, maxblueaut, minredaut, minblueaut, chromina, sigma, lumema, sigma_L, redyel, skinc, nsknc);
|
||||
Nb[hcr * 3 + wcr] = nb;
|
||||
ch_M[hcr * 3 + wcr] = chaut;
|
||||
max_r[hcr * 3 + wcr] = maxredaut;
|
||||
@ -996,13 +996,12 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p
|
||||
}
|
||||
}
|
||||
|
||||
int kall = 2;
|
||||
bool wavcontlutili = false;
|
||||
|
||||
CurveFactory::curveWavContL(wavcontlutili, params.wavelet.wavclCurve, wavclCurve,/* hist16C, dummy,*/ 1);
|
||||
|
||||
if((params.wavelet.enabled)) {
|
||||
ipf.ip_wavelet(labView, labView, kall, WaveParams, wavCLVCurve, waOpacityCurveRG, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, wavclCurve, wavcontlutili, 1);
|
||||
if(params.wavelet.enabled) {
|
||||
ipf.ip_wavelet(labView, labView, 2, WaveParams, wavCLVCurve, waOpacityCurveRG, waOpacityCurveBY, waOpacityCurveW, waOpacityCurveWL, wavclCurve, wavcontlutili, 1);
|
||||
}
|
||||
|
||||
wavCLVCurve.Reset();
|
||||
@ -1053,25 +1052,19 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p
|
||||
float CAMMean = NAN;
|
||||
|
||||
if (params.sharpening.enabled) {
|
||||
float d;
|
||||
double dd;
|
||||
|
||||
int sk = 1;
|
||||
|
||||
if(settings->ciecamfloat) {
|
||||
ipf.ciecam_02float (cieView, float(adap), begh, endh, 1, 2, labView, ¶ms, customColCurve1, customColCurve2, customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, 1, true, d, sk, 1);
|
||||
float d;
|
||||
ipf.ciecam_02float (cieView, float(adap), begh, endh, 1, 2, labView, ¶ms, customColCurve1, customColCurve2, customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, 1, true, d, 1, 1);
|
||||
} else {
|
||||
double dd;
|
||||
ipf.ciecam_02 (cieView, adap, begh, endh, 1, 2, labView, ¶ms, customColCurve1, customColCurve2, customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, 1, true, dd, 1, 1);
|
||||
}
|
||||
} else {
|
||||
float d;
|
||||
|
||||
double dd;
|
||||
int sk = 1;
|
||||
|
||||
if(settings->ciecamfloat) {
|
||||
ipf.ciecam_02float (cieView, float(adap), begh, endh, 1, 2, labView, ¶ms, customColCurve1, customColCurve2, customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, 1, true, d, sk, 1);
|
||||
float d;
|
||||
ipf.ciecam_02float (cieView, float(adap), begh, endh, 1, 2, labView, ¶ms, customColCurve1, customColCurve2, customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, 1, true, d, 1, 1);
|
||||
} else {
|
||||
double dd;
|
||||
ipf.ciecam_02 (cieView, adap, begh, endh, 1, 2, labView, ¶ms, customColCurve1, customColCurve2, customColCurve3, dummy, dummy, CAMBrightCurveJ, CAMBrightCurveQ, CAMMean, 5, 1, true, dd, 1, 1);
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ public:
|
||||
}
|
||||
|
||||
char buffer[32];
|
||||
sprintf (buffer, "%.1fs %s", sec / 10., sec & 0x4000 ? ",Custom" : "");
|
||||
sprintf (buffer, "%.1fs %s", sec / 10., (sec & 0x4000) ? ",Custom" : "");
|
||||
return buffer;
|
||||
}
|
||||
};
|
||||
@ -965,7 +965,7 @@ public:
|
||||
std::ostringstream candidates;
|
||||
|
||||
for (r = choices.lower_bound(lensID); r != choices.upper_bound(lensID); r++) {
|
||||
double a1, a2, f1, f2, lensAperture, dif;
|
||||
double a1, a2, f1, f2, dif;
|
||||
|
||||
if( !extractLensInfo( r->second , f1, f2, a1, a2) ) {
|
||||
continue;
|
||||
@ -988,6 +988,7 @@ public:
|
||||
}
|
||||
|
||||
if( maxApertureAtFocal > 0.1) {
|
||||
double lensAperture;
|
||||
if( maxApertureAtFocal < a1 - 0.15 || maxApertureAtFocal > a2 + 0.15) {
|
||||
continue;
|
||||
}
|
||||
|
@ -147,10 +147,10 @@ public:
|
||||
{
|
||||
int a = t->toInt();
|
||||
std::ostringstream str;
|
||||
str << "MF = " << (a & 1 ? "Yes" : "No") << std::endl;
|
||||
str << "D = " << (a & 2 ? "Yes" : "No") << std::endl;
|
||||
str << "G = " << (a & 4 ? "Yes" : "No") << std::endl;
|
||||
str << "VR = " << (a & 8 ? "Yes" : "No");
|
||||
str << "MF = " << ((a & 1) ? "Yes" : "No") << std::endl;
|
||||
str << "D = " << ((a & 2) ? "Yes" : "No") << std::endl;
|
||||
str << "G = " << ((a & 4) ? "Yes" : "No") << std::endl;
|
||||
str << "VR = " << ((a & 8) ? "Yes" : "No");
|
||||
return str.str();
|
||||
}
|
||||
};
|
||||
@ -196,13 +196,13 @@ public:
|
||||
{
|
||||
int a = t->toInt();
|
||||
std::ostringstream str;
|
||||
str << "Continuous = " << (a & 1 ? "Yes" : "No") << std::endl;
|
||||
str << "Delay = " << (a & 2 ? "Yes" : "No") << std::endl;
|
||||
str << "PC Control = " << (a & 4 ? "Yes" : "No") << std::endl;
|
||||
str << "White-Balance Bracketing = " << (a & 8 ? "Yes" : "No") << std::endl;
|
||||
str << "Exposure Bracketing = " << (a & 16 ? "Yes" : "No") << std::endl;
|
||||
str << "Auto ISO = " << (a & 32 ? "Yes" : "No") << std::endl;
|
||||
str << "IR Control = " << (a & 64 ? "Yes" : "No");
|
||||
str << "Continuous = " << ((a & 1) ? "Yes" : "No") << std::endl;
|
||||
str << "Delay = " << ((a & 2) ? "Yes" : "No") << std::endl;
|
||||
str << "PC Control = " << ((a & 4) ? "Yes" : "No") << std::endl;
|
||||
str << "White-Balance Bracketing = " << ((a & 8) ? "Yes" : "No") << std::endl;
|
||||
str << "Exposure Bracketing = " << ((a & 16) ? "Yes" : "No") << std::endl;
|
||||
str << "Auto ISO = " << ((a & 32) ? "Yes" : "No") << std::endl;
|
||||
str << "IR Control = " << ((a & 64) ? "Yes" : "No");
|
||||
return str.str();
|
||||
}
|
||||
};
|
||||
|
@ -1911,12 +1911,12 @@ public:
|
||||
PAAFPointSelectedInterpreter() {}
|
||||
virtual std::string toString (Tag* t)
|
||||
{
|
||||
const char *ps[] = {"Upper-left", "Top", "Upper-right", "Left", "Mid-left", "Center", "Mid-right", "Right", "Lower-left", "Bottom", "Lower-right"};
|
||||
int c = t->toInt(0, SHORT);
|
||||
|
||||
if( !c ) {
|
||||
return "Auto";
|
||||
} else {
|
||||
const char *ps[] = {"Upper-left", "Top", "Upper-right", "Left", "Mid-left", "Center", "Mid-right", "Right", "Lower-left", "Bottom", "Lower-right"};
|
||||
for( int iBit = 0; iBit < 11; iBit++)
|
||||
if( c & (1 << iBit) ) {
|
||||
return ps[iBit];
|
||||
|
@ -207,13 +207,11 @@ void TagDirectory::printAll (unsigned int level) const
|
||||
for (size_t i = 0; i < tags.size(); i++) {
|
||||
std::string name = tags[i]->nameToString ();
|
||||
|
||||
if (tags[i]->isDirectory())
|
||||
if (tags[i]->isDirectory()) {
|
||||
for (int j = 0; tags[i]->getDirectory(j); j++) {
|
||||
printf ("%s+-- DIRECTORY %s[%d]:\n", prefixStr, name.c_str(), j);
|
||||
tags[i]->getDirectory(j)->printAll (level + 1);
|
||||
}
|
||||
else {
|
||||
std::string value = tags[i]->valueToString ();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -696,7 +694,7 @@ void TagDirectory::applyChange (std::string name, std::string value)
|
||||
}
|
||||
|
||||
TagDirectoryTable::TagDirectoryTable ()
|
||||
: zeroOffset(0), valuesSize(0)
|
||||
: values(nullptr), zeroOffset(0), valuesSize(0), defaultType(INVALID)
|
||||
{
|
||||
}
|
||||
|
||||
@ -1269,9 +1267,8 @@ Tag::~Tag ()
|
||||
}
|
||||
|
||||
// if there are directories behind the tag, delete them
|
||||
int i = 0;
|
||||
|
||||
if (directory) {
|
||||
int i = 0;
|
||||
while (directory[i]) {
|
||||
delete directory[i++];
|
||||
}
|
||||
@ -1600,11 +1597,10 @@ std::string Tag::nameToString (int i)
|
||||
std::string Tag::valueToString ()
|
||||
{
|
||||
|
||||
char buffer[1024];
|
||||
|
||||
if (attrib && attrib->interpreter) {
|
||||
return attrib->interpreter->toString (this);
|
||||
} else {
|
||||
char buffer[1024];
|
||||
toString (buffer);
|
||||
return buffer;
|
||||
}
|
||||
@ -2831,7 +2827,6 @@ int ExifManager::createJPEGMarker (const TagDirectory* root, const rtengine::pro
|
||||
sset2 (42, buffer + offs, order);
|
||||
offs += 2;
|
||||
sset4 (8, buffer + offs, order);
|
||||
offs += 4;
|
||||
|
||||
TagDirectory* cl;
|
||||
|
||||
@ -2964,7 +2959,6 @@ int ExifManager::createTIFFHeader (const TagDirectory* root, const rtengine::pro
|
||||
sset2 (42, buffer + offs, order);
|
||||
offs += 2;
|
||||
sset4 (8, buffer + offs, order);
|
||||
offs += 4;
|
||||
|
||||
int endOffs = cl->write (8, buffer);
|
||||
|
||||
|
@ -28,7 +28,9 @@
|
||||
#include <cstdlib>
|
||||
#include <cmath>
|
||||
#include <glibmm.h>
|
||||
|
||||
#include "../rtengine/procparams.h"
|
||||
#include "../rtengine/noncopyable.h"
|
||||
|
||||
class CacheImageData;
|
||||
|
||||
@ -178,7 +180,8 @@ public:
|
||||
};
|
||||
|
||||
// a class representing a single tag
|
||||
class Tag
|
||||
class Tag :
|
||||
public rtengine::NonCopyable
|
||||
{
|
||||
|
||||
protected:
|
||||
@ -202,6 +205,7 @@ public:
|
||||
Tag (TagDirectory* parent, const TagAttrib* attr, unsigned char *data, TagType t);
|
||||
Tag (TagDirectory* parent, const TagAttrib* attr, int data, TagType t); // create a new tag from array (used
|
||||
Tag (TagDirectory* parent, const TagAttrib* attr, const char* data); // create a new tag from array (used
|
||||
|
||||
~Tag ();
|
||||
void initType (unsigned char *data, TagType type);
|
||||
void initInt (int data, TagType t, int count = 1);
|
||||
@ -533,7 +537,7 @@ protected:
|
||||
double deltaMin = 1000.;
|
||||
|
||||
for ( r = choices.lower_bound( lensID ); r != choices.upper_bound(lensID); ++r ) {
|
||||
double lensAperture, dif;
|
||||
double dif;
|
||||
|
||||
if( !extractLensInfo( r->second , f1, f2, a1, a2) ) {
|
||||
continue;
|
||||
@ -548,6 +552,7 @@ protected:
|
||||
}
|
||||
|
||||
if( maxApertureAtFocal > 0.1) {
|
||||
double lensAperture;
|
||||
if( maxApertureAtFocal < a1 - 0.15 || maxApertureAtFocal > a2 + 0.15) {
|
||||
continue;
|
||||
}
|
||||
|
@ -1966,7 +1966,7 @@ public:
|
||||
{
|
||||
// Get the value; Depending on the camera model, this parameter can be a BYTE or a SHORT
|
||||
TagType astype = t->getType();
|
||||
int a;
|
||||
int a = 0;
|
||||
|
||||
if (astype == BYTE) {
|
||||
a = t->getValue()[ofs];
|
||||
@ -1975,7 +1975,7 @@ public:
|
||||
}
|
||||
|
||||
// Decode the value
|
||||
if(a > 0.) {
|
||||
if(a > 0) {
|
||||
return pow(2., 6. - (double(a) / 8.));
|
||||
} else {
|
||||
return 0.;
|
||||
@ -1984,7 +1984,7 @@ public:
|
||||
virtual int toInt (Tag* t, int ofs, TagType astype)
|
||||
{
|
||||
// Get the value; Depending on the camera model, this parameter can be a BYTE or a SHORT
|
||||
int a;
|
||||
int a = 0;
|
||||
|
||||
if (astype == INVALID || astype == AUTO) {
|
||||
astype = t->getType();
|
||||
@ -2026,7 +2026,7 @@ public:
|
||||
{
|
||||
// Get the value; Depending on the camera model, this parameter can be a BYTE or a SHORT
|
||||
TagType astype = t->getType();
|
||||
int a;
|
||||
int a = 0;
|
||||
|
||||
if (astype == BYTE) {
|
||||
a = t->getValue()[ofs];
|
||||
@ -2035,7 +2035,7 @@ public:
|
||||
}
|
||||
|
||||
// Decode the value
|
||||
if(a > 0.) {
|
||||
if(a > 0) {
|
||||
return pow(2., (double(a) / 8. - 1.) / 2.);
|
||||
} else {
|
||||
return 0.;
|
||||
@ -2044,7 +2044,7 @@ public:
|
||||
virtual int toInt (Tag* t, int ofs, TagType astype)
|
||||
{
|
||||
// Get the value; Depending on the camera model, this parameter can be a BYTE or a SHORT
|
||||
int a;
|
||||
int a = 0;
|
||||
|
||||
if (astype == INVALID || astype == AUTO) {
|
||||
astype = t->getType();
|
||||
@ -2085,7 +2085,7 @@ public:
|
||||
virtual int toInt (Tag* t, int ofs, TagType astype)
|
||||
{
|
||||
// Get the value; Depending on the camera model, this parameter can be a BYTE or a SHORT
|
||||
int a;
|
||||
int a = 0;
|
||||
|
||||
if (astype == INVALID || astype == AUTO) {
|
||||
astype = t->getType();
|
||||
@ -2235,7 +2235,7 @@ public:
|
||||
}
|
||||
virtual int toInt (Tag* t, int ofs, TagType astype)
|
||||
{
|
||||
int a;
|
||||
int a = 0;
|
||||
|
||||
if (astype == INVALID || astype == AUTO) {
|
||||
astype = t->getType();
|
||||
|
@ -8,7 +8,7 @@ set (BASESOURCEFILES
|
||||
coarsepanel.cc cacorrection.cc chmixer.cc blackwhite.cc
|
||||
resize.cc icmpanel.cc crop.cc shadowshighlights.cc
|
||||
impulsedenoise.cc dirpyrdenoise.cc epd.cc
|
||||
exifpanel.cc toolpanel.cc lensprofile.cc
|
||||
exifpanel.cc toolpanel.cc lensprofile.cc lockablecolorpicker.cc
|
||||
sharpening.cc vibrance.cc rgbcurves.cc colortoning.cc
|
||||
whitebalance.cc vignetting.cc gradient.cc pcvignette.cc rotate.cc distortion.cc
|
||||
crophandler.cc dirbrowser.cc
|
||||
|
@ -35,7 +35,6 @@ static double one2one(double val)
|
||||
Adjuster::Adjuster (Glib::ustring vlabel, double vmin, double vmax, double vstep, double vdefault, Gtk::Image *imgIcon1, Gtk::Image *imgIcon2, double2double_fun slider2value_, double2double_fun value2slider_)
|
||||
{
|
||||
|
||||
Gtk::HBox *hbox2 = NULL;
|
||||
label = NULL;
|
||||
adjusterListener = NULL;
|
||||
afterReset = false;
|
||||
@ -107,6 +106,8 @@ Adjuster::Adjuster (Glib::ustring vlabel, double vmin, double vmax, double vstep
|
||||
if (!imgIcon1 || !imgIcon2) {
|
||||
pack_start (*slider, true, true);
|
||||
} else {
|
||||
Gtk::HBox *hbox2 = NULL;
|
||||
|
||||
// A second HBox is necessary
|
||||
hbox2 = Gtk::manage (new Gtk::HBox());
|
||||
|
||||
|
@ -68,7 +68,7 @@ protected:
|
||||
void notifyListener (bool queueEmptied);
|
||||
|
||||
public:
|
||||
BatchQueue (FileCatalog* aFileCatalog);
|
||||
explicit BatchQueue (FileCatalog* aFileCatalog);
|
||||
~BatchQueue ();
|
||||
|
||||
void addEntries (const std::vector<BatchQueueEntry*>& entries, bool head = false, bool save = true);
|
||||
|
@ -33,7 +33,7 @@ public:
|
||||
static Cairo::RefPtr<Cairo::ImageSurface> headIcon;
|
||||
static Cairo::RefPtr<Cairo::ImageSurface> tailIcon;
|
||||
|
||||
BatchQueueButtonSet (BatchQueueEntry* myEntry);
|
||||
explicit BatchQueueButtonSet (BatchQueueEntry* myEntry);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -24,10 +24,6 @@
|
||||
#include "soundman.h"
|
||||
#include "rtimage.h"
|
||||
|
||||
struct BQProcessLoaded {
|
||||
BatchQueue* bq;
|
||||
};
|
||||
|
||||
int processLoadedBatchQueueUIThread (void* data)
|
||||
{
|
||||
|
||||
|
@ -55,7 +55,7 @@ class BatchQueuePanel : public Gtk::VBox,
|
||||
|
||||
public:
|
||||
|
||||
BatchQueuePanel (FileCatalog* aFileCatalog);
|
||||
explicit BatchQueuePanel (FileCatalog* aFileCatalog);
|
||||
|
||||
void setParent (RTWindow* p)
|
||||
{
|
||||
|
@ -42,6 +42,10 @@ BatchToolPanelCoordinator::BatchToolPanelCoordinator (FilePanel* parent) : ToolP
|
||||
toolPanels.erase (ipi);
|
||||
}
|
||||
|
||||
if (toolBar) {
|
||||
toolBar->setBatchMode ();
|
||||
}
|
||||
|
||||
toolPanelNotebook->remove_page (*metadataPanel);
|
||||
metadataPanel = 0;
|
||||
toiM = 0;
|
||||
|
@ -48,7 +48,7 @@ protected:
|
||||
|
||||
public:
|
||||
|
||||
BatchToolPanelCoordinator (FilePanel* parent);
|
||||
explicit BatchToolPanelCoordinator (FilePanel* parent);
|
||||
|
||||
// FileSelectionChangeListener interface
|
||||
void selectionChanged (const std::vector<Thumbnail*>& selected);
|
||||
|
@ -21,7 +21,8 @@
|
||||
BrowserFilter::BrowserFilter () : exifFilterEnabled (false),
|
||||
showTrash (true),
|
||||
showNotTrash (true),
|
||||
showOriginal (false)
|
||||
showOriginal (false),
|
||||
multiselect (false)
|
||||
{
|
||||
for (int i = 0; i < 6; i++) {
|
||||
showRanked[i] = true;
|
||||
|
@ -24,7 +24,9 @@
|
||||
|
||||
CacheImageData::CacheImageData ()
|
||||
: md5(""), supported(false), format(FT_Invalid), rankOld(-1), inTrashOld(false), recentlySaved(false),
|
||||
timeValid(false), exifValid(false), redAWBMul(-1.0), greenAWBMul(-1.0), blueAWBMul(-1.0), thumbImgType(0)
|
||||
timeValid(false), year(0), month(0), day(0), hour(0), min(0), sec(0), exifValid(false),
|
||||
fnumber(0.0), shutter(0.0), focalLen(0.0), focalLen35mm(0.0), focusDist(0.f), iso(0),
|
||||
redAWBMul(-1.0), greenAWBMul(-1.0), blueAWBMul(-1.0), rotate(0), thumbImgType(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -24,11 +24,14 @@
|
||||
|
||||
#include <glibmm/ustring.h>
|
||||
|
||||
#include "../rtengine/noncopyable.h"
|
||||
|
||||
#include "threadutils.h"
|
||||
|
||||
class Thumbnail;
|
||||
|
||||
class CacheManager
|
||||
class CacheManager :
|
||||
public rtengine::NonCopyable
|
||||
{
|
||||
private:
|
||||
using Entries = std::map<std::string, Thumbnail*>;
|
||||
@ -41,12 +44,7 @@ private:
|
||||
|
||||
void applyCacheSizeLimitation () const;
|
||||
|
||||
CacheManager () = default;
|
||||
CacheManager (const CacheManager&) = delete;
|
||||
CacheManager& operator= (const CacheManager&) = delete;
|
||||
|
||||
public:
|
||||
|
||||
static CacheManager* getInstance ();
|
||||
|
||||
void init ();
|
||||
@ -69,7 +67,6 @@ public:
|
||||
const Glib::ustring& fname,
|
||||
const Glib::ustring& fext,
|
||||
const Glib::ustring& md5) const;
|
||||
|
||||
};
|
||||
|
||||
#define cacheMgr CacheManager::getInstance()
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
Clipboard clipboard;
|
||||
|
||||
Clipboard::Clipboard () : partProfile (false) {}
|
||||
Clipboard::Clipboard () : partProfile (false), _hasIPTC(false), hasDiagonalCurveDataType(DCT_Empty), hasFlatCurveDataType(FCT_Empty) {}
|
||||
|
||||
Clipboard::~Clipboard ()
|
||||
{
|
||||
|
@ -37,7 +37,7 @@ protected:
|
||||
std::vector<GradientMilestone> bgGradient;
|
||||
|
||||
public:
|
||||
ColoredBar (eRTOrientation orient);
|
||||
explicit ColoredBar (eRTOrientation orient);
|
||||
|
||||
void expose(Glib::RefPtr<Gdk::Window> destWindow);
|
||||
void expose(Cairo::RefPtr<Cairo::ImageSurface> destSurface);
|
||||
|
@ -124,9 +124,8 @@ void CoordinateAdjuster::createWidgets(const std::vector<Axis> &axis)
|
||||
|
||||
set_spacing(3);
|
||||
|
||||
AxisAdjuster *currAdjuster = NULL;
|
||||
|
||||
for (unsigned int i = 0; i < count; ++i) {
|
||||
AxisAdjuster *currAdjuster = NULL;
|
||||
const Axis *currAxis = &(axis.at(i));
|
||||
axisAdjusters.at(i) = new AxisAdjuster(this, currAxis, i);
|
||||
currAdjuster = axisAdjusters.at(i);
|
||||
|
@ -1,223 +0,0 @@
|
||||
/*
|
||||
* This file is part of RawTherapee.
|
||||
*
|
||||
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <png.h>
|
||||
|
||||
void png_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
|
||||
{
|
||||
png_size_t check;
|
||||
|
||||
/* fread() returns 0 on error, so it is OK to store this in a png_size_t
|
||||
* instead of an int, which is what fread() actually returns.
|
||||
*/
|
||||
check = (png_size_t)fread(data, (png_size_t)1, length, (FILE *)png_ptr->io_ptr);
|
||||
|
||||
if (check != length) {
|
||||
png_error(png_ptr, "Read Error");
|
||||
}
|
||||
}
|
||||
|
||||
void png_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
|
||||
{
|
||||
png_uint_32 check;
|
||||
|
||||
check = fwrite(data, 1, length, (FILE *)(png_ptr->io_ptr));
|
||||
|
||||
if (check != length) {
|
||||
png_error(png_ptr, "Write Error");
|
||||
}
|
||||
}
|
||||
|
||||
void png_flush(png_structp png_ptr)
|
||||
{
|
||||
FILE *io_ptr;
|
||||
io_ptr = (FILE *)CVT_PTR((png_ptr->io_ptr));
|
||||
|
||||
if (io_ptr != NULL) {
|
||||
fflush(io_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned char* loadPNG (char* fname, int& w, int& h)
|
||||
{
|
||||
|
||||
FILE *file = fopen (fname, "rb");
|
||||
|
||||
unsigned char header[8];
|
||||
fread (header, 1, 8, file);
|
||||
|
||||
png_structp png = png_create_read_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0);
|
||||
png_infop info = png_create_info_struct (png);
|
||||
png_infop end_info = png_create_info_struct (png);
|
||||
|
||||
if (setjmp (png_jmpbuf(png))) {
|
||||
png_destroy_read_struct (&png, &info, &end_info);
|
||||
fclose (file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//set up png read
|
||||
png_set_read_fn (png, file, png_read_data);
|
||||
png_set_sig_bytes (png, 8);
|
||||
|
||||
png_read_info(png, info);
|
||||
|
||||
unsigned long width, height;
|
||||
int bit_depth, color_type, interlace_type, compression_type, filter_method;
|
||||
png_get_IHDR(png, info, &width, &height, &bit_depth, &color_type, &interlace_type,
|
||||
&compression_type, &filter_method);
|
||||
|
||||
//converting to 32bpp format
|
||||
if (color_type == PNG_COLOR_TYPE_PALETTE) {
|
||||
png_set_palette_to_rgb(png);
|
||||
}
|
||||
|
||||
if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
|
||||
png_set_gray_to_rgb(png);
|
||||
}
|
||||
|
||||
if (png_get_valid(png, info, PNG_INFO_tRNS)) {
|
||||
png_set_tRNS_to_alpha(png);
|
||||
}
|
||||
|
||||
if (interlace_type != PNG_INTERLACE_NONE) {
|
||||
png_destroy_read_struct (&png, &info, &end_info);
|
||||
fclose (file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (color_type & PNG_COLOR_MASK_ALPHA) {
|
||||
png_set_strip_alpha(png);
|
||||
}
|
||||
|
||||
//setting gamma
|
||||
double gamma;
|
||||
|
||||
if (png_get_gAMA(png, info, &gamma)) {
|
||||
png_set_gamma(png, 2.0, gamma);
|
||||
} else {
|
||||
png_set_gamma(png, 2.0, 0.45455);
|
||||
}
|
||||
|
||||
int bps = 8;
|
||||
|
||||
//updating png info struct
|
||||
png_read_update_info(png, info);
|
||||
png_get_IHDR(png, info, &width, &height, &bit_depth, &color_type, &interlace_type,
|
||||
&compression_type, &filter_method);
|
||||
|
||||
if (color_type & PNG_COLOR_MASK_ALPHA) {
|
||||
png_set_strip_alpha(png);
|
||||
}
|
||||
|
||||
png_read_update_info(png, info);
|
||||
png_get_IHDR(png, info, &width, &height, &bit_depth, &color_type, &interlace_type,
|
||||
&compression_type, &filter_method);
|
||||
|
||||
|
||||
unsigned char* data = new unsigned char[width * height * 3];
|
||||
int rowlen = width * 3;
|
||||
unsigned char *row = new unsigned char [rowlen];
|
||||
|
||||
for (unsigned int i = 0; i < height; i++) {
|
||||
|
||||
png_read_row (png, (png_byte*)row, NULL);
|
||||
memcpy (data + 3 * i * width, row, 3 * width);
|
||||
}
|
||||
|
||||
png_read_end (png, 0);
|
||||
png_destroy_read_struct (&png, &info, &end_info);
|
||||
|
||||
delete [] row;
|
||||
fclose(file);
|
||||
|
||||
w = width;
|
||||
h = height;
|
||||
return data;
|
||||
}
|
||||
|
||||
void savePNG (char* fname, unsigned char* data1, unsigned char* data2, int w, int h)
|
||||
{
|
||||
|
||||
FILE* file = fopen(fname, "wb");
|
||||
|
||||
png_structp png = png_create_write_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0);
|
||||
png_infop info = png_create_info_struct(png);
|
||||
|
||||
if (setjmp(png_jmpbuf(png))) {
|
||||
png_destroy_write_struct (&png, &info);
|
||||
fclose(file);
|
||||
return;
|
||||
}
|
||||
|
||||
png_set_write_fn (png, file, png_write_data, png_flush);
|
||||
png_set_compression_level(png, 6);
|
||||
|
||||
int width = w;
|
||||
int height = h;
|
||||
int bps = 8;
|
||||
|
||||
png_set_IHDR(png, info, width, height, bps, PNG_COLOR_TYPE_RGB_ALPHA,
|
||||
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_BASE);
|
||||
|
||||
|
||||
int rowlen = width * 4;
|
||||
unsigned char *row = new unsigned char [rowlen];
|
||||
|
||||
png_write_info(png, info);
|
||||
|
||||
for (unsigned int i = 0; i < height; i++) {
|
||||
for (int j = 0; j < width; j++) {
|
||||
int ofs = 3 * (width * i + j);
|
||||
unsigned char alpha = data2[ofs] - data1[ofs];
|
||||
|
||||
if (i == 8 && j == 8) {
|
||||
printf ("alpha=%d pix=%d\n", (int)alpha, (int)(data1[ofs + 0] / (1.0 - alpha / 255.0)));
|
||||
}
|
||||
|
||||
if (alpha < 255) {
|
||||
row[4 * j + 0] = data1[ofs + 0] / (1.0 - alpha / 255.0);
|
||||
row[4 * j + 1] = data1[ofs + 1] / (1.0 - alpha / 255.0);
|
||||
row[4 * j + 2] = data1[ofs + 2] / (1.0 - alpha / 255.0);
|
||||
} else {
|
||||
|
||||
}
|
||||
|
||||
row[4 * j + 3] = 255 - alpha;
|
||||
}
|
||||
|
||||
png_write_row (png, (png_byte*)row);
|
||||
}
|
||||
|
||||
png_write_end(png, info);
|
||||
png_destroy_write_struct(&png, &info);
|
||||
|
||||
delete [] row;
|
||||
fclose (file);
|
||||
}
|
||||
|
||||
int main (int argc, char* argv[])
|
||||
{
|
||||
|
||||
int w, h;
|
||||
unsigned char* data1 = loadPNG (argv[1], w, h);
|
||||
unsigned char* data2 = loadPNG (argv[2], w, h);
|
||||
savePNG (argv[3], data1, data2, w, h);
|
||||
|
||||
}
|
@ -22,6 +22,7 @@
|
||||
#include <cstring>
|
||||
#include "guiutils.h"
|
||||
#include "cropwindow.h"
|
||||
#include "imagearea.h"
|
||||
#include "../rtengine/dcrop.h"
|
||||
#include "../rtengine/refreshmap.h"
|
||||
#include "../rtengine/rt_math.h"
|
||||
@ -32,6 +33,7 @@ CropHandler::CropHandler ()
|
||||
: zoom(10), ww(0), wh(0), imx(-1), imy(-1), imw(0), imh(0), cax(-1), cay(-1),
|
||||
cx(0), cy(0), cw(0), ch(0), cropX(0), cropY(0), cropW(0), cropH(0), enabled(false),
|
||||
cropimg(NULL), cropimgtrue(NULL), cropimg_width(0), cropimg_height(0),
|
||||
cix(0), ciy(0), ciw(0), cih(0), cis(1),
|
||||
initial(false), isLowUpdatePriority(false), ipc(NULL), crop(NULL),
|
||||
displayHandler(NULL)
|
||||
{
|
||||
@ -188,6 +190,15 @@ void CropHandler::setZoom (int z, int centerx, int centery)
|
||||
}
|
||||
}
|
||||
|
||||
float CropHandler::getZoomFactor ()
|
||||
{
|
||||
if (zoom >= 1000) {
|
||||
return zoom / 1000;
|
||||
} else {
|
||||
return 1.f / (float)zoom;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CropHandler::setWSize (int w, int h)
|
||||
{
|
||||
@ -465,6 +476,95 @@ bool CropHandler::getEnabled ()
|
||||
return enabled;
|
||||
}
|
||||
|
||||
void CropHandler::colorPick (const rtengine::Coord &pickerPos, float &r, float &g, float &b, float &rpreview, float &gpreview, float &bpreview, LockableColorPicker::Size size)
|
||||
{
|
||||
|
||||
if (!cropPixbuf || !cropPixbuftrue) {
|
||||
r = g = b = 0.f;
|
||||
rpreview = gpreview = bpreview = 0.f;
|
||||
return;
|
||||
}
|
||||
|
||||
int xSize = (int)size;
|
||||
int ySize = (int)size;
|
||||
int pixbufW = cropPixbuftrue->get_width();
|
||||
int pixbufH = cropPixbuftrue->get_height();
|
||||
rtengine::Coord topLeftPos(pickerPos.x - xSize/2, pickerPos.y - ySize/2);
|
||||
|
||||
if (topLeftPos.x > pixbufW || topLeftPos.y > pixbufH || topLeftPos.x + xSize < 0 || topLeftPos.y + ySize < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Store the position of the center of the picker
|
||||
int radius = (int)size / 2;
|
||||
|
||||
// X/Width clip
|
||||
if (topLeftPos.x < 0) {
|
||||
xSize += topLeftPos.x;
|
||||
topLeftPos.x = 0;
|
||||
}
|
||||
if (topLeftPos.x + xSize > pixbufW) {
|
||||
xSize = pixbufW - topLeftPos.x;
|
||||
}
|
||||
// Y/Height clip
|
||||
if (topLeftPos.y < 0) {
|
||||
ySize += topLeftPos.y;
|
||||
topLeftPos.y = 0;
|
||||
}
|
||||
if (topLeftPos.y + ySize > pixbufH) {
|
||||
ySize = pixbufH - topLeftPos.y;
|
||||
}
|
||||
|
||||
// Accumulating the data
|
||||
std::uint32_t r2=0, g2=0, b2=0;
|
||||
std::uint32_t count = 0;
|
||||
const guint8* data = cropPixbuftrue->get_pixels();
|
||||
for (int j = topLeftPos.y ; j < topLeftPos.y + ySize ; ++j) {
|
||||
const guint8* data2 = data + cropPixbuftrue->get_rowstride()*j;
|
||||
for (int i = topLeftPos.x ; i < topLeftPos.x + xSize ; ++i) {
|
||||
const guint8* data3 = data2 + i*3;
|
||||
rtengine::Coord currPos(i, j);
|
||||
rtengine::Coord delta = pickerPos - currPos;
|
||||
rtengine::PolarCoord p(delta);
|
||||
if (p.radius <= radius) {
|
||||
r2 += *data3;
|
||||
g2 += *(data3+1);
|
||||
b2 += *(data3+2);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Averaging
|
||||
r = (float)r2 / (float)count / 255.f;
|
||||
g = (float)g2 / (float)count / 255.f;
|
||||
b = (float)b2 / (float)count / 255.f;
|
||||
|
||||
// Accumulating the data
|
||||
r2=0, g2=0, b2=0;
|
||||
count = 0;
|
||||
data = cropPixbuf->get_pixels();
|
||||
for (int j = topLeftPos.y ; j < topLeftPos.y + ySize ; ++j) {
|
||||
const guint8* data2 = data + cropPixbuf->get_rowstride()*j;
|
||||
for (int i = topLeftPos.x ; i < topLeftPos.x + xSize ; ++i) {
|
||||
const guint8* data3 = data2 + i*3;
|
||||
rtengine::Coord currPos(i, j);
|
||||
rtengine::Coord delta = pickerPos - currPos;
|
||||
rtengine::PolarCoord p(delta);
|
||||
if (p.radius <= radius) {
|
||||
r2 += *data3;
|
||||
g2 += *(data3+1);
|
||||
b2 += *(data3+2);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Averaging
|
||||
rpreview = (float)r2 / (float)count / 255.f;
|
||||
gpreview = (float)g2 / (float)count / 255.f;
|
||||
bpreview = (float)b2 / (float)count / 255.f;
|
||||
}
|
||||
|
||||
void CropHandler::getSize (int& w, int& h)
|
||||
{
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "../rtengine/rtengine.h"
|
||||
#include "threadutils.h"
|
||||
#include "edit.h"
|
||||
#include "lockablecolorpicker.h"
|
||||
#include <gtkmm.h>
|
||||
|
||||
class CropDisplayHandler
|
||||
@ -94,23 +95,26 @@ public:
|
||||
}
|
||||
void setEditSubscriber (EditSubscriber* newSubscriber);
|
||||
|
||||
void newImage (rtengine::StagedImageProcessor* ipc_, bool isDetailWindow);
|
||||
void setZoom (int z, int centerx = -1, int centery = -1);
|
||||
double getFitZoom ();
|
||||
void newImage (rtengine::StagedImageProcessor* ipc_, bool isDetailWindow);
|
||||
void setZoom (int z, int centerx = -1, int centery = -1);
|
||||
float getZoomFactor ();
|
||||
double getFitZoom ();
|
||||
double getFitCropZoom();
|
||||
void setWSize (int w, int h);
|
||||
void getWSize (int& w, int &h);
|
||||
void setWSize (int w, int h);
|
||||
void getWSize (int& w, int &h);
|
||||
void getAnchorPosition (int& x, int& y);
|
||||
void setAnchorPosition (int x, int y, bool update = true);
|
||||
void moveAnchor (int deltaX, int deltaY, bool update = true);
|
||||
void centerAnchor (bool update = true);
|
||||
void getPosition (int& x, int& y);
|
||||
void getSize (int& w, int& h);
|
||||
void moveAnchor (int deltaX, int deltaY, bool update = true);
|
||||
void centerAnchor (bool update = true);
|
||||
void getPosition (int& x, int& y);
|
||||
void getSize (int& w, int& h);
|
||||
void getFullImageSize (int& w, int& h);
|
||||
|
||||
void setEnabled (bool e);
|
||||
bool getEnabled ();
|
||||
|
||||
void colorPick (const rtengine::Coord &pickerPos, float &r, float &g, float &b, float &rpreview, float &gpreview, float &bpreview, LockableColorPicker::Size size);
|
||||
|
||||
rtengine::DetailedCrop* getCrop()
|
||||
{
|
||||
return crop;
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "cursormanager.h"
|
||||
#include "options.h"
|
||||
#include "imagearea.h"
|
||||
#include "lockablecolorpicker.h"
|
||||
|
||||
using namespace rtengine;
|
||||
|
||||
@ -65,13 +66,13 @@ ZoomStep zoomSteps[] = {
|
||||
#define MAXZOOMSTEPS 20
|
||||
#define ZOOM11INDEX 13
|
||||
|
||||
CropWindow::CropWindow (ImageArea* parent, rtengine::StagedImageProcessor* ipc_, bool isLowUpdatePriority_, bool isDetailWindow)
|
||||
CropWindow::CropWindow (ImageArea* parent, bool isLowUpdatePriority_, bool isDetailWindow)
|
||||
: ObjectMOBuffer(parent), state(SNormal), press_x(0), press_y(0), action_x(0), action_y(0), pickedObject(-1), pickModifierKey(0), rot_deg(0), onResizeArea(false), deleted(false),
|
||||
fitZoomEnabled(true), fitZoom(false), isLowUpdatePriority(isLowUpdatePriority_), cropLabel(Glib::ustring("100%")),
|
||||
fitZoomEnabled(true), fitZoom(false), isLowUpdatePriority(isLowUpdatePriority_), hoveredPicker(nullptr), cropLabel(Glib::ustring("100%")),
|
||||
backColor(options.bgcolor), decorated(true), isFlawnOver(false), titleHeight(30), sideBorderWidth(3), lowerBorderWidth(3),
|
||||
upperBorderWidth(1), sepWidth(2), xpos(30), ypos(30), width(0), height(0), imgAreaX(0), imgAreaY(0), imgAreaW(0), imgAreaH(0),
|
||||
imgX(-1), imgY(-1), imgW(1), imgH(1), iarea(parent), cropZoom(0), zoomVersion(0), exposeVersion(0), cropgl(NULL),
|
||||
pmlistener(NULL), pmhlistener(NULL), observedCropWin(NULL), ipc(ipc_)
|
||||
pmlistener(NULL), pmhlistener(NULL), observedCropWin(NULL)
|
||||
{
|
||||
Glib::RefPtr<Pango::Context> context = parent->get_pango_context () ;
|
||||
Pango::FontDescription fontd = context->get_font_description ();
|
||||
@ -109,7 +110,14 @@ CropWindow::CropWindow (ImageArea* parent, rtengine::StagedImageProcessor* ipc_,
|
||||
minWidth = bsw + iw + 2 * sideBorderWidth;
|
||||
|
||||
cropHandler.setDisplayHandler(this);
|
||||
cropHandler.newImage (ipc_, isDetailWindow);
|
||||
cropHandler.newImage (parent->getImProcCoordinator(), isDetailWindow);
|
||||
}
|
||||
|
||||
CropWindow::~CropWindow ()
|
||||
{
|
||||
for (auto colorPicker : colorPickers) {
|
||||
delete colorPicker;
|
||||
}
|
||||
}
|
||||
|
||||
void CropWindow::enable()
|
||||
@ -265,6 +273,34 @@ void CropWindow::flawnOver (bool isFlawnOver)
|
||||
this->isFlawnOver = isFlawnOver;
|
||||
}
|
||||
|
||||
void CropWindow::scroll (int state, GdkScrollDirection direction, int x, int y)
|
||||
{
|
||||
if ((state & GDK_CONTROL_MASK) && onArea(ColorPicker, x, y)) {
|
||||
// resizing a color picker
|
||||
if (direction == GDK_SCROLL_UP) {
|
||||
hoveredPicker->incSize();
|
||||
updateHoveredPicker();
|
||||
iarea->redraw ();
|
||||
}else if (direction == GDK_SCROLL_DOWN) {
|
||||
hoveredPicker->decSize();
|
||||
updateHoveredPicker();
|
||||
iarea->redraw ();
|
||||
}
|
||||
} else {
|
||||
// not over a color picker, we zoom in/out
|
||||
int newCenterX = x;
|
||||
int newCenterY = y;
|
||||
|
||||
screenCoordToImage(newCenterX, newCenterY, newCenterX, newCenterY);
|
||||
|
||||
if (direction == GDK_SCROLL_UP && !isMaxZoom()) {
|
||||
zoomIn (true, newCenterX, newCenterY);
|
||||
} else if (!isMinZoom()) {
|
||||
zoomOut (true, newCenterX, newCenterY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CropWindow::buttonPress (int button, int type, int bstate, int x, int y)
|
||||
{
|
||||
|
||||
@ -274,7 +310,7 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y)
|
||||
iarea->grabFocus (this);
|
||||
|
||||
if (button == 1) {
|
||||
if (type == GDK_2BUTTON_PRESS && onArea (CropImage, x, y) && (state == SNormal || state == SCropImgMove)) {
|
||||
if (type == GDK_2BUTTON_PRESS && onArea (CropImage, x, y) && iarea->getToolMode () != TMColorPicker && (state == SNormal || state == SCropImgMove)) {
|
||||
if (fitZoomEnabled) {
|
||||
if (fitZoom) {
|
||||
state = SNormal;
|
||||
@ -308,7 +344,35 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y)
|
||||
press_y = height;
|
||||
} else {
|
||||
if (onArea (CropImage, x, y)) { // events inside of the image domain
|
||||
if (onArea (CropTopLeft, x, y)) {
|
||||
if (iarea->getToolMode () == TMColorPicker) {
|
||||
if (hoveredPicker) {
|
||||
if ((bstate & GDK_CONTROL_MASK) && !(bstate & GDK_SHIFT_MASK)) {
|
||||
hoveredPicker->decSize();
|
||||
updateHoveredPicker();
|
||||
needRedraw = true;
|
||||
} else if (!(bstate & GDK_CONTROL_MASK) && (bstate & GDK_SHIFT_MASK)) {
|
||||
hoveredPicker->rollDisplayedValues();
|
||||
needRedraw = true;
|
||||
} else if (!(bstate & GDK_CONTROL_MASK) && !(bstate & GDK_SHIFT_MASK)) {
|
||||
// Color Picker drag starts
|
||||
state = SDragPicker;
|
||||
}
|
||||
} else {
|
||||
// Add a new Color Picker
|
||||
rtengine::Coord imgPos;
|
||||
screenCoordToImage(x, y, imgPos.x, imgPos.y);
|
||||
LockableColorPicker *newPicker = new LockableColorPicker(this, &cropHandler.colorParams.output, &cropHandler.colorParams.working);
|
||||
colorPickers.push_back(newPicker);
|
||||
hoveredPicker = newPicker;
|
||||
updateHoveredPicker(&imgPos);
|
||||
state = SDragPicker;
|
||||
press_x = x;
|
||||
press_y = y;
|
||||
action_x = 0;
|
||||
action_y = 0;
|
||||
needRedraw = true;
|
||||
}
|
||||
} else if (onArea (CropTopLeft, x, y)) {
|
||||
state = SResizeTL;
|
||||
press_x = x;
|
||||
action_x = cropHandler.cropParams.x;
|
||||
@ -430,6 +494,18 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y)
|
||||
action_x = 0;
|
||||
action_y = 0;
|
||||
}
|
||||
} else if (iarea->getToolMode () == TMColorPicker && hoveredPicker) {
|
||||
if ((bstate & GDK_CONTROL_MASK) && !(bstate & GDK_SHIFT_MASK)) {
|
||||
if (hoveredPicker->decSize()) {
|
||||
updateHoveredPicker();
|
||||
needRedraw = true;
|
||||
}
|
||||
} else if (!(bstate & GDK_CONTROL_MASK) && (bstate & GDK_SHIFT_MASK)) {
|
||||
hoveredPicker->rollDisplayedValues();
|
||||
} else if (!(bstate & GDK_CONTROL_MASK) && !(bstate & GDK_SHIFT_MASK)) {
|
||||
// Color Picker drag starts
|
||||
state = SDragPicker;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -473,6 +549,37 @@ void CropWindow::buttonPress (int button, int type, int bstate, int x, int y)
|
||||
action_y = 0;
|
||||
}
|
||||
}
|
||||
else if (iarea->getToolMode () == TMColorPicker && type == GDK_BUTTON_PRESS && state == SNormal) {
|
||||
if (hoveredPicker) {
|
||||
if((bstate & GDK_CONTROL_MASK) && (bstate & GDK_SHIFT_MASK)) {
|
||||
// Deleting all pickers !
|
||||
for (auto colorPicker : colorPickers) {
|
||||
delete colorPicker;
|
||||
}
|
||||
colorPickers.clear();
|
||||
hoveredPicker = nullptr;
|
||||
state = SDeletePicker;
|
||||
needRedraw = true;
|
||||
} else if ((bstate & GDK_CONTROL_MASK) && !(bstate & GDK_SHIFT_MASK)) {
|
||||
if (hoveredPicker->incSize()) {
|
||||
updateHoveredPicker();
|
||||
needRedraw = true;
|
||||
}
|
||||
} else if (!(bstate & GDK_CONTROL_MASK) && !(bstate & GDK_SHIFT_MASK)) {
|
||||
// Deleting the hovered picker
|
||||
for (std::vector<LockableColorPicker*>::iterator i = colorPickers.begin(); i != colorPickers.end(); ++i) {
|
||||
if (*i == hoveredPicker) {
|
||||
colorPickers.erase(i);
|
||||
delete hoveredPicker;
|
||||
hoveredPicker = nullptr;
|
||||
state = SDeletePicker;
|
||||
needRedraw = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (needRedraw) {
|
||||
@ -506,6 +613,10 @@ void CropWindow::buttonRelease (int button, int num, int bstate, int x, int y)
|
||||
}
|
||||
|
||||
needRedraw = true;
|
||||
} else if (state == SCropWinMove) {
|
||||
if (iarea->showColorPickers () && !colorPickers.empty()) {
|
||||
needRedraw = true;
|
||||
}
|
||||
} else if (state == SCropImgMove) {
|
||||
cropHandler.update ();
|
||||
|
||||
@ -602,6 +713,10 @@ void CropWindow::buttonRelease (int button, int num, int bstate, int x, int y)
|
||||
} else {
|
||||
iarea->object = 0;
|
||||
}
|
||||
} else if (state == SDeletePicker) {
|
||||
needRedraw = true;
|
||||
} else if (state == SNormal && iarea->getToolMode() == TMColorPicker && !hoveredPicker && button == 3) {
|
||||
iarea->setToolHand ();
|
||||
}
|
||||
|
||||
if (cropgl && (state == SCropSelecting || state == SResizeH1 || state == SResizeH2 || state == SResizeW1 || state == SResizeW2 || state == SResizeTL || state == SResizeTR || state == SResizeBL || state == SResizeBR || state == SCropMove)) {
|
||||
@ -620,7 +735,7 @@ void CropWindow::buttonRelease (int button, int num, int bstate, int x, int y)
|
||||
return;
|
||||
}
|
||||
|
||||
if (state != SEditDrag3 && state != SEditPick3 && button == 3 && !(bstate & (GDK_SHIFT_MASK|GDK_CONTROL_MASK))) {
|
||||
if (state != SDeletePicker && state != SEditDrag3 && state != SEditPick3 && button == 3 && !(bstate & (GDK_SHIFT_MASK|GDK_CONTROL_MASK))) {
|
||||
iarea->pipetteVal[0] = iarea->pipetteVal[1] = iarea->pipetteVal[2] = -1.f;
|
||||
|
||||
needRedraw = iarea->object == 1;
|
||||
@ -778,6 +893,26 @@ void CropWindow::pointerMoved (int bstate, int x, int y)
|
||||
action_x = new_action_x;
|
||||
action_y = new_action_y;
|
||||
iarea->redraw ();
|
||||
} else if (state == SDragPicker) {
|
||||
Coord imgPos;
|
||||
action_x = x - press_x;
|
||||
action_x = y - press_y;
|
||||
screenCoordToImage (x, y, imgPos.x, imgPos.y);
|
||||
if (imgPos.x < 0) {
|
||||
imgPos.x = 0;
|
||||
}else if (imgPos.x >= iarea->getImProcCoordinator()->getFullWidth()) {
|
||||
imgPos.x = iarea->getImProcCoordinator()->getFullWidth()-1;
|
||||
}
|
||||
if (imgPos.y < 0) {
|
||||
imgPos.y = 0;
|
||||
}else if (imgPos.y >= iarea->getImProcCoordinator()->getFullHeight()) {
|
||||
imgPos.y = iarea->getImProcCoordinator()->getFullHeight()-1;
|
||||
}
|
||||
updateHoveredPicker (&imgPos);
|
||||
iarea->redraw ();
|
||||
} else if (state == SNormal && iarea->getToolMode () == TMColorPicker && onArea(ColorPicker, x, y)) {
|
||||
// TODO: we could set the hovered picker as Highlighted here
|
||||
// Keep this if statement, the onArea will find out the hoveredPicker and will be used to update the cursor
|
||||
} else if (editSubscriber) {
|
||||
rtengine::Crop* crop = static_cast<rtengine::Crop*>(cropHandler.getCrop());
|
||||
|
||||
@ -931,6 +1066,16 @@ bool CropWindow::onArea (CursorArea a, int x, int y)
|
||||
case CropImage:
|
||||
return x >= xpos + imgX + imgAreaX && y >= ypos + imgY + imgAreaY && x < xpos + imgX + imgAreaX + imgW && y < ypos + imgY + imgAreaY + imgH;
|
||||
|
||||
case ColorPicker:
|
||||
for (auto colorPicker : colorPickers) {
|
||||
if (colorPicker->isOver(x, y)) {
|
||||
hoveredPicker = colorPicker;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
hoveredPicker = nullptr;
|
||||
return false;
|
||||
|
||||
case CropBorder:
|
||||
return
|
||||
(x >= xpos + imgAreaX && y >= ypos + imgAreaY && x < xpos + imgAreaX + imgAreaW && y < ypos + imgAreaY + imgAreaH) &&
|
||||
@ -1048,6 +1193,8 @@ void CropWindow::updateCursor (int x, int y)
|
||||
cursorManager.setCursor (iarea->get_window(), CSMove);
|
||||
} else if (onArea (CropResize, x, y)) {
|
||||
cursorManager.setCursor (iarea->get_window(), CSResizeDiagonal);
|
||||
} else if (tm == TMColorPicker && hoveredPicker) {
|
||||
cursorManager.setCursor (iarea->get_window(), CSMove);
|
||||
} else if (tm == TMHand && (onArea (CropTopLeft, x, y))) {
|
||||
cursorManager.setCursor (iarea->get_window(), CSResizeTopLeft);
|
||||
} else if (tm == TMHand && (onArea (CropTopRight, x, y))) {
|
||||
@ -1083,6 +1230,8 @@ void CropWindow::updateCursor (int x, int y)
|
||||
cursorManager.setCursor (iarea->get_window(), CSCropSelect);
|
||||
} else if (tm == TMStraighten) {
|
||||
cursorManager.setCursor (iarea->get_window(), CSStraighten);
|
||||
} else if (tm == TMColorPicker) {
|
||||
cursorManager.setCursor (iarea->get_window(), CSAddColPicker);
|
||||
}
|
||||
} else {
|
||||
int objectID = -1;
|
||||
@ -1121,6 +1270,8 @@ void CropWindow::updateCursor (int x, int y)
|
||||
cursorManager.setCursor (iarea->get_window(), CSResizeBottomRight);
|
||||
} else if (state == SCropWinResize) {
|
||||
cursorManager.setCursor (iarea->get_window(), CSResizeDiagonal);
|
||||
} else if (state == SDragPicker) {
|
||||
cursorManager.setCursor (iarea->get_window(), CSMove2D);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1128,6 +1279,8 @@ void CropWindow::expose (Cairo::RefPtr<Cairo::Context> cr)
|
||||
{
|
||||
MyMutex::MyLock lock(cropHandler.cimg);
|
||||
|
||||
bool isPreviewImg = false;
|
||||
|
||||
if (decorated) {
|
||||
drawDecoration (cr);
|
||||
}
|
||||
@ -1640,6 +1793,8 @@ void CropWindow::expose (Cairo::RefPtr<Cairo::Context> cr)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
isPreviewImg = true;
|
||||
} else {
|
||||
// cropHandler.cropPixbuf is null
|
||||
int cropX, cropY;
|
||||
@ -1674,6 +1829,12 @@ void CropWindow::expose (Cairo::RefPtr<Cairo::Context> cr)
|
||||
}
|
||||
}
|
||||
|
||||
if ((state == SNormal || state == SDragPicker) && isPreviewImg && iarea->showColorPickers()) {
|
||||
for (auto colorPicker : colorPickers) {
|
||||
colorPicker->draw(cr);
|
||||
}
|
||||
}
|
||||
|
||||
//t2.set ();
|
||||
// printf ("etime --> %d, %d\n", t2.etime (t1), t4.etime (t3));
|
||||
}
|
||||
@ -1888,10 +2049,10 @@ void CropWindow::buttonPressed (LWButton* button, int actionCode, void* actionDa
|
||||
} else if (button == bZoom100) { // zoom 100
|
||||
zoom11 ();
|
||||
} else if (button == bClose) { // close
|
||||
if(ipc->updateTryLock()) {
|
||||
if(iarea->getImProcCoordinator()->updateTryLock()) {
|
||||
deleted = true;
|
||||
iarea->cropWindowClosed (this);
|
||||
ipc->updateUnLock();
|
||||
iarea->getImProcCoordinator()->updateUnLock();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1902,6 +2063,31 @@ void CropWindow::redrawNeeded (LWButton* button)
|
||||
iarea->redraw ();
|
||||
}
|
||||
|
||||
void CropWindow::updateHoveredPicker (rtengine::Coord *imgPos)
|
||||
{
|
||||
|
||||
if (!hoveredPicker) {
|
||||
return;
|
||||
}
|
||||
|
||||
rtengine::Coord cropPos;
|
||||
float r=0.f, g=0.f, b=0.f;
|
||||
float rpreview=0.f, gpreview=0.f, bpreview=0.f;
|
||||
if (imgPos) {
|
||||
imageCoordToCropImage(imgPos->x, imgPos->y, cropPos.x, cropPos.y);
|
||||
hoveredPicker->setPosition (*imgPos);
|
||||
} else {
|
||||
rtengine::Coord imgPos2;
|
||||
hoveredPicker->getImagePosition(imgPos2);
|
||||
imageCoordToCropImage(imgPos2.x, imgPos2.y, cropPos.x, cropPos.y);
|
||||
}
|
||||
LockableColorPicker::Validity validity = checkValidity (hoveredPicker, cropPos);
|
||||
hoveredPicker->setValidity (validity);
|
||||
if (validity == LockableColorPicker::Validity::INSIDE) {
|
||||
cropHandler.colorPick(cropPos, r, g, b, rpreview, gpreview, bpreview, hoveredPicker->getSize());
|
||||
hoveredPicker->setRGB (r, g, b, rpreview, gpreview, bpreview);
|
||||
}
|
||||
}
|
||||
void CropWindow::changeZoom (int zoom, bool notify, int centerx, int centery)
|
||||
{
|
||||
|
||||
@ -1924,6 +2110,43 @@ void CropWindow::changeZoom (int zoom, bool notify, int centerx, int centery)
|
||||
iarea->redraw ();
|
||||
}
|
||||
|
||||
LockableColorPicker::Validity CropWindow::checkValidity (LockableColorPicker* picker, const rtengine::Coord &pos)
|
||||
{
|
||||
|
||||
if (!cropHandler.cropPixbuftrue) {
|
||||
return LockableColorPicker::Validity::OUTSIDE;
|
||||
}
|
||||
rtengine::Coord cropTopLeft, cropBottomRight, cropSize;
|
||||
int skip;
|
||||
cropHandler.getWindow(cropTopLeft.x, cropTopLeft.y, cropSize.x, cropSize.y, skip);
|
||||
cropBottomRight = cropTopLeft + cropSize;
|
||||
rtengine::Coord pickerPos, cropPickerPos;
|
||||
picker->getImagePosition(pickerPos);
|
||||
rtengine::Coord minPos(0, 0);
|
||||
rtengine::Coord maxPos(cropHandler.cropPixbuftrue->get_width(), cropHandler.cropPixbuftrue->get_height());
|
||||
rtengine::Coord halfPickerSize((int)picker->getSize()/2, (int)picker->getSize()/2);
|
||||
imageCoordToCropImage (pickerPos.x, pickerPos.y, cropPickerPos.x, cropPickerPos.y);
|
||||
imageCoordToCropImage (cropTopLeft.x, cropTopLeft.y, minPos.x, minPos.y);
|
||||
imageCoordToCropImage (cropBottomRight.x, cropBottomRight.y, maxPos.x, maxPos.y);
|
||||
rtengine::Coord pickerMinPos = cropPickerPos - halfPickerSize;
|
||||
rtengine::Coord pickerMaxPos = cropPickerPos + halfPickerSize;
|
||||
if (pickerMaxPos.x < minPos.x || pickerMaxPos.y < minPos.y || pickerMinPos.x > maxPos.x || pickerMinPos.y > maxPos.y) {
|
||||
return LockableColorPicker::Validity::OUTSIDE;
|
||||
} else if (pickerMinPos >= minPos && pickerMaxPos < maxPos) {
|
||||
return LockableColorPicker::Validity::INSIDE;
|
||||
} else {
|
||||
return LockableColorPicker::Validity::CROSSING;
|
||||
}
|
||||
}
|
||||
|
||||
void CropWindow::deleteColorPickers ()
|
||||
{
|
||||
for (auto colorPicker : colorPickers) {
|
||||
delete colorPicker;
|
||||
}
|
||||
colorPickers.clear();
|
||||
}
|
||||
|
||||
void CropWindow::screenCoordToCropBuffer (int phyx, int phyy, int& cropx, int& cropy)
|
||||
{
|
||||
|
||||
@ -1945,8 +2168,8 @@ void CropWindow::screenCoordToImage (int phyx, int phyy, int& imgx, int& imgy)
|
||||
|
||||
int cropX, cropY;
|
||||
cropHandler.getPosition (cropX, cropY);
|
||||
imgx = cropX + (phyx - xpos - imgX) / zoomSteps[cropZoom].zoom;
|
||||
imgy = cropY + (phyy - ypos - imgY) / zoomSteps[cropZoom].zoom;
|
||||
imgx = cropX + (phyx - xpos - imgX - imgAreaX) / zoomSteps[cropZoom].zoom;
|
||||
imgy = cropY + (phyy - ypos - imgY - imgAreaY) / zoomSteps[cropZoom].zoom;
|
||||
}
|
||||
|
||||
void CropWindow::screenCoordToCropCanvas (int phyx, int phyy, int& prevx, int& prevy)
|
||||
@ -1983,6 +2206,14 @@ void CropWindow::imageCoordToCropBuffer (int imgx, int imgy, int& phyx, int& phy
|
||||
phyy = (imgy - cropY) * zoomSteps[cropZoom].zoom + /*ypos + imgY +*/ crop->getUpperBorder();
|
||||
}
|
||||
|
||||
void CropWindow::imageCoordToCropImage (int imgx, int imgy, int& phyx, int& phyy)
|
||||
{
|
||||
int cropX, cropY;
|
||||
cropHandler.getPosition (cropX, cropY);
|
||||
phyx = (imgx - cropX) * zoomSteps[cropZoom].zoom;
|
||||
phyy = (imgy - cropY) * zoomSteps[cropZoom].zoom;
|
||||
}
|
||||
|
||||
int CropWindow::scaleValueToImage (int value)
|
||||
{
|
||||
return int(double(value) / zoomSteps[cropZoom].zoom);
|
||||
@ -2220,6 +2451,16 @@ void CropWindow::drawObservedFrame (Cairo::RefPtr<Cairo::Context> cr, int rw, in
|
||||
void CropWindow::cropImageUpdated ()
|
||||
{
|
||||
|
||||
for (auto colorPicker : colorPickers) {
|
||||
Coord imgPos, cropPos;
|
||||
colorPicker->getImagePosition(imgPos);
|
||||
imageCoordToCropImage(imgPos.x, imgPos.y, cropPos.x, cropPos.y);
|
||||
float r=0.f, g=0.f, b=0.f;
|
||||
float rpreview=0.f, gpreview=0.f, bpreview=0.f;
|
||||
colorPicker->setValidity (checkValidity (colorPicker, cropPos));
|
||||
cropHandler.colorPick(cropPos, r, g, b, rpreview, gpreview, bpreview, colorPicker->getSize());
|
||||
colorPicker->setRGB (r, g, b, rpreview, gpreview, bpreview);
|
||||
}
|
||||
iarea->redraw ();
|
||||
}
|
||||
|
||||
@ -2281,7 +2522,61 @@ void CropWindow::delCropWindowListener (CropWindowListener* l)
|
||||
}
|
||||
}
|
||||
|
||||
EditDataProvider* CropWindow::getImageArea()
|
||||
ImageArea* CropWindow::getImageArea()
|
||||
{
|
||||
return iarea;
|
||||
}
|
||||
|
||||
void CropWindow::setCropGUIListener (CropGUIListener* cgl)
|
||||
{
|
||||
cropgl = cgl;
|
||||
}
|
||||
|
||||
void CropWindow::setPointerMotionListener (PointerMotionListener* pml)
|
||||
{
|
||||
pmlistener = pml;
|
||||
if (pml) {
|
||||
pml->signal_cycle_rgb().connect( sigc::mem_fun(*this, &CropWindow::cycleRGB) );
|
||||
pml->signal_cycle_hsv().connect( sigc::mem_fun(*this, &CropWindow::cycleHSV) );
|
||||
}
|
||||
}
|
||||
|
||||
PointerMotionListener* CropWindow::getPointerMotionListener ()
|
||||
{
|
||||
return pmlistener;
|
||||
}
|
||||
|
||||
void CropWindow::setPointerMotionHListener (PointerMotionListener* pml)
|
||||
{
|
||||
pmhlistener = pml;
|
||||
}
|
||||
|
||||
// crop window listeners
|
||||
void CropWindow::addCropWindowListener (CropWindowListener* l)
|
||||
{
|
||||
listeners.push_back (l);
|
||||
}
|
||||
|
||||
void CropWindow::cycleRGB ()
|
||||
{
|
||||
bool redraw = false;
|
||||
for (auto colorPicker : colorPickers) {
|
||||
redraw |= colorPicker->cycleRGB ();
|
||||
}
|
||||
|
||||
if (redraw) {
|
||||
iarea->redraw ();
|
||||
}
|
||||
}
|
||||
|
||||
void CropWindow::cycleHSV ()
|
||||
{
|
||||
bool redraw = false;
|
||||
for (auto colorPicker : colorPickers) {
|
||||
redraw |= colorPicker->cycleHSV ();
|
||||
}
|
||||
|
||||
if (redraw) {
|
||||
iarea->redraw ();
|
||||
}
|
||||
}
|
||||
|
@ -59,6 +59,10 @@ class CropWindow : public LWButtonListener, public CropDisplayHandler, public Ed
|
||||
bool fitZoom;
|
||||
bool isLowUpdatePriority;
|
||||
|
||||
// color pickers
|
||||
std::vector<LockableColorPicker*> colorPickers;
|
||||
LockableColorPicker* hoveredPicker;
|
||||
|
||||
// decoration
|
||||
LWButton *bZoomIn, *bZoomOut, *bZoom100, /**bZoomFit,*/ *bClose;
|
||||
LWButtonSet buttonSet;
|
||||
@ -90,7 +94,6 @@ class CropWindow : public LWButtonListener, public CropDisplayHandler, public Ed
|
||||
std::list<CropWindowListener*> listeners;
|
||||
|
||||
CropWindow* observedCropWin; // Pointer to the currently active detail CropWindow
|
||||
rtengine::StagedImageProcessor* ipc;
|
||||
|
||||
bool onArea (CursorArea a, int x, int y);
|
||||
void updateCursor (int x, int y);
|
||||
@ -100,13 +103,19 @@ class CropWindow : public LWButtonListener, public CropDisplayHandler, public Ed
|
||||
void drawUnscaledSpotRectangle (Cairo::RefPtr<Cairo::Context> cr, int rectSize);
|
||||
void drawObservedFrame (Cairo::RefPtr<Cairo::Context> cr, int rw = 0, int rh = 0);
|
||||
void changeZoom (int zoom, bool notify = true, int centerx = -1, int centery = -1);
|
||||
void updateHoveredPicker (rtengine::Coord *imgPos = nullptr);
|
||||
void cycleRGB ();
|
||||
void cycleHSV ();
|
||||
|
||||
LockableColorPicker::Validity checkValidity (LockableColorPicker* picker, const rtengine::Coord &pos);
|
||||
|
||||
// Used by the mainCropWindow only
|
||||
void getObservedFrameArea (int& x, int& y, int& w, int& h, int rw = 0, int rh = 0);
|
||||
|
||||
public:
|
||||
CropHandler cropHandler;
|
||||
CropWindow (ImageArea* parent, rtengine::StagedImageProcessor* ipc_, bool isLowUpdatePriority_, bool isDetailWindow);
|
||||
CropWindow (ImageArea* parent, bool isLowUpdatePriority_, bool isDetailWindow);
|
||||
~CropWindow ();
|
||||
|
||||
void setDecorated (bool decorated)
|
||||
{
|
||||
@ -120,6 +129,7 @@ public:
|
||||
{
|
||||
observedCropWin = cw;
|
||||
}
|
||||
void deleteColorPickers ();
|
||||
|
||||
void screenCoordToCropBuffer (int phyx, int phyy, int& cropx, int& cropy);
|
||||
void screenCoordToImage (int phyx, int phyy, int& imgx, int& imgy);
|
||||
@ -127,6 +137,7 @@ public:
|
||||
void imageCoordToCropCanvas (int imgx, int imgy, int& phyx, int& phyy);
|
||||
void imageCoordToScreen (int imgx, int imgy, int& phyx, int& phyy);
|
||||
void imageCoordToCropBuffer (int imgx, int imgy, int& phyx, int& phyy);
|
||||
void imageCoordToCropImage (int imgx, int imgy, int& phyx, int& phyy);
|
||||
int scaleValueToImage (int value);
|
||||
float scaleValueToImage (float value);
|
||||
double scaleValueToImage (double value);
|
||||
@ -157,6 +168,7 @@ public:
|
||||
bool isInside (int x, int y);
|
||||
|
||||
|
||||
void scroll (int state, GdkScrollDirection direction, int x, int y);
|
||||
void buttonPress (int button, int num, int state, int x, int y);
|
||||
void buttonRelease (int button, int num, int state, int x, int y);
|
||||
void pointerMoved (int bstate, int x, int y);
|
||||
@ -179,24 +191,13 @@ public:
|
||||
void setCropAnchorPosition (int& w, int& h);
|
||||
|
||||
// listeners
|
||||
void setCropGUIListener (CropGUIListener* cgl)
|
||||
{
|
||||
cropgl = cgl;
|
||||
}
|
||||
void setPointerMotionListener (PointerMotionListener* pml)
|
||||
{
|
||||
pmlistener = pml;
|
||||
}
|
||||
void setPointerMotionHListener (PointerMotionListener* pml)
|
||||
{
|
||||
pmhlistener = pml;
|
||||
}
|
||||
void setCropGUIListener (CropGUIListener* cgl);
|
||||
void setPointerMotionListener (PointerMotionListener* pml);
|
||||
PointerMotionListener* getPointerMotionListener ();
|
||||
void setPointerMotionHListener (PointerMotionListener* pml);
|
||||
|
||||
// crop window listeners
|
||||
void addCropWindowListener (CropWindowListener* l)
|
||||
{
|
||||
listeners.push_back (l);
|
||||
}
|
||||
void addCropWindowListener (CropWindowListener* l);
|
||||
void delCropWindowListener (CropWindowListener* l);
|
||||
|
||||
// crophandlerlistener interface
|
||||
@ -208,7 +209,7 @@ public:
|
||||
void remoteMove (int deltaX, int deltaY);
|
||||
void remoteMoveReady ();
|
||||
|
||||
EditDataProvider* getImageArea();
|
||||
ImageArea* getImageArea();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -44,6 +44,7 @@ void CursorManager::init (Glib::RefPtr<Gdk::Window> mainWin)
|
||||
Glib::RefPtr<Gdk::Pixbuf> hand = RTImage::createFromFile ("cross.png");
|
||||
Glib::RefPtr<Gdk::Pixbuf> close_hand = RTImage::createFromFile ("closedhand.png");
|
||||
Glib::RefPtr<Gdk::Pixbuf> wbpick = RTImage::createFromFile ("gtk-color-picker-small.png");
|
||||
Glib::RefPtr<Gdk::Pixbuf> cpick = RTImage::createFromFile ("gtk-color-picker-add.png");
|
||||
Glib::RefPtr<Gdk::Pixbuf> empty = RTImage::createFromFile ("empty.png");
|
||||
Glib::RefPtr<Gdk::Pixbuf> move2D = RTImage::createFromFile ("move-2D.png");
|
||||
Glib::RefPtr<Gdk::Pixbuf> move1DH = RTImage::createFromFile ("move-1D-h.png");
|
||||
@ -52,7 +53,8 @@ void CursorManager::init (Glib::RefPtr<Gdk::Window> mainWin)
|
||||
|
||||
cHand = hand ? new Gdk::Cursor (cAdd->get_display(), hand, 10, 10) : new Gdk::Cursor (Gdk::HAND2);
|
||||
cClosedHand = close_hand ? new Gdk::Cursor (cAdd->get_display(), close_hand, 10, 10) : new Gdk::Cursor (Gdk::HAND2);
|
||||
cWB = wbpick ? new Gdk::Cursor (cAdd->get_display(), wbpick, 1, 12) : new Gdk::Cursor (Gdk::ARROW);
|
||||
cWB = wbpick ? new Gdk::Cursor (cAdd->get_display(), wbpick, 3, 15) : new Gdk::Cursor (Gdk::ARROW);
|
||||
cAddPicker = cpick ? new Gdk::Cursor (cAdd->get_display(), cpick, 3, 18) : new Gdk::Cursor (Gdk::ARROW);
|
||||
cHidden = empty ? new Gdk::Cursor (cAdd->get_display(), empty, 12, 12) : new Gdk::Cursor (Gdk::FLEUR);
|
||||
cMove2D = move2D ? new Gdk::Cursor (cAdd->get_display(), move2D, 11, 11) : new Gdk::Cursor (Gdk::FLEUR);
|
||||
cMove1DH = move1DH ? new Gdk::Cursor (cAdd->get_display(), move1DH, 11, 11) : new Gdk::Cursor (Gdk::FLEUR);
|
||||
@ -100,6 +102,8 @@ void CursorManager::setCursor (Glib::RefPtr<Gdk::Window> window, CursorShape sha
|
||||
window->set_cursor (*cMoveRotate);
|
||||
} else if (shape == CSSpotWB) {
|
||||
window->set_cursor (*cWB);
|
||||
} else if (shape == CSAddColPicker) {
|
||||
window->set_cursor (*cAddPicker);
|
||||
} else if (shape == CSCropSelect) {
|
||||
window->set_cursor (*cHand);
|
||||
} else if (shape == CSMoveLeft) {
|
||||
|
@ -26,7 +26,7 @@ enum CursorShape {
|
||||
CSMoveRight, CSResizeWidth, CSResizeHeight, CSResizeDiagonal,
|
||||
CSResizeTopLeft, CSResizeTopRight, CSResizeBottomLeft, CSResizeBottomRight,
|
||||
CSMove2D, CSMove1DH, CSMove1DV, CSMoveRotate,
|
||||
CSSpotWB, CSCropSelect, CSStraighten, CSPlus, CSWait, CSEmpty
|
||||
CSSpotWB, CSAddColPicker, CSCropSelect, CSStraighten, CSPlus, CSWait, CSEmpty
|
||||
};
|
||||
|
||||
class CursorManager
|
||||
@ -51,6 +51,7 @@ protected:
|
||||
Gdk::Cursor* cHand;
|
||||
Gdk::Cursor* cClosedHand;
|
||||
Gdk::Cursor* cWB;
|
||||
Gdk::Cursor* cAddPicker;
|
||||
Gdk::Cursor* cHidden;
|
||||
Gdk::Cursor* cMove2D;
|
||||
Gdk::Cursor* cMove1DH;
|
||||
|
@ -113,10 +113,9 @@ CurveEditor* CurveEditorGroup::addCurve(CurveType cType, Glib::ustring curveLabe
|
||||
*/
|
||||
void CurveEditorGroup::newLine()
|
||||
{
|
||||
Gtk::HBox* headerBox;
|
||||
|
||||
if (curveEditors.size() > numberOfPackedCurve) {
|
||||
headerBox = Gtk::manage (new Gtk::HBox ());
|
||||
Gtk::HBox* headerBox = Gtk::manage (new Gtk::HBox ());
|
||||
|
||||
if (!numberOfPackedCurve) {
|
||||
headerBox->pack_start(*curveGroupLabel, Gtk::PACK_SHRINK, 2);
|
||||
@ -381,7 +380,7 @@ void CurveEditorGroup::setUnChanged (bool uc, CurveEditor* ce)
|
||||
}
|
||||
}
|
||||
|
||||
CurveEditorSubGroup::CurveEditorSubGroup(Glib::ustring& curveDir) : curveDir(curveDir), lastFilename("")
|
||||
CurveEditorSubGroup::CurveEditorSubGroup(Glib::ustring& curveDir) : curveDir(curveDir), lastFilename(""), valLinear(0), valUnchanged(0), parent(nullptr), curveBBoxPos(0)
|
||||
{
|
||||
leftBar = NULL;
|
||||
bottomBar = NULL;
|
||||
|
@ -154,7 +154,7 @@ protected:
|
||||
* This variable will be updated with actions in the
|
||||
* dialogs.
|
||||
*/
|
||||
CurveEditorSubGroup(Glib::ustring& curveDir);
|
||||
explicit CurveEditorSubGroup(Glib::ustring& curveDir);
|
||||
|
||||
Glib::ustring outputFile ();
|
||||
Glib::ustring inputFile ();
|
||||
|
@ -1117,12 +1117,10 @@ bool DiagonalCurveEditorSubGroup::curveReset(CurveEditor *ce)
|
||||
case (DCT_NURBS) : // = Control cage
|
||||
NURBSCurve->reset (dce->NURBSResetCurve, dce->getIdentityValue());
|
||||
return true;
|
||||
break;
|
||||
|
||||
case (DCT_Spline) : // = Custom
|
||||
customCurve->reset (dce->customResetCurve, dce->getIdentityValue());
|
||||
return true;
|
||||
break;
|
||||
|
||||
case (DCT_Parametric) : {
|
||||
DiagonalCurveEditor* dCurve = static_cast<DiagonalCurveEditor*>(parent->displayedCurve);
|
||||
@ -1137,12 +1135,10 @@ bool DiagonalCurveEditorSubGroup::curveReset(CurveEditor *ce)
|
||||
shcSelector->reset();
|
||||
paramCurve->reset (dce->paramResetCurve, dce->getIdentityValue());
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -59,7 +59,7 @@ std::vector<Glib::ustring> listSubDirs (const Glib::RefPtr<Gio::File>& dir, bool
|
||||
} catch (const Glib::Exception& exception) {
|
||||
|
||||
if (options.rtSettings.verbose) {
|
||||
std::cerr << "Failed to list subdirectories of \"" << dir->get_basename() << "\": " << exception.what () << std::endl;
|
||||
std::cerr << "Failed to list subdirectories of \"" << dir->get_parse_name() << "\": " << exception.what () << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -208,10 +208,12 @@ public:
|
||||
virtual void screenCoordToImage (int phyx, int phyy, int& imgx, int& imgy) = 0;
|
||||
/// Convert the image coords to the widget's DrawingArea (i.e. preview area) coords
|
||||
virtual void imageCoordToScreen (int imgx, int imgy, int& phyx, int& phyy) = 0;
|
||||
/// Convert the image coords to the crop's canvas coords
|
||||
/// Convert the image coords to the crop's canvas coords (full image + padding)
|
||||
virtual void imageCoordToCropCanvas (int imgx, int imgy, int& phyx, int& phyy) = 0;
|
||||
/// Convert the image coords to the edit buffer coords
|
||||
/// Convert the image coords to the edit buffer coords (includes borders)
|
||||
virtual void imageCoordToCropBuffer (int imgx, int imgy, int& phyx, int& phyy) = 0;
|
||||
/// Convert the image coords to the displayed image coords (no borders here)
|
||||
virtual void imageCoordToCropImage (int imgx, int imgy, int& phyx, int& phyy) = 0;
|
||||
/// Convert a size value from the preview's scale to the image's scale
|
||||
virtual int scaleValueToImage (int value) = 0;
|
||||
/// Convert a size value from the preview's scale to the image's scale
|
||||
@ -463,7 +465,7 @@ protected:
|
||||
} action; /// object mode only, ignored in Pipette mode
|
||||
|
||||
public:
|
||||
EditSubscriber (EditType editType);
|
||||
explicit EditSubscriber (EditType editType);
|
||||
virtual ~EditSubscriber () {}
|
||||
|
||||
void setEditProvider(EditDataProvider *provider);
|
||||
|
@ -21,9 +21,9 @@
|
||||
|
||||
enum ImgEditState {SNormal, SCropMove, SHandMove, SResizeW1, SResizeW2, SResizeH1, SResizeH2, SResizeTL, SResizeTR, SResizeBL, SResizeBR,
|
||||
SCropSelecting, SRotateSelecting, SCropWinMove, SCropFrameMove, SCropImgMove, SCropWinResize, SObservedMove,
|
||||
SEditDrag1, SEditDrag2, SEditDrag3, SEditPick1, SEditPick2, SEditPick3
|
||||
SEditDrag1, SEditDrag2, SEditDrag3, SEditPick1, SEditPick2, SEditPick3, SDragPicker, SDeletePicker
|
||||
};
|
||||
enum CursorArea {CropWinButtons, CropToolBar, CropImage, CropBorder, CropTop, CropTopLeft, CropTopRight, CropBottom, CropBottomLeft,
|
||||
enum CursorArea {CropWinButtons, CropToolBar, CropImage, ColorPicker, CropBorder, CropTop, CropTopLeft, CropTopRight, CropBottom, CropBottomLeft,
|
||||
CropBottomRight, CropLeft, CropRight, CropInside, CropResize, CropObserved
|
||||
};
|
||||
|
||||
|
@ -223,7 +223,7 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
ColorManagementToolbar (rtengine::StagedImageProcessor* const& ipc) :
|
||||
explicit ColorManagementToolbar (rtengine::StagedImageProcessor* const& ipc) :
|
||||
intentBox (Glib::ustring (), true),
|
||||
processor (ipc)
|
||||
{
|
||||
@ -392,6 +392,7 @@ EditorPanel::EditorPanel (FilePanel* filePanel)
|
||||
|
||||
iareapanel = new ImageAreaPanel ();
|
||||
tpc->setEditProvider(iareapanel->imageArea);
|
||||
tpc->getToolBar()->setLockablePickerToolListener(iareapanel->imageArea);
|
||||
|
||||
Gtk::HBox* toolBarPanel = Gtk::manage (new Gtk::HBox ());
|
||||
toolBarPanel->pack_start (*hidehp, Gtk::PACK_SHRINK, 1);
|
||||
|
@ -138,7 +138,7 @@ protected:
|
||||
|
||||
|
||||
public:
|
||||
EditorPanel (FilePanel* filePanel = NULL);
|
||||
explicit EditorPanel (FilePanel* filePanel = NULL);
|
||||
virtual ~EditorPanel ();
|
||||
|
||||
void open (Thumbnail* tmb, rtengine::InitialImage* isrc);
|
||||
|
@ -37,7 +37,7 @@ EditWindow* EditWindow::getInstance(RTWindow* p)
|
||||
{
|
||||
EditWindow editWnd;
|
||||
|
||||
EditWindowInstance(RTWindow* p) : editWnd(p)
|
||||
explicit EditWindowInstance(RTWindow* p) : editWnd(p)
|
||||
{
|
||||
// Determine the other display and maximize the window on that
|
||||
const Glib::RefPtr< Gdk::Window >& wnd = p->get_window();
|
||||
|
@ -42,7 +42,7 @@ public:
|
||||
// Should only be created once, auto-creates window on correct display
|
||||
static EditWindow* getInstance(RTWindow* p);
|
||||
|
||||
EditWindow (RTWindow* p);
|
||||
explicit EditWindow (RTWindow* p);
|
||||
|
||||
void addEditorPanel (EditorPanel* ep, const std::string &name);
|
||||
void remEditorPanel (EditorPanel* ep);
|
||||
|
@ -102,7 +102,7 @@ void ExtProgStore::init ()
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
bool ExtProgStore::searchProgram (const Glib::ustring& name,
|
||||
const Glib::ustring& exePath,
|
||||
const Glib::ustring& exePath86,
|
||||
@ -111,7 +111,6 @@ bool ExtProgStore::searchProgram (const Glib::ustring& name,
|
||||
bool allowQueueProcess)
|
||||
{
|
||||
|
||||
#ifdef WIN32
|
||||
// get_user_special_dir crashes on some Windows configurations.
|
||||
static Glib::ustring progFilesDir, progFilesDirx86;
|
||||
|
||||
@ -196,10 +195,10 @@ bool ExtProgStore::searchProgram (const Glib::ustring& name,
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool ExtProgStore::spawnCommandAsync (const Glib::ustring& cmd)
|
||||
{
|
||||
|
@ -44,13 +44,14 @@ class ExtProgStore
|
||||
MyMutex mtx; // covers actions
|
||||
std::vector<ExtProgAction> actions;
|
||||
|
||||
#ifdef WIN32
|
||||
bool searchProgram (const Glib::ustring& name,
|
||||
const Glib::ustring& exePath,
|
||||
const Glib::ustring& exePath86,
|
||||
int maxVer,
|
||||
bool allowRaw,
|
||||
bool allowQueueProcess);
|
||||
|
||||
#endif
|
||||
public:
|
||||
static ExtProgStore* getInstance();
|
||||
|
||||
|
@ -487,13 +487,13 @@ void FileBrowser::rightClicked (ThumbBrowserEntryBase* entry)
|
||||
untrash->set_sensitive (false);
|
||||
|
||||
for (size_t i = 0; i < selected.size(); i++)
|
||||
if ((static_cast<FileBrowserEntry*>(selected[i]))->thumbnail->getStage() == 1) {
|
||||
if ((static_cast<FileBrowserEntry*>(selected[i]))->thumbnail->getStage()) {
|
||||
untrash->set_sensitive (true);
|
||||
break;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < selected.size(); i++)
|
||||
if ((static_cast<FileBrowserEntry*>(selected[i]))->thumbnail->getStage() == 0) {
|
||||
if (!(static_cast<FileBrowserEntry*>(selected[i]))->thumbnail->getStage()) {
|
||||
trash->set_sensitive (true);
|
||||
break;
|
||||
}
|
||||
@ -512,7 +512,6 @@ void FileBrowser::rightClicked (ThumbBrowserEntryBase* entry)
|
||||
submenuDF->attach (*Gtk::manage(autoDF = new Gtk::MenuItem (M("FILEBROWSER_AUTODARKFRAME"))), 0, 1, p, p + 1);
|
||||
p++;
|
||||
submenuDF->attach (*Gtk::manage(thisIsDF = new Gtk::MenuItem (M("FILEBROWSER_MOVETODARKFDIR"))), 0, 1, p, p + 1);
|
||||
p++;
|
||||
selectDF->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), selectDF));
|
||||
autoDF->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), autoDF));
|
||||
thisIsDF->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), thisIsDF ));
|
||||
@ -527,7 +526,6 @@ void FileBrowser::rightClicked (ThumbBrowserEntryBase* entry)
|
||||
submenuFF->attach (*Gtk::manage(autoFF = new Gtk::MenuItem (M("FILEBROWSER_AUTOFLATFIELD"))), 0, 1, p, p + 1);
|
||||
p++;
|
||||
submenuFF->attach (*Gtk::manage(thisIsFF = new Gtk::MenuItem (M("FILEBROWSER_MOVETOFLATFIELDDIR"))), 0, 1, p, p + 1);
|
||||
p++;
|
||||
selectFF->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), selectFF));
|
||||
autoFF->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), autoFF));
|
||||
thisIsFF->signal_activate().connect (sigc::bind(sigc::mem_fun(*this, &FileBrowser::menuItemActivated), thisIsFF ));
|
||||
@ -612,7 +610,7 @@ void FileBrowser::addEntry_ (FileBrowserEntry* entry)
|
||||
entry->addButtonSet (new FileThumbnailButtonSet (entry));
|
||||
entry->getThumbButtonSet()->setRank (entry->thumbnail->getRank());
|
||||
entry->getThumbButtonSet()->setColorLabel (entry->thumbnail->getColorLabel());
|
||||
entry->getThumbButtonSet()->setInTrash (entry->thumbnail->getStage() == 1);
|
||||
entry->getThumbButtonSet()->setInTrash (entry->thumbnail->getStage());
|
||||
entry->getThumbButtonSet()->setButtonListener (this);
|
||||
entry->resize (getThumbnailHeight());
|
||||
|
||||
@ -1134,8 +1132,9 @@ bool FileBrowser::keyPressed (GdkEventKey* event)
|
||||
bool ctrl = event->state & GDK_CONTROL_MASK;
|
||||
bool shift = event->state & GDK_SHIFT_MASK;
|
||||
bool alt = event->state & GDK_MOD1_MASK;
|
||||
#ifdef __WIN32__
|
||||
bool altgr = event->state & GDK_MOD2_MASK;
|
||||
|
||||
#endif
|
||||
if ((event->keyval == GDK_C || event->keyval == GDK_c || event->keyval == GDK_Insert) && ctrl) {
|
||||
copyProfile ();
|
||||
return true;
|
||||
@ -1474,8 +1473,8 @@ bool FileBrowser::checkFilter (ThumbBrowserEntryBase* entryb) // true -> entry
|
||||
((entry->thumbnail->isRecentlySaved() && filter.showRecentlySaved[0]) && !filter.showRecentlySaved[1]) ||
|
||||
((!entry->thumbnail->isRecentlySaved() && filter.showRecentlySaved[1]) && !filter.showRecentlySaved[0]) ||
|
||||
|
||||
(entry->thumbnail->getStage() == 1 && !filter.showTrash) ||
|
||||
(entry->thumbnail->getStage() == 0 && !filter.showNotTrash)) {
|
||||
(entry->thumbnail->getStage() && !filter.showTrash) ||
|
||||
(!entry->thumbnail->getStage() && !filter.showNotTrash)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1568,11 +1567,11 @@ void FileBrowser::toTrashRequested (std::vector<FileBrowserEntry*> tbe)
|
||||
|
||||
// no need to notify listeners as item goes to trash, likely to be deleted
|
||||
|
||||
if (tbe[i]->thumbnail->getStage() == 1) {
|
||||
if (tbe[i]->thumbnail->getStage()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tbe[i]->thumbnail->setStage (1);
|
||||
tbe[i]->thumbnail->setStage (true);
|
||||
|
||||
if (tbe[i]->getThumbButtonSet()) {
|
||||
tbe[i]->getThumbButtonSet()->setRank (tbe[i]->thumbnail->getRank());
|
||||
@ -1592,11 +1591,11 @@ void FileBrowser::fromTrashRequested (std::vector<FileBrowserEntry*> tbe)
|
||||
for (size_t i = 0; i < tbe.size(); i++) {
|
||||
// if thumbnail was marked inTrash=true then param file must be there, no need to run customprofilebuilder
|
||||
|
||||
if (tbe[i]->thumbnail->getStage() == 0) {
|
||||
if (!tbe[i]->thumbnail->getStage()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
tbe[i]->thumbnail->setStage (0);
|
||||
tbe[i]->thumbnail->setStage (false);
|
||||
|
||||
if (tbe[i]->getThumbButtonSet()) {
|
||||
tbe[i]->getThumbButtonSet()->setRank (tbe[i]->thumbnail->getRank());
|
||||
@ -1715,7 +1714,7 @@ void FileBrowser::buttonPressed (LWButton* button, int actionCode, void* actionD
|
||||
FileBrowserEntry* entry = static_cast<FileBrowserEntry*>(actionData);
|
||||
tbe.push_back (entry);
|
||||
|
||||
if (entry->thumbnail->getStage() == 0) {
|
||||
if (!entry->thumbnail->getStage()) {
|
||||
toTrashRequested (tbe);
|
||||
} else {
|
||||
fromTrashRequested (tbe);
|
||||
|
@ -989,9 +989,6 @@ void FileCatalog::copyMoveRequested (std::vector<FileBrowserEntry*> tbe, bool m
|
||||
fc.set_filename(tbe[0]->filename);
|
||||
//!!! TODO prevent dialog closing on "enter" key press
|
||||
|
||||
bool filecopymovecomplete;
|
||||
int i_copyindex;
|
||||
|
||||
if( fc.run() == Gtk::RESPONSE_OK ) {
|
||||
Glib::ustring dest_Dir = fc.get_current_folder();
|
||||
|
||||
@ -1020,8 +1017,8 @@ void FileCatalog::copyMoveRequested (std::vector<FileBrowserEntry*> tbe, bool m
|
||||
/* comparison of src_Dir and dest_Dir is done per image for compatibility with
|
||||
possible future use of Collections as source where each file's source path may be different.*/
|
||||
|
||||
filecopymovecomplete = false;
|
||||
i_copyindex = 1;
|
||||
bool filecopymovecomplete = false;
|
||||
int i_copyindex = 1;
|
||||
|
||||
while(!filecopymovecomplete) {
|
||||
// check for filename conflicts at destination - prevent overwriting (actually RT will crash on overwriting attempt)
|
||||
@ -1225,8 +1222,6 @@ void FileCatalog::setExportPanel (ExportPanel* expanel)
|
||||
void FileCatalog::renameRequested (std::vector<FileBrowserEntry*> tbe)
|
||||
{
|
||||
|
||||
bool success;
|
||||
|
||||
RenameDialog* renameDlg = new RenameDialog ((Gtk::Window*)get_toplevel());
|
||||
|
||||
for (size_t i = 0; i < tbe.size(); i++) {
|
||||
@ -1236,7 +1231,7 @@ void FileCatalog::renameRequested (std::vector<FileBrowserEntry*> tbe)
|
||||
Glib::ustring dirName = Glib::path_get_dirname (tbe[i]->filename);
|
||||
Glib::ustring baseName = Glib::path_get_basename (tbe[i]->filename);
|
||||
|
||||
success = false;
|
||||
bool success = false;
|
||||
|
||||
do {
|
||||
if (renameDlg->run () == Gtk::RESPONSE_OK) {
|
||||
|
@ -43,7 +43,7 @@ class DirEntry
|
||||
public:
|
||||
Glib::ustring fullName;
|
||||
|
||||
DirEntry (const Glib::ustring& n) : fullName (n) {}
|
||||
explicit DirEntry (const Glib::ustring& n) : fullName (n) {}
|
||||
|
||||
bool operator< (DirEntry& other)
|
||||
{
|
||||
|
@ -52,7 +52,6 @@ FilePanel::FilePanel () : parent(NULL)
|
||||
dirpaned->pack1 (*placespaned, false, true);
|
||||
|
||||
tpc = new BatchToolPanelCoordinator (this);
|
||||
tpc->removeWbTool();
|
||||
fileCatalog = Gtk::manage ( new FileCatalog (tpc->coarse, tpc->getToolBar(), this) );
|
||||
ribbonPane = Gtk::manage ( new Gtk::Paned() );
|
||||
ribbonPane->add(*fileCatalog);
|
||||
|
@ -44,7 +44,7 @@ public:
|
||||
static Cairo::RefPtr<Cairo::ImageSurface> colorLabelIcon_4;
|
||||
static Cairo::RefPtr<Cairo::ImageSurface> colorLabelIcon_5;
|
||||
|
||||
FileThumbnailButtonSet (FileBrowserEntry* myEntry);
|
||||
explicit FileThumbnailButtonSet (FileBrowserEntry* myEntry);
|
||||
void setRank (int stars);
|
||||
void setColorLabel (int colorlabel);
|
||||
void setInTrash (bool inTrash);
|
||||
|
@ -1080,11 +1080,35 @@ void TextOrIcon::switchTo(TOITypes type)
|
||||
|
||||
BackBuffer::BackBuffer() : x(0), y(0), w(0), h(0), offset(0, 0), dirty(true) {}
|
||||
|
||||
void BackBuffer::setDestPosition(int x, int y)
|
||||
{
|
||||
// values will be clamped when used...
|
||||
this->x = x;
|
||||
this->y = y;
|
||||
}
|
||||
|
||||
void BackBuffer::setSrcOffset(int x, int y)
|
||||
{
|
||||
// values will be clamped when used...
|
||||
offset.x = x;
|
||||
offset.y = y;
|
||||
offset.set(x, y);
|
||||
}
|
||||
|
||||
void BackBuffer::setSrcOffset(const rtengine::Coord &newOffset)
|
||||
{
|
||||
// values will be clamped when used...
|
||||
offset = newOffset;
|
||||
}
|
||||
|
||||
void BackBuffer::getSrcOffset(int &x, int &y)
|
||||
{
|
||||
// values will be clamped when used...
|
||||
offset.get(x, y);
|
||||
}
|
||||
|
||||
void BackBuffer::getSrcOffset(rtengine::Coord &offset)
|
||||
{
|
||||
// values will be clamped when used...
|
||||
offset = this->offset;
|
||||
}
|
||||
|
||||
// Note: newW & newH must be > 0
|
||||
@ -1092,12 +1116,16 @@ bool BackBuffer::setDrawRectangle(Glib::RefPtr<Gdk::Window> window, int newX, in
|
||||
{
|
||||
assert(newW && newH);
|
||||
|
||||
bool newSize = w != newW || h != newH;
|
||||
bool newSize = (newW > 0 && w != newW) || (newH > 0 && h != newH);
|
||||
|
||||
x = newX;
|
||||
y = newY;
|
||||
w = newW;
|
||||
h = newH;
|
||||
if (newH > 0) {
|
||||
w = newW;
|
||||
}
|
||||
if (newH > 0) {
|
||||
h = newH;
|
||||
}
|
||||
|
||||
// WARNING: we're assuming that the surface type won't change during all the execution time of RT. I guess it may be wrong when the user change the gfx card display settings!?
|
||||
if (updateBackBufferSize && newSize && window) {
|
||||
@ -1113,14 +1141,18 @@ bool BackBuffer::setDrawRectangle(Glib::RefPtr<Gdk::Window> window, int newX, in
|
||||
// Note: newW & newH must be > 0
|
||||
bool BackBuffer::setDrawRectangle(Cairo::Format format, int newX, int newY, int newW, int newH, bool updateBackBufferSize)
|
||||
{
|
||||
assert(!newW && !newH);
|
||||
assert(newW && newH);
|
||||
|
||||
bool newSize = w != newW || h != newH;
|
||||
bool newSize = (newW > 0 && w != newW) || (newH > 0 && h != newH);
|
||||
|
||||
x = newX;
|
||||
y = newY;
|
||||
w = newW;
|
||||
h = newH;
|
||||
if (newH > 0) {
|
||||
w = newW;
|
||||
}
|
||||
if (newH > 0) {
|
||||
h = newH;
|
||||
}
|
||||
|
||||
// WARNING: we're assuming that the surface type won't change during all the execution time of RT. I guess it may be wrong when the user change the gfx card display settings!?
|
||||
if (updateBackBufferSize && newSize) {
|
||||
@ -1136,7 +1168,7 @@ bool BackBuffer::setDrawRectangle(Cairo::Format format, int newX, int newY, int
|
||||
/*
|
||||
* Copy the backbuffer to a Gdk::Window
|
||||
*/
|
||||
void BackBuffer::copySurface(Glib::RefPtr<Gdk::Window> window, GdkRectangle *rectangle)
|
||||
void BackBuffer::copySurface(Glib::RefPtr<Gdk::Window> &window, GdkRectangle *rectangle)
|
||||
{
|
||||
if (surface && window) {
|
||||
// TODO: look out if window can be different on each call, and if not, store a reference to the window
|
||||
@ -1190,7 +1222,7 @@ void BackBuffer::copySurface(BackBuffer *destBackBuffer, GdkRectangle *rectangle
|
||||
/*
|
||||
* Copy the BackBuffer to another Cairo::Surface
|
||||
*/
|
||||
void BackBuffer::copySurface(Cairo::RefPtr<Cairo::ImageSurface> destSurface, GdkRectangle *rectangle)
|
||||
void BackBuffer::copySurface(Cairo::RefPtr<Cairo::ImageSurface> &destSurface, GdkRectangle *rectangle)
|
||||
{
|
||||
if (surface && destSurface) {
|
||||
// compute the source offset
|
||||
@ -1212,3 +1244,23 @@ void BackBuffer::copySurface(Cairo::RefPtr<Cairo::ImageSurface> destSurface, Gdk
|
||||
}
|
||||
}
|
||||
|
||||
void BackBuffer::copySurface(Cairo::RefPtr<Cairo::Context> &context, GdkRectangle *rectangle)
|
||||
{
|
||||
if (surface && context) {
|
||||
// compute the source offset
|
||||
int offsetX = rtengine::LIM<int>(offset.x, 0, surface->get_width());
|
||||
int offsetY = rtengine::LIM<int>(offset.y, 0, surface->get_height());
|
||||
|
||||
// now copy the off-screen Surface to the destination Surface
|
||||
context->set_source(surface, x - offsetX, y - offsetY);
|
||||
context->set_line_width(0.);
|
||||
|
||||
if (rectangle) {
|
||||
context->rectangle(rectangle->x, rectangle->y, rectangle->width, rectangle->height);
|
||||
} else {
|
||||
context->rectangle(x, y, w, h);
|
||||
}
|
||||
|
||||
context->fill();
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include <gtkmm.h>
|
||||
#include "../rtengine/rtengine.h"
|
||||
#include "../rtengine/coord.h"
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
@ -79,7 +80,7 @@ public:
|
||||
class ConnectionBlocker
|
||||
{
|
||||
public:
|
||||
ConnectionBlocker (sigc::connection& connection) : connection (connection)
|
||||
explicit ConnectionBlocker (sigc::connection& connection) : connection (connection)
|
||||
{
|
||||
wasBlocked = connection.block();
|
||||
}
|
||||
@ -101,7 +102,7 @@ private:
|
||||
Gtk::Container *pC;
|
||||
|
||||
public:
|
||||
ExpanderBox( Gtk::Container *p);
|
||||
explicit ExpanderBox( Gtk::Container *p);
|
||||
~ExpanderBox( )
|
||||
{
|
||||
delete pC;
|
||||
@ -382,33 +383,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Handle point coordinates
|
||||
*/
|
||||
template <class T>
|
||||
class Point
|
||||
{
|
||||
public:
|
||||
T x, y;
|
||||
Point()
|
||||
{
|
||||
x = T(0);
|
||||
y = T(0);
|
||||
}
|
||||
|
||||
Point(T coordX, T coordY)
|
||||
{
|
||||
x = coordX;
|
||||
y = coordY;
|
||||
}
|
||||
|
||||
void setCoords(T coordX, T coordY)
|
||||
{
|
||||
x = coordX;
|
||||
y = coordY;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Handle backbuffers as automatically as possible
|
||||
*/
|
||||
@ -417,7 +391,7 @@ class BackBuffer
|
||||
|
||||
protected:
|
||||
int x, y, w, h; // Rectangle where the colored bar has to be drawn
|
||||
Point<int> offset; // Offset of the source region to draw, relative to the top left corner
|
||||
rtengine::Coord offset; // Offset of the source region to draw, relative to the top left corner
|
||||
Cairo::RefPtr<Cairo::ImageSurface> surface;
|
||||
bool dirty; // mean that the Surface has to be (re)allocated
|
||||
|
||||
@ -426,13 +400,19 @@ public:
|
||||
|
||||
// set the destination drawing rectangle; return true if the dimensions are different
|
||||
// Note: newW & newH must be > 0
|
||||
bool setDrawRectangle(Glib::RefPtr<Gdk::Window> window, int newX, int newY, int newW, int newH, bool updateBackBufferSize = true);
|
||||
bool setDrawRectangle(Cairo::Format format, int newX, int newY, int newW, int newH, bool updateBackBufferSize = true);
|
||||
bool setDrawRectangle(Glib::RefPtr<Gdk::Window> window, int newX, int newY, int newW=-1, int newH=-1, bool updateBackBufferSize = true);
|
||||
bool setDrawRectangle(Cairo::Format format, int newX, int newY, int newW=-1, int newH=-1, bool updateBackBufferSize = true);
|
||||
// set the destination drawing location, do not modify other parameters like size and offset. Use setDrawRectangle to set all parameters at the same time
|
||||
void setDestPosition(int x, int y);
|
||||
void setSrcOffset(int x, int y);
|
||||
void setSrcOffset(const rtengine::Coord &newOffset);
|
||||
void getSrcOffset(int &x, int &y);
|
||||
void getSrcOffset(rtengine::Coord &offset);
|
||||
|
||||
void copySurface(Glib::RefPtr<Gdk::Window> window, GdkRectangle *rectangle = NULL);
|
||||
void copySurface(Glib::RefPtr<Gdk::Window> &window, GdkRectangle *rectangle = NULL);
|
||||
void copySurface(BackBuffer *destBackBuffer, GdkRectangle *rectangle = NULL);
|
||||
void copySurface(Cairo::RefPtr<Cairo::ImageSurface> destSurface, GdkRectangle *rectangle = NULL);
|
||||
void copySurface(Cairo::RefPtr<Cairo::ImageSurface> &destSurface, GdkRectangle *rectangle = NULL);
|
||||
void copySurface(Cairo::RefPtr<Cairo::Context> &context, GdkRectangle *rectangle = NULL);
|
||||
|
||||
void setDirty(bool isDirty)
|
||||
{
|
||||
|
@ -353,7 +353,8 @@ void HistogramPanel::toggle_button_full ()
|
||||
//
|
||||
// HistogramRGBArea
|
||||
HistogramRGBArea::HistogramRGBArea () ://needChroma unactive by default
|
||||
frozen(false), valid(false), needRed(true), needGreen(true), needBlue(true), needLuma(true), rawMode(false), showMode(options.histogramBar), barDisplayed(options.histogramBar), needChroma(false)
|
||||
val(0), r(0), g(0), b(0), frozen(false), valid(false), needRed(true), needGreen(true), needBlue(true), needLuma(true), rawMode(false),
|
||||
showMode(options.histogramBar), barDisplayed(options.histogramBar), needChroma(false), parent(nullptr)
|
||||
{
|
||||
|
||||
harih = new HistogramRGBAreaIdleHelper;
|
||||
|
@ -144,7 +144,7 @@ protected:
|
||||
|
||||
public:
|
||||
|
||||
HistogramArea(FullModeListener *fml = NULL);
|
||||
explicit HistogramArea(FullModeListener *fml = NULL);
|
||||
~HistogramArea();
|
||||
|
||||
void renderHistogram ();
|
||||
|
@ -95,7 +95,7 @@ protected:
|
||||
|
||||
public:
|
||||
|
||||
History (bool bookmarkSupport = true);
|
||||
explicit History (bool bookmarkSupport = true);
|
||||
|
||||
void setProfileChangeListener (ProfileChangeListener* tpc_)
|
||||
{
|
||||
|
@ -18,7 +18,7 @@
|
||||
*/
|
||||
#include "ilabel.h"
|
||||
|
||||
ILabel::ILabel (Glib::ustring lab) : label(lab) {}
|
||||
ILabel::ILabel (const Glib::ustring &lab) : label(lab) {}
|
||||
|
||||
void ILabel::on_realize()
|
||||
{
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user