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 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <fcntl.h>
33 
34 #include "../../operations/convertformat.hh"
35 #include "raw_preprocessor.hh"
36 #include "../../operations/ca_correct.hh"
37 #include "../../operations/amaze_demosaic.hh"
38 #include "../../operations/lmmse_demosaic.hh"
39 #include "../../operations/igv_demosaic.hh"
40 #include "../../operations/xtrans_demosaic.hh"
41 #include "../../operations/fast_demosaic.hh"
42 #include "../../operations/fast_demosaic_xtrans.hh"
43 #include "../../operations/false_color_correction.hh"
44 #include "raw_output.hh"
45 #include "../../operations/hotpixels.hh"
46 #include "../../operations/lensfun.hh"
47 
48 #include "raw_developer.hh"
49 
50 
RawDeveloperV1Par()51 PF::RawDeveloperV1Par::RawDeveloperV1Par():
52   OpParBase(), output_format( VIPS_FORMAT_NOTSET ),
53   lf_prop_camera_maker( "lf_camera_maker", this ),
54   lf_prop_camera_model( "lf_camera_model", this ),
55   lf_prop_lens( "lf_lens", this ),
56   enable_distortion( "lf_enable_distortion", this, false ),
57   enable_tca( "lf_enable_tca", this, false ),
58   enable_vignetting( "lf_enable_vignetting", this, false ),
59   enable_all( "lf_enable_all", this, false ),
60   tca_method("tca_method",this,PF::PF_TCA_CORR_PROFILED_AUTO,"TCA_CORR_PROFILED_AUTO",_("profiled + auto")),
61   demo_method("demo_method",this,PF::PF_DEMO_AMAZE,"AMAZE","Amaze"),
62 	fcs_steps("fcs_steps",this,0),
63 	caching_enabled( true )
64 {
65   tca_method.add_enum_value(PF::PF_TCA_CORR_AUTO,"TCA_CORR_AUTO",_("auto"));
66   tca_method.add_enum_value(PF::PF_TCA_CORR_PROFILED,"TCA_CORR_PROFILED",_("profiled"));
67   tca_method.add_enum_value(PF::PF_TCA_CORR_PROFILED_AUTO,"TCA_CORR_PROFILED_AUTO",_("profiled + auto"));
68   //tca_method.add_enum_value(PF::PF_TCA_CORR_MANUAL,"TCA_CORR_MANUAL",_("manual"));
69 
70   demo_method.add_enum_value(PF::PF_DEMO_AMAZE,"AMAZE","Amaze");
71   //demo_method.add_enum_value(PF::PF_DEMO_FAST,"FAST","Fast");
72   demo_method.add_enum_value(PF::PF_DEMO_LMMSE,"LMMSE","LMMSE");
73   demo_method.add_enum_value(PF::PF_DEMO_IGV,"IGV","Igv");
74 
75   amaze_demosaic = new_amaze_demosaic();
76   lmmse_demosaic = new_lmmse_demosaic();
77   igv_demosaic = new_igv_demosaic();
78   xtrans_demosaic = new_xtrans_demosaic();
79   fast_demosaic = new_fast_demosaic();
80   fast_demosaic_xtrans = new_fast_demosaic_xtrans();
81   FastDemosaicXTransPar* xtrans_par =
82       dynamic_cast<FastDemosaicXTransPar*>(fast_demosaic_xtrans->get_par());
83   if( xtrans_par ) xtrans_par->set_normalize( true );
84   raw_preprocessor = new_raw_preprocessor_v1();
85   ca_correct = new_ca_correct();
86   lensfun = new_lensfun();
87   raw_output = new_raw_output_v1();
88   hotpixels = new_hotpixels();
89   convert_format = new_convert_format();
90 	for(int ifcs = 0; ifcs < 4; ifcs++)
91 		fcs[ifcs] = new_false_color_correction();
92 
93   map_properties( raw_preprocessor->get_par()->get_properties() );
94   map_properties( ca_correct->get_par()->get_properties() );
95   map_properties( raw_output->get_par()->get_properties() );
96   map_properties( hotpixels->get_par()->get_properties() );
97 
98   set_type("raw_developer" );
99 
100   set_default_name( _("RAW developer") );
101 }
102 
103 
104 
get_wb_mode()105 PF::wb_mode_t PF::RawDeveloperV1Par::get_wb_mode()
106 {
107   PF::wb_mode_t result = PF::WB_CAMERA;
108   PF::RawPreprocessorV1Par* par = dynamic_cast<PF::RawPreprocessorV1Par*>( raw_preprocessor->get_par() );
109   if( par ) result = par->get_wb_mode();
110   return result;
111 }
112 
113 
set_wb(float r,float g,float b)114 void PF::RawDeveloperV1Par::set_wb(float r, float g, float b)
115 {
116   PF::RawPreprocessorV1Par* par = dynamic_cast<PF::RawPreprocessorV1Par*>( raw_preprocessor->get_par() );
117   if( par ) par->set_wb(r,g,b);
118 }
119 
get_hotp_fixed()120 int PF::RawDeveloperV1Par::get_hotp_fixed()
121 {
122   int result = 0;
123   PF::HotPixelsPar* par = dynamic_cast<PF::HotPixelsPar*>( hotpixels->get_par() );
124   if( par ) result = par->get_pixels_fixed();
125   return result;
126 }
127 
get_wb(float * mul)128 void PF::RawDeveloperV1Par::get_wb(float* mul)
129 {
130   PF::RawPreprocessorV1Par* par = dynamic_cast<PF::RawPreprocessorV1Par*>( raw_preprocessor->get_par() );
131   if( par ) {
132     mul[0] = par->get_wb_red();
133     mul[1] = par->get_wb_green();
134     mul[2] = par->get_wb_blue();
135   }
136 }
137 
138 
get_lf_maker()139 std::string PF::RawDeveloperV1Par::get_lf_maker()
140 {
141   std::string result;
142   LensFunPar* lfpar = dynamic_cast<LensFunPar*>( lensfun->get_par() );
143   if( !lfpar ) {
144     std::cout<<"RawDeveloperPar::build(): could not get LensFunPar object."<<std::endl;
145     return result;
146   }
147   return lfpar->camera_maker();
148 }
149 
150 
get_lf_model()151 std::string PF::RawDeveloperV1Par::get_lf_model()
152 {
153   std::string result;
154   LensFunPar* lfpar = dynamic_cast<LensFunPar*>( lensfun->get_par() );
155   if( !lfpar ) {
156     std::cout<<"RawDeveloperPar::build(): could not get LensFunPar object."<<std::endl;
157     return result;
158   }
159   return lfpar->camera_model();
160 }
161 
162 
get_lf_lens()163 std::string PF::RawDeveloperV1Par::get_lf_lens()
164 {
165   std::string result;
166   LensFunPar* lfpar = dynamic_cast<LensFunPar*>( lensfun->get_par() );
167   if( !lfpar ) {
168     std::cout<<"RawDeveloperPar::build(): could not get LensFunPar object."<<std::endl;
169     return result;
170   }
171   return lfpar->lens();
172 }
173 
174 
build(std::vector<VipsImage * > & in,int first,VipsImage * imap,VipsImage * omap,unsigned int & level)175 VipsImage* PF::RawDeveloperV1Par::build(std::vector<VipsImage*>& in, int first,
176 				     VipsImage* imap, VipsImage* omap,
177 				     unsigned int& level)
178 {
179   if( (in.size()<1) || (in[0]==NULL) )
180     return NULL;
181 
182   VipsImage* out_demo;
183   std::vector<VipsImage*> in2;
184 
185   size_t blobsz;
186   if( PF_VIPS_IMAGE_GET_BLOB( in[0], "raw_image_data", &image_data, &blobsz ) ) {
187     std::cout<<"RawDeveloperV1Par::build(): could not extract raw_image_data."<<std::endl;
188     return NULL;
189   }
190 	//std::cout<<"RawDeveloperV1Par::build(): blobsz="<<blobsz<<std::endl;
191   if( blobsz != sizeof(dcraw_data_t) ) {
192     std::cout<<"RawDeveloperV1Par::build(): wrong raw_image_data size."<<std::endl;
193     return NULL;
194   }
195 
196 
197   LensFunPar* lfpar = dynamic_cast<LensFunPar*>( lensfun->get_par() );
198   if( !lfpar ) {
199     std::cout<<"RawDeveloperPar::build(): could not get LensFunPar object."<<std::endl;
200     return NULL;
201   }
202   int lf_modflags = lfpar->get_flags( in[0] );
203 
204   VipsImage* input_img = in[0];
205   //std::cout<<"RawDeveloperV1Par::build(): input_img->Bands="<<input_img->Bands<<std::endl;
206   if( input_img->Bands != 3 ) {
207     raw_preprocessor->get_par()->set_image_hints( in[0] );
208     raw_preprocessor->get_par()->set_format( VIPS_FORMAT_FLOAT );
209     VipsImage* image = raw_preprocessor->get_par()->build( in, 0, NULL, NULL, level );
210     //VipsImage* image = in[0]; PF_REF( image, "");
211     if( !image )
212       return NULL;
213 
214     VipsImage* out_ca = NULL;
215     PF::ProcessorBase* demo = NULL;
216     if( PF::check_xtrans(image_data->idata.filters) ) {
217       out_ca = image;
218       //PF_REF( out_ca, "RawDeveloperV1Par::build(): in[0] ref for xtrans");
219       //demo = fast_demosaic_xtrans;
220       demo = xtrans_demosaic;
221     } else {
222       in2.push_back( image );
223       hotpixels->get_par()->set_image_hints( image );
224       hotpixels->get_par()->set_format( VIPS_FORMAT_FLOAT );
225       HotPixelsPar* hppar = dynamic_cast<HotPixelsPar*>( hotpixels->get_par() );
226       hppar->set_pixels_fixed( 0 );
227       VipsImage* out_hotp = hotpixels->get_par()->build( in2, 0, NULL, NULL, level );
228       g_object_unref( image );
229       //VipsImage* out_hotp = image;
230 
231       CACorrectPar* capar = dynamic_cast<CACorrectPar*>( ca_correct->get_par() );
232       if( !capar ) {
233         std::cout<<"RawDeveloperPar::build(): could not get CACorrectPar object."<<std::endl;
234         return NULL;
235       }
236 
237       capar->set_enable_ca( false );
238       capar->set_auto_ca( false );
239       if( enable_tca.get() || enable_all.get() ) {
240         switch(tca_method.get_enum_value().first) {
241         case PF::PF_TCA_CORR_AUTO:
242           capar->set_enable_ca( true );
243           capar->set_auto_ca( true );
244           break;
245         case PF::PF_TCA_CORR_PROFILED_AUTO:
246           if( (lf_modflags & LF_MODIFY_TCA) == 0) {
247             capar->set_enable_ca( true );
248             capar->set_auto_ca( true );
249           }
250           break;
251         case PF::PF_TCA_CORR_MANUAL:
252           capar->set_enable_ca( true );
253           capar->set_auto_ca( false );
254           break;
255         default:
256           break;
257         }
258       }
259 
260       in2.clear(); in2.push_back( out_hotp );
261       ca_correct->get_par()->set_image_hints( out_hotp );
262       ca_correct->get_par()->set_format( VIPS_FORMAT_FLOAT );
263       out_ca = ca_correct->get_par()->build( in2, 0, NULL, NULL, level );
264       g_object_unref( out_hotp );
265       //VipsImage* out_ca = out_hotp;
266 
267       switch( demo_method.get_enum_value().first ) {
268       case PF::PF_DEMO_FAST: demo = fast_demosaic; break;
269       case PF::PF_DEMO_AMAZE: demo = amaze_demosaic; break;
270       case PF::PF_DEMO_LMMSE: demo = lmmse_demosaic; break;
271       case PF::PF_DEMO_IGV: demo = igv_demosaic; break;
272       default: break;
273       }
274       //PF::ProcessorBase* demo = amaze_demosaic;
275       //PF::ProcessorBase* demo = igv_demosaic;
276       //PF::ProcessorBase* demo = fast_demosaic;
277     }
278     if( !demo ) return NULL;
279     in2.clear(); in2.push_back( out_ca );
280     demo->get_par()->set_image_hints( out_ca );
281     demo->get_par()->set_format( VIPS_FORMAT_FLOAT );
282     out_demo = demo->get_par()->build( in2, 0, NULL, NULL, level );
283     g_object_unref( out_ca );
284 
285     for(int ifcs = 0; ifcs < VIPS_MIN(fcs_steps.get(),4); ifcs++) {
286       VipsImage* temp = out_demo;
287       in2.clear(); in2.push_back( temp );
288       fcs[ifcs]->get_par()->set_image_hints( temp );
289 			fcs[ifcs]->get_par()->set_format( VIPS_FORMAT_FLOAT );
290 			out_demo = fcs[ifcs]->get_par()->build( in2, 0, NULL, NULL, level );
291 			PF_UNREF( temp, "RawDeveloperV1Par::build(): temp unref");
292 		}
293   } else {
294     raw_preprocessor->get_par()->set_image_hints( in[0] );
295     raw_preprocessor->get_par()->set_format( VIPS_FORMAT_FLOAT );
296     VipsImage* image = raw_preprocessor->get_par()->build( in, 0, NULL, NULL, level );
297     if( !image )
298       return NULL;
299 
300     out_demo = image;
301   }
302 
303   /**/
304   lensfun->get_par()->set_image_hints( out_demo );
305   lensfun->get_par()->set_format( VIPS_FORMAT_FLOAT );
306   lfpar->set_vignetting_enabled( enable_vignetting.get() || enable_all.get() );
307   lfpar->set_distortion_enabled( enable_distortion.get() || enable_all.get() );
308   lfpar->set_tca_enabled( false );
309   if( enable_tca.get() || enable_all.get() ) {
310     switch(tca_method.get_enum_value().first) {
311     case PF::PF_TCA_CORR_PROFILED:
312       lfpar->set_tca_enabled( true );
313       break;
314     case PF::PF_TCA_CORR_PROFILED_AUTO:
315       if( lf_modflags & LF_MODIFY_TCA )
316         lfpar->set_tca_enabled( true );
317       break;
318     default:
319       break;
320     }
321   }
322   in2.clear(); in2.push_back( out_demo );
323   VipsImage* out_lf = lensfun->get_par()->build( in2, 0, NULL, NULL, level );
324   g_object_unref( out_demo );
325 
326 
327   raw_output->get_par()->set_image_hints( out_lf );
328   raw_output->get_par()->set_format( VIPS_FORMAT_FLOAT );
329   RawPreprocessorV1Par* rppar = dynamic_cast<RawPreprocessorV1Par*>( raw_preprocessor->get_par() );
330   RawOutputV1Par* ropar = dynamic_cast<RawOutputV1Par*>( raw_output->get_par() );
331   if( rppar && ropar ) {
332     switch( rppar->get_wb_mode() ) {
333     case WB_SPOT:
334     case WB_COLOR_SPOT:
335       ropar->set_wb( rppar->get_wb_red(), rppar->get_wb_green(), rppar->get_wb_blue() );
336       break;
337     default:
338       ropar->set_wb( rppar->get_wb_red()*rppar->get_camwb_corr_red(),
339           rppar->get_wb_green()*rppar->get_camwb_corr_green(),
340           rppar->get_wb_blue()*rppar->get_camwb_corr_blue() );
341       break;
342     }
343   }
344 
345   in2.clear(); in2.push_back( out_lf );
346   VipsImage* out = raw_output->get_par()->build( in2, 0, NULL, NULL, level );
347   g_object_unref( out_lf );
348   /**/
349 
350   //VipsImage* gamma_in = out_demo;
351   VipsImage* gamma_in = out;
352   VipsImage* gamma = gamma_in;
353   /*
354   if( vips_gamma(gamma_in, &gamma, "exponent", (float)(2.2), NULL) ) {
355     g_object_unref(gamma_in);
356     return NULL;
357   }
358   */
359 
360   /*
361   void *data;
362   size_t data_length;
363   cmsHPROFILE profile_in;
364   if( gamma ) {
365     if( !vips_image_get_blob( gamma, VIPS_META_ICC_NAME,
366                               &data, &data_length ) ) {
367 
368       profile_in = cmsOpenProfileFromMem( data, data_length );
369       if( profile_in ) {
370         char tstr[1024];
371         cmsGetProfileInfoASCII(profile_in, cmsInfoDescription, "en", "US", tstr, 1024);
372         std::cout<<"RawDeveloperV1::build(): convert_format input profile: "<<tstr<<std::endl;
373         cmsCloseProfile( profile_in );
374       }
375     }
376   }
377   */
378 
379   VipsImage* out2;
380   std::vector<VipsImage*> in3;
381   in3.push_back( gamma );
382   convert_format->get_par()->set_image_hints( gamma );
383   convert_format->get_par()->set_format( get_format() );
384   out2 = convert_format->get_par()->build( in3, 0, NULL, NULL, level );
385   g_object_unref( gamma );
386 
387   set_image_hints( out2 );
388   /*
389   if( out2 ) {
390     if( !vips_image_get_blob( out2, VIPS_META_ICC_NAME,
391                               &data, &data_length ) ) {
392 
393       profile_in = cmsOpenProfileFromMem( data, data_length );
394       if( profile_in ) {
395         char tstr[1024];
396         cmsGetProfileInfoASCII(profile_in, cmsInfoDescription, "en", "US", tstr, 1024);
397         std::cout<<"RawDeveloperV1::build(): convert_format output profile: "<<tstr<<std::endl;
398         cmsCloseProfile( profile_in );
399       }
400     }
401   }
402   */
403 
404 //std::cout<<"RawDeveloperV1::build(): output image: "<<out2<<std::endl;
405   return out2;
406 }
407