Code

now that selection description includes style (filtered, clipped), we need to update...
[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     NRPixBlock *out = new NRPixBlock;
49     nr_pixblock_setup_fast(out, NR_PIXBLOCK_MODE_R8G8B8A8N, x0, y0, x1, y1, true);
51     // this primitive is defined for non-premultiplied RGBA values,
52     // thus convert them to that format before blending
53     bool free_in_on_exit = false;
54     if (in->mode != NR_PIXBLOCK_MODE_R8G8B8A8N) {
55         NRPixBlock *original_in = in;
56         in = new NRPixBlock;
57         nr_pixblock_setup_fast(in, NR_PIXBLOCK_MODE_R8G8B8A8N,
58                                original_in->area.x0, original_in->area.y0,
59                                original_in->area.x1, original_in->area.y1,
60                                false);
61         nr_blit_pixblock_pixblock(in, original_in);
62         free_in_on_exit = true;
63     }
65     unsigned char *in_data = NR_PIXBLOCK_PX(in);
66     unsigned char *out_data = NR_PIXBLOCK_PX(out);
68     (void)in_data;
69     (void)out_data;
71     int size = 4 * (y1-y0) * (x1-x0);
72     int i;
74     for (int color=0;color<4;color++){
75         int _vsize = tableValues[color].size();
76         double _intercept = intercept[color];
77         double _slope = slope[color];
78         double _amplitude = amplitude[color];
79         double _exponent = exponent[color];
80         double _offset = offset[color];
81         switch(type[color]){
82             case COMPONENTTRANSFER_TYPE_IDENTITY:
83                 for(i=color;i<size;i+=4){
84                     out_data[i]=in_data[i];
85                 }
86                 break;
87             case COMPONENTTRANSFER_TYPE_TABLE:
88                 if (_vsize<=1){
89                     if (_vsize==1) {
90                         g_warning("A component transfer table has to have at least two values.");
91                     }
92                     for(i=color;i<size;i+=4){
93                         out_data[i]=in_data[i];
94                     }
95                 } else {
96                     std::vector<gdouble> _tableValues(tableValues[color]);
97                     // Scale by 255 and add .5 to avoid having to add it later for rounding purposes
98                     for(i=0;i<_vsize;i++) {
99                         _tableValues[i] = std::max(0.,std::min(255.,255*_tableValues[i])) + .5;
100                     }
101                     for(i=color;i<size;i+=4){
102                         int k = FAST_DIVIDE<255>((_vsize-1) * in_data[i]);
103                         double dx = ((_vsize-1) * in_data[i])/255.0 - k;
104                         out_data[i] = static_cast<unsigned char>(_tableValues[k] + dx * (_tableValues[k+1] - _tableValues[k]));
105                     }
106                 }
107                 break;
108             case COMPONENTTRANSFER_TYPE_DISCRETE:
109                 if (_vsize==0){
110                     for(i=color;i<size;i+=4){
111                         out_data[i] = in_data[i];
112                     }
113                 } else {
114                     std::vector<unsigned char> _tableValues(_vsize);
115                     // Convert to unsigned char
116                     for(i=0;i<_vsize;i++) {
117                         _tableValues[i] = static_cast<unsigned char>(std::max(0.,std::min(255.,255*tableValues[color][i])) + .5);
118                     }
119                     for(i=color;i<size;i+=4){
120                         int k = FAST_DIVIDE<255>((_vsize-1) * in_data[i]);
121                         out_data[i] =  _tableValues[k];
122                     }
123                 }
124                 break;
125             case COMPONENTTRANSFER_TYPE_LINEAR:
126                 _intercept = 255*_intercept + .5;
127                 for(i=color;i<size;i+=4){
128                     out_data[i] = CLAMP_D_TO_U8(_slope * in_data[i] + _intercept);
129                 }
130                 break;
131             case COMPONENTTRANSFER_TYPE_GAMMA:
132                 _amplitude *= pow(255.0, -_exponent+1);
133                 _offset = 255*_offset + .5;
134                 for(i=color;i<size;i+=4){
135                     out_data[i] = CLAMP_D_TO_U8(_amplitude * pow((double)in_data[i], _exponent) + _offset);
136                 }
137                 break;
138             case COMPONENTTRANSFER_TYPE_ERROR:
139                 //TODO: report an error here
140                 g_warning("Component tranfer type \"error\".");
141                 break;
142             default:
143                 g_warning("Invalid tranfer type %d.", type[color]);
144         }
145     }
147     if (free_in_on_exit) {
148         nr_pixblock_release(in);
149         delete in;
150     }
152     out->empty = FALSE;
153     slot.set(_output, out);
154     return 0;
157 void FilterComponentTransfer::area_enlarge(NRRectL &/*area*/, Geom::Matrix const &/*trans*/)
161 } /* namespace Filters */
162 } /* namespace Inkscape */
164 /*
165   Local Variables:
166   mode:c++
167   c-file-style:"stroustrup"
168   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
169   indent-tabs-mode:nil
170   fill-column:99
171   End:
172 */
173 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :