Hi, currently in poppler we use bisection to fill radial shadings (see 
Gfx::doRadialShFill while (ia < radialMaxSplits) code)

That the code tries to find the biggest possible areas with the same color to 
avoid doing much partitions while still doing a proper shading.

This has the problem that not all functions are lineal in color, for example 
the function to draw the corners in 
https://bugs.freedesktop.org/show_bug.cgi?id=20238 where the bisection gets

1 0.002167 0.002167 0.002167                                                    
                             
2 0.004349 0.004349 0.004349                                                    
                             
3 0.006531 0.006531 0.006531                                                    
                             
4 0.008698 0.008698 0.008698                                                    
                             
130 0.008560 0.008560 0.008560                                                  
                             
131 0.000488 0.000488 0.000488                                                  
                             
193 0.000000 0.000000 0.000000                                                  
                             
224 0.000000 0.000000 0.000000                                                  
                             
240 0.000000 0.000000 0.000000                                                  
                             
248 0.000000 0.000000 0.000000                                                  
                             
252 0.000000 0.000000 0.000000                                                  
                             
254 0.000000 0.000000 0.000000                                                  
                             
255 0.000000 0.000000 0.000000                                                  
                             
256 0.000000 0.000000 0.000000                                                  
                             

We have the bad luck that (4 + 256) / 2 = 130 and 130 as input to the function 
returns the "same" color than 4, so the algorithm assumes the color is 
constant from 4 to 130 when it actually is not.

The solution i can easily see is the attached patch, that is instead of 
bisecting, increasing the value by 1 and seeing if it's still the same or not. 
This way the said pdf renders correctly but it's obviously slower.

The other thing i can think of is doing "some" samples after deciding the 
values 4 and 130 have the same color and that all the values in between will 
have the same color like testing 35, 67 and 99 too, but this will probably fix 
this pdf (did not test) but still would be possible to hit a pdf that fails.

What do you think, should we go to the slow but "correct" path or use the way 
that is still fast and patches the pdf we found that fails.

Also, do you have any other idea?

Albert
diff --git a/poppler/Gfx.cc b/poppler/Gfx.cc
index ccf818a..f9328ab 100644
--- a/poppler/Gfx.cc
+++ b/poppler/Gfx.cc
@@ -2804,15 +2804,8 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) {
 
   // fill the circles
   while (ia < radialMaxSplits) {
-
-    // go as far along the t axis (toward t1) as we can, such that the
-    // color difference is within the tolerance (radialColorDelta) --
-    // this uses bisection (between the current value, t, and t1),
-    // limited to radialMaxSplits points along the t axis; require at
-    // least one split to avoid problems when the innermost and
-    // outermost colors are the same
-    ib = radialMaxSplits;
-    sb = sMax;
+    ib = ia + 1;
+    sb = sMin + ((double)ib / (double)radialMaxSplits) * (sMax - sMin);
     tb = t0 + sb * (t1 - t0);
     if (tb < t0) {
       shading->getColor(t0, &colorB);
@@ -2821,16 +2814,17 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) {
     } else {
       shading->getColor(tb, &colorB);
     }
-    while (ib - ia > 1) {
+    while (ib < radialMaxSplits)
+    {
       for (k = 0; k < nComps; ++k) {
 	if (abs(colorB.c[k] - colorA.c[k]) > radialColorDelta) {
 	  break;
 	}
       }
-      if (k == nComps && ib < radialMaxSplits) {
+      if (k < nComps) {
 	break;
       }
-      ib = (ia + ib) / 2;
+      ib = ib + 1;
       sb = sMin + ((double)ib / (double)radialMaxSplits) * (sMax - sMin);
       tb = t0 + sb * (t1 - t0);
       if (tb < t0) {
_______________________________________________
poppler mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/poppler

Reply via email to