Code

Connector tool: make connectors avoid the convex hull of shapes.
[inkscape.git] / src / display / nr-filter-component-transfer.cpp
1 /*
2  * feComponentTransfer filter primitive renderer
3  *
4  * Authors:
5  *   Felipe CorrĂȘa da Silva Sanches <felipe.sanches@gmail.com>
6  *   Jasper van de Gronde <th.v.d.gronde@hccnet.nl>
7  *
8  * Copyright (C) 2007 authors
9  *
10  * Released under GNU GPL, read the file 'COPYING' for more information
11  */
13 #include "display/nr-filter-component-transfer.h"
14 #include "display/nr-filter-units.h"
15 #include "display/nr-filter-utils.h"
16 #include "libnr/nr-pixblock.h"
17 #include "libnr/nr-blit.h"
18 #include "libnr/nr-pixops.h"
19 #include <math.h>
21 namespace Inkscape {
22 namespace Filters {
24 FilterComponentTransfer::FilterComponentTransfer()
25 {
26 }
28 FilterPrimitive * FilterComponentTransfer::create() {
29     return new FilterComponentTransfer();
30 }
32 FilterComponentTransfer::~FilterComponentTransfer()
33 {}
35 int FilterComponentTransfer::render(FilterSlot &slot, FilterUnits const &/*units*/) {
36     NRPixBlock *in = slot.get(_input);
38     if (!in) {
39         g_warning("Missing source image for feComponentTransfer (in=%d)", _input);
40         return 1;
41     }
43     int x0=in->area.x0;
44     int x1=in->area.x1;
45     int y0=in->area.y0;
46     int y1=in->area.y1;
48     // this primitive is defined for RGBA values,
49     // thus convert them to that format before blending
50     bool free_in_on_exit = false;
51     if (in->mode != NR_PIXBLOCK_MODE_R8G8B8A8N && in->mode != NR_PIXBLOCK_MODE_R8G8B8A8P) {
52         NRPixBlock *original_in = in;
53         in = new NRPixBlock;
54         nr_pixblock_setup_fast(in, NR_PIXBLOCK_MODE_R8G8B8A8N,
55                                original_in->area.x0, original_in->area.y0,
56                                original_in->area.x1, original_in->area.y1,
57                                false);
58         nr_blit_pixblock_pixblock(in, original_in);
59         free_in_on_exit = true;
60     }
61     bool premultiplied = in->mode == NR_PIXBLOCK_MODE_R8G8B8A8P;
63     NRPixBlock *out = new NRPixBlock;
64     nr_pixblock_setup_fast(out, in->mode, x0, y0, x1, y1, true);
66     unsigned char *in_data = NR_PIXBLOCK_PX(in);
67     unsigned char *out_data = NR_PIXBLOCK_PX(out);
69     (void)in_data;
70     (void)out_data;
72     int size = 4 * (y1-y0) * (x1-x0);
73     int i;
75     int color=4;
76     while(color-->0) {
77         int _vsize = tableValues[color].size();
78         double _intercept = intercept[color];
79         double _slope = slope[color];
80         double _amplitude = amplitude[color];
81         double _exponent = exponent[color];
82         double _offset = offset[color];
83         switch(type[color]){
84             case COMPONENTTRANSFER_TYPE_IDENTITY:
85                 for(i=color;i<size;i+=4){
86                     out_data[i]=in_data[i];
87                 }
88                 break;
89             case COMPONENTTRANSFER_TYPE_TABLE:
90                 if (_vsize<=1){
91                     if (_vsize==1) {
92                         g_warning("A component transfer table has to have at least two values.");
93                     }
94                     for(i=color;i<size;i+=4){
95                         out_data[i]=in_data[i];
96                     }
97                 } else {
98                     if (!premultiplied || color==3) {
99                         std::vector<gdouble> _tableValues(tableValues[color]);
100                         // Scale by 255 and add .5 to avoid having to add it later for rounding purposes
101                         //   Note that this means that CLAMP_D_TO_U8 cannot be used here (as it includes rounding!)
102                         for(i=0;i<_vsize;i++) {
103                             _tableValues[i] = std::max(0.,std::min(255.,255*_tableValues[i])) + .5;
104                         }
105                         for(i=color;i<size;i+=4){
106                             int k = FAST_DIVIDE<255>((_vsize-1) * in_data[i]);
107                             double dx = ((_vsize-1) * in_data[i])/255.0 - k;
108                             out_data[i] = static_cast<unsigned char>(_tableValues[k] + dx * (_tableValues[k+1] - _tableValues[k]));
109                         }
110                     } else {
111                         std::vector<gdouble> _tableValues(tableValues[color]);
112                         for(i=0;i<_vsize;i++) {
113                             _tableValues[i] = std::max(0.,std::min(1.,_tableValues[i]));
114                         }
115                         for(i=color;i<size;i+=4){
116                             if (in_data[i+3-color]==0) continue;
117                             int k = ((_vsize-1) * in_data[i]) / in_data[i+3-color];
118                             double dx = ((_vsize-1) * in_data[i]) / (double)in_data[i+3-color] - k;
119                             out_data[i] = CLAMP_D_TO_U8_ALPHA(out_data[i+3-color] * (_tableValues[k] + dx * (_tableValues[k+1] - _tableValues[k])), out_data[i+3-color]); // CLAMP includes rounding!
120                         }
121                     }
122                 }
123                 break;
124             case COMPONENTTRANSFER_TYPE_DISCRETE:
125                 if (_vsize==0){
126                     for(i=color;i<size;i+=4){
127                         out_data[i] = in_data[i];
128                     }
129                 } else {
130                     if (!premultiplied || color==3) {
131                         std::vector<unsigned char> _tableValues(_vsize);
132                         // Convert to unsigned char
133                         for(i=0;i<_vsize;i++) {
134                             _tableValues[i] = CLAMP_D_TO_U8(255*tableValues[color][i]);
135                         }
136                         for(i=color;i<size;i+=4){
137                             int k = FAST_DIVIDE<255>((_vsize-1) * in_data[i]);
138                             out_data[i] =  _tableValues[k];
139                         }
140                     } else {
141                         std::vector<gdouble> _tableValues(tableValues[color]);
142                         for(i=0;i<_vsize;i++) {
143                             _tableValues[i] = std::max(0.,std::min(1.,_tableValues[i]));
144                         }
145                         for(i=color;i<size;i+=4){
146                             if (in_data[i+3-color]==0) continue;
147                             int k = ((_vsize-1) * in_data[i]) / in_data[i+3-color];
148                             out_data[i] = CLAMP_D_TO_U8_ALPHA(out_data[i+3-color] * _tableValues[k], out_data[i+3-color]);
149                         }
150                     }
151                 }
152                 break;
153             case COMPONENTTRANSFER_TYPE_LINEAR:
154                 if (!premultiplied || color==3) {
155                     _intercept = 255*_intercept;
156                     for(i=color;i<size;i+=4){
157                         out_data[i] = CLAMP_D_TO_U8(_slope * in_data[i] + _intercept); // CLAMP includes rounding!
158                     }
159                 } else {
160                     for(i=color;i<size;i+=4){
161                         if (in_data[i+3-color]==0) continue;
162                         double out = _slope * in_data[i] / in_data[i+3-color] + _intercept;
163                         out_data[i] = CLAMP_D_TO_U8_ALPHA(out_data[i+3-color] * out, out_data[i+3-color]);
164                     }
165                 }
166                 break;
167             case COMPONENTTRANSFER_TYPE_GAMMA:
168                 if (!premultiplied || color==3) {
169                     _amplitude *= pow(255.0, -_exponent+1); // The input should be divided by 255, then exponentiated and then multiplied by 255 again, instead the amplitude is modified accordingly.
170                     _offset = 255*_offset;
171                     for(i=color;i<size;i+=4){
172                         out_data[i] = CLAMP_D_TO_U8(_amplitude * pow((double)in_data[i], _exponent) + _offset);
173                     }
174                 } else {
175                     for(i=color;i<size;i+=4){
176                         if (in_data[i+3-color]==0) continue;
177                         double out = _amplitude * pow((double)in_data[i] / in_data[i+3-color], _exponent) + _offset;
178                         out_data[i] = CLAMP_D_TO_U8_ALPHA(out_data[i+3-color] * out, out_data[i+3-color]);
179                     }
180                 }
181                 break;
182             case COMPONENTTRANSFER_TYPE_ERROR:
183                 //TODO: report an error here
184                 g_warning("Component tranfer type \"error\".");
185                 break;
186             default:
187                 g_warning("Invalid tranfer type %d.", type[color]);
188         }
189     }
191     if (free_in_on_exit) {
192         nr_pixblock_release(in);
193         delete in;
194     }
196     out->empty = FALSE;
197     slot.set(_output, out);
198     return 0;
201 void FilterComponentTransfer::area_enlarge(NRRectL &/*area*/, Geom::Matrix const &/*trans*/)
205 } /* namespace Filters */
206 } /* namespace Inkscape */
208 /*
209   Local Variables:
210   mode:c++
211   c-file-style:"stroustrup"
212   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
213   indent-tabs-mode:nil
214   fill-column:99
215   End:
216 */
217 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :