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 PF_PIXEL_PROCESSOR__H
31 #define PF_PIXEL_PROCESSOR__H
32 
33 #include <iostream>
34 
35 //#include "processor.hh"
36 //#include "layer.hh"
37 #include "operation.hh"
38 #include "color.hh"
39 
40 namespace PF
41 {
42 
43 #define PIXELPROC_TEMPLATE_DEF                  \
44   typename T_, colorspace_t CS_,                  \
45     int CHMIN_, int CHMAX_,                       \
46     bool PREVIEW_, typename OP_PAR_
47 
48 #define PIXELPROC_TEMPLATE_IMP                  \
49   T, CS, CHMIN, CHMAX, PREVIEW, OP_PAR
50 
51 
52 #define PIXELPROC_TEMPLATE_DEF_CS_SPEC                  \
53   typename T_,                                           \
54     int CHMIN_, int CHMAX_,                               \
55     bool PREVIEW_, typename OP_PAR_
56 
57 #define PIXELPROC_TEMPLATE_IMP_CS_SPEC(CS_SPEC) \
58   T, CS_SPEC, CHMIN, CHMAX, PREVIEW, OP_PAR
59 
60 
61 
62   class PixelProcessorPar: public OpParBase
63   {
64     Property<float> color_blend;
65 
66   public:
PixelProcessorPar()67     PixelProcessorPar():
68       OpParBase(),
69       color_blend("color_blend",this,0)
70     {
71     }
has_imap()72     bool has_imap() { return false; }
has_omap()73     bool has_omap() { return false; }
needs_input()74     bool needs_input() { return true; }
75 
get_color_blend()76     float get_color_blend() { return( color_blend.get() ); }
77   };
78 
79 
80 
81 
82 
83 
84   template < OP_TEMPLATE_DEF, class OP_PAR, template < PIXELPROC_TEMPLATE_DEF > class PEL_PROC >
85   class PixelProcessor: public IntensityProc<T, has_imap>
86   {
87     typedef OP_PAR OpParams;
88   public:
render(VipsRegion ** ir,int n,int in_first,VipsRegion * imap,VipsRegion *,VipsRegion * oreg,OP_PAR * par)89     void render(VipsRegion** ir, int n, int in_first,
90                 VipsRegion* imap, VipsRegion* ,
91                 VipsRegion* oreg, OP_PAR* par)
92     {
93       PEL_PROC<PIXELPROC_TEMPLATE_IMP> proc(par);
94 
95       float intensity = par->get_intensity();
96       float blend = par->get_color_blend();
97       float nblend = -1.0f * blend;
98       VipsRect *r = &oreg->valid;
99       int sz = oreg->im->Bands;//IM_REGION_N_ELEMENTS( oreg );
100       int line_size = r->width * oreg->im->Bands; //layer->in_all[0]->Bands;
101 
102 #ifdef _NDEBUG
103       std::cout<<"PixelProcessor::render(): "<<std::endl
104                <<"  name: "<<par->get_config_ui()->get_layer()->get_name()<<std::endl
105                <<"  input region:  top="<<ir[in_first]->valid.top
106                <<" left="<<ir[in_first]->valid.left
107                <<" width="<<ir[in_first]->valid.width
108                <<" height="<<ir[in_first]->valid.height<<std::endl
109                <<"  output region: top="<<oreg->valid.top
110                <<" left="<<oreg->valid.left
111                <<" width="<<oreg->valid.width
112                <<" height="<<oreg->valid.height<<std::endl;
113 #endif
114 
115       const int NMAX = 100;
116       const int nch = oreg->im->Bands;
117       T* p[NMAX+1];
118       T* pout;
119       T* pimap;
120 
121       if(n > NMAX) n = NMAX;
122 
123       int x, y, ch, dx=CHMAX-CHMIN+1;//, CHMAXplus1=CHMAX+1;
124       int ximap, ni;
125 
126       //std::cout<<"PixelProcessor::render(): CHMIN="<<CHMIN<<"  CHMAX="<<CHMAX
127       //    <<"PF::ColorspaceInfo<CS>::NCH="<<PF::ColorspaceInfo<CS>::NCH<<std::endl;
128 
129       for( y = 0; y < r->height; y++ ) {
130 
131         for( ni = 0; ni < n; ni++)
132           p[ni] = (T*)VIPS_REGION_ADDR( ir[ni], r->left, r->top + y );
133         pout = (T*)VIPS_REGION_ADDR( oreg, r->left, r->top + y );
134         if(has_imap) pimap = (T*)VIPS_REGION_ADDR( imap, r->left, r->top + y );
135 
136         for( x=0, ximap=0; x < line_size; ) {
137           float intensity_real = this->get_intensity( intensity, pimap, ximap );
138           for( ch=0; ch<CHMIN; ch++, x++ ) pout[x] = p[0][x];
139           proc.process( p, n, in_first, sz, x, intensity_real/*get_intensity( intensity, pimap, ximap )*/, pout );
140           x += dx;
141           //for( ch=CHMAX+1; ch<PF::ColorspaceInfo<CS>::NCH; ch++, x++ ) pout[x] = p[0][x];
142           for( ch=CHMAX+1; ch<nch; ch++, x++ ) pout[x] = p[0][x];
143           //for( ch=0; ch<PF::ColorspaceInfo<CS>::NCH; ch++, x++ ) pout[x] = p[0][x];
144         }
145         if( CS != PF_COLORSPACE_RGB || blend == 0 ) continue;
146 
147         if( blend > 0 ) {
148           // Blend the output luminance with the input colors
149           // Preserves the color information of the input image
150           // Equivalent to the "luminosity blend" in photoshop
151           double ired, ig, ib;
152           double ored, og, ob;
153           double ored2, og2, ob2;
154           for( x=0, ximap=0; x < line_size; ) {
155             ored = (double(pout[x]) + FormatInfo<T>::MIN)/FormatInfo<T>::RANGE;
156             og = (double(pout[x+1]) + FormatInfo<T>::MIN)/FormatInfo<T>::RANGE;
157             ob = (double(pout[x+2]) + FormatInfo<T>::MIN)/FormatInfo<T>::RANGE;
158             double lumi = PF::luminance( ored, og, ob );
159             ired = (double(p[0][x]) + FormatInfo<T>::MIN)/FormatInfo<T>::RANGE;
160             ig = (double(p[0][x+1]) + FormatInfo<T>::MIN)/FormatInfo<T>::RANGE;
161             ib = (double(p[0][x+2]) + FormatInfo<T>::MIN)/FormatInfo<T>::RANGE;
162             //std::cout<<"Input:  "<<ired<<" "<<ig<<" "<<ib<<std::endl;
163             //std::cout<<"Output: "<<ored<<" "<<og<<" "<<ob<<std::endl;
164             ored2 = ired; og2 = ig; ob2 = ib;
165             PF::lc_blend( ored2, og2, ob2, lumi );
166             pout[x] = (T)(( (ored2*blend)+(ored*(1.0f-blend)) )*FormatInfo<T>::RANGE - FormatInfo<T>::MIN);
167             pout[x+1] = (T)(( (og2*blend)+(og*(1.0f-blend)) )*FormatInfo<T>::RANGE - FormatInfo<T>::MIN);
168             pout[x+2] = (T)(( (ob2*blend)+(ob*(1.0f-blend)) )*FormatInfo<T>::RANGE - FormatInfo<T>::MIN);
169             //std::cout<<"ired="<<ired<<"  ored="<<ored<<"  (ored*blend)+(ired*(1.0f-blend))="<<(ored*blend)+(ired*(1.0f-blend))<<std::endl;
170             //std::cout<<"p[x]="<<p[0][x]<<"  pout[x]="<<pout[x]<<std::endl;
171             x += 3;
172           }
173         } else if( blend < 0 ) {
174           // Blend the output color with the input luminance
175           // Preserves the luminance information of the input image
176           // Equivalent to the "color blend" in photoshop
177           double ired, ig, ib;
178           double ored, og, ob;
179           double ored2, og2, ob2;
180           for( x=0, ximap=0; x < line_size; ) {
181             ired = (double(p[0][x]) + FormatInfo<T>::MIN)/FormatInfo<T>::RANGE;
182             ig = (double(p[0][x+1]) + FormatInfo<T>::MIN)/FormatInfo<T>::RANGE;
183             ib = (double(p[0][x+2]) + FormatInfo<T>::MIN)/FormatInfo<T>::RANGE;
184             ored = (double(pout[x]) + FormatInfo<T>::MIN)/FormatInfo<T>::RANGE;
185             og = (double(pout[x+1]) + FormatInfo<T>::MIN)/FormatInfo<T>::RANGE;
186             ob = (double(pout[x+2]) + FormatInfo<T>::MIN)/FormatInfo<T>::RANGE;
187             double lumi = PF::luminance( ired, ig, ib );
188             ored2 = ored; og2 = og; ob2 = ob;
189             PF::lc_blend( ored2, og2, ob2, lumi );
190             pout[x] = (T)(( (ored2*nblend)+(ored*(1.0f-nblend)) )*FormatInfo<T>::RANGE - FormatInfo<T>::MIN);
191             pout[x+1] = (T)(( (og2*nblend)+(og*(1.0f-nblend)) )*FormatInfo<T>::RANGE - FormatInfo<T>::MIN);
192             pout[x+2] = (T)(( (ob2*nblend)+(ob*(1.0f-nblend)) )*FormatInfo<T>::RANGE - FormatInfo<T>::MIN);
193             x += 3;
194           }
195         }
196       }
197     }
198   };
199 
200 }
201 
202 #endif
203