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 <vector>
14 namespace NR {
16 FilterConvolveMatrix::FilterConvolveMatrix()
17 : bias(0),
18 edgeMode(0),
19 preserveAlpha(false)
20 {}
22 FilterPrimitive * FilterConvolveMatrix::create() {
23 return new FilterConvolveMatrix();
24 }
26 FilterConvolveMatrix::~FilterConvolveMatrix()
27 {}
29 static bool inside_area(int px, int py, int w, int h){
30 if (px<0) return false;
31 if (py<0) return false;
32 if (px>w) return false;
33 if (py>h) return false;
34 return true;
35 }
37 int FilterConvolveMatrix::render(FilterSlot &slot, Matrix const &trans) {
38 NRPixBlock *in = slot.get(_input);
39 NRPixBlock *out = new NRPixBlock;
41 nr_pixblock_setup_fast(out, in->mode,
42 in->area.x0, in->area.y0, in->area.x1, in->area.y1,
43 true);
45 unsigned char *in_data = NR_PIXBLOCK_PX(in);
46 unsigned char *out_data = NR_PIXBLOCK_PX(out);
48 double result_R, result_G, result_B, result_A;
49 int i, j, x, y;
50 int width = in->area.x1 - in->area.x0;
51 int height = in->area.y1 - in->area.y0;
53 double div=0;
55 if (divisor != 0){
56 div = divisor;
57 } else {
58 for (i=0;i<orderX*orderY;i++){
59 div += kernelMatrix[i];
60 }
61 }
63 for (x=targetX; x < width - (orderX - targetX); x++){
64 for (y=targetY; y < height - (orderY - targetY); y++){
65 result_R = 0;
66 result_G = 0;
67 result_B = 0;
68 result_A = 0;
69 for (i=0; i < orderY; i++){
70 for (j=0; j < orderX; j++){
71 if (inside_area(x - targetX + j, y - targetY + i, width, height)){
72 result_R += ( (double) in_data[4*( x - targetX + j + width*(y - targetY + i) )] * kernelMatrix[orderX-j-1 + orderX*(orderY-i-1)] );
73 result_G += ( (double) in_data[4*( x - targetX + j + width*(y - targetY + i) )+1] * kernelMatrix[orderX-j-1 + orderX*(orderY-i-1)] );
74 result_B += ( (double) in_data[4*( x - targetX + j + width*(y - targetY + i) )+2] * kernelMatrix[orderX-j-1 + orderX*(orderY-i-1)] );
75 result_A += ( (double) in_data[4*( x - targetX + j + width*(y - targetY + i) )+3] * kernelMatrix[orderX-j-1 + orderX*(orderY-i-1)] );
76 }
77 }
78 }
79 result_R = result_R / div + bias;
80 result_G = result_G / div + bias;
81 result_B = result_B / div + bias;
82 result_A = result_A / div + bias;
84 result_R = (result_R > 0 ? result_R : 0);
85 result_G = (result_G > 0 ? result_G : 0);
86 result_B = (result_B > 0 ? result_B : 0);
87 result_A = (result_A > 0 ? result_A : 0);
89 out_data[4*( x + width*y )] = (result_R < 255 ? (unsigned char)result_R : 255);
90 out_data[4*( x + width*y )+1] = (result_G < 255 ? (unsigned char)result_G : 255);
91 out_data[4*( x + width*y )+2] = (result_B < 255 ? (unsigned char)result_B : 255);
92 out_data[4*( x + width*y )+3] = (result_A < 255 ? (unsigned char)result_A : 255);
93 }
94 }
96 out->empty = FALSE;
97 slot.set(_output, out);
98 return 0;
99 }
101 void FilterConvolveMatrix::set_targetX(int coord) {
102 targetX = coord;
103 }
105 void FilterConvolveMatrix::set_targetY(int coord) {
106 targetY = coord;
107 }
109 void FilterConvolveMatrix::set_orderX(int coord) {
110 orderX = coord;
111 }
113 void FilterConvolveMatrix::set_orderY(int coord) {
114 orderY = coord;
115 }
117 void FilterConvolveMatrix::set_divisor(double d) {
118 divisor = d;
119 }
121 void FilterConvolveMatrix::set_bias(double b) {
122 bias = b;
123 }
125 void FilterConvolveMatrix::set_kernelMatrix(std::vector<gdouble> &km) {
126 kernelMatrix = km;
127 }
129 void FilterConvolveMatrix::set_edgeMode(int mode){
130 edgeMode = mode;
131 }
133 void FilterConvolveMatrix::set_preserveAlpha(bool pa){
134 preserveAlpha = pa;
135 }
137 void FilterConvolveMatrix::area_enlarge(NRRectL &area, Matrix const &trans)
138 {
139 //Seems to me that since this filter's operation is resolution dependent,
140 // some spurious pixels may still appear at the borders when low zooming or rotating. Needs a better fix.
141 area.x0 -= targetX;
142 area.y0 -= targetY;
143 area.x1 += orderX - targetX;
144 area.y1 += orderY - targetY;
145 }
147 } /* namespace NR */
149 /*
150 Local Variables:
151 mode:c++
152 c-file-style:"stroustrup"
153 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
154 indent-tabs-mode:nil
155 fill-column:99
156 End:
157 */
158 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :