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 #ifndef COLOR_CORRECTION_HH 31 #define COLOR_CORRECTION_HH 32 33 #include <string> 34 35 #include "../base/color.hh" 36 #include "../base/processor.hh" 37 38 namespace PF 39 { 40 41 class ColorCorrectionPar: public OpParBase 42 { 43 Property<float> offs, r_offs, g_offs, b_offs; 44 Property<float> slope, r_slope, g_slope, b_slope; 45 Property<float> pow, r_pow, g_pow, b_pow; 46 Property<float> saturation; 47 Property<bool> is_log; 48 49 ICCProfile* icc_data; 50 51 cmsHPROFILE lab_profile; 52 cmsHTRANSFORM transform, transform_inv; 53 54 public: 55 56 ColorCorrectionPar(); 57 ~ColorCorrectionPar(); 58 get_transform()59 cmsHTRANSFORM get_transform() { return transform; } get_transform_inv()60 cmsHTRANSFORM get_transform_inv() { return transform_inv; } 61 get_icc_data()62 ICCProfile* get_icc_data() { return icc_data; } 63 set_offset(float r,float g,float b)64 void set_offset(float r, float g, float b) {offs.set(0); r_offs.set(r); g_offs.set(g); b_offs.set(b);} get_r_offset()65 float get_r_offset() { return (offs.get() + r_offs.get()); } get_g_offset()66 float get_g_offset() { return (offs.get() + g_offs.get()); } get_b_offset()67 float get_b_offset() { return (offs.get() + b_offs.get()); } 68 //float get_r_slope() { return ((slope.get() + 1.0f) * (r_slope.get() + 1.0f)); } 69 //float get_g_slope() { return ((slope.get() + 1.0f) * (g_slope.get() + 1.0f)); } 70 //float get_b_slope() { return ((slope.get() + 1.0f) * (b_slope.get() + 1.0f)); } 71 //float get_r_power() { return ((1.0f - pow.get()) * (1.0f - r_pow.get())); } 72 //float get_g_power() { return ((1.0f - pow.get()) * (1.0f - g_pow.get())); } 73 //float get_b_power() { return ((1.0f - pow.get()) * (1.0f - b_pow.get())); } set_slope(float r,float g,float b)74 void set_slope(float r, float g, float b) {slope.set(1); r_slope.set(r); g_slope.set(g); b_slope.set(b);} get_r_slope()75 float get_r_slope() { return ((slope.get()) * (r_slope.get())); } get_g_slope()76 float get_g_slope() { return ((slope.get()) * (g_slope.get())); } get_b_slope()77 float get_b_slope() { return ((slope.get()) * (b_slope.get())); } set_power(float r,float g,float b)78 void set_power(float r, float g, float b) {pow.set(1); r_pow.set(r); g_pow.set(g); b_pow.set(b);} get_r_power()79 float get_r_power() { return ((pow.get()) * (r_pow.get())); } get_g_power()80 float get_g_power() { return ((pow.get()) * (g_pow.get())); } get_b_power()81 float get_b_power() { return ((pow.get()) * (b_pow.get())); } 82 set_saturation(float s)83 void set_saturation(float s) { saturation.set(s); } get_saturation()84 float get_saturation() { return saturation.get(); } 85 get_log_encoding()86 bool get_log_encoding() { return is_log.get(); } 87 has_intensity()88 bool has_intensity() { return false; } has_opacity()89 bool has_opacity() { return true; } needs_input()90 bool needs_input() { return true; } 91 92 VipsImage* build(std::vector<VipsImage*>& in, int first, 93 VipsImage* imap, VipsImage* omap, 94 unsigned int& level); 95 }; 96 97 98 99 template < OP_TEMPLATE_DEF > 100 class ColorCorrection 101 { 102 public: render(VipsRegion ** ireg,int n,int in_first,VipsRegion * imap,VipsRegion * omap,VipsRegion * oreg,OpParBase * par)103 void render(VipsRegion** ireg, int n, int in_first, 104 VipsRegion* imap, VipsRegion* omap, 105 VipsRegion* oreg, OpParBase* par) 106 { 107 } 108 }; 109 110 111 112 113 template < class BLENDER, int CHMIN, int CHMAX, bool has_imap, bool has_omap, bool PREVIEW > 114 class ColorCorrection< float, BLENDER, PF_COLORSPACE_RGB, CHMIN, CHMAX, has_imap, has_omap, PREVIEW > 115 { 116 public: render(VipsRegion ** ireg,int n,int in_first,VipsRegion * imap,VipsRegion * omap,VipsRegion * oreg,OpParBase * par)117 void render(VipsRegion** ireg, int n, int in_first, 118 VipsRegion* imap, VipsRegion* omap, 119 VipsRegion* oreg, OpParBase* par) 120 { 121 ColorCorrectionPar* opar = dynamic_cast<ColorCorrectionPar*>(par); 122 if( !opar ) return; 123 VipsRect *r = &oreg->valid; 124 int line_size = r->width * oreg->im->Bands; 125 //int width = r->width; 126 int height = r->height; 127 128 float* pin; 129 float* pout; 130 float* p; 131 float* q; 132 float RGB[3], L; 133 int x, y, k, i; 134 135 const float minus = -1.f; 136 137 /* Do the actual processing 138 */ 139 140 float r_offs = opar->get_r_offset(); 141 float g_offs = opar->get_g_offset(); 142 float b_offs = opar->get_b_offset(); 143 float r_slope = opar->get_r_slope(); 144 float g_slope = opar->get_g_slope(); 145 float b_slope = opar->get_b_slope(); 146 float r_pow = opar->get_r_power(); 147 float g_pow = opar->get_g_power(); 148 float b_pow = opar->get_b_power(); 149 float saturation = opar->get_saturation(); 150 bool is_log = opar->get_log_encoding(); 151 152 ICCProfile* profile = opar->get_icc_data(); 153 154 //for(int ti=0;ti<100;ti++) { 155 //if((ti%10)==0) std::cout<<"basic_adjustments: ti="<<ti<<" corner="<<r->left<<","<<r->top<<std::endl; 156 for( y = 0; y < height; y++ ) { 157 pin = (float*)VIPS_REGION_ADDR( ireg[0], r->left, r->top + y ); 158 pout = (float*)VIPS_REGION_ADDR( oreg, r->left, r->top + y ); 159 160 for( x = 0; x < line_size; x+=3 ) { 161 162 RGB[0] = pin[x]; 163 RGB[1] = pin[x+1]; 164 RGB[2] = pin[x+2]; 165 166 if( is_log ) { 167 RGB[0] = lin_to_ACEScc(RGB[0]); 168 RGB[1] = lin_to_ACEScc(RGB[1]); 169 RGB[2] = lin_to_ACEScc(RGB[2]); 170 } 171 172 RGB[0] *= r_slope; 173 RGB[1] *= g_slope; 174 RGB[2] *= b_slope; 175 176 RGB[0] += r_offs; 177 RGB[1] += g_offs; 178 RGB[2] += b_offs; 179 180 pout[x] = (RGB[0]<0) ? RGB[0] : powf(RGB[0], r_pow); 181 pout[x+1] = (RGB[1]<0) ? RGB[1] : powf(RGB[1], g_pow); 182 pout[x+2] = (RGB[2]<0) ? RGB[2] : powf(RGB[2], b_pow); 183 184 if( is_log ) { 185 pout[x] = ACEScc_to_lin(pout[x]); 186 pout[x+1] = ACEScc_to_lin(pout[x+1]); 187 pout[x+2] = ACEScc_to_lin(pout[x+2]); 188 } 189 190 if(profile && saturation != 1) { 191 L = profile->get_lightness(pout[x], pout[x+1], pout[x+2]); 192 pout[x] = L + saturation * (pout[x] - L); 193 pout[x+1] = L + saturation * (pout[x+1] - L); 194 pout[x+2] = L + saturation * (pout[x+2] - L); 195 } 196 } 197 } 198 } 199 }; 200 201 202 203 204 ProcessorBase* new_color_correction(); 205 } 206 207 #endif 208 209 210