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 "rawimagesource.hh"
31 
32 //#define RT_EMU
33 
RawImageSource()34 rtengine::RawImageSource::RawImageSource(): FC_roffset(0), FC_coffset(0), image_data(NULL), plistener(NULL)
35 {
36 }
37 
38 
39 
ca_correct(VipsRegion * ir,VipsRegion * oreg,bool autoCA,float cared,float cablue)40 void rtengine::RawImageSource::ca_correct(VipsRegion* ir, VipsRegion* oreg, bool autoCA, float cared, float cablue)
41 {
42   int x, y;
43   int border = 8;
44   int border2 = border*2;
45 
46   VipsRect *r = &oreg->valid;
47   int raw_left = (r->left/2)*2;
48   int raw_top = (r->top/2)*2;
49   int raw_right = r->left+r->width-1;
50   int raw_bottom = r->top+r->height-1;
51 
52   // Make sure the border is entirely processed
53   //if( raw_left < border ) raw_left = 0;
54   //if( raw_top < border ) raw_top = 0;
55   //if( raw_right > (ir->im->Xsize-border-1) ) raw_right = ir->im->Xsize-1;
56   //if( raw_bottom > (ir->im->Ysize-border-1) ) raw_bottom = ir->im->Ysize-1;
57 
58   // Portion of the image to be processed (pixels border is excluded)
59   VipsRect r_img = {border, border, ir->im->Xsize-border2, ir->im->Ysize-border2};
60   //std::cout<<"image: "<<ir->im->Xsize<<","<<ir->im->Ysize<<"+"<<0<<"+"<<0<<std::endl;
61   //std::cout<<"r_img: "<<r_img.width<<","<<r_img.height<<"+"<<r_img.left<<"+"<<r_img.top<<std::endl;
62   //VipsRect r_img = {0, 0, ir->im->Xsize, ir->im->Ysize};
63 
64   /*for(int i = 0; i < 3; i++) {
65     for(int j = 0; j < 2; j++) {
66       for(int k = 0; k < 16; k++) {
67         printf("%f ", fitparams[i][j][k]);
68       }
69       printf("\n");
70     }
71   }*/
72 
73   // Output region aligned to Bayer pattern and with pixels border excluded
74   VipsRect r_raw = {raw_left, raw_top, raw_right-raw_left+1, raw_bottom-raw_top+1};
75   if( (r_raw.width%2) ) r_raw.width += 1;
76   if( (r_raw.height%2) ) r_raw.height += 1;
77   //std::cout<<"r_raw(1): "<<r_raw.width<<","<<r_raw.height<<"+"<<r_raw.left<<"+"<<r_raw.top<<std::endl;
78   vips_rect_intersectrect (&r_raw, &r_img, &r_raw);
79   //std::cout<<"r_raw(2): "<<r_raw.width<<","<<r_raw.height<<"+"<<r_raw.left<<"+"<<r_raw.top<<std::endl;
80 
81 #ifndef NDEBUG
82   std::cout<<"RawImageSource::ca_correct(): rawData.init( "<<ir->valid.width<<", "<<ir->valid.height<<", "
83            <<ir->valid.top<<", "<<ir->valid.left<<" )"<<std::endl;
84 #endif
85 
86   // Initialization of pixel matrices
87   tile_top = ir->valid.top;
88   tile_left = ir->valid.left;
89   rawData.init( ir->valid.width, ir->valid.height, ir->valid.top, ir->valid.left, true );
90   for( y = 0; y < ir->valid.height; y++ ) {
91     PF::raw_pixel_t* ptr = ir ? (PF::raw_pixel_t*)VIPS_REGION_ADDR( ir, ir->valid.left, y+ir->valid.top ) : NULL;
92     //rawData.set_row( y+ir->valid.top, ptr );
93     if(ptr) {
94       PF::raw_pixel_t* optr = rawData[y+ir->valid.top].get_pixels() + ir->valid.left;
95       memcpy(optr, ptr, ir->valid.width*sizeof(PF::raw_pixel_t));
96     }
97   }
98   //return;
99   //red.Init( r_raw.width, r_raw.height, r_raw.top, r_raw.left );
100   //green.Init( r_raw.width, r_raw.height, r_raw.top, r_raw.left );
101   //blue.Init( r_raw.width, r_raw.height, r_raw.top, r_raw.left );
102 
103   // Call to demosaicing method
104   CA_correct_RT(0, 0, ir->im->Xsize, ir->im->Ysize,
105                     r_raw.left, r_raw.top, r_raw.width, r_raw.height,
106                     autoCA, cared, cablue);
107 
108   VipsRect r_out;
109   vips_rect_intersectrect (r, &r_img, &r_out);
110 
111   int xx;
112   for( y = 0; y < r_out.height; y++ ) {
113     //float* ptr = (float*)VIPS_REGION_ADDR( oreg, r_out.left, y+r_out.top );
114     PF::raw_pixel_t* ptr = (PF::raw_pixel_t*)VIPS_REGION_ADDR( oreg, r_out.left, y+r_out.top );
115     for( x = 0; x < r_out.width; x++ ) {
116       ptr[x][0] = rawData[y+r_out.top][x+r_out.left];
117       ptr[x][1] = rawData[y+r_out.top].color(x+r_out.left);
118 /*
119 #ifdef RT_EMU
120       // RawTherapee emulation
121       ptr[x*3] = CLAMP( red[y+r_out.top][x+r_out.left]/65535, 0, 95 );
122       ptr[x*3+1] = CLAMP( green[y+r_out.top][x+r_out.left]/65535, 0, 95 );
123       ptr[x*3+2] = CLAMP( blue[y+r_out.top][x+r_out.left]/65535, 0, 95 );
124 #else
125       ptr[xx] = CLAMP( red[y+r_out.top][x+r_out.left], 0, 1 );
126       ptr[xx+1] = CLAMP( green[y+r_out.top][x+r_out.left], 0, 1 );
127       ptr[xx+2] = CLAMP( blue[y+r_out.top][x+r_out.left], 0, 1 );
128 #endif
129 */
130     }
131   }
132 }
133 
134 
135 
no_demosaic(VipsRegion * ir,VipsRegion * oreg)136 void rtengine::RawImageSource::no_demosaic(VipsRegion* ir, VipsRegion* oreg)
137 {
138   int x, xx, y;
139   VipsRect *r = &oreg->valid;
140   // Initialization of pixel matrices
141   for( y = 0; y < r->height; y++ ) {
142     PF::raw_pixel_t* ptr = ir ? (PF::raw_pixel_t*)VIPS_REGION_ADDR( ir, r->left, y+r->top ) : NULL;
143     float* optr = (float*)VIPS_REGION_ADDR( oreg, r->left, y+r->top );
144     for( x = 0, xx = 0; x < r->width; x++, xx+=3 ) {
145       optr[xx] = ptr[x][0];
146       optr[xx+1] = ptr[x][0];
147       optr[xx+2] = ptr[x][0];
148     }
149   }
150 }
151 
152 
153 
154 
155 
156 
amaze_demosaic(VipsRegion * ir,VipsRegion * oreg)157 void rtengine::RawImageSource::amaze_demosaic(VipsRegion* ir, VipsRegion* oreg)
158 {
159   int x, y;
160   int border = 16;
161 
162   VipsRect *r = &oreg->valid;
163   int raw_left = (r->left/2)*2;
164   int raw_top = (r->top/2)*2;
165   int raw_right = r->left+r->width-1;
166   int raw_bottom = r->top+r->height-1;
167 
168   // Make sure the border is entirely processed
169   //if( raw_left < border ) raw_left = 0;
170   //if( raw_top < border ) raw_top = 0;
171   //if( raw_right > (ir->im->Xsize-border-1) ) raw_right = ir->im->Xsize-1;
172   //if( raw_bottom > (ir->im->Ysize-border-1) ) raw_bottom = ir->im->Ysize-1;
173 
174   // Portion of the image to be processed (a 16 pixels border is excluded)
175   VipsRect r_img = {16, 16, ir->im->Xsize-32, ir->im->Ysize-32};
176   //std::cout<<"image: "<<ir->im->Xsize<<","<<ir->im->Ysize<<"+"<<0<<"+"<<0<<std::endl;
177   //std::cout<<"r_img: "<<r_img.width<<","<<r_img.height<<"+"<<r_img.left<<"+"<<r_img.top<<std::endl;
178   //VipsRect r_img = {0, 0, ir->im->Xsize, ir->im->Ysize};
179 
180   // Output region aligned to Bayer pattern and with 16 pixels border excluded
181   VipsRect r_raw = {raw_left, raw_top, raw_right-raw_left+1, raw_bottom-raw_top+1};
182   if( (r_raw.width%2) ) r_raw.width += 1;
183   if( (r_raw.height%2) ) r_raw.height += 1;
184   //std::cout<<"r_raw(1): "<<r_raw.width<<","<<r_raw.height<<"+"<<r_raw.left<<"+"<<r_raw.top<<std::endl;
185   vips_rect_intersectrect (&r_raw, &r_img, &r_raw);
186   //std::cout<<"r_raw(2): "<<r_raw.width<<","<<r_raw.height<<"+"<<r_raw.left<<"+"<<r_raw.top<<std::endl;
187 
188 #ifndef NDEBUG
189   std::cout<<"rawData.init( "<<ir->valid.width<<", "<<ir->valid.height<<", "
190            <<ir->valid.top<<", "<<ir->valid.left<<" )"<<std::endl;
191 
192   {
193   float* p = (float*)VIPS_REGION_ADDR( ir, ir->valid.top, ir->valid.left );
194   std::cout<<"top= "<<ir->valid.top<<std::endl;
195   std::cout<<"left="<<ir->valid.left<<std::endl;
196   std::cout<<"p[0]="<<p[0]<<std::endl;
197   std::cout<<"p[1]="<<p[1]<<std::endl;
198   std::cout<<"p[2]="<<p[2]<<std::endl;
199   std::cout<<"p[3]="<<p[3]<<std::endl;
200   }
201 #endif
202 
203   // Initialization of pixel matrices
204   tile_top = ir->valid.top;
205   tile_left = ir->valid.left;
206   rawData.init( ir->valid.width, ir->valid.height, ir->valid.top, ir->valid.left );
207   for( y = 0; y < ir->valid.height; y++ ) {
208     PF::raw_pixel_t* ptr = ir ? (PF::raw_pixel_t*)VIPS_REGION_ADDR( ir, ir->valid.left, y+ir->valid.top ) : NULL;
209     rawData.set_row( y+ir->valid.top, ptr );
210   }
211   red.Init( r_raw.width, r_raw.height, r_raw.top, r_raw.left );
212   green.Init( r_raw.width, r_raw.height, r_raw.top, r_raw.left );
213   blue.Init( r_raw.width, r_raw.height, r_raw.top, r_raw.left );
214 
215   // Call to demosaicing method
216   amaze_demosaic_RT(0, 0, ir->im->Xsize, ir->im->Ysize,
217                     r_raw.left, r_raw.top, r_raw.width, r_raw.height);
218 
219   VipsRect r_out;
220   vips_rect_intersectrect (r, &r_img, &r_out);
221 
222   int xx;
223   for( y = 0; y < r_out.height; y++ ) {
224     float* ptr = (float*)VIPS_REGION_ADDR( oreg, r_out.left, y+r_out.top );
225     for( x = 0, xx = 0; x < r_out.width; x++, xx+=3 ) {
226 #ifdef RT_EMU
227       /* RawTherapee emulation */
228       ptr[x*3] = CLAMP( red[y+r_out.top][x+r_out.left]/65535, 0, 95 );
229       ptr[x*3+1] = CLAMP( green[y+r_out.top][x+r_out.left]/65535, 0, 95 );
230       ptr[x*3+2] = CLAMP( blue[y+r_out.top][x+r_out.left]/65535, 0, 95 );
231 #else
232       ptr[xx] = CLAMP( red[y+r_out.top][x+r_out.left], 0, 1 );
233       ptr[xx+1] = CLAMP( green[y+r_out.top][x+r_out.left], 0, 1 );
234       ptr[xx+2] = CLAMP( blue[y+r_out.top][x+r_out.left], 0, 1 );
235 #endif
236     }
237   }
238 }
239 
240 
241 
rcd_demosaic(VipsRegion * ir,VipsRegion * oreg)242 void rtengine::RawImageSource::rcd_demosaic(VipsRegion* ir, VipsRegion* oreg)
243 {
244   int x, y;
245   int border = 8;
246 
247   VipsRect *r = &oreg->valid;
248   int raw_left = (r->left/2)*2;
249   int raw_top = (r->top/2)*2;
250   int raw_right = r->left+r->width-1;
251   int raw_bottom = r->top+r->height-1;
252 
253   // Make sure the border is entirely processed
254   //if( raw_left < border ) raw_left = 0;
255   //if( raw_top < border ) raw_top = 0;
256   //if( raw_right > (ir->im->Xsize-border-1) ) raw_right = ir->im->Xsize-1;
257   //if( raw_bottom > (ir->im->Ysize-border-1) ) raw_bottom = ir->im->Ysize-1;
258 
259   // Portion of the image to be processed (a 16 pixels border is excluded)
260   VipsRect r_img = {border, border, ir->im->Xsize-border*2, ir->im->Ysize-border*2};
261   //std::cout<<"image: "<<ir->im->Xsize<<","<<ir->im->Ysize<<"+"<<0<<"+"<<0<<std::endl;
262   //std::cout<<"r_img: "<<r_img.width<<","<<r_img.height<<"+"<<r_img.left<<"+"<<r_img.top<<std::endl;
263   //VipsRect r_img = {0, 0, ir->im->Xsize, ir->im->Ysize};
264 
265   // Output region aligned to Bayer pattern and with 16 pixels border excluded
266   VipsRect r_raw = {raw_left, raw_top, raw_right-raw_left+1, raw_bottom-raw_top+1};
267   if( (r_raw.width%2) ) r_raw.width += 1;
268   if( (r_raw.height%2) ) r_raw.height += 1;
269   //std::cout<<"r_raw(1): "<<r_raw.width<<","<<r_raw.height<<"+"<<r_raw.left<<"+"<<r_raw.top<<std::endl;
270   vips_rect_intersectrect (&r_raw, &r_img, &r_raw);
271   //std::cout<<"r_raw(2): "<<r_raw.width<<","<<r_raw.height<<"+"<<r_raw.left<<"+"<<r_raw.top<<std::endl;
272 
273 #ifndef NDEBUG
274   std::cout<<"rcd_demosaic(): rawData.init( "<<ir->valid.width<<", "<<ir->valid.height<<", "
275            <<ir->valid.top<<", "<<ir->valid.left<<" )"<<std::endl;
276 #endif
277 
278   // Initialization of pixel matrices
279   tile_top = ir->valid.top;
280   tile_left = ir->valid.left;
281   rawData.init( ir->valid.width, ir->valid.height, ir->valid.top, ir->valid.left );
282   for( y = 0; y < ir->valid.height; y++ ) {
283     PF::raw_pixel_t* ptr = ir ? (PF::raw_pixel_t*)VIPS_REGION_ADDR( ir, ir->valid.left, y+ir->valid.top ) : NULL;
284     rawData.set_row( y+ir->valid.top, ptr );
285   }
286   red.Init( r_raw.width, r_raw.height, r_raw.top, r_raw.left );
287   green.Init( r_raw.width, r_raw.height, r_raw.top, r_raw.left );
288   blue.Init( r_raw.width, r_raw.height, r_raw.top, r_raw.left );
289 
290   // Call to demosaicing method
291   rcd_demosaic_RT(0, 0, ir->im->Xsize, ir->im->Ysize,
292       ir->valid.left, ir->valid.top, ir->valid.width, ir->valid.height);
293 
294   VipsRect r_out;
295   vips_rect_intersectrect (r, &r_img, &r_out);
296 
297   int xx;
298   for( y = 0; y < r_out.height; y++ ) {
299     float* ptr = (float*)VIPS_REGION_ADDR( oreg, r_out.left, y+r_out.top );
300     for( x = 0, xx = 0; x < r_out.width; x++, xx+=3 ) {
301 #ifdef RT_EMU
302       /* RawTherapee emulation */
303       ptr[x*3] = CLAMP( red[y+r_out.top][x+r_out.left]/65535, 0, 95 );
304       ptr[x*3+1] = CLAMP( green[y+r_out.top][x+r_out.left]/65535, 0, 95 );
305       ptr[x*3+2] = CLAMP( blue[y+r_out.top][x+r_out.left]/65535, 0, 95 );
306 #else
307       ptr[xx] = CLAMP( red[y+r_out.top][x+r_out.left], 0, 1 );
308       ptr[xx+1] = CLAMP( green[y+r_out.top][x+r_out.left], 0, 1 );
309       ptr[xx+2] = CLAMP( blue[y+r_out.top][x+r_out.left], 0, 1 );
310 #endif
311     }
312   }
313 }
314 
315 
316 
lmmse_demosaic(VipsRegion * ir,VipsRegion * oreg)317 void rtengine::RawImageSource::lmmse_demosaic(VipsRegion* ir, VipsRegion* oreg)
318 {
319   int x, y;
320   int padding = 10;
321 
322   VipsRect *r = &oreg->valid;
323   int raw_left = (r->left/2)*2;
324   int raw_top = (r->top/2)*2;
325   int raw_right = r->left+r->width-1;
326   int raw_bottom = r->top+r->height-1;
327 
328   // Make sure the border is entirely processed
329   //if( raw_left < border ) raw_left = 0;
330   //if( raw_top < border ) raw_top = 0;
331   //if( raw_right > (ir->im->Xsize-border-1) ) raw_right = ir->im->Xsize-1;
332   //if( raw_bottom > (ir->im->Ysize-border-1) ) raw_bottom = ir->im->Ysize-1;
333 
334   // Portion of the image to be processed (a 10 pixels border is excluded)
335   VipsRect r_img = {padding, padding, ir->im->Xsize-padding*2, ir->im->Ysize-padding*2};
336   //std::cout<<"image: "<<ir->im->Xsize<<","<<ir->im->Ysize<<"+"<<0<<"+"<<0<<std::endl;
337   //std::cout<<"r_img: "<<r_img.width<<","<<r_img.height<<"+"<<r_img.left<<"+"<<r_img.top<<std::endl;
338   //VipsRect r_img = {0, 0, ir->im->Xsize, ir->im->Ysize};
339 
340   // Output region aligned to Bayer pattern and with 16 pixels border excluded
341   VipsRect r_raw = {raw_left, raw_top, raw_right-raw_left+1, raw_bottom-raw_top+1};
342   if( (r_raw.width%2) ) r_raw.width += 1;
343   if( (r_raw.height%2) ) r_raw.height += 1;
344   //std::cout<<"r_raw(1): "<<r_raw.width<<","<<r_raw.height<<"+"<<r_raw.left<<"+"<<r_raw.top<<std::endl;
345   vips_rect_intersectrect (&r_raw, &r_img, &r_raw);
346   //std::cout<<"r_raw(2): "<<r_raw.width<<","<<r_raw.height<<"+"<<r_raw.left<<"+"<<r_raw.top<<std::endl;
347 
348 #ifndef NDEBUG
349   std::cout<<"rawData.init( "<<ir->valid.width<<", "<<ir->valid.height<<", "
350            <<ir->valid.top<<", "<<ir->valid.left<<" )"<<std::endl;
351 #endif
352 
353   // Initialization of pixel matrices
354   tile_top = ir->valid.top;
355   tile_left = ir->valid.left;
356   rawData.init( ir->valid.width, ir->valid.height, ir->valid.top, ir->valid.left );
357   for( y = 0; y < ir->valid.height; y++ ) {
358     PF::raw_pixel_t* ptr = ir ? (PF::raw_pixel_t*)VIPS_REGION_ADDR( ir, ir->valid.left, y+ir->valid.top ) : NULL;
359     rawData.set_row( y+ir->valid.top, ptr );
360   }
361   red.Init( r_raw.width, r_raw.height, r_raw.top, r_raw.left );
362   green.Init( r_raw.width, r_raw.height, r_raw.top, r_raw.left );
363   blue.Init( r_raw.width, r_raw.height, r_raw.top, r_raw.left );
364 
365   // Call to demosaicing method
366   lmmse_demosaic_RT(0, 0, ir->im->Xsize, ir->im->Ysize,
367                     r_raw.left, r_raw.top, r_raw.width, r_raw.height, 0);
368 
369   VipsRect r_out;
370   vips_rect_intersectrect (r, &r_img, &r_out);
371 
372   int xx;
373   for( y = 0; y < r_out.height; y++ ) {
374     float* ptr = (float*)VIPS_REGION_ADDR( oreg, r_out.left, y+r_out.top );
375     for( x = 0, xx = 0; x < r_out.width; x++, xx+=3 ) {
376 #ifdef RT_EMU
377       /* RawTherapee emulation */
378       ptr[x*3] = CLAMP( red[y+r_out.top][x+r_out.left]/65535, 0, 95 );
379       ptr[x*3+1] = CLAMP( green[y+r_out.top][x+r_out.left]/65535, 0, 95 );
380       ptr[x*3+2] = CLAMP( blue[y+r_out.top][x+r_out.left]/65535, 0, 95 );
381 #else
382       ptr[xx] = CLAMP( red[y+r_out.top][x+r_out.left], 0, 1 );
383       ptr[xx+1] = CLAMP( green[y+r_out.top][x+r_out.left], 0, 1 );
384       ptr[xx+2] = CLAMP( blue[y+r_out.top][x+r_out.left], 0, 1 );
385 #endif
386     }
387   }
388 }
389 
390 
391 
igv_demosaic(VipsRegion * ir,VipsRegion * oreg)392 void rtengine::RawImageSource::igv_demosaic(VipsRegion* ir, VipsRegion* oreg)
393 {
394 	int x, y;
395 
396   VipsRect *r = &oreg->valid;
397 
398 	// Portion of the image to be processed (a 16 pixels border is excluded)
399   VipsRect r_img = {7, 7, ir->im->Xsize-14, ir->im->Ysize-14};
400 
401 	// Initialization of pixel matrices
402 	tile_top = ir->valid.top;
403 	tile_left = ir->valid.left;
404   rawData.init( ir->valid.width, ir->valid.height, ir->valid.top, ir->valid.left );
405   for( y = 0; y < ir->valid.height; y++ ) {
406     PF::raw_pixel_t* ptr = ir ? (PF::raw_pixel_t*)VIPS_REGION_ADDR( ir, ir->valid.left, y+ir->valid.top ) : NULL;
407     rawData.set_row( y+ir->valid.top, ptr );
408   }
409   red.Init( ir->valid.width, ir->valid.height, ir->valid.top, ir->valid.left );
410   green.Init( ir->valid.width, ir->valid.height, ir->valid.top, ir->valid.left );
411   blue.Init( ir->valid.width, ir->valid.height, ir->valid.top, ir->valid.left );
412 
413 	// Call to demosaicing method
414 	igv_demosaic_RT(0, 0, ir->im->Xsize, ir->im->Ysize,
415 									ir->valid.left, ir->valid.top, ir->valid.width, ir->valid.height);
416 
417   VipsRect r_out;
418   vips_rect_intersectrect (r, &r_img, &r_out);
419 
420   int xx;
421   for( y = 0; y < r_out.height; y++ ) {
422     float* ptr = (float*)VIPS_REGION_ADDR( oreg, r_out.left, y+r_out.top );
423     for( x = 0, xx = 0; x < r_out.width; x++, xx+=3 ) {
424 #ifdef RT_EMU
425       /* RawTherapee emulation */
426       ptr[x*3] = red[y+r_out.top][x+r_out.left]/65535;
427       ptr[x*3+1] = green[y+r_out.top][x+r_out.left]/65535;
428       ptr[x*3+2] = blue[y+r_out.top][x+r_out.left]/65535;
429 #else
430       ptr[xx] = CLAMP( red[y+r_out.top][x+r_out.left], 0, 1 );
431       ptr[xx+1] = CLAMP( green[y+r_out.top][x+r_out.left], 0, 1 );
432       ptr[xx+2] = CLAMP( blue[y+r_out.top][x+r_out.left], 0, 1 );
433 #endif
434     }
435   }
436 }
437 
438 
439 
xtrans_demosaic(VipsRegion * ir,VipsRegion * oreg)440 void rtengine::RawImageSource::xtrans_demosaic(VipsRegion* ir, VipsRegion* oreg)
441 {
442   int x, y;
443   int border = 12;
444 
445   VipsRect *r = &oreg->valid;
446   int raw_left = (r->left/2)*2;
447   int raw_top = (r->top/2)*2;
448   int raw_right = r->left+r->width-1;
449   int raw_bottom = r->top+r->height-1;
450 
451   // Make sure the border is entirely processed
452   //if( raw_left < border ) raw_left = 0;
453   //if( raw_top < border ) raw_top = 0;
454   //if( raw_right > (ir->im->Xsize-border-1) ) raw_right = ir->im->Xsize-1;
455   //if( raw_bottom > (ir->im->Ysize-border-1) ) raw_bottom = ir->im->Ysize-1;
456 
457   // Portion of the image to be processed (a 16 pixels border is excluded)
458   VipsRect r_img = {border, border, ir->im->Xsize-border*2, ir->im->Ysize-border*2};
459   //std::cout<<"image: "<<ir->im->Xsize<<","<<ir->im->Ysize<<"+"<<0<<"+"<<0<<std::endl;
460   //std::cout<<"r_img: "<<r_img.width<<","<<r_img.height<<"+"<<r_img.left<<"+"<<r_img.top<<std::endl;
461   //VipsRect r_img = {0, 0, ir->im->Xsize, ir->im->Ysize};
462 
463   // Output region aligned to Bayer pattern and with 16 pixels border excluded
464   VipsRect r_raw = {raw_left, raw_top, raw_right-raw_left+1, raw_bottom-raw_top+1};
465   if( (r_raw.width%2) ) r_raw.width += 1;
466   if( (r_raw.height%2) ) r_raw.height += 1;
467   //std::cout<<"r_raw(1): "<<r_raw.width<<","<<r_raw.height<<"+"<<r_raw.left<<"+"<<r_raw.top<<std::endl;
468   vips_rect_intersectrect (&r_raw, &r_img, &r_raw);
469   //std::cout<<"r_raw(2): "<<r_raw.width<<","<<r_raw.height<<"+"<<r_raw.left<<"+"<<r_raw.top<<std::endl;
470 
471 #ifndef NDEBUG
472   std::cout<<"X-trans demosaicing: rawData.init( "<<ir->valid.width<<", "<<ir->valid.height<<", "
473            <<ir->valid.top<<", "<<ir->valid.left<<" )"<<std::endl;
474 #endif
475 
476   // Initialization of pixel matrices
477   tile_top = ir->valid.top;
478   tile_left = ir->valid.left;
479   rawData.init( ir->valid.width, ir->valid.height, 0, 0 /*ir->valid.top, ir->valid.left*/ );
480   rawDataBuf = (float**)malloc( ir->valid.height * sizeof(float*) );
481   float* tempBuf = (float*)malloc( ir->valid.width * ir->valid.height * sizeof(float) );
482   for( y = 0; y < ir->valid.height; y++ ) {
483     PF::raw_pixel_t* ptr = ir ? (PF::raw_pixel_t*)VIPS_REGION_ADDR( ir, ir->valid.left, y+ir->valid.top ) : NULL;
484     rawData.set_row( y/*+ir->valid.top*/, ptr );
485   }
486 
487   float* bufptr = tempBuf;
488   for( y = 0; y < ir->valid.height; y++ ) {
489     rawDataBuf[y] = bufptr;
490     for( x = 0; x < ir->valid.width; x++ ) {
491       *bufptr = rawData[y][x]; bufptr++;
492     }
493   }
494 
495   //red.Init( r_raw.width, r_raw.height, 8, 8 /*r_raw.top, r_raw.left*/ );
496   //green.Init( r_raw.width, r_raw.height, 8, 8 /*r_raw.top, r_raw.left*/ );
497   //blue.Init( r_raw.width, r_raw.height, 8, 8 /*r_raw.top, r_raw.left*/ );
498   red.Init( ir->valid.width, ir->valid.height, 0, 0 );
499   green.Init( ir->valid.width, ir->valid.height, 0, 0 );
500   blue.Init( ir->valid.width, ir->valid.height, 0, 0 );
501 
502   // Call to demosaicing method
503   xtrans_demosaic_RT(ir->valid.left, ir->valid.top, ir->valid.width, ir->valid.height,
504                     r_raw.left, r_raw.top, r_raw.width, r_raw.height);
505 
506   free( rawDataBuf );
507   free( tempBuf );
508 
509   VipsRect r_out;
510   vips_rect_intersectrect (r, &r_img, &r_out);
511   //std::cout<<"r_out: "<<r_out.width<<","<<r_out.height<<"+"<<r_out.left<<"+"<<r_out.top<<std::endl;
512 
513   int xx;
514   for( y = 0; y < r_out.height; y++ ) {
515     float* ptr = (float*)VIPS_REGION_ADDR( oreg, r_out.left, y+r_out.top );
516     for( x = 0, xx = 0; x < r_out.width; x++, xx+=3 ) {
517 #ifdef RT_EMU
518       /* RawTherapee emulation */
519       ptr[x*3] = CLAMP( red[y+border][x+border]/65535, 0, 95 );
520       ptr[x*3+1] = CLAMP( green[y+border][x+border]/65535, 0, 95 );
521       ptr[x*3+2] = CLAMP( blue[y+border][x+border]/65535, 0, 95 );
522 #else
523       //ptr[xx] = CLAMP( red[y+r_out.top][x+r_out.left], 0, 1 );
524       //ptr[xx+1] = CLAMP( green[y+r_out.top][x+r_out.left], 0, 1 );
525       //ptr[xx+2] = CLAMP( blue[y+r_out.top][x+r_out.left], 0, 1 );
526       ptr[xx] = CLAMP( red[y+border][x+border], 0, 1 );
527       ptr[xx+1] = CLAMP( green[y+border][x+border], 0, 1 );
528       ptr[xx+2] = CLAMP( blue[y+border][x+border], 0, 1 );
529 #endif
530     }
531   }
532 }
533 
534 
535 
536