Code

Merging in from trunk
[inkscape.git] / src / display / nr-filter-morphology.cpp
index 07b1b1d94b4403156de8252b74357314132bf730..2df3ff807433a204186e4c3dfa741af1765d72eb 100644 (file)
@@ -9,8 +9,13 @@
  * Released under GNU GPL, read the file 'COPYING' for more information
  */
 
+#include <cmath>
 #include "display/nr-filter-morphology.h"
-namespace NR {
+#include "display/nr-filter-units.h"
+#include "libnr/nr-blit.h"
+
+namespace Inkscape {
+namespace Filters {
 
 FilterMorphology::FilterMorphology()
 {
@@ -23,41 +28,64 @@ FilterPrimitive * FilterMorphology::create() {
 FilterMorphology::~FilterMorphology()
 {}
 
-int FilterMorphology::render(FilterSlot &slot, Matrix const &trans) {
+int FilterMorphology::render(FilterSlot &slot, FilterUnits const &units) {
     NRPixBlock *in = slot.get(_input);
+    if (!in) {
+        g_warning("Missing source image for feMorphology (in=%d)", _input);
+        return 1;
+    }
+
     NRPixBlock *out = new NRPixBlock;
 
+    // this primitive is defined for premultiplied RGBA values,
+    // thus convert them to that format
+    bool free_in_on_exit = false;
+    if (in->mode != NR_PIXBLOCK_MODE_R8G8B8A8P) {
+        NRPixBlock *original_in = in;
+        in = new NRPixBlock;
+        nr_pixblock_setup_fast(in, NR_PIXBLOCK_MODE_R8G8B8A8P,
+                               original_in->area.x0, original_in->area.y0,
+                               original_in->area.x1, original_in->area.y1,
+                               true);
+        nr_blit_pixblock_pixblock(in, original_in);
+        free_in_on_exit = true;
+    }
+
+    Geom::Matrix p2pb = units.get_matrix_primitiveunits2pb();
+    int const xradius = (int)round(this->xradius * p2pb.expansionX());
+    int const yradius = (int)round(this->yradius * p2pb.expansionY());
+
     int x0=in->area.x0;
     int y0=in->area.y0;
     int x1=in->area.x1;
-    int y1=in->area.y1;            
+    int y1=in->area.y1;
     int w=x1-x0, h=y1-y0;
-    int x,y,i,j;
+    int x, y, i, j;
     int rmax,gmax,bmax,amax;
     int rmin,gmin,bmin,amin;
-    
+
     nr_pixblock_setup_fast(out, in->mode, x0, y0, x1, y1, true);
 
     unsigned char *in_data = NR_PIXBLOCK_PX(in);
     unsigned char *out_data = NR_PIXBLOCK_PX(out);
 
-    for(x=xradius; x<w-xradius; x++){
-        for(y=yradius; y<h-yradius; y++){
-            rmin=rmax=in_data[4*(x + w*y)];
-            gmin=gmax=in_data[4*(x + w*y)+1];
-            bmin=bmax=in_data[4*(x + w*y)+2];
-            amin=amax=in_data[4*(x + w*y)+3];
-            for(i=x-xradius;i<x+xradius;i++){
-                for(j=y-yradius;j<y+yradius;j++){
+    for(x = 0 ; x < w ; x++){
+        for(y = 0 ; y < h ; y++){
+            rmin = gmin = bmin = amin = 255;
+            rmax = gmax = bmax = amax = 0;
+            for(i = x - xradius ; i < x + xradius ; i++){
+                if (i < 0 || i >= w) continue;
+                for(j = y - yradius ; j < y + yradius ; j++){
+                    if (j < 0 || j >= h) continue;
                     if(in_data[4*(i + w*j)]>rmax) rmax = in_data[4*(i + w*j)];
                     if(in_data[4*(i + w*j)+1]>gmax) gmax = in_data[4*(i + w*j)+1];
                     if(in_data[4*(i + w*j)+2]>bmax) bmax = in_data[4*(i + w*j)+2];
                     if(in_data[4*(i + w*j)+3]>amax) amax = in_data[4*(i + w*j)+3];
-                                                            
+
                     if(in_data[4*(i + w*j)]<rmin) rmin = in_data[4*(i + w*j)];
                     if(in_data[4*(i + w*j)+1]<gmin) gmin = in_data[4*(i + w*j)+1];
                     if(in_data[4*(i + w*j)+2]<bmin) bmin = in_data[4*(i + w*j)+2];
-                    if(in_data[4*(i + w*j)+3]<amin) amin = in_data[4*(i + w*j)+3];                    
+                    if(in_data[4*(i + w*j)+3]<amin) amin = in_data[4*(i + w*j)+3];
                 }
             }
             if (Operator==MORPHOLOGY_OPERATOR_DILATE){
@@ -73,33 +101,46 @@ int FilterMorphology::render(FilterSlot &slot, Matrix const &trans) {
             }
         }
     }
-   
+
+    if (free_in_on_exit) {
+        nr_pixblock_release(in);
+        delete in;
+    }
+
     out->empty = FALSE;
     slot.set(_output, out);
     return 0;
 }
 
-void FilterMorphology::area_enlarge(NRRectL &area, Matrix const &trans)
+void FilterMorphology::area_enlarge(NRRectL &area, Geom::Matrix const &trans)
 {
-    area.x0-=xradius;
-    area.x1+=xradius;
-    area.y0-=yradius;
-    area.y1+=yradius;            
+    int const enlarge_x = (int)std::ceil(this->xradius * (std::fabs(trans[0]) + std::fabs(trans[1])));
+    int const enlarge_y = (int)std::ceil(this->yradius * (std::fabs(trans[2]) + std::fabs(trans[3])));
+
+    area.x0 -= enlarge_x;
+    area.x1 += enlarge_x;
+    area.y0 -= enlarge_y;
+    area.y1 += enlarge_y;
 }
 
 void FilterMorphology::set_operator(FilterMorphologyOperator &o){
     Operator = o;
 }
 
-void FilterMorphology::set_xradius(int x){
+void FilterMorphology::set_xradius(double x){
     xradius = x;
 }
 
-void FilterMorphology::set_yradius(int y){
+void FilterMorphology::set_yradius(double y){
     yradius = y;
 }
 
-} /* namespace NR */
+FilterTraits FilterMorphology::get_input_traits() {
+    return TRAIT_PARALLER;
+}
+
+} /* namespace Filters */
+} /* namespace Inkscape */
 
 /*
   Local Variables: