Table of Contents
The symbol
returns the reader to the top of the Table of Contents.
Introduction
This article presents a revision to the Known Colors Palette Tool. In
the header of changed paragraphs appears the graphic
and
in the header of new paragraphs appears the graphic
.
As before, the results of this this revision accomplishes what the
earlier revision tool did but adds an algorithm to correctly display
the tool on a High Def monitor.
All of the graphics, presented in this article, initially display as
thumbnails. This allows the reader to click on an image to open it in
the reader's default graphics display program. Most images are really
too small to display their details. All images in this article are PNG
images.
Background
To understand the workings of the revised Known Color Palette Tool
(hereafter KCPTool), the reader may need some background in color spaces.
These models are used to specify color values using color components
(or coordinates). As programmers, we are probably most familiar with
the RGB model. But to perform color matching we need a different
model, one that produces results that are, to the greatest extent
possible, the same as human-perceived color attributes.
The discussion of each color space is, of necessity, brief and
somewhat shallow. For readers who may be interested in further
reading, I have included a number of links to Wikipedia articles. Each
link can be opened in a new tab.
Color Models
[^]
One of the problems with color is the overwhelming number of color
models. In this introduction, I will limit the discussion of color
models to RYB (just because we are all familiar with it from grade
school), RGB, XYZ, and CIE Lab, those that are used in determining
color closeness.
I have also included a discussion of the HSL color space because some
readers believe that it is a useful model upon which to determine
color closeness. Through the experiments that I conducted testing the
various closest color matching algorithms, I have found that the
"best" algorithm is the newest (Delta E 2000).
RYB Color Space
[^]
Most of us were introduced to the RYB (red, yellow, blue) color space
when we were in grade school. The introduction probably (at least
hopefully) gave us an understanding that colors could be mixed
together to form new colors (the colors of nursery school paint).
The RYB model is a subtractive model in which red, yellow, and blue
pigments are mixed, thereby subtracting (absorbing)
some wavelengths of light while reflecting others. It is most suitable
for explaining the mixing of paints, dyes, and inks. It is generally
not useful in describing colors in the displays on computer monitors
and LED and plasma devices.
RGB Color Space
[^]
As developers, the RGB (red, green, blue) model is probably the most
familiar (after the RYB). The model is used to specify color on
computer monitors and LCD and plasma devices. It, and the HSL model,
is used to specify colors in web pages.
The RGB model is additive in that red, green, and blue
light is mixed to produce a large number of colors.
However, the gamut
(range) of colors is generally limited to well below the possible
number of colors due to hardware limitations.
Usually the values of red, green, and blue are specified as integers
in the range [0,255] or as hexadecimal digits in the range [00,FF]. In
portions of this article, normalized values of red, green, and blue
are specified in the range [0.0,1.0]. I use the lowercase letters
"r", "g", and "b" to denote these
normalized RGB components.
The CSS 3 Color Module
provides the following example for specifying the color Red using the
RGB model.
em { color: #F00 } /* #rgb */
em { color: #FF0000 } /* #rrggbb */
em { color: rgb(255,0,0) }
em { color: rgb(100%, 0%, 0%) }
HSL Color Space
[^]
The HSL (hue, saturation, lightness) color space is a cylindrical
representation of the RGB model. Hue is measured in degrees around the
circumference of the cylinder. Red is at 0°, green at 120°,
and blue at 240°, then wrapping back to red at 360°. Note that
there is a discontinuity at 0° and 360°. Saturation is
measured in percent from the center of the cylinder to its radius.
Lightness is measured in percent from the bottom to the top of the
cylinder.
The most common use of the HSL model is in color selection tools. The
HSL model is also used in feature detection (e.g., facial recognition,
object recognition, medical image analysis, etc.).
The HSL model is derived from the RGB model. The transformation from
RGB to HSL is as follows.
- The RGB cube is rotated such that the Black vertex is at the bottom and the White vertex is at the top.
- The Red, Yellow, Green, Cyan, Blue, and Magenta points are forced onto a plane, forming a hexagon.
- The hexagon is expanded vertically upward and downward forming a hexagonal prism.
- The hexagonal prism is forced into a cylinder.
As with the RGB color space, the CSS 3 Color Module
provides a way for specifying colors using the HSL model.
* { color: hsl(0, 100%, 50%) } /* red */
* { color: hsl(120, 100%, 50%) } /* lime */
* { color: hsl(120, 100%, 25%) } /* dark green */
* { color: hsl(120, 100%, 75%) } /* light green */
* { color: hsl(120, 75%, 75%) } /* pastel green */
CIE XYZ Color Space
[^]
The CIE XYZ color space is a mathematically defined color space. In
1931, the International Commission on Illumination (CIE) convened a
session to update recommendations. The session concluded with the
formalization of the CIE 1931 XYZ color space (herein referred to as
the XYZ color space).
Although it is a mathematically defined color space, it was derived
from physical experiments conducted in the 1920's. The experiments
were aimed at the RGB color space. From the experimental results was
derived the XYZ color space.
For the purposes of the KCPTool, the XYZ color space is the intermediary
between the RGB color space and the CIE Lab color space, the latter
being used for color matching.
CIE Lab Color Space
[^]
The CIE Lab color space is derived from the XYZ color space. Although
derived from the XYZ color space, the intent of its authors was to
create a color space that was more perceptually uniform to the human
eye.
The CIE Lab color space components are L (lightness)
and the two color components a, and
b. As depicted in the figure to the right, the
a axis is associated with red and green components;
while the b axis is associated with the yellow and
blue components. Note that in CIE Lab, a color cannot be made of, say,
yellow and blue. Nor can a color be made of red and green. This model
is called a color opponent
process.
Although many have suggested that color differences be computed using
the HSL color space, I have found that the difference equations based
on the CIE Lab color space perform much better than the RGB and HSL
Euclidean differences.
In the KCPTool,
values in the RGB color space are transformed into the XYZ color space
and from the XYZ color space into the CIE Lab color space. With the
exception of the Delta RGB difference equation, the CIE Lab color
components are used in determining closest color.
Difference Equations
[^]
A color difference is a measure of how closely two colors match. Most
common, but usually not very satisfactory, are the Euclidean
distance equations. Although they provide a gross estimate of
color difference, observers find that the results were not what were
expected. Less common, but far more perceptually uniform, are the
color differences that use the CIE Lab color space.
The KCPTool
offers four color difference equation algorithms from which to choose
when performing color matching. The author recommends Delta E 2000 as
the algorithm of choice.
An implementation of the Difference Equations is contained in the
Difference_Equations class. The implementation is provided in the
individual discussions.
Delta RGB
The Delta RGB closest color algorithm is a simple device
dependent Euclidian distance algorithm using the GDI+ Color structure's Red,
Green, and Blue components. The portion of the Delta Equations class
that computes the Delta RGB is:
using System;
using System.Drawing;
namespace KnownColorsPalette
{
public partial class Delta_Equations
{
public static double delta_RGB_TSMI ( Color color_1,
Color color_2 )
{
double delta_R = ( double ) ( color_1.R - color_2.R );
double delta_G = ( double ) ( color_1.G - color_2.G );
double delta_B = ( double ) ( color_1.B - color_2.B );
return ( Math.Sqrt ( delta_R * delta_R +
delta_G * delta_G +
delta_B * delta_B ) );
}
}
}
Delta E
The Delta E closest color algorithm is a simple device
independent Euclidian distance algorithm using the
colors' CIE L, a, and b components. The portion of the Delta
Equations class that computes Delta E is:
using System;
namespace KnownColorsPalette
{
public partial class Delta_Equations
{
public static double delta_E_TSMI ( CIELab_Color cielab_1,
CIELab_Color cielab_2 )
{
double delta_CIE_a = cielab_1.CIE_a - cielab_2.CIE_a;
double delta_CIE_b = cielab_1.CIE_b - cielab_2.CIE_b;
double delta_CIE_L = cielab_1.CIE_L - cielab_2.CIE_L;
return ( Math.Sqrt ( ( delta_CIE_L * delta_CIE_L ) +
( delta_CIE_a * delta_CIE_a ) +
( delta_CIE_b * delta_CIE_b ) ) );
}
}
}
Delta E 1994
The Delta E 1994 closest color algorithm is a device
independent color matching algorithm that uses the
colors' CIE Lab components.
From
Colorwiki
[^]
A technical committee of the CIE (TC 1-29) published an equation in
1995 called CIE94. The equation is similar to CMC but the weighting
functions are largely based on RIT/DuPont tolerance data derived from
automotive paint experiments where sample surfaces are smooth. It also
has ratios, labeled kL (lightness) and Kc (chroma) and the commercial
factor (cf) but these tend to be preset in software and are not often
exposed for the user.
The portion of the Delta Equations class that computes Delta E 1994
is:
using System;
namespace KnownColorsPalette
{
public partial class Delta_Equations
{
public static double delta_E_1994_TSMI ( CIELab_Color cielab_1,
CIELab_Color cielab_2 )
{
double C1;
double C2;
double CIE_1_a_squared = cielab_1.CIE_a * cielab_1.CIE_a;
double CIE_1_b_squared = cielab_1.CIE_b * cielab_1.CIE_b;
double CIE_2_a_squared = cielab_2.CIE_a * cielab_2.CIE_a;
double CIE_2_b_squared = cielab_2.CIE_b * cielab_2.CIE_b;
double delta_a;
double delta_a_squared;
double delta_b;
double delta_b_squared;
double delta_C_ab;
double delta_C_ab_divisor;
double delta_C_ab_squared;
double delta_E_Lab;
double delta_H_ab;
double delta_H_ab_divisor;
double delta_L;
double delta_L_squared;
double K_1;
double K_2 ;
delta_L = cielab_1.CIE_L - cielab_2.CIE_L;
delta_L_squared = delta_L * delta_L;
delta_a = cielab_1.CIE_a - cielab_2.CIE_a;
delta_a_squared = delta_a * delta_a;
delta_b = cielab_1.CIE_b - cielab_2.CIE_b;
delta_b_squared = delta_b * delta_b;
delta_E_Lab = Math.Sqrt ( delta_L_squared +
delta_a_squared +
delta_b_squared );
C1 = Math.Sqrt ( CIE_1_a_squared + CIE_1_b_squared );
C2 = Math.Sqrt ( CIE_2_a_squared + CIE_2_b_squared );
delta_C_ab = C1 - C2;
delta_C_ab_squared = delta_C_ab * delta_C_ab;
if ( ( delta_a_squared + delta_b_squared ) >=
delta_C_ab_squared )
{ delta_H_ab = Math.Sqrt ( delta_a_squared +
delta_b_squared -
delta_C_ab_squared );
}
else
{
delta_H_ab = 0.0;
}
K_1 = 0.045;
K_2 = 0.015;
delta_C_ab_divisor = 1.0 + ( K_1 * C1 );
delta_H_ab_divisor = 1.0 + ( K_2 * C1 );
delta_C_ab /= delta_C_ab_divisor;
delta_H_ab /= delta_H_ab_divisor;
return ( Math.Sqrt ( delta_L_squared +
delta_C_ab * delta_C_ab +
delta_H_ab * delta_H_ab ) );
}
}
}
Delta E 2000
The Delta E 2000 closest color algorithm is the recommended
device independent color matching algorithm that uses the
colors' CIE Lab components.
From
Colorwiki
[^]
Delta-E 2000 is the first major revision of the Delta E 1994 equation.
Unlike Delta E 1994, which assumes that L* correctly reflects the
perceived differences in lightness, Delta E 2000 varies the weighting
of L* depending on where in the lightness range the color falls. Delta
E 2000 is still under consideration and does not seem to be widely
supported in graphics arts applications.
The portion of the Delta Equations class that computes Delta E 2000
is:
using System;
namespace KnownColorsPalette
{
public partial class Delta_Equations
{
public static double delta_E_2000_TSMI ( CIELab_Color cielab_1,
CIELab_Color cielab_2 )
{
double c = Math.Pow ( 25, 7 );
double CIE_1_a_squared = cielab_1.CIE_a * cielab_1.CIE_a;
double CIE_1_b_squared = cielab_1.CIE_b * cielab_1.CIE_b;
double CIE_2_a_squared = cielab_2.CIE_a * cielab_2.CIE_a;
double CIE_2_b_squared = cielab_2.CIE_b * cielab_2.CIE_b;
double E00;
double t;
double weighting_factor_C = 1.0;
double weighting_factor_H = 1.0;
double weighting_factor_L = 1.0;
double xC1;
double xC2;
double xCX;
double xCY;
double xDC;
double xDH;
double xDL;
double xGX;
double xH1;
double xH2;
double xHX;
double xLX;
double xNN;
double xPH;
double xRC;
double xRT;
double xSC;
double xSH;
double xSL;
double xTX;
xC1 = Math.Sqrt( CIE_1_a_squared + CIE_1_b_squared );
xC2 = Math.Sqrt( CIE_2_a_squared + CIE_2_b_squared );
xCX = ( xC1 + xC2 ) / 2.0;
t = Math.Pow ( xCX, 7 );
xGX = 0.5 * ( 1.0 - Math.Sqrt ( t / ( t + c ) ) );
xNN = ( 1.0 + xGX ) * cielab_1.CIE_a;
xC1 = Math.Sqrt ( xNN * xNN + CIE_1_b_squared );
xH1 = CieLab2Hue ( xNN, cielab_1.CIE_b );
xNN = ( 1.0 + xGX ) * cielab_2.CIE_a;
xC2 = Math.Sqrt ( xNN * xNN + CIE_2_b_squared );
xH2 = CieLab2Hue ( xNN, cielab_2.CIE_b );
xDL = cielab_2.CIE_L - cielab_1.CIE_L;
xDC = xC2 - xC1;
if ( ( xC1 * xC2 ) == 0 )
{
xDH = 0.0;
}
else
{
t = xH2 - xH1;
xNN = Math.Round ( t, 12 );
if ( Math.Abs ( xNN ) <= 180 )
{
xDH = t;
}
else
{
if ( xNN > 180 )
{
xDH = t - 360.0;
}
else
{
xDH = t + 360.0;
}
}
}
xDH = 2.0 * Math.Sqrt ( xC1 * xC2 ) *
Math.Sin ( MathUtilities.deg2rad (
xDH / 2.0 ) );
xLX = ( cielab_1.CIE_L - cielab_2.CIE_L ) / 2.0;
xCY = ( xC1 + xC2 ) / 2.0;
t = xH1 + xH2;
if ( ( xC1 * xC2 ) == 0 )
{
xHX = t;
}
else
{
xNN = Math.Abs ( Math.Round ( ( xH1 - xH2 ), 12 ) );
if ( xNN > 180 )
{
if ( t < 360.0 )
{
xHX = t + 360.0;
}
else
{
xHX = t - 360.0;
}
}
else
{
xHX = t;
}
xHX /= 2;
}
xTX = 1.0 - 0.17 * Math.Cos ( MathUtilities.deg2rad (
xHX - 30.0 ) ) +
0.24 * Math.Cos ( MathUtilities.deg2rad (
2.0 * xHX ) ) +
0.32 * Math.Cos ( MathUtilities.deg2rad (
3.0 * xHX + 6.0 ) ) -
0.20 * Math.Cos ( MathUtilities.deg2rad (
4.0 * xHX - 63.0 ) );
t = ( xHX - 275.0 ) / 25.0;
xPH = 30.0 * Math.Exp ( - ( t * t ) );
t = Math.Pow ( xCY, 7 );
xRC = 2.0 * Math.Sqrt ( t / ( t + c ) );
t = xLX - 50.0;
xSL = 1.0 + ( 0.015 * ( t * t ) ) /
Math.Sqrt ( 20.0 + ( t * t ) );
xSC = 1.0 + 0.045 * xCY;
xSH = 1.0 + 0.015 * xCY * xTX;
xRT = - Math.Sin ( MathUtilities.deg2rad (
2.0 * xPH ) ) * xRC;
xDL /= ( weighting_factor_L * xSL );
xDC /= ( weighting_factor_C * xSC );
xDH /= ( weighting_factor_H * xSH );
E00 = Math.Sqrt ( ( xDL * xDL ) +
( xDC * xDC ) +
( xDH * xDH ) +
( xRT * xDC * xDH ) );
return ( E00 );
}
private static double CieLab2Hue( double a,
double b )
{
double bias = 0.0;
if ( ( a >= 0.0 ) && ( b == 0.0 ) )
{
return 0.0;
}
if ( ( a < 0.0 ) && ( b == 0.0 ) )
{
return 180.0;
}
if ( ( a == 0.0 ) && ( b > 0.0 ) )
{
return 90.0;
}
if ( ( a == 0.0 ) && ( b < 0.0 ) )
{
return 270.0;
}
if ( ( a > 0.0 ) && ( b > 0.0 ) )
{
bias = 0.0;
}
if ( a < 0.0 )
{
bias = 180.0;
}
if ( ( a > 0.0 ) && ( b < 0.0 ) )
{
bias = 360.0;
}
return ( MathUtilities.rad2deg ( Math.Atan ( b / a ) ) +
bias );
}
}
}
Known Colors Palette Tool
The KCPTool is
based upon Microsoft's KnownColor
Enumeration . That set of colors is referred to as "web
safe." As a result, most colors that are chosen for a web page
should be drawn from the Known Colors. Note that the CSS 3 Color Module refers
to the names of the Microsoft "Known Colors" as the
"Extended color keywords."
Extended_Color Class
To process colors efficiently (eliminating the need to create
instances of different color spaces on the fly), the Extended_Color class was
defined. The properties of the class are
public class Extended_Color
{
public CIELab_Color CIELab_color;
public Color color;
public HSL_Color HSL_color;
public RGB_Color RGB_color;
public XYZ_Color XYZ_color;
:
:
In addition to the GDI+ Color structure, Extended_Color contains instances of, in their
order of use, the RGB_Color, XYZ_Color, and CIELab_Color classes. The HSL_Color class is an artifact of earlier
development, retained in case that a well performing difference
equation based on the HSL color space is found.
The properties of the four classes are
public class CIELab_Color
{
public double CIE_L;
public double CIE_a;
public double CIE_b;
:
:
public class HSL_Color
{
public double Hue; public double Saturation; public double Lightness; :
:
public class RGB_Color
{
public double r; public double g; public double b; :
:
public class XYZ_Color
{
public double X;
public double Y;
public double Z;
:
:
During the assignment of values to their double precision target, each
value is rounded to three decimal places. The rounding function used
in the KCPTool is
found in the MathUtilities
class,
namespace KnownColorsPalette
{
public class MathUtilities
{
private static int [ ] powers = new int [ 10 ] {
1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
public static double round ( double number,
int decimal_places )
{
int power;
int t;
if ( ( decimal_places < 0 ) || ( decimal_places > 9 ) )
{
throw new ArgumentException (
"Precision out of range [0,9]",
"decimal_places" );
}
power = powers [ decimal_places ];
t = ( int ) ( ( number * ( double ) power ) + 0.5 );
return ( ( double ) t / ( double ) power );
}
public static double rad2deg ( double radians )
{
return ( radians / Math.PI * 180.0 );
}
public static double deg2rad ( double degrees )
{
return ( degrees * Math.PI / 180.0 );
}
}
}
As the KCPTool
retrieves each of the 140 known colors, an instance of Extended_Color is instantiated.
Its constructor accepts the GDI+ Color structure.
public Extended_Color ( Color color )
{
double r = ( double ) color.R / 255.0; double g = ( double ) color.G / 255.0; double b = ( double ) color.B / 255.0;
this.color = color;
HSL_color = HSL_Color.Fromrgb ( color, r, g, b );
RGB_color = RGB_Color.Fromrgb ( r, g, b );
XYZ_color = XYZ_Color.Fromrgb ( r, g, b );
CIELab_color = CIELab_Color.FromXYZ ( XYZ_color );
}
Performing a Stable Sort of the Extended Colors
When the 140
Extended_Color instances
have been created, 25
panels are created (eliminating the need to create instances of the
panels on the fly), each containing color squares sorted in one of the
25 possible ways. The RGB color squares are sorted in RGB, RBG, GRB,
GBR, BRG, and BGR order; the HSL color squares in HSL, HLS, SHL, SLH,
LHS, and LSH order; the XYZ color squares in XYZ, XZY, YXZ, YZX, ZXY,
and ZYX order; and the CIE LAB color squares in LAB, LBA, ALB, ABL,
BLA, and BAL order. In addition, the color squares are sorted by color
name.
The comparator for the sorts is encapsulated in the
Color_Comparer class. The
class exposes the Comparer method that compares two
Extended_Color instances.
Note that comparisons must operate against Color.Name, RGB components,
HSL components, XYZ components, and CIE Lab components. The Comparer
must sort color space components in a stable order
specified by the invoker.
To perform a stable sort, the Comparer must be initialized. Because
the single letter "B" caused a conflict between
RGB and CIE LAB, the decision was
made to initialize the
Color_Comparer
with an array of strings. This was accomplished using the constructor
public Color_Comparer ( string [ ] fields )
{
validate_fields ( fields, "fields" );
fields_to_compare = fields;
}
validate_fields insures that only those color fields,
recognized by Color_Comparer are supplied. For the purposes
of the current version of KCPTool, these include:
- NAME
- RED
- GREEN
- BLUE
- HUE
- SATURATION
- LIGHTNESS
- X
- Y
- Z
- CIE_L
- CIE_A
- CIE_B
To sort a List of Extended_Colors in the order
Saturation, Hue, and finally Lightness, the following would suffice
List < Extended_Color > colors =
new List < Extended_Color > (
known_colors.Count );
Color_Comparer cc = new Color_Comparer (
new string [ ] {
"SATURATION",
"HUE",
"LIGHTNESS" } );
colors.Sort ( cc );
Abbreviating the Compare method to show only those sort fields:
public int Compare ( Extended_Color color_1,
Extended_Color color_2 )
{
int result = 0;
if ( color_1 == null )
{
result = ( ( color_2 == null ) ? 0 : 1 );
}
else if ( color_2 == null )
{
result = -1;
}
else
{
foreach ( string field in fields_to_compare )
{
switch ( field.ToUpper ( ) )
{
:
:
case "HUE":
result = color_1.HSL_color.Hue.
CompareTo (
color_2.HSL_color.Hue );
break;
case "SATURATION":
result = color_1.HSL_color.Saturation.
CompareTo (
color_2.HSL_color.Saturation );
break;
case "LIGHTNESS":
result = color_1.HSL_color.Lightness.
CompareTo (
color_2.HSL_color.Lightness );
break;
:
:
default:
break;
}
if ( result != 0 )
{
break;
}
}
}
return ( result );
}
When the Extended_Color
List is sorted, it is used to populate the panel. In the
example immediately above, the panel is the SHL panel.
Color Squares Panels
Each panel is composed of color squares. The color squares are
instances of a Custom_Button class. An instance of Extended_Color was added to the
to Button class to provide
all of the color space information needed when a user clicks on, Tabs
to, or hovers over a color square.
Fixing the Tooltip Bug
Each color square has a tooltip set to the name of the known color.
Additionally, each color square has a MouseEnter event handler
declared.
tooltip.SetToolTip ( color_square,
color.color.Name );
color_square.MouseEnter +=
new EventHandler ( tooltip_reinitializer );
The event handler, tooltip_reinitializer, contains
private void tooltip_reinitializer ( Object sender,
EventArgs e )
{
tooltip.Active = false;
tooltip.Active = true;
}
The purpose of the event-handler is to fix a bug that keeps a tooltip
from being displayed once that its display timeout has been reached.
It is my belief that the bug is caused by a reentrancy error in the
tooltip timer code. I strongly recommend that any control that has a
tooltip, also declare the same, or functionally equivalent, event
handler. All of the KCPTool controls that have tooltips also associate
this hander with the control's MouseEnter event.
Options Menu
Clipboard
The Clipboard submenu allows the user to specify the format of the
string placed on the clipboard when any Save To Clipboard command is
executed. The following depicts what is placed on the clipboard for
each choice.
- All
- {Name=Tomato,RGB=(255,99,71)=#FF6347=(FF,63,47)}
- Name
- Tomato
- RGB Decimal
- (255,99,71)
- RGB Hexadecimal
- #FF6347
The default format is RGB Hexadecimal.
Although the transfer to the Clipboard is not the same as setting the
color in a color editing application, it does provide a means whereby
the data can be captured and copied into the application.
Color Metrics
The Color Metrics submenu of the Options menu item determines
when color metrics for a particular color square will be displayed.
The default is a left mouse click on the color square of interest. But
the user can specify to display the color metrics when the mouse
hovers over the color square or when the cursor is tabbed to the color
square. Lastly, and least useful, is to display the color metrics
under any of the preceding events.
When the user clicks on, hovers over, or tabs to a desired color
square, the contents of the Color Metrics group box will be filled.
Once the color metrics fields are filled, left-clicking on the color
square in the Color Metrics group box will cause the color data to be
placed on the clipboard.
The default is left mouse click.
Color Difference
The Color Difference submenu of the Options menu item allows the
user to specify which color difference equation to use for determining
the difference between colors. The user can specify one of Delta RGB,
Delta E, Delta E 1994, or Delta E 2000 algorithm.
The default is Delta E 2000.
Cursor Shape
The Color Shape submenu of the Options menu item allows the user to
specify which cursor shape should be used while dragging the cursor
during Mouse Over positioning. The user can specify either cross or
reticule.
The default is cross.
Distinguish Chosen
The Distinguish Chosen submenu allows the user to specify whether a
border will be placed around the currently chosen color button (chosen
either algorithmically or by a user action) to exaggerate its appearance.
The current version of the Known Colors Palette Tool does not provide
any visual clue as to which of the 140 buttons is the chosen button.
The following choices are available.
- None - the chosen button will not be differentiated
- Border - a solid border will surround the chosen button
- Moving - a moving border will surround the chosen button
The default format is a Moving border.
Contrasting Colors
The Contrasting Colors area of the tool has been revised. It now
displays two contrasting colors: the first is the computed contrasting
color and the second is the known color obtained from the computed
contrasting color.
void compute_known_and_contrasting_colors (
Color color,
ref Color known_color,
ref Color contrasting_color,
ref Color known_contrasting_color,
ref Extended_Color known_extended_color )
{
known_color = nearest_known_color ( color );
contrasting_color = Color.FromArgb ( 255 - color.R,
255 - color.G,
255 - color.B );
known_contrasting_color = nearest_known_color (
contrasting_color );
known_extended_color = new Extended_Color ( color );
}
Determining the Closest Color
There are two ways in which to specify that a color be closest matched
to one of the Known Colors.
-
Left-click on Color Picker to display the standard Windows Color
Dialog. Choose a color and click OK. The color will be displayed on
the face of the Color Picker button.
-
Left-click and hold down the Mouse Over button. The cursor changes
to a cross or reticule (depending on the chosen Cursor Shape
option). Drag the cross or reticule to some color on the screen for
which a color match is desired. Release the mouse. The color under
the cross or reticule, when the mouse was released, will be
displayed on the face of the Mouse Over button.
In both cases, the RGB metrics for the chosen color will appear within
the Find Closest To group box and the Find Closest button will be
enabled.
Left-click on the Find Closest button to display the closest Known
Color match.
Save to Clipboard Buttons
In the figure to the left, four buttons are bordered by a red square.
When the button is active, clicking on it will cause the color
information to be copied to the clipboard. The information that will
be placed on the clipboard is that specified by the
Clipboard submenu.
There is an exception: the Computed Contrasting Color, although it is
a color, may not be a known color. For that reason, a color name will
not be placed on the clipboard.
Multi-Monitor Color under Cursor
Having offered to install the KCPTool on a colleague's machine, I was not ready
for its first use. My colleague used multiple monitors. And as would
have it, he attempted a closest color match using the Mouse Over
functionality. The overly simple GetPixel method that I had used was
not up to the task, causing an exception when the cursor was released
over any location that was not on the Primary Monitor.
I searched the web for an answer and found John Gietzen's elegant
solution on StackOverflow. I slightly modified his code and, when
I substituted the following code, the problem went away. (The
get_pixel method is found in the WIN32API class,
included in the downloadable source code.)
public static Color get_pixel ( Point location )
{
Bitmap screen_pixel = new Bitmap (
1,
1,
PixelFormat.Format32bppArgb );
using ( Graphics destination = Graphics.FromImage (
screen_pixel ) )
{
using ( Graphics source = Graphics.FromHwnd (
IntPtr.Zero ) )
{
IntPtr source_DC = source.GetHdc ( );
IntPtr destination_DC = destination.GetHdc ( );
BitBlt ( destination_DC,
0,
0,
1,
1,
source_DC,
location.X,
location.Y,
( int ) CopyPixelOperation.SourceCopy );
}
}
return ( screen_pixel.GetPixel ( 0, 0 ) );
}
Installing KCPTool
Included in the downloadable source, is a directory named
"Deploy" and under that is a subdirectory named
"setup". Contained in that subdirectory is the installer
setup_FW.exe that will install KCPTool on any machine on which it is
executed. If modifications are made to the KCPTool, and the project is recompiled,
the file KnownColorsPalette.iss may need to be recompiled and executed
to create the setup_FW.exe.
The tools needed to rebuild the installer are
-
Inno Setup
[^] - a free installer for Windows programs
-
ISTool
[^]- a visual script editor/generator for the
Inno Setup compiler
Both of these tools are useful additions to a developer's tool
box.
Acknowledgements
The greatest source of information that I used during the writing of
this article was Wikipedia. In
addition to its numerous articles, the Wikipedia
Commons contains a wealth of images that are all in the public
domain. Most of the images in this article were obtained from
Wikipedia Commons.
The equations in this article and in the associated project software
were obtained from Wikipedia and from the EasyRGB site.
I would also like to acknowledge the comments and suggestions of my
readers. The suggestions have caused some interesting revisions that I
would never have thought of, thereby improving the KCPTool.
I would especially like to acknowledge the assistance of Jeff Hay-Roe,
a Code Project member who was willing to test the
KCPTool on High
Def monitors. With his help, the tool now appears stable on High Def
monitors.
References
- Absolute color space, Wikipedia.
- CIE 1931 color space, Wikipedia.
- CIE 1964 color space, Wikipedia.
- CIE Lab Color Space, Wikipedia.
- CIE XYZ Color Space, Wikipedia.
- CIELUV, Wikipedia.
- Color Models, Intel.
- Color Models, Wikipedia.
- Color of a Screen Pixel, John Gietzen, StackOverflow
- Color Space Conversions, Alan Roberts, British Broadcasting Company.
- Color Spaces, Couleur.org.
- Color Spaces, Wikipedia.
- CSS 3 Color Module, World Wide Web Consortium.
- Delta E: The Color Difference, Colorwiki.
- Difference Equations, Wikipedia.
- Euclidean distance, Wikipedia.
- Hexagonal Prism, Wikipedia.
- How to Calculate a Complementary Colour/Color, Serennu.
- HSL and HSV, Wikipedia.
- KnownColor Enumeration, Microsoft.
- Munsell color system, Wikipedia.
- Opponent Process, Wikipedia.
- RGB Color Space, Wikipedia.
- RYB Color Space, Wikipedia.
- Stable Sort Method, Egghead Cafe.
- The CIE XYZ and xyY Color Spaces, Douglas A. Kerr, Stanford University.
- The Munsell Color System, ApplePainter.com.
History
- August 21, 2011 - Original article.
- August 22, 2011 - Removed ill-conceived screen resolution algorithm.
- August 30, 2011 - Repaired typographical errors; updated the KCPTool to version 2.3.
- September 17, 2011
- Repaired deployment post build commands
- Added balanced screens for differing resolutions
- Added capability to save and restore options
- Repaired the method by which a color under the cursor is determined
- Updated the KCPTool to version 3.0.
- May 22, 2015
-
Created the KnownColorsPalette class library and removed the tool
from within the class library
-
Added choice of borders that places either a stationary border or
a moving border around the current known color button to exaggerate
its appearance
-
Added contrasting color and clipboard save button
-
Added known contrasting color and clipboard save button
-
Added find closest color clipboard save button
-
Synchronized the main menu items with the context menu items
-
Updated the
KCPTool
to version 4.4
- June 1, 2015 />
-
Wrote an algorithm that sets Form dimensions so as to provide
support for High Def monitors
-
Updated the
KCPTool
to version 4.5
- November 25, 2015
-
Repaired a bug that prevented Known Color information to be copied
to the clip board.
-
Revised the Inno Setup script.
-
Updated the
KCPTool
to version 5.1