[cairo] Compositing benchmarks

Bill Spitzak spitzak at d2.com
Tue Mar 6 04:40:58 PST 2007


Carl Worth wrote:

> I think the reason is simply that we haven't gotten around to fixing
> it yet. I'd love to see someone implement a software "mipmap"-like
> approach for image scaling. It would eliminate one of the few
> visual-quality warts still left in cairo.

A mipmap is only useful if the image is going to be drawn many times. 
This perhaps could be done if the source surface could store it for 
reuse, but this would have to be a special mipmap-surface type and 
(similar to that jpeg->pdf stuff) would require the destination surface 
to recognize and use the mipmap source directly.

The more immediate and useful solution for Cairo is to do filtered 
sampling of more than 4 pixels of the source image. I believe that for 
Cairo, a pixel-aligned box filter is quite sufficient, and has the 
advantage of blending smoothly with how cairo enlarges images. The 
following will do it, there is just a small matter of optimizing it :-)

All variables are floating point.

Take the center of the destination pixel X,Y (this would be two numbers 
ending in .5).

Back-project X,Y to get x,y source coordinate.

Back-project X+1,Y and subtract x,y to get dux,duy.
Back-project X,Y+1 and subtract x,y to get dvx,dvy.
(above two steps can be simplified a lot if perspective is not done)

// Produce the pixel-aligned rectangle of approximately equal size:
A = fabs(dux*dvy-duy*dvx);
W = dux*dux+dvx*dvx;
H = duy*duy+dvy*dvy;
if (W>H) {
   W = sqrt(W);
   H = A/W;
} else if (H > 0) {
   H = sqrt(H);
   W = A/H;
}
// Box filter must be at least 1 in size.
if (W < 1) W = 1;
if (H < 1) H = 1;

Now consider the rectangle of size W,H centered on x,y. Multiply every 
pixel that intersects this rectangle by the area of the intersection, 
add all these together, and divide by W*H. This is the resulting sample.

optimizations:

The most useful optimization is to detect W==1 and H==1 as early as 
possible in the above and do the current cairo sampling, which is 
equivalent.

Less important, though it seems obvious, is to do a 2-pass algorithim, 
as the weight for each pixel is the horizontal weight times the vertical 
weight.

In each direction there are only 2 pixels with fractional weights 
(sometimes these "fractions" are 0 and 1) and floor(W-1) pixels that are 
multiplied by 1.

The next step down in quality is to round W and H to the nearest 
integers, making the division an integer and making the above two 
fractions always add to 1.

Further reductions in quality would be to round the edges of the 
rectangle to integers for any direction where the size is greater than 
1. This makes each pass be two cases: either average n pixels or do the 
current cairo weighted sum of 2 pixels.

Another reduction in quality is to set W==H==sqrt(A). I suspect OS/X 
quartz may be doing this.

Going the other way, the best way to improve quality is to sample a 
axis-aligned "parallelogram" by doing integer offsets to the nearest 
value. I would not try anything fancier (such as trying to figure out 
the intersection with an arbitrary parallelogram) as this is overkill, 
it is better to use better sampling filters (ie apply different weights 
to the pixels depending on how far they are from x,y).



More information about the cairo mailing list