1 /*
2 * feConvolveMatrix 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-convolve-matrix.h"
13 #include "display/nr-filter-units.h"
14 #include "display/nr-filter-utils.h"
15 #include <vector>
17 namespace Inkscape {
18 namespace Filters {
20 FilterConvolveMatrix::FilterConvolveMatrix()
21 {}
23 FilterPrimitive * FilterConvolveMatrix::create() {
24 return new FilterConvolveMatrix();
25 }
27 FilterConvolveMatrix::~FilterConvolveMatrix()
28 {}
30 static bool inside_area(int px, int py, int w, int h){
31 if (px<0) return false;
32 if (py<0) return false;
33 if (px>w) return false;
34 if (py>h) return false;
35 return true;
36 }
38 int FilterConvolveMatrix::render(FilterSlot &slot, FilterUnits const &/*units*/) {
39 NRPixBlock *in = slot.get(_input);
40 if (!in) {
41 g_warning("Missing source image for feConvolveMatrix (in=%d)", _input);
42 return 1;
43 }
45 NRPixBlock *out = new NRPixBlock;
47 nr_pixblock_setup_fast(out, in->mode,
48 in->area.x0, in->area.y0, in->area.x1, in->area.y1,
49 true);
51 unsigned char *in_data = NR_PIXBLOCK_PX(in);
52 unsigned char *out_data = NR_PIXBLOCK_PX(out);
54 double result_R, result_G, result_B, result_A;
55 int i, j, x, y;
56 int width = in->area.x1 - in->area.x0;
57 int height = in->area.y1 - in->area.y0;
59 unsigned int index;
60 unsigned int kernel_index;
62 for (x=targetX; x < width - (orderX - targetX); x++){
63 for (y=targetY; y < height - (orderY - targetY); y++){
64 result_R = 0;
65 result_G = 0;
66 result_B = 0;
67 result_A = 0;
68 for (i=0; i < orderY; i++){
69 for (j=0; j < orderX; j++){
70 if (inside_area(x - targetX + j, y - targetY + i, width, height)){
71 index = 4*( x - targetX + j + width*(y - targetY + i) );
72 kernel_index = orderX-j-1 + orderX*(orderY-i-1);
73 result_R += ( (double) in_data[index++] * kernelMatrix[kernel_index] );
74 result_G += ( (double) in_data[index++] * kernelMatrix[kernel_index] );
75 result_B += ( (double) in_data[index++] * kernelMatrix[kernel_index] );
76 result_A += ( (double) in_data[index] * kernelMatrix[kernel_index] );
77 }
78 }
79 }
80 unsigned int out_index = 4*( x + width*y );
81 out_data[out_index++] = CLAMP_D_TO_U8(result_R / divisor + bias); // CLAMP includes rounding!
82 out_data[out_index++] = CLAMP_D_TO_U8(result_G / divisor + bias);
83 out_data[out_index++] = CLAMP_D_TO_U8(result_B / divisor + bias);
85 if( preserveAlpha ) {
86 out_data[out_index] = in_data[out_index];
87 } else {
88 out_data[out_index] = CLAMP_D_TO_U8(result_A / divisor + bias);
89 }
90 }
91 }
93 out->empty = FALSE;
94 slot.set(_output, out);
95 return 0;
96 }
98 void FilterConvolveMatrix::set_targetX(int coord) {
99 targetX = coord;
100 }
102 void FilterConvolveMatrix::set_targetY(int coord) {
103 targetY = coord;
104 }
106 void FilterConvolveMatrix::set_orderX(int coord) {
107 orderX = coord;
108 }
110 void FilterConvolveMatrix::set_orderY(int coord) {
111 orderY = coord;
112 }
114 void FilterConvolveMatrix::set_divisor(double d) {
115 divisor = d;
116 }
118 void FilterConvolveMatrix::set_bias(double b) {
119 bias = b;
120 }
122 void FilterConvolveMatrix::set_kernelMatrix(std::vector<gdouble> &km) {
123 kernelMatrix = km;
124 }
126 void FilterConvolveMatrix::set_edgeMode(FilterConvolveMatrixEdgeMode mode){
127 edgeMode = mode;
128 }
130 void FilterConvolveMatrix::set_preserveAlpha(bool pa){
131 preserveAlpha = pa;
132 }
134 void FilterConvolveMatrix::area_enlarge(NRRectL &area, Geom::Matrix const &/*trans*/)
135 {
136 //Seems to me that since this filter's operation is resolution dependent,
137 // some spurious pixels may still appear at the borders when low zooming or rotating. Needs a better fix.
138 area.x0 -= targetX;
139 area.y0 -= targetY;
140 area.x1 += orderX - targetX;
141 area.y1 += orderY - targetY;
142 }
144 FilterTraits FilterConvolveMatrix::get_input_traits() {
145 return TRAIT_PARALLER;
146 }
148 } /* namespace Filters */
149 } /* namespace Inkscape */
151 /*
152 Local Variables:
153 mode:c++
154 c-file-style:"stroustrup"
155 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
156 indent-tabs-mode:nil
157 fill-column:99
158 End:
159 */
160 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :