[cairo] Use 8-bit colour values internally

Jason Dorje Short jdorje at users.sf.net
Mon Aug 22 20:37:04 PDT 2005


Billy Biggs wrote:
>   The 16-bit representation of colours (cairo_color_t's shorts) is only
> used by the fill_rectangles implementation for the image and Xlib
> backends.  However, neither really needs this much precision: pixman and
> X both convert back to 8 bit internally by shifting.

In the pixman code in the patch it looks like pixman is using 16-bit 
values...

>   I would rather see cairo internally just store the values as 8-bit.
> I'd also rather cairo round rather than truncate and push towards 1.  I
> admit that this is a matter of taste and not correctness.  Some test
> output would change, for example the 0.3 used in the linear-gradient
> test will map to 77/255 rather than 76/255.

With some good preprocessor macros this could be made a lot more 
transparent and less error-prone.

> ------------------------------------------------------------------------
> 
> Index: cairo-color.c
> ===================================================================
> RCS file: /cvs/cairo/cairo/src/cairo-color.c,v
> retrieving revision 1.15
> diff -p -u -r1.15 cairo-color.c
> --- cairo-color.c	13 Aug 2005 08:04:55 -0000	1.15
> +++ cairo-color.c	23 Aug 2005 00:46:26 -0000
> @@ -38,13 +38,13 @@
>  #include "cairoint.h"
>  
>  static cairo_color_t const cairo_color_white = {
> -    1.0,    1.0,    1.0,    1.0,
> -    0xffff, 0xffff, 0xffff, 0xffff
> +    1.0,  1.0,  1.0,  1.0,
> +    0xff, 0xff, 0xff, 0xff
>  };

#define COLOR_MAX 255
#define COLOR_TO_INT(c) ((int)(c) * (double)COLOR_MAX + 0.5))

#define COLOR(r, g, b, a) \
   {                       \
     (r), (g), (b), (a),   \
     COLOR_TO_INT(r), COLOR_TO_INT(g), COLOR_TO_INT(b), COLOR_TO_INT(a) \
   }

static cairo_color_t const cairo_color_white
     = COLOR(1.0, 1.0, 1.0, 1.0);

> -/* We multiply colors by (0x10000 - epsilon), such that we get a uniform
> - * range even for 0xffff.  In other words, (1.0 - epsilon) would convert
> - * to 0xffff, not 0xfffe.
> - */
> -#define CAIRO_COLOR_ONE_MINUS_EPSILON (65536.0 - 1e-5)
> -
>  static void
> -_cairo_color_compute_shorts (cairo_color_t *color)
> +_cairo_color_compute_chars (cairo_color_t *color)
>  {
> -    color->red_short   = color->red   * color->alpha * CAIRO_COLOR_ONE_MINUS_EPSILON;
> -    color->green_short = color->green * color->alpha * CAIRO_COLOR_ONE_MINUS_EPSILON;
> -    color->blue_short  = color->blue  * color->alpha * CAIRO_COLOR_ONE_MINUS_EPSILON;
> -    color->alpha_short = color->alpha * CAIRO_COLOR_ONE_MINUS_EPSILON;
> +    color->red_char   = floor (color->red   * color->alpha * 255.0 + 0.5);
> +    color->green_char = floor (color->green * color->alpha * 255.0 + 0.5);
> +    color->blue_char  = floor (color->blue  * color->alpha * 255.0 + 0.5);
> +    color->alpha_char = floor (color->alpha * 255.0 + 0.5);
>  }

   color->red_char = COLOR_TO_INT(color->red * color->alpha);

Looks like the uniform-distribution hack here is trying to do the same 
thing you're doing with rounding (otherwise 0.{9} would never give 
COLOR_MAX, always COLOR_MAX-1).  Clearly rounding is more accurate 
though (if I understand rightly what this code does).

> -    pixman_color.red   = color->red_short;
> -    pixman_color.green = color->green_short;
> -    pixman_color.blue  = color->blue_short;
> -    pixman_color.alpha = color->alpha_short;
> +    pixman_color.red   = color->red_char << 8;
> +    pixman_color.green = color->green_char << 8;
> +    pixman_color.blue  = color->blue_char << 8;
> +    pixman_color.alpha = color->alpha_char << 8;

#define COLOR_INT_TO_SHORT(c) ((c) << 8)

> -    unsigned short red_short;
> -    unsigned short green_short;
> -    unsigned short blue_short;
> -    unsigned short alpha_short;
> +    unsigned char red_char;
> +    unsigned char green_char;
> +    unsigned char blue_char;
> +    unsigned char alpha_char;

typedef color_int_t char;

(Naming could use some improvement.)

-jason


More information about the cairo mailing list