_cairo_color_double_to_short(): Use standard rounding algorithm

The _cairo_color_double_to_short() function converts a double
precision floating point value in the range of [0.0, 1.0] to a
uint16_t integer by dividing the [0.0, 1.0] range into 65536
equal-sized intervals and then associating each interval with an
integer.

Under the assumption that an integer i corresponds to the real value i
/ 65535.0 this algorithm introduces more error than necessary as can
be seen from the following picture showing the analogous
transformation for two-bit integers:

    +-----------+-----------+-----------+-----------+
   0b00         |  0b01     |      0b10 |          0b11
    +-----------+-----------+-----------+-----------+

which shows that some floating point values are not converted to the
integer that would minimize the error in value that that integer
corresponds to.

Instead, this patch uses standard rounding, which makes the diagram
look like this:

    +-------+---------------+---------------+-------+
   0b00     |      0b01     |      0b10     |      0b11
    +-------+---------------+---------------+-------+

It's clear that if the values corresponding to the given integers are
fixed, then it's not possible to decrease the resulting error by
moving any of the interval boundaries.

See this thread for more information:

    http://lists.freedesktop.org/archives/cairo/2013-October/024691.html

Reference images updated:

  pthread-similar.ref.png
  record-paint-alpha.ref.png
  record90-paint-alpha.argb32.ref
  record90-paint-alpha.rgb24.ref.png
  xcb-huge-image-shm.ref.png
  xcb-huge-subimage.ref.png

All of these have only one-step differences to the old images.
This commit is contained in:
Søren Sandmann Pedersen 2013-10-09 15:53:16 -04:00
parent 6f05ecf488
commit 98fef3cef2
7 changed files with 3 additions and 8 deletions

View file

@ -78,18 +78,13 @@ _cairo_stock_color (cairo_stock_t stock)
}
/* Convert a double in [0.0, 1.0] to an integer in [0, 65535]
* The conversion is designed to divide the input range into 65536
* equally-sized regions. This is achieved by multiplying by 65536 and
* then special-casing the result of an input value of 1.0 so that it
* maps to 65535 instead of 65536.
* The conversion is designed to choose the integer i such that
* i / 65535.0 is as close as possible to the input value.
*/
uint16_t
_cairo_color_double_to_short (double d)
{
uint32_t i;
i = (uint32_t) (d * 65536);
i -= (i >> 16);
return i;
return d * 65535.0 + 0.5;
}
static void

Binary file not shown.

Before

Width:  |  Height:  |  Size: 170 B

After

Width:  |  Height:  |  Size: 176 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 256 B

After

Width:  |  Height:  |  Size: 245 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 B

After

Width:  |  Height:  |  Size: 105 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 B

After

Width:  |  Height:  |  Size: 105 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 B

After

Width:  |  Height:  |  Size: 97 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 B

After

Width:  |  Height:  |  Size: 97 B