1 /*
2 * feMorphology 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-morphology.h"
13 #include "display/nr-filter-units.h"
14 #include "libnr/nr-blit.h"
16 namespace Inkscape {
17 namespace Filters {
19 FilterMorphology::FilterMorphology()
20 {
21 }
23 FilterPrimitive * FilterMorphology::create() {
24 return new FilterMorphology();
25 }
27 FilterMorphology::~FilterMorphology()
28 {}
30 int FilterMorphology::render(FilterSlot &slot, FilterUnits const &units) {
31 NRPixBlock *in = slot.get(_input);
32 if (!in) {
33 g_warning("Missing source image for feMorphology (in=%d)", _input);
34 return 1;
35 }
37 NRPixBlock *out = new NRPixBlock;
39 // this primitive is defined for premultiplied RGBA values,
40 // thus convert them to that format
41 bool free_in_on_exit = false;
42 if (in->mode != NR_PIXBLOCK_MODE_R8G8B8A8P) {
43 NRPixBlock *original_in = in;
44 in = new NRPixBlock;
45 nr_pixblock_setup_fast(in, NR_PIXBLOCK_MODE_R8G8B8A8P,
46 original_in->area.x0, original_in->area.y0,
47 original_in->area.x1, original_in->area.y1,
48 true);
49 nr_blit_pixblock_pixblock(in, original_in);
50 free_in_on_exit = true;
51 }
53 Geom::Matrix p2pb = units.get_matrix_primitiveunits2pb();
54 int const xradius = (int)round(this->xradius * p2pb.expansionX());
55 int const yradius = (int)round(this->yradius * p2pb.expansionY());
57 int x0=in->area.x0;
58 int y0=in->area.y0;
59 int x1=in->area.x1;
60 int y1=in->area.y1;
61 int w=x1-x0, h=y1-y0;
62 int x, y, i, j;
63 int rmax,gmax,bmax,amax;
64 int rmin,gmin,bmin,amin;
66 nr_pixblock_setup_fast(out, in->mode, x0, y0, x1, y1, true);
68 unsigned char *in_data = NR_PIXBLOCK_PX(in);
69 unsigned char *out_data = NR_PIXBLOCK_PX(out);
71 for(x = 0 ; x < w ; x++){
72 for(y = 0 ; y < h ; y++){
73 rmin = gmin = bmin = amin = 255;
74 rmax = gmax = bmax = amax = 0;
75 for(i = x - xradius ; i < x + xradius ; i++){
76 if (i < 0 || i >= w) continue;
77 for(j = y - yradius ; j < y + yradius ; j++){
78 if (j < 0 || j >= h) continue;
79 if(in_data[4*(i + w*j)]>rmax) rmax = in_data[4*(i + w*j)];
80 if(in_data[4*(i + w*j)+1]>gmax) gmax = in_data[4*(i + w*j)+1];
81 if(in_data[4*(i + w*j)+2]>bmax) bmax = in_data[4*(i + w*j)+2];
82 if(in_data[4*(i + w*j)+3]>amax) amax = in_data[4*(i + w*j)+3];
84 if(in_data[4*(i + w*j)]<rmin) rmin = in_data[4*(i + w*j)];
85 if(in_data[4*(i + w*j)+1]<gmin) gmin = in_data[4*(i + w*j)+1];
86 if(in_data[4*(i + w*j)+2]<bmin) bmin = in_data[4*(i + w*j)+2];
87 if(in_data[4*(i + w*j)+3]<amin) amin = in_data[4*(i + w*j)+3];
88 }
89 }
90 if (Operator==MORPHOLOGY_OPERATOR_DILATE){
91 out_data[4*(x + w*y)]=rmax;
92 out_data[4*(x + w*y)+1]=gmax;
93 out_data[4*(x + w*y)+2]=bmax;
94 out_data[4*(x + w*y)+3]=amax;
95 } else {
96 out_data[4*(x + w*y)]=rmin;
97 out_data[4*(x + w*y)+1]=gmin;
98 out_data[4*(x + w*y)+2]=bmin;
99 out_data[4*(x + w*y)+3]=amin;
100 }
101 }
102 }
104 if (free_in_on_exit) {
105 nr_pixblock_release(in);
106 delete in;
107 }
109 out->empty = FALSE;
110 slot.set(_output, out);
111 return 0;
112 }
114 void FilterMorphology::area_enlarge(NRRectL &area, Geom::Matrix const &trans)
115 {
116 int const enlarge_x = (int)round(this->xradius * trans.expansionX());
117 int const enlarge_y = (int)round(this->yradius * trans.expansionY());
119 area.x0 -= enlarge_x;
120 area.x1 += enlarge_x;
121 area.y0 -= enlarge_y;
122 area.y1 += enlarge_y;
123 }
125 void FilterMorphology::set_operator(FilterMorphologyOperator &o){
126 Operator = o;
127 }
129 void FilterMorphology::set_xradius(double x){
130 xradius = x;
131 }
133 void FilterMorphology::set_yradius(double y){
134 yradius = y;
135 }
137 FilterTraits FilterMorphology::get_input_traits() {
138 return TRAIT_PARALLER;
139 }
141 } /* namespace Filters */
142 } /* namespace Inkscape */
144 /*
145 Local Variables:
146 mode:c++
147 c-file-style:"stroustrup"
148 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
149 indent-tabs-mode:nil
150 fill-column:99
151 End:
152 */
153 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :