summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSøren Sandmann Pedersen <ssp@redhat.com>2012-11-21 11:43:31 -0500
committerSøren Sandmann Pedersen <ssp@redhat.com>2012-11-22 01:16:54 -0500
commit978bab253d1d061b00b5e80aa45ab6986aac466f (patch)
treee84f15abf0333dd351d1f04e7a56498499efd8ee
parent74319e9d39f5d7f85cb75fcb91343f298b0e62e2 (diff)
Add text file rounding.txt describing how rounding worksrounding
It is not entirely obvious how pixman gets from "location in the source image" to "pixel value stored in the destination". This file describes how the filters work, and in particular how positions are rounded to samples.
-rw-r--r--pixman/rounding.txt134
1 files changed, 134 insertions, 0 deletions
diff --git a/pixman/rounding.txt b/pixman/rounding.txt
new file mode 100644
index 00000000..1a19f450
--- /dev/null
+++ b/pixman/rounding.txt
@@ -0,0 +1,134 @@
+*** General notes about rounding
+
+Suppose a function is sampled at positions [k + o] where k is an
+integer and o is a fractional offset 0 <= o < 1.
+
+To round a value to the nearest sample, breaking ties by rounding up,
+we can do this:
+
+ round(x) = floor(x - o + 0.5) + o
+
+That is, first subtract o to let us pretend that the samples are at
+integer coordinates, then add 0.5 and floor to round to nearest
+integer, then add the offset back in.
+
+To break ties by rounding down:
+
+ round(x) = ceil(x - o - 0.5) + o
+
+or if we have an epsilon value:
+
+ round(x) = floor(x - o + 0.5 - e) + o
+
+To always round *up* to the next sample:
+
+ round_up(x) = ceil(x - o) + o
+
+To always round *down* to the previous sample:
+
+ round_down(x) = floor(x - o) + o
+
+If a set of samples is stored in an array, you get from the sample
+position to an index by subtracting the position of the first sample
+in the array:
+
+ index(s) = s - first_sample
+
+
+*** Application to pixman
+
+In pixman, images are sampled with o = 0.5, that is, pixels are
+located midways between integers. We usually break ties by rounding
+down (i.e., "round towards north-west").
+
+
+-- NEAREST filtering:
+
+The NEAREST filter simply picks the closest pixel to the given
+position:
+
+ round(x) = floor(x - 0.5 + 0.5 - e) + 0.5 = floor (x - e) + 0.5
+
+The first sample of a pixman image has position 0.5, so to find the
+index in the pixel array, we have to subtract 0.5:
+
+ floor (x - e) + 0.5 - 0.5 = floor (x - e).
+
+Therefore a 16.16 fixed-point image location is turned into a pixel
+value with NEAREST filtering by doing this:
+
+ pixels[((y - e) >> 16) * stride + ((x - e) >> 16)]
+
+where stride is the number of pixels allocated per scanline and e =
+0x0001.
+
+
+-- CONVOLUTION filtering:
+
+A convolution matrix is considered a sampling of a function f at
+values surrounding 0. For example, this convolution matrix:
+
+ [a, b, c, d]
+
+is interpreted as the values of a function f:
+
+ a = f(-1.5)
+ b = f(-0.5)
+ c = f(0.5)
+ d = f(1.5)
+
+The sample offset in this case is o = 0.5 and the first sample has
+position s0 = -1.5. If the matrix is:
+
+ [a, b, c, d, e]
+
+the sample offset is o = 0 and the first sample has position s0 =
+-2.0. In general we have
+
+ s0 = (- width / 2.0 + 0.5).
+
+and
+
+ o = frac (s0)
+
+To evaluate f at a position between the samples, we round to the
+closest sample, and then we subtract the position of the first sample
+to get the index in the matrix:
+
+ f(t) = matrix[floor(t - o + 0.5) + o - s0]
+
+Note that in this case we break ties by rounding up.
+
+If we write s0 = m + o, where m is an integer, this is equivalent to
+
+ f(t) = matrix[floor(t - o + 0.5) + o - (m + o)]
+ = matrix[floor(t - o + 0.5 - m) + o - o]
+ = matrix[floor(t - s0 + 0.5)]
+
+The convolution filter in pixman positions f such that 0 aligns with
+the given position x. For a given pixel x0 in the image, the closest
+sample of f is then computed by taking (x - x0) and rounding that to
+the closest index:
+
+ i = floor ((x0 - x) - s0 + 0.5)
+
+To perform the convolution, we have to find the first pixel x0 whose
+corresponding sample has index 0. We can write x0 = k + 0.5, where k
+is an integer:
+
+ 0 = floor(k + 0.5 - x - s0 + 0.5)
+
+ = k + floor(1 - x - s0)
+
+ = k - ceil(x + s0 - 1)
+
+ = k - floor(x + s0 - e)
+
+ = k - floor(x - (width - 1) / 2.0 - e)
+
+And so the final formula for the index k of x0 in the image is:
+
+ k = floor(x - (width - 1) / 2.0 - e)
+
+Computing the result is then simply a matter of convolving all the
+pixels starting at k with all the samples in the matrix.