[cairo] [RFC] high-quality pixman image downscaling
Bill Spitzak
spitzak at gmail.com
Mon Jul 13 11:38:08 PDT 2009
Jeff Muizelaar wrote:
> I've added the cairo list back to the cc.
>
> On Mon, Jul 06, 2009 at 07:15:43PM -0700, Bill Spitzak wrote:
>> Jeff Muizelaar wrote:
>>
>>>> The api you designed does not allow an arbitrary integer division to be
>>>> specified as you can only do original_width/integer values and thus the
>>>> only integer scales allowed are factors of both the width and height. I
>>>> would change this to a pair of integers (the scale is then 1/x,1/y, and
>>>> there is certainly no rounding problems).
>>> I don't understand this comment. The scaled size is specified by
>>> scaled_width/scaled_height. What limitations does this have?
>> It cannot specify an integer scale that is not a divisor of the original
>> size. The nearest integer scale is not likely to be a divisor of the
>> image width and height.
>
> I understand what you mean now. Can you explain what the advantage of
> this would be?
I figured it had to be an integer scale in order to get a fast
implementation. Your idea of alternating two different integer-sized
scales sounds like an interesting alternative that I had not thought of,
however.
I think alternating two integer box filters is going to produce some
annoying artifacts, especially when the scale is between 1 and 2. But I
am not sure if it will be worse than the artifacts introduced when the
box filter output is linear-interpolated to make the finale image.
From a mathematical point of view it seems easier to choose the nearest
integer scale figured out from the CTM. Any artifacts would be the same
for a given CTM no matter how the source image is cropped, while if the
destination is integer-sized then the artifacts will change depending on
the original's dimensions.
> Currently the scaling code is designed around scaling to
> an integer number of pixels. The plan for scaling to an integer scale
> that is not a divisor would be to go through the two pass algorithm.
> i.e. scale to the nearest integer number of pixels and then resample
> that to desired size.
This sounds the same as what I was thinking of, though I always saw
"interger scale" as being a scale factor of 1/N where N is an integer.
>
>>>> A big problem is edge repeat. To allow algorithims like you are
>>>> suggesting requires "repeat" handling of the edges of all images ALL THE
>>>> TIME.
>>> Only the lanczos algorithm requires any edge handling. Currently, the
>>> code truncates the filter and therefor will not sample outside of the
>>> image.
>> I think there may be some confusion on either my or your part, as the
>> need to handle box filters that extend outside the source image, and the
>> need to handle scale factors that don't evenly divide the size of the
>> image, are related.
>
> The current box filters never extend outside the source image. Scale
> factors that don't evenly divide the size of the image are handled by
> two different strategies:
> 1) the box filter size alternates between two integer values such that
> there is no extension
This is an interesting idea that I had not thought of. It won't really
alternate but it is fairly easy to choose which of two sizes to use
interatively as you progress across the image. I would be very worried
about artifacts such as diagonal lines looking crooked, though I am not
sure if they are worse than the ones introduced by the linear
interpolation step.
> 2) the box filter size is not an integer
This would be much much slower than an integer sized box filter, as one
pixel contributes to two output pixels.
>> I suspect that removing the need to decide what type of padding is being
>> done by the sampling will make it more efficient and thus a good first step.
>
> We still need to support the different other repeat types so removing
> REPEAT_NONE doesn't help much. Doing the clip efficiently is probably
> the more interesting part.
The other repeat types can be successfully simulated, IMHO, though I
have not done enough testing of this:
The actual source area scaled down would be larger than the image, with
the correct repeat type applied to it. The image size would be rounded
up to a multiple of the integer scale factor, and the rectangle
positioned so that the center of one pixel on all edges of the output
image lies outside or on the edge of the source image.
This would allow the center of all final output pixels to lie between
two pixels of the intermediate image and make the linear interpolation
easy with no edge cases to worry about.
When repeat-tiling it would produce an aliased line between the tiles as
it selected between the left and right versions of the image. However
these two locations would already be strongly blended together into the
same value so this should not be visible.
Mirror tiling should work perfectly with this.
Repeat-outside for perfect results would require a larger intermediate
image such that the outermost pixels are entirely sampled from outside
the source. But the error only exists more than 1 intermediate pixel
from the edge and I think the incorrect version (where all the sides are
blended into each other) may be less objectionable than the correct version.
Black-outside would "work" but would *require* a full outside pixel,
just like perfect repeat-outside would. Certainly blending any color
into the outside samples would be obviously wrong so it cannot cheat
like the repeat-outside version. Besides users want sharp black outside
edges so I think it is pointless to even continue to consider it a
filtering option and the best thing to do would be to eradicate it from
the low-level code.
More information about the cairo
mailing list