PreviousUpNext

15.4.1582  src/lib/x-kit/xclient/src/color/rgb.pkg

## rgb.pkg
#
# RGB colors 
#
# See also:
#     src/lib/x-kit/xclient/src/color/hue-saturation-value.pkg
#     src/lib/x-kit/xclient/src/color/rgb8.pkg

# Compiled by:
#     src/lib/x-kit/xclient/xclient-internals.sublib

stipulate
    include package   rw_float_vector;                                          # Enable   vec[i]   and   vec[i] := f   notations.
    #
    package f8b =  eight_byte_float;                                            # eight_byte_float      is from   src/lib/std/eight-byte-float.pkg
    package fv  =  rw_float_vector;                                             # rw_float_vector       is from   src/lib/std/rw-float-vector.pkg
herein

    package rgb
    :       Rgb                                                                 # Rgb                   is from   src/lib/x-kit/xclient/src/color/rgb.api
    {

        # We represent an RGB color value by a
        # record of 64-bit floats holding
        # red, green, blue in that order.
        # (The compiler will optimize this to
        # a very efficient packed representation.)
        # 
        Rgb = { red:    Float,
                green:  Float,
                blue:   Float
              };



        fun rgb_from_floats (red, green, blue)                                  # Should do some sort of validation (restriction to [0,1) interval). What exception should we throw? Or should we silently truncate?  XXX BUGGO FIXME.
            =
            { red, green, blue };

        fun rgb_to_floats (rgb: Rgb)
            =
            (rgb.red, rgb.green, rgb.blue);                                     # Eventually we'll probably want to suppress index checking here for speed, using unsafe:: operations or whatever. XXX BUGGO FIXME.



        fun rgb_from_unts  (red, green, blue)
            =
            { red   =>  unt_to_float  red,
              green =>  unt_to_float  green,
              blue  =>  unt_to_float  blue
            }
            where
                fun unt_to_float u
                    =
                    {   i  = unt::to_int     u;

                        f  = f8b::from_int  i;

                        f  = f / 65535.0;                                       # Our unts run 0 -> 65535.

                        f;
                    };
              end;              
        

        fun rgb_to_unts  { red, green, blue }
            =
            ( float_to_unt  red,
              float_to_unt  green,
              float_to_unt  blue
            )
            where
                fun float_to_unt f
                    =
                    {   f = (f < 0.0) ?? 0.0 :: f;
                        f = (f > 1.0) ?? 1.0 :: f;

                        f = f * 65535.99;               # Our unts run 0 -> 65535.

                        unt::from_int (f8b::truncate f);
                    };
            end;


        fun same_rgb (a: Rgb, b: Rgb)
            =   f8b::(====) (a.red,   b.red  )
            and f8b::(====) (a.green, b.green)
            and f8b::(====) (a.blue,  b.blue )
            ;


        # Ensure that all color components
        # are in 0.0 -> 1.0 inclusive:
        #
        fun rgb_normalize (rgb as { red, green, blue })
            =
            {   if (red   >= 0.0   and   red   <= 0.0
                and green >= 0.0   and   green <= 0.0
                and blue  >= 0.0   and   blue  <= 0.0
                )
                    rgb;
                else
                    red   =  red   >= 0.0  ??  red    ::  0.0;
                    red   =  red   <= 1.0  ??  red    ::  1.0;
                    #
                    green =  green >= 0.0  ??  green  ::  0.0;
                    green =  green <= 1.0  ??  green  ::  1.0;
                    #
                    blue  =  blue  >= 0.0  ??  blue   ::  0.0;
                    blue  =  blue  <= 1.0  ??  blue   ::  1.0;
                    #
                    { red, green, blue };
                fi;
            };

        fun rgb_to_string (c: Rgb)
            =
            sprintf "{ red => %g, green => %g, blue => %g }"
                     c.red      c.green      c.blue;

        fun rgb_complement (c:  Rgb)                                    # Set each component c to (1.0-c).
            =
            { red   =>  1.0 - c.red,
              green =>  1.0 - c.green,
              blue  =>  1.0 - c.blue
            };

        fun rgb_scale (w: Float, a: Rgb)                                # Multiply color components by given factor, then clip to 0.0 -> 1.0 range.
            =
            {   red   =  w * a.red;
                green =  w * a.green;
                blue  =  w * a.blue;

                rgb_normalize { red, green, blue };
            };

        fun rgb_mix01 (w: Float, a: Rgb, b: Rgb)                        # Linear interpolation in RGB space.  0.0 yields first color, 1.0 yields second color. (The "01" in name is mnemonic of the  0.0 -> 1.0 arg range.)
              =
              { red   =>  (1.0 - w) * a.red    +   w * b.red,
                green =>  (1.0 - w) * a.green  +   w * b.green,
                blue  =>  (1.0 - w) * a.blue   +   w * b.blue
              };

        fun rgb_mix11 (w: Float, a: Rgb, b: Rgb)                        # Linear interpolation in RGB space. -1.0 yields first color, 1.0 yields second color. (The "11" in name is mnemonic of the  -1.0 -> 1.0 arg range.)
              =
              rgb_mix01 ((w + 1.0) * 0.5, a, b);

        fun rgb_from_name  colorname
            =
            rgb_from_floats  (x11_color_name::to_floats  colorname);

        fun rgb_to_grayscale (c: Rgb)
            =
            ( 0.2126 * c.red                                            # Rec 601 coefficients -- see http://en.wikipedia.org/wiki/Luma_(video)
            + 0.7152 * c.green
            + 0.0722 * c.blue);

        fun rgb_is_light (c: Rgb)                                       # TRUE iff   (rgb_to_grayscale c) > 0.5.
            =
            (rgb_to_grayscale c) > 0.5;



        # Predefine a few common colors for convenience:
        #
        black   = rgb_from_floats (0.0, 0.0, 0.0);
        gray    = rgb_from_floats (0.5, 0.5, 0.5);
        white   = rgb_from_floats (1.0, 1.0, 1.0);
        #
        red     = rgb_from_floats (1.0, 0.0, 0.0);
        green   = rgb_from_floats (0.0, 1.0, 0.0);
        blue    = rgb_from_floats (0.0, 0.0, 1.0);
        #
        cyan    = rgb_from_floats (0.0, 1.0, 1.0);
        magenta = rgb_from_floats (1.0, 0.0, 1.0);
        yellow  = rgb_from_floats (1.0, 1.0, 0.0);
    };
end;

## COPYRIGHT (c) 1994 by AT&T Bell Laboratories
## Subsequent changes by Jeff Prothero Copyright (c) 2010-2015,
## released per terms of SMLNJ-COPYRIGHT.


Comments and suggestions to: bugs@mythryl.org

PreviousUpNext