Code

Fixed rendering glitch in bicubic scaler
authorkiirala <kiirala@users.sourceforge.net>
Tue, 24 Jul 2007 12:48:54 +0000 (12:48 +0000)
committerkiirala <kiirala@users.sourceforge.net>
Tue, 24 Jul 2007 12:48:54 +0000 (12:48 +0000)
src/display/nr-filter-utils.cpp
src/display/nr-filter-utils.h
src/display/pixblock-scaler.cpp

index 85faadebcd86018873e67e6467735c6e274ab5ea..52c8ecc7d27dfef18cb898eb1cce24c465349b10 100644 (file)
@@ -2,10 +2,27 @@
 
 namespace NR {
 
-int clamp(int val) {
+int clamp(int const val) {
     if (val < 0) return 0;
     if (val > 255) return 255;
     return val;
 }
-       
+
+int clamp_alpha(int const val, int const alpha) {
+    if (val < 0) return 0;
+    if (val > alpha) return alpha;
+    return val;
+}
+
 } //namespace NR
+
+/*
+  Local Variables:
+  mode:c++
+  c-file-style:"stroustrup"
+  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+  indent-tabs-mode:nil
+  fill-column:99
+  End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
index b591b37cb759662d8f76e5cb3cedb5f8ad16e50e..5ac6fa5ab405711a58e2c2c84b10d3281b5c9d4c 100644 (file)
@@ -23,13 +23,23 @@ namespace NR {
  * \return 0 if the value is smaller than 0, 255 if it is greater 255, else v
  * \param v the value to clamp
  */
-int clamp(int val);
+int clamp(int const val);
 
 /**
  * Macro to use the clamp function with double inputs and unsigned char output
  */
 #define CLAMP_D_TO_U8(v) (unsigned char) clamp((int)round((v)))
 
+/**
+ * Clamps an integer to a value between 0 and alpha. Useful when handling
+ * images with premultiplied alpha, as setting some of RGB channels
+ * to a value bigger than alpha confuses the alpha blending in Inkscape
+ * \return 0 if val is negative, alpha if val is bigger than alpha, val otherwise
+ * \param val the value to clamp
+ * \param alpha the maximum value to clamp to
+ */
+int clamp_alpha(int const val, int const alpha);
+
 } /* namespace NR */
 
 #endif /* __NR_FILTER_UTILS_H__ */
index c5acaace0b3e5f4f033accc3ac7457715e031dcd..d65cfd4e0d78178a49c92289ac5f231df38635ad 100644 (file)
@@ -15,6 +15,7 @@
 #include <cmath>
 using std::floor;
 
+#include "display/nr-filter-utils.h"
 #include "libnr/nr-pixblock.h"
 
 namespace NR {
@@ -61,16 +62,16 @@ inline int sampley(unsigned const char a, unsigned const char b,
  * Returns the interpolated value in 8-bit format, ready to be written
  * to output buffer.
  */
-inline unsigned char samplex(const int a, const int b, const int c, const int d, const double len) {
+inline int samplex(const int a, const int b, const int c, const int d, const double len) {
     double lenf = len - floor(len);
     int sum = 0;
     sum += (int)(a * (((-1.0 / 3.0) * lenf + 4.0 / 5.0) * lenf - 7.0 / 15.0) * lenf);
     sum += (int)(b * (((lenf - 9.0 / 5.0) * lenf - 1.0 / 5.0) * lenf + 1.0));
     sum += (int)(c * ((((1 - lenf) - 9.0 / 5.0) * (1 - lenf) - 1.0 / 5.0) * (1 - lenf) + 1.0));
     sum += (int)(d * (((-1.0 / 3.0) * (1 - lenf) + 4.0 / 5.0) * (1 - lenf) - 7.0 / 15.0) * (1 - lenf));
-    if (sum < 0) sum = 0;
-    if (sum >= 256*256) sum = 255 * 256;
-    return (unsigned char)(sum / 256);
+    //if (sum < 0) sum = 0;
+    //if (sum > 255 * 256) sum = 255 * 256;
+    return sum / 256;
 }
 
 /**
@@ -169,10 +170,24 @@ void scale_bicubic(NRPixBlock *to, NRPixBlock *from)
                                from_x);
 
             _check_index(to, to_y * to->rs + to_x * 4, __LINE__);
-            NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4] = result.r;
-            NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 1] = result.g;
-            NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 2] = result.b;
-            NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 3] = result.a;
+
+            if (to->mode == NR_PIXBLOCK_MODE_R8G8B8A8P) {
+                /* Clamp the colour channels to range from 0 to result.a to
+                 * make sure, we don't exceed 100% per colour channel with
+                 * images that have premultiplied alpha */
+
+                result.a = clamp(result.a);
+
+                NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4] = clamp_alpha(result.r, result.a);
+                NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 1] = clamp_alpha(result.g, result.a);
+                NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 2] = clamp_alpha(result.b, result.a);
+                NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 3] = result.a;
+            } else {
+                NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4] = clamp(result.r);
+                NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 1] = clamp(result.g);
+                NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 2] = clamp(result.b);
+                NR_PIXBLOCK_PX(to)[to_y * to->rs + to_x * 4 + 3] = clamp(result.a);
+            }
         }
     }
 }