1 /*
2 * feComponentTransfer filter primitive renderer
3 *
4 * Authors:
5 * Felipe CorrĂȘa da Silva Sanches <felipe.sanches@gmail.com>
6 *
7 * Copyright (C) 2007 authors
8 *
9 * Released under GNU GPL, read the file 'COPYING' for more information
10 */
12 #include "display/nr-filter-component-transfer.h"
13 #include "display/nr-filter-units.h"
14 #include "display/nr-filter-utils.h"
15 #include "libnr/nr-pixblock.h"
16 #include "libnr/nr-blit.h"
17 #include <math.h>
19 namespace NR {
21 FilterComponentTransfer::FilterComponentTransfer()
22 {
23 }
25 FilterPrimitive * FilterComponentTransfer::create() {
26 return new FilterComponentTransfer();
27 }
29 FilterComponentTransfer::~FilterComponentTransfer()
30 {}
32 int FilterComponentTransfer::render(FilterSlot &slot, FilterUnits const &/*units*/) {
33 NRPixBlock *in = slot.get(_input);
35 if (!in) {
36 g_warning("Missing source image for feComponentTransfer (in=%d)", _input);
37 return 1;
38 }
40 int x0=in->area.x0;
41 int x1=in->area.x1;
42 int y0=in->area.y0;
43 int y1=in->area.y1;
45 NRPixBlock *out = new NRPixBlock;
46 nr_pixblock_setup_fast(out, NR_PIXBLOCK_MODE_R8G8B8A8N, x0, y0, x1, y1, true);
48 // this primitive is defined for non-premultiplied 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) {
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 }
62 unsigned char *in_data = NR_PIXBLOCK_PX(in);
63 unsigned char *out_data = NR_PIXBLOCK_PX(out);
65 (void)in_data;
66 (void)out_data;
68 int size = 4 * (y1-y0) * (x1-x0);
69 int i;
71 for (int color=0;color<4;color++){
72 int _vsize = tableValues[color].size();
73 std::vector<gdouble> _tableValues = tableValues[color];
74 double _intercept = intercept[color];
75 double _slope = slope[color];
76 double _amplitude = amplitude[color];
77 double _exponent = exponent[color];
78 double _offset = offset[color];
79 switch(type[color]){
80 case COMPONENTTRANSFER_TYPE_IDENTITY:
81 for(i=color;i<size;i+=4){
82 out_data[i]=in_data[i];
83 }
84 break;
85 case COMPONENTTRANSFER_TYPE_TABLE:
86 if (_vsize==0){
87 for(i=color;i<size;i+=4){
88 out_data[i]=in_data[i];
89 }
90 } else {
91 for(i=color;i<size;i+=4){
92 int k = (int)(((_vsize-1) * (double)in_data[i])/256);
93 double dx = ((_vsize-1) * (double)in_data[i])/256 - k;
94 out_data[i] = CLAMP_D_TO_U8(256 * (_tableValues[k] + dx * (_tableValues[k+1] - _tableValues[k]) ));
95 }
96 }
97 break;
98 case COMPONENTTRANSFER_TYPE_DISCRETE:
99 if (_vsize==0){
100 for(i=color;i<size;i+=4){
101 out_data[i] = in_data[i];
102 }
103 } else {
104 for(i=color;i<size;i+=4){
105 out_data[i] = CLAMP_D_TO_U8(256 * _tableValues[(int)((_vsize-1)*(double)in_data[i]/256)] );
106 }
107 }
108 break;
109 case COMPONENTTRANSFER_TYPE_LINEAR:
110 for(i=color;i<size;i+=4){
111 out_data[i] = CLAMP_D_TO_U8(256 * (_slope * (double)in_data[i]/256 + _intercept));
112 }
113 break;
114 case COMPONENTTRANSFER_TYPE_GAMMA:
115 for(i=color;i<size;i+=4){
116 out_data[i] = CLAMP_D_TO_U8(256 * (_amplitude * pow((double)in_data[i]/256, _exponent) + _offset));
117 }
118 break;
119 case COMPONENTTRANSFER_TYPE_ERROR:
120 //TODO: report an error here
121 break;
122 }
123 }
125 if (free_in_on_exit) {
126 nr_pixblock_release(in);
127 delete in;
128 }
130 out->empty = FALSE;
131 slot.set(_output, out);
132 return 0;
133 }
135 void FilterComponentTransfer::area_enlarge(NRRectL &/*area*/, Matrix const &/*trans*/)
136 {
137 }
139 } /* namespace NR */
141 /*
142 Local Variables:
143 mode:c++
144 c-file-style:"stroustrup"
145 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
146 indent-tabs-mode:nil
147 fill-column:99
148 End:
149 */
150 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :