Code

Fix for bug #577012
authorJasper van de Gronde <jasper.vandegronde@gmail.com>
Tue, 18 May 2010 07:53:46 +0000 (09:53 +0200)
committerJasper van de Gronde <jasper.vandegronde@gmail.com>
Tue, 18 May 2010 07:53:46 +0000 (09:53 +0200)
src/libnr/nr-compose-transform.cpp
src/libnr/nr-pixops.h

index e7c2865698f31ecef2c49387972e43238b573f2e..05852bf07859bee67a33942b89ad715fc7cc1a92 100644 (file)
@@ -65,11 +65,14 @@ nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h,
        int x, y;
 
        if (alpha == 0) return;
+    if (alpha>255) {
+        g_warning("In transform PPN alpha=%u>255",alpha);
+    }
 
-    // Both alpha and color components are stored temporarily with a range of [0,255^2], so more supersampling and we get an overflow
-    if (xd+yd>16) {
-        xd = 8;
-        yd = 8;
+    // The color component is stored temporarily with a range of [0,255^3], so more supersampling and we get an overflow (fortunately Inkscape's preferences also doesn't allow a higher setting)
+    if (xd+yd>8) {
+        xd = 4;
+        yd = 4;
     }
 
        xsize = (1 << xd);
@@ -122,38 +125,42 @@ nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h,
                                        if ((sy >= 0) && (sy < sh)) {
                                                const unsigned char *s;
                                                s = spx + sy * srs + sx * 4;
-                                               r += NR_PREMUL_112 (s[0], s[3]);
+                                               r += NR_PREMUL_112 (s[0], s[3]); // s in [0,255]
                                                g += NR_PREMUL_112 (s[1], s[3]);
                                                b += NR_PREMUL_112 (s[2], s[3]);
                                                a += s[3];
+                        // a=sum(s3)
+                        // r,g,b in [0,sum(s3)*255]
                                        }
                                }
                        }
                        a = (a*alpha + rounding_fix) >> dbits;
+            // a=sum(s3)*alpha/size=avg(s3)*alpha
             // Compare to nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P
                        if (a != 0) {
-                               r = (r + rounding_fix) >> dbits;
-                               g = (g + rounding_fix) >> dbits;
-                               b = (b + rounding_fix) >> dbits;
+                               r = (r*alpha + rounding_fix) >> dbits;
+                               g = (g*alpha + rounding_fix) >> dbits;
+                               b = (b*alpha + rounding_fix) >> dbits;
+                // r,g,b in [0,avg(s3)*alpha*255]=[0,a*255]
                 if (a == 255*255) {
                                        /* Full coverage, demul src */
-                                       d[0] = NR_NORMALIZE_21(r);
-                                       d[1] = NR_NORMALIZE_21(g);
-                                       d[2] = NR_NORMALIZE_21(b);
+                                       d[0] = NR_NORMALIZE_31(r);
+                                       d[1] = NR_NORMALIZE_31(g);
+                                       d[2] = NR_NORMALIZE_31(b);
                                        d[3] = NR_NORMALIZE_21(a);
                 } else if (d[3] == 0) {
                     /* Only foreground, demul src */
-                    d[0] = NR_DEMUL_221(r,a);
-                    d[1] = NR_DEMUL_221(g,a);
-                    d[2] = NR_DEMUL_221(b,a);
+                    d[0] = NR_DEMUL_321(r,a);
+                    d[1] = NR_DEMUL_321(g,a);
+                    d[2] = NR_DEMUL_321(b,a);
                     d[3] = NR_NORMALIZE_21(a);
                                } else {
                                        unsigned int ca;
                                        /* Full composition */
                                        ca = NR_COMPOSEA_213(a, d[3]);
-                                       d[0] = NR_COMPOSEPNN_221131 (r, a, d[0], d[3], ca);
-                                       d[1] = NR_COMPOSEPNN_221131 (g, a, d[1], d[3], ca);
-                                       d[2] = NR_COMPOSEPNN_221131 (b, a, d[2], d[3], ca);
+                                       d[0] = NR_COMPOSEPNN_321131 (r, a, d[0], d[3], ca);
+                                       d[1] = NR_COMPOSEPNN_321131 (g, a, d[1], d[3], ca);
+                                       d[2] = NR_COMPOSEPNN_321131 (b, a, d[2], d[3], ca);
                                        d[3] = NR_NORMALIZE_31(ca);
                                }
                        }
@@ -272,19 +279,19 @@ nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_n (unsigned char *px, int w, int h
                        }
                        a = (a*alpha + rounding_fix) >> dbits;
                        if (a != 0) {
-                               r = (r + rounding_fix) >> dbits;
-                               g = (g + rounding_fix) >> dbits;
-                               b = (b + rounding_fix) >> dbits;
+                               r = (r*alpha + rounding_fix) >> dbits;
+                               g = (g*alpha + rounding_fix) >> dbits;
+                               b = (b*alpha + rounding_fix) >> dbits;
                                if ((a == 255*255) || (d[3] == 0)) {
                                        /* Transparent BG, premul src */
-                                       d[0] = NR_NORMALIZE_21(r);
-                                       d[1] = NR_NORMALIZE_21(g);
-                                       d[2] = NR_NORMALIZE_21(b);
+                                       d[0] = NR_NORMALIZE_31(r);
+                                       d[1] = NR_NORMALIZE_31(g);
+                                       d[2] = NR_NORMALIZE_31(b);
                                        d[3] = NR_NORMALIZE_21(a);
                                } else {
-                                       d[0] = NR_COMPOSEPPP_2211 (r, a, d[0]);
-                                       d[1] = NR_COMPOSEPPP_2211 (g, a, d[1]);
-                                       d[2] = NR_COMPOSEPPP_2211 (b, a, d[2]);
+                                       d[0] = NR_COMPOSEPPP_3211 (r, a, d[0]);
+                                       d[1] = NR_COMPOSEPPP_3211 (g, a, d[1]);
+                                       d[2] = NR_COMPOSEPPP_3211 (b, a, d[2]);
                                        d[3] = NR_COMPOSEA_211(a, d[3]);
                                }
                        }
@@ -309,11 +316,14 @@ void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, in
        int i;
 
        if (alpha == 0) return;
+    if (alpha>255) {
+        g_warning("In transform PPN alpha=%u>255",alpha);
+    }
 
-    // Both alpha and color components are stored temporarily with a range of [0,255^2], so more supersampling and we get an overflow
-    if (xd+yd>16) {
-        xd = 8;
-        yd = 8;
+    // The color component is stored temporarily with a range of [0,255^3], so more supersampling and we get an overflow (fortunately Inkscape's preferences also doesn't allow a higher setting)
+    if (xd+yd>8) {
+        xd = 4;
+        yd = 4;
     }
 
     dbits = xd + yd;
index 417e5e2c9e18df498a32700ccec7a5422723a205..7eafd1a9d368add0ece8dc9511982d5d99aaf4a1 100644 (file)
@@ -53,6 +53,7 @@ static inline unsigned int NR_COMPOSENNP_11113(unsigned int fc, unsigned int fa,
 static inline unsigned int NR_COMPOSENNP_11111(unsigned int fc, unsigned int fa, unsigned int bc, unsigned int ba) { return NR_NORMALIZE_31(NR_COMPOSENNP_11113(fc, fa, bc, ba)); }
 
 // Operation: (1 - fa) * bc * ba + fc
+static inline unsigned int NR_COMPOSEPNP_32114(unsigned int fc, unsigned int fa, unsigned int bc, unsigned int ba) { return (255*255 - fa) * ba * bc + 255 * fc; }
 static inline unsigned int NR_COMPOSEPNP_22114(unsigned int fc, unsigned int fa, unsigned int bc, unsigned int ba) { return (255*255 - fa) * ba * bc + 255*255 * fc; }
 static inline unsigned int NR_COMPOSEPNP_11113(unsigned int fc, unsigned int fa, unsigned int bc, unsigned int ba) { return (255 - fa) * ba * bc + 255*255 * fc; }
 static inline unsigned int NR_COMPOSEPNP_22111(unsigned int fc, unsigned int fa, unsigned int bc, unsigned int ba) { return NR_NORMALIZE_41(NR_COMPOSEPNP_22114(fc, fa, bc, ba)); }
@@ -65,6 +66,7 @@ static inline unsigned int NR_COMPOSENNN_111121(unsigned int fc, unsigned int fa
 
 // Operation: ((1 - fa) * bc * ba + fc)/a
 //   Reuses non-normalized versions of NR_COMPOSEPNP
+static inline unsigned int NR_COMPOSEPNN_321131(unsigned int fc, unsigned int fa, unsigned int bc, unsigned int ba, unsigned int a) { return DIV_ROUND(NR_COMPOSEPNP_32114(fc, fa, bc, ba), a); }
 static inline unsigned int NR_COMPOSEPNN_221131(unsigned int fc, unsigned int fa, unsigned int bc, unsigned int ba, unsigned int a) { return DIV_ROUND(NR_COMPOSEPNP_22114(fc, fa, bc, ba), a); }
 static inline unsigned int NR_COMPOSEPNN_111121(unsigned int fc, unsigned int fa, unsigned int bc, unsigned int ba, unsigned int a) { return DIV_ROUND(NR_COMPOSEPNP_11113(fc, fa, bc, ba), a); }
 
@@ -81,13 +83,15 @@ static inline unsigned int NR_COMPOSENPP_1111(unsigned int fc, unsigned int fa,
 // Operation: (1 - fa) * bc + fc
 //   (1-fa)*bc+fc = bc-fa*bc+fc = (bc+fc)-fa*bc
 // This rewritten form results in faster code (found out through testing)
-static inline unsigned int NR_COMPOSEPPP_2224(unsigned int fc, unsigned int fa, unsigned int bc) { return 255*255*(bc+fc) - fa*bc; }
+static inline unsigned int NR_COMPOSEPPP_2224(unsigned int fc, unsigned int fa, unsigned int bc) { return 255*255*(bc+fc) - fa*bc; } // Note that this can temporarily overflow (but it probably doesn't cause problems)
   // NR_COMPOSEPPP_2224 assumes that fa and fc have a common component (fa=a*x and fc=c*x), because then the maximum value is: 
   //   (255*255-255*x)*255*255 + 255*x*255*255 = 255*255*( (255*255-255*x) + 255*x ) = 255*255*255*( (255-x)+x ) = 255*255*255*255
+static inline unsigned int NR_COMPOSEPPP_3213(unsigned int fc, unsigned int fa, unsigned int bc) { return 255*255*bc + fc - fa*bc; }
 static inline unsigned int NR_COMPOSEPPP_2213(unsigned int fc, unsigned int fa, unsigned int bc) { return 255*(255*bc+fc) - fa*bc; }
 static inline unsigned int NR_COMPOSEPPP_1213(unsigned int fc, unsigned int fa, unsigned int bc) { return 255*255*(bc+fc) - fa*bc; }
 static inline unsigned int NR_COMPOSEPPP_1112(unsigned int fc, unsigned int fa, unsigned int bc) { return 255*(bc+fc) - fa*bc; }
 static inline unsigned int NR_COMPOSEPPP_2221(unsigned int fc, unsigned int fa, unsigned int bc) { return NR_NORMALIZE_41(NR_COMPOSEPPP_2224(fc, fa, bc)); }
+static inline unsigned int NR_COMPOSEPPP_3211(unsigned int fc, unsigned int fa, unsigned int bc) { return NR_NORMALIZE_31(NR_COMPOSEPPP_3213(fc, fa, bc)); }
 static inline unsigned int NR_COMPOSEPPP_2211(unsigned int fc, unsigned int fa, unsigned int bc) { return NR_NORMALIZE_31(NR_COMPOSEPPP_2213(fc, fa, bc)); }
 static inline unsigned int NR_COMPOSEPPP_1211(unsigned int fc, unsigned int fa, unsigned int bc) { return NR_NORMALIZE_21(NR_COMPOSEPPP_1213(fc, fa, bc)); }
 static inline unsigned int NR_COMPOSEPPP_1111(unsigned int fc, unsigned int fa, unsigned int bc) { return NR_NORMALIZE_21(NR_COMPOSEPPP_1112(fc, fa, bc)); }