Calculate accurate weighted average in YdownXdown (aka Smooth Bresenham)
When iterating through the destination image while scaling down, we know the fractional source area that should in theory cover a destination pixel. In practice a pixel has size 1 and the averaging box and number of source pixels must be integral. We can correct the resulting error by assigning weights into the averaging box.
The former implementation weighted "only a bit" with the d0
/ d1
variables, but it didn't take x fractions into account and also missed to pad up the weight to 1 for consecutive y rows. That seems to be the main reason why the outcome of the former YdownXdown
looked "coarse" and "jagged".
This commit implements the wighted average almost exactly as Tim Kientzle suggested it in "Scaling Bitmaps with Bresenham" (C/C++ User's Journal, October 1995), just extended for 2 dimensions and adapted to the exiting Splash.cc code.
This can be used in addition to !626, or as sole alternative, and shall help fixing #950.
I'm not going to touch other {X,Y}down
variants in this MR. If requested it can be done in another MR, but I'd spend time rather on a long term replacement for the scaling code.
#950
Visual inspection: Embedded images fromFrom left to right: Splash Bresenham, Splash Smooth Bresenham (proposed change), Cairo.
Performance
We need some additional integer multiplications per source pixel to calculate the weighted average. This shows up as moderate performance penalty in my test: