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