Triangle-kernel filtering problems at non-integer ratios
I went with Jason R's idea of adjusting the linear filtering, except I didn't like the idea of doing a division on every output pixel, using more than just a simple kernel or how normalising that way would ruin the smooth borders. So instead I modified the kernel itself, which it turns out is done by flattening the peak of the triangle.



It seems like a pretty good solution, and you can see how the sum of the triangles progresses into something resembling a Gaussian function.

Here's how it's done, first of all there's a 'knee' joining the flat top with the rest of the triangle. It ping-pongs on the horizontal axis between 0 and 0.5 like so. Note: $n$ is the scale multiplier for the width of the kernel and the size of the downscaling, it's always 1 or lower, it's the reciprocal of the number displayed at the top of the animation. The smaller $n$, the smaller the output image, the wider the kernel over the original image.

$knee = 0.5 - |(n^{-1} \mod 1) - 0.5|$

Next we need to calculate the height of the top of the flattened triangle, which is done like this:

$m = \lfloor n^{-1} + 0.5\rfloor$

$top = \frac{1 - knee \cdot n}{2m - nm^2}$

And finally we turn it into an affine function which we can use directly when calculating weights:

$c_1 = \frac{-top}{n^{-1}-knee}$

$c_0 = \frac{-c_1}{n}$

The above is calculated only once and $knee$, $top$, $c_1$ and $c_0$ are stored and used when computing weights like this:

$$f(x) =
  \begin{cases} 
      \hfill top   \hfill &amp; \text{ if $|x| \leq knee$ } \\
      \hfill c_1 x + c_0 \hfill &amp; \text{ if $knee &lt; |x| \leq n^{-1}$ } \\
      \hfill 0   \hfill &amp; \text{ otherwise } \\
  \end{cases}$$