1 /*
2  */
3 
4 /*
5 
6     Copyright (C) 2014 Ferrero Andrea
7 
8     This program is free software: you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation, either version 3 of the License, or
11     (at your option) any later version.
12 
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     GNU General Public License for more details.
17 
18     You should have received a copy of the GNU General Public License
19     along with this program. If not, see <http://www.gnu.org/licenses/>.
20 
21 
22  */
23 
24 /*
25 
26     These files are distributed with PhotoFlow - http://aferrero2707.github.io/PhotoFlow/
27 
28  */
29 
30 
31 
32 
33 template<typename T, colorspace_t colorspace, int CHMIN, int CHMAX, bool has_omap>
34 class BlendLuminosity: public BlendBase<T, colorspace, CHMIN, CHMAX, has_omap>
35 {
36   int pos, ch;
37   ICCProfile* data;
38 public:
set_icc_data(ICCProfile * d)39   void set_icc_data( ICCProfile* d ) { data = d; }
blend(const float &,T *,T * top,T * out,const int & x,int &)40   void blend(const float& , T* , T* top, T* out, const int& x, int& )
41   {
42     pos = x;
43     for( ch=CHMIN; ch<=CHMAX; ch++, pos++ ) {
44       out[pos] = top[pos];
45     }
46   }
47 };
48 
49 
50 
51 /*
52   RGB colorspace
53  */
54 template<typename T, int CHMIN, int CHMAX>
55 class BlendLuminosity<T, PF_COLORSPACE_RGB, CHMIN, CHMAX, false>:
56   public BlendBase<T, PF_COLORSPACE_RGB, CHMIN, CHMAX, false>
57 {
58   int pos, ch;
59   float temp_top;
60   float irgb[3];
61   float rgb[3];
62   ICCProfile* data;
63 public:
set_icc_data(ICCProfile * d)64   void set_icc_data( ICCProfile* d ) { data = d; }
blend(const float & opacity,T * bottom,T * top,T * out,const int & x,int &)65   void blend(const float& opacity, T* bottom, T* top, T* out, const int& x, int& /*xomap*/)
66   {
67     // RGB values of the bottom layer
68     irgb[0] = (float(bottom[x]) + FormatInfo<T>::MIN)/FormatInfo<T>::RANGE;
69     irgb[1] = (float(bottom[x+1]) + FormatInfo<T>::MIN)/FormatInfo<T>::RANGE;
70     irgb[2] = (float(bottom[x+2]) + FormatInfo<T>::MIN)/FormatInfo<T>::RANGE;
71 
72     // RGB values of the top layer
73     float ored = (double(top[x]) + FormatInfo<T>::MIN)/FormatInfo<T>::RANGE;
74     float ogreen = (double(top[x+1]) + FormatInfo<T>::MIN)/FormatInfo<T>::RANGE;
75     float oblue = (double(top[x+2]) + FormatInfo<T>::MIN)/FormatInfo<T>::RANGE;
76 /*
77     if( data->get_trc_type()!=PF_TRC_LINEAR ) {
78       //std::cout<<"BlendLuminance: perceptual -> linear: "<<irgb[0]<<" -> "<<data->perceptual_trc_vec[ (int)(irgb[0]*65535) ]<<std::endl;
79       // RGB values are encoded perceptually
80       irgb[0] = data->perceptual2linear( irgb[0] );
81       irgb[1] = data->perceptual2linear( irgb[1] );
82       irgb[2] = data->perceptual2linear( irgb[2] );
83       ored = data->perceptual2linear( ored );
84       ogreen = data->perceptual2linear( ogreen );
85       oblue = data->perceptual2linear( oblue );
86 
87       //irgb[0] = data->perceptual_trc_vec[ (int)(irgb[0]*65535) ];
88       //irgb[1] = data->perceptual_trc_vec[ (int)(irgb[1]*65535) ];
89       //irgb[2] = data->perceptual_trc_vec[ (int)(irgb[2]*65535) ];
90       //ored = data->perceptual_trc_vec[ (int)(ored*65535) ];
91       //ogreen = data->perceptual_trc_vec[ (int)(ogreen*65535) ];
92       //oblue = data->perceptual_trc_vec[ (int)(oblue*65535) ];
93 
94       //irgb[0] = cmsEvalToneCurveFloat( data->perceptual_trc, irgb[0] );
95       //irgb[1] = cmsEvalToneCurveFloat( data->perceptual_trc, irgb[0] );
96       //irgb[2] = cmsEvalToneCurveFloat( data->perceptual_trc, irgb[0] );
97     }
98 */
99     // Luminance value of the top layer
100     //float lumi = PF::luminance( ored, ogreen, oblue );
101     float iL = data->get_lightness( irgb[0], irgb[1], irgb[2] );
102     float oL = data->get_lightness( ored, ogreen, oblue );
103     float Ldiff = oL - iL;
104 
105     // Luminosity blend: the color of the bottom layer is mixed with
106     // the luminance of the top one
107     //rgb[0] = irgb[0]; rgb[1] = irgb[1]; rgb[2] = irgb[2];
108     //PF::lc_blend( rgb[0], rgb[1], rgb[2], lumi );
109     rgb[0] = irgb[0] + Ldiff;
110     rgb[1] = irgb[1] + Ldiff;
111     rgb[2] = irgb[2] + Ldiff;
112 
113     // Clip out-of-bound values
114     float min = MIN3( rgb[0], rgb[1], rgb[2] );
115     float max = MAX3( rgb[0], rgb[1], rgb[2] );
116     if( min < FormatInfo<T>::MIN ) {
117       float lumi = data->get_lightness( rgb[0], rgb[1], rgb[2] );
118       float D = lumi - min;
119       rgb[0] = lumi + (((rgb[0] - lumi) * lumi) / D);
120       rgb[1] = lumi + (((rgb[1] - lumi) * lumi) / D);
121       rgb[2] = lumi + (((rgb[2] - lumi) * lumi) / D);
122     }
123     if( max > FormatInfo<T>::MAX ) {
124       float lumi = data->get_lightness( rgb[0], rgb[1], rgb[2] );
125       float d = max - lumi;
126       float D = FormatInfo<T>::MAX - min;
127       rgb[0] = lumi + (((rgb[0] - lumi) * D) / d);
128       rgb[1] = lumi + (((rgb[1] - lumi) * D) / d);
129       rgb[2] = lumi + (((rgb[2] - lumi) * D) / d);
130     }
131 
132     pos = x;
133     for( ch=CHMIN; ch<=CHMAX; ch++, pos++ ) {
134       out[pos] = (T)(( (rgb[ch]*opacity)+(irgb[ch]*(1.0f-opacity)) )*FormatInfo<T>::RANGE - FormatInfo<T>::MIN);
135     }
136   }
137 };
138 
139 template<typename T, int CHMIN, int CHMAX>
140 class BlendLuminosity<T, PF_COLORSPACE_RGB, CHMIN, CHMAX, true>:
141   public BlendBase<T, PF_COLORSPACE_RGB, CHMIN, CHMAX, true>
142 {
143   BlendLuminosity<T, PF_COLORSPACE_RGB, CHMIN, CHMAX, false> blender;
144   float opacity_real;
145   ICCProfile* data;
146 public:
set_icc_data(ICCProfile * d)147   void set_icc_data( ICCProfile* d ) { data = d; blender.set_icc_data(data); }
blend(const float & opacity,T * bottom,T * top,T * out,const int & x,int & xomap)148   void blend(const float& opacity, T* bottom, T* top, T* out, const int& x, int& xomap)
149   {
150     float opacity_real = opacity*(this->pmap[xomap]+FormatInfo<T>::MIN)/(FormatInfo<T>::RANGE);
151     xomap += 1;
152     blender.blend( opacity_real, bottom, top, out, x, xomap );
153   }
154 };
155 
156 
157 
158 
159 /*
160   Lab colorspace
161  */
162 template<typename T, int CHMIN, int CHMAX>
163 class BlendLuminosity<T, PF_COLORSPACE_LAB, CHMIN, CHMAX, false>:
164   public BlendBase<T, PF_COLORSPACE_LAB, CHMIN, CHMAX, false>
165 {
166   int pos, ch;
167   double temp_top;
168   double rgb[3];
169   ICCProfile* data;
170 public:
set_icc_data(ICCProfile * d)171   void set_icc_data( ICCProfile* d ) { data = d; }
blend(const float & opacity,T * bottom,T * top,T * out,const int & x,int &)172   void blend(const float& opacity, T* bottom, T* top, T* out, const int& x, int& /*xomap*/)
173   {
174     pos = x;
175     for( ch=CHMIN; ch<=0; ch++, pos++ )
176       out[pos] = static_cast<T>( opacity*top[pos]+(1.0f-opacity)*bottom[pos] );
177     for( ; ch<=CHMAX; ch++, pos++ )
178       out[pos] = bottom[pos];
179   }
180 };
181 
182 template<typename T, int CHMIN, int CHMAX>
183 class BlendLuminosity<T, PF_COLORSPACE_LAB, CHMIN, CHMAX, true>:
184   public BlendBase<T, PF_COLORSPACE_LAB, CHMIN, CHMAX, true>
185 {
186   BlendLuminosity<T, PF_COLORSPACE_LAB, CHMIN, CHMAX, false> blender;
187   float opacity_real;
188   ICCProfile* data;
189 public:
set_icc_data(ICCProfile * d)190   void set_icc_data( ICCProfile* d ) { data = d; blender.set_icc_data(data); }
blend(const float & opacity,T * bottom,T * top,T * out,const int & x,int & xomap)191   void blend(const float& opacity, T* bottom, T* top, T* out, const int& x, int& xomap)
192   {
193     float opacity_real = opacity*(this->pmap[xomap]+FormatInfo<T>::MIN)/(FormatInfo<T>::RANGE);
194     xomap += 1;
195     blender.blend( opacity_real, bottom, top, out, x, xomap );
196   }
197 };
198 
199 
200