Code

Fix for helperfns_read_vector (which could go on trying to read numbers for ever...
authorjaspervdg <jaspervdg@users.sourceforge.net>
Tue, 31 Mar 2009 20:41:47 +0000 (20:41 +0000)
committerjaspervdg <jaspervdg@users.sourceforge.net>
Tue, 31 Mar 2009 20:41:47 +0000 (20:41 +0000)
src/display/nr-filter-component-transfer.cpp
src/filters/componenttransfer.cpp
src/helper-fns.h
src/sp-gradient.cpp

index 74d66fbe4a406373bcfc73ad43f19b93021dcd75..6f9e2b712a9e32e34771d7f432f61bcae2e283f5 100644 (file)
@@ -45,13 +45,10 @@ int FilterComponentTransfer::render(FilterSlot &slot, FilterUnits const &/*units
     int y0=in->area.y0;
     int y1=in->area.y1;
 
-    NRPixBlock *out = new NRPixBlock;
-    nr_pixblock_setup_fast(out, NR_PIXBLOCK_MODE_R8G8B8A8N, x0, y0, x1, y1, true);
-
-    // this primitive is defined for non-premultiplied RGBA values,
+    // this primitive is defined for RGBA values,
     // thus convert them to that format before blending
     bool free_in_on_exit = false;
-    if (in->mode != NR_PIXBLOCK_MODE_R8G8B8A8N) {
+    if (in->mode != NR_PIXBLOCK_MODE_R8G8B8A8N && in->mode != NR_PIXBLOCK_MODE_R8G8B8A8P) {
         NRPixBlock *original_in = in;
         in = new NRPixBlock;
         nr_pixblock_setup_fast(in, NR_PIXBLOCK_MODE_R8G8B8A8N,
@@ -61,6 +58,11 @@ int FilterComponentTransfer::render(FilterSlot &slot, FilterUnits const &/*units
         nr_blit_pixblock_pixblock(in, original_in);
         free_in_on_exit = true;
     }
+    bool premultiplied = in->mode == NR_PIXBLOCK_MODE_R8G8B8A8P;
+    g_message("Premultiplied=%s", premultiplied?"yes":"no");
+
+    NRPixBlock *out = new NRPixBlock;
+    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);
@@ -71,7 +73,8 @@ int FilterComponentTransfer::render(FilterSlot &slot, FilterUnits const &/*units
     int size = 4 * (y1-y0) * (x1-x0);
     int i;
 
-    for (int color=0;color<4;color++){
+    int color=4;
+    while(color-->0) {
         int _vsize = tableValues[color].size();
         double _intercept = intercept[color];
         double _slope = slope[color];
@@ -93,15 +96,28 @@ int FilterComponentTransfer::render(FilterSlot &slot, FilterUnits const &/*units
                         out_data[i]=in_data[i];
                     }
                 } else {
-                    std::vector<gdouble> _tableValues(tableValues[color]);
-                    // Scale by 255 and add .5 to avoid having to add it later for rounding purposes
-                    for(i=0;i<_vsize;i++) {
-                        _tableValues[i] = std::max(0.,std::min(255.,255*_tableValues[i])) + .5;
-                    }
-                    for(i=color;i<size;i+=4){
-                        int k = FAST_DIVIDE<255>((_vsize-1) * in_data[i]);
-                        double dx = ((_vsize-1) * in_data[i])/255.0 - k;
-                        out_data[i] = static_cast<unsigned char>(_tableValues[k] + dx * (_tableValues[k+1] - _tableValues[k]));
+                    if (!premultiplied || color==3) {
+                        std::vector<gdouble> _tableValues(tableValues[color]);
+                        // Scale by 255 and add .5 to avoid having to add it later for rounding purposes
+                        for(i=0;i<_vsize;i++) {
+                            _tableValues[i] = std::max(0.,std::min(255.,255*_tableValues[i])) + .5;
+                        }
+                        for(i=color;i<size;i+=4){
+                            int k = FAST_DIVIDE<255>((_vsize-1) * in_data[i]);
+                            double dx = ((_vsize-1) * in_data[i])/255.0 - k;
+                            out_data[i] = static_cast<unsigned char>(_tableValues[k] + dx * (_tableValues[k+1] - _tableValues[k]));
+                        }
+                    } else {
+                        std::vector<gdouble> _tableValues(tableValues[color]);
+                        for(i=0;i<_vsize;i++) {
+                            _tableValues[i] = std::max(0.,std::min(1.,_tableValues[i]));
+                        }
+                        for(i=color;i<size;i+=4){
+                            if (in_data[i+3-color]==0) continue;
+                            int k = ((_vsize-1) * in_data[i]) / in_data[i+3-color];
+                            double dx = ((_vsize-1) * in_data[i]) / (double)in_data[i+3-color] - k;
+                            out_data[i] = static_cast<unsigned char>(out_data[i+3-color] * (_tableValues[k] + dx * (_tableValues[k+1] - _tableValues[k])) + .5);
+                        }
                     }
                 }
                 break;
@@ -111,28 +127,54 @@ int FilterComponentTransfer::render(FilterSlot &slot, FilterUnits const &/*units
                         out_data[i] = in_data[i];
                     }
                 } else {
-                    std::vector<unsigned char> _tableValues(_vsize);
-                    // Convert to unsigned char
-                    for(i=0;i<_vsize;i++) {
-                        _tableValues[i] = static_cast<unsigned char>(std::max(0.,std::min(255.,255*tableValues[color][i])) + .5);
-                    }
-                    for(i=color;i<size;i+=4){
-                        int k = FAST_DIVIDE<255>((_vsize-1) * in_data[i]);
-                        out_data[i] =  _tableValues[k];
+                    if (!premultiplied || color==3) {
+                        std::vector<unsigned char> _tableValues(_vsize);
+                        // Convert to unsigned char
+                        for(i=0;i<_vsize;i++) {
+                            _tableValues[i] = static_cast<unsigned char>(std::max(0.,std::min(255.,255*tableValues[color][i])) + .5);
+                        }
+                        for(i=color;i<size;i+=4){
+                            int k = FAST_DIVIDE<255>((_vsize-1) * in_data[i]);
+                            out_data[i] =  _tableValues[k];
+                        }
+                    } else {
+                        std::vector<gdouble> _tableValues(tableValues[color]);
+                        for(i=0;i<_vsize;i++) {
+                            _tableValues[i] = std::max(0.,std::min(1.,_tableValues[i]));
+                        }
+                        for(i=color;i<size;i+=4){
+                            if (in_data[i+3-color]==0) continue;
+                            int k = ((_vsize-1) * in_data[i]) / in_data[i+3-color];
+                            out_data[i] =  static_cast<unsigned char>(out_data[i+3-color] * _tableValues[k] + .5);
+                        }
                     }
                 }
                 break;
             case COMPONENTTRANSFER_TYPE_LINEAR:
-                _intercept = 255*_intercept + .5;
-                for(i=color;i<size;i+=4){
-                    out_data[i] = CLAMP_D_TO_U8(_slope * in_data[i] + _intercept);
+                if (!premultiplied || color==3) {
+                    _intercept = 255*_intercept + .5;
+                    for(i=color;i<size;i+=4){
+                        out_data[i] = CLAMP_D_TO_U8(_slope * in_data[i] + _intercept);
+                    }
+                } else {
+                    for(i=color;i<size;i+=4){
+                        if (in_data[i+3-color]==0) continue;
+                        out_data[i] = CLAMP_D_TO_U8(out_data[i+3-color] * (_slope * in_data[i] / in_data[i+3-color] + _intercept) + .5);
+                    }
                 }
                 break;
             case COMPONENTTRANSFER_TYPE_GAMMA:
-                _amplitude *= pow(255.0, -_exponent+1);
-                _offset = 255*_offset + .5;
-                for(i=color;i<size;i+=4){
-                    out_data[i] = CLAMP_D_TO_U8(_amplitude * pow((double)in_data[i], _exponent) + _offset);
+                if (!premultiplied || color==3) {
+                    _amplitude *= pow(255.0, -_exponent+1); // The input should be divided by 255, then exponentiated and then multiplied by 255 again, instead the amplitude is modified accordingly.
+                    _offset = 255*_offset + .5;
+                    for(i=color;i<size;i+=4){
+                        out_data[i] = CLAMP_D_TO_U8(_amplitude * pow((double)in_data[i], _exponent) + _offset);
+                    }
+                } else {
+                    for(i=color;i<size;i+=4){
+                        if (in_data[i+3-color]==0) continue;
+                        out_data[i] = CLAMP_D_TO_U8(out_data[i+3-color] * (_amplitude * pow((double)in_data[i] / in_data[i+3-color], _exponent) + _offset) + .5);
+                    }
                 }
                 break;
             case COMPONENTTRANSFER_TYPE_ERROR:
index 162b67703380e523f7ff023e12ce634dc3bba7c9..f2f68e05dc297731b023231ae63877805b3350b2 100644 (file)
@@ -194,7 +194,6 @@ sp_feComponentTransfer_set(SPObject *object, unsigned int key, gchar const *valu
                 ((SPObjectClass *) feComponentTransfer_parent_class)->set(object, key, value);
             break;
     }
-
 }
 
 /**
index 9d3380bf2cee47a0cac4783ab62c1a3587ba5a06..18e065a8dc85074842e37ac3bf2e807871846ad0 100644 (file)
@@ -94,24 +94,23 @@ inline std::vector<gdouble> helperfns_read_vector(const gchar* value, int size){
  */
 inline std::vector<gdouble> helperfns_read_vector(const gchar* value){
         std::vector<gdouble> v;
-        std::istringstream is(value);
-        gdouble d;
-        std::string str;
 
-        is >> str;
-        while(str.size())
+        gchar const* beg = value;
+        while(isspace(*beg)) beg++;
+        while(*beg)
         {
             char *end;
-            double ret = g_strtod(str.c_str(), &end);
-            if (*end){
-                g_warning("helper-fns::helperfns_read_vector() Unable to convert \"%s\" to number", str.c_str());
+            double ret = g_strtod(beg, &end);
+            if (end==beg){
+                g_warning("helper-fns::helperfns_read_vector() Unable to convert \"%s\" to number", beg);
                 // We could leave this out, too. If strtod can't convert
                 // anything, it will return zero.
                 ret = 0;
             }
-            v.push_back(d);
+            v.push_back(ret);
 
-            is >> str;
+            beg = end;
+            while(isspace(*beg)) beg++;
         }
         return v;
 }
index 5c973cf0df4ad04c76bf0cfc7111862ce2f5625f..3abb91690c9f08512c59f6348ee60cd7d64d661a 100644 (file)
@@ -30,6 +30,7 @@
 #include <sigc++/adaptors/bind.h>
 
 #include "libnr/nr-gradient.h"
+#include "libnr/nr-pixops.h"
 #include "svg/svg.h"
 #include "svg/svg-color.h"
 #include "svg/css-ostringstream.h"
@@ -1098,23 +1099,11 @@ sp_gradient_ensure_colors(SPGradient *gr)
         gint o0 = (gint) floor(gr->vector.stops[i].offset * (NCOLORS - 0.001));
         gint o1 = (gint) floor(gr->vector.stops[i + 1].offset * (NCOLORS - 0.001));
         if (o1 > o0) {
-            gint dr = ((r1 - r0) << 16) / (o1 - o0);
-            gint dg = ((g1 - g0) << 16) / (o1 - o0);
-            gint db = ((b1 - b0) << 16) / (o1 - o0);
-            gint da = ((a1 - a0) << 16) / (o1 - o0);
-            gint r = r0 << 16;
-            gint g = g0 << 16;
-            gint b = b0 << 16;
-            gint a = a0 << 16;
             for (int j = o0; j < o1 + 1; j++) {
-                gr->color[4 * j] = r >> 16;
-                gr->color[4 * j + 1] = g >> 16;
-                gr->color[4 * j + 2] = b >> 16;
-                gr->color[4 * j + 3] = a >> 16;
-                r += dr;
-                g += dg;
-                b += db;
-                a += da;
+                gr->color[4 * j + 0] = r0 + DIV_ROUND((j-o0)*(r1-r0),(o1-o0));
+                gr->color[4 * j + 1] = g0 + DIV_ROUND((j-o0)*(g1-g0),(o1-o0));
+                gr->color[4 * j + 2] = b0 + DIV_ROUND((j-o0)*(b1-b0),(o1-o0));
+                gr->color[4 * j + 3] = a0 + DIV_ROUND((j-o0)*(a1-a0),(o1-o0));
             }
         }
     }