已知颜色调色板工具






4.37/5 (9投票s)
提供一个有助于从已知颜色中选择颜色的工具。

引言
颜色是互联网的呼吸。本文讨论了一些颜色调色板,然后介绍了一个可用于选择网页合适颜色的工具。
背景
颜色历史
在计算的早期历史中,颜色并不是成功应用程序的重要属性。大多数计算机终端都有绿色或琥珀色的显示屏。此外,大多数终端都是面向文本的,每行显示固定数量的字符,每屏显示固定数量的行。在很大程度上,运行在计算机终端上的大多数应用程序都是命令行解释器、文本编辑器和调制解调器控制应用程序。虽然有图形终端可用,但它们非常昂贵,并且仅在专业环境中使用。
1973年,施乐帕洛阿尔托研究中心(PARC)开发了个人工作站,这是现代个人计算机的前身。1975年,PARC推出了图形用户界面,其熟悉的桌面和图标。为了支持这些,PARC开发了位图图形。
1981年,随着个人计算机的推出,IBM还推出了彩色图形适配器(CGA),应用程序开发人员可以使用十六种颜色。

1984年,IBM推出了增强图形适配器(EGA),具有64种颜色。

然后,在1987年,IBM推出了视频图形阵列(VGA)。VGA调色板提供了256种颜色。

随着X窗口的引入,一个名为X11颜色名称的调色板可用了。X11颜色名称与早期颜色调色板最重要的区别在于,可以通过指定其名称或RGB三元组来选择颜色。
最后,随着.NET Framework 1.1的推出,已知颜色调色板由微软正式化。尽管此调色板包含微软用于显示各种系统实体的一些颜色(例如,ActiveBorder
、AppWorkspace
、Control Dark 等),但在枚举已知颜色时,我们可以排除这些Microsoft系统颜色。
需求
在测试颜色命中测试用户控件时,我需要一个测试图像。我决定显示美国时区就足够了。因为我准备的文章将在互联网上查看,所以我决定使用已知颜色为图像着色。
我使用Microsoft Paint创建图像。在图像准备过程中,我偶然发现了该工具的颜色?编辑颜色...对话框中的一些限制。
- 显示的颜色不是已知颜色。
- 最初显示的颜色不是已知颜色。
- 当鼠标悬停在颜色上时,对话框不会显示颜色名称。
为了解决这两个问题,我构建了已知颜色调色板工具。对该工具的要求包括:
- 显示的颜色应为已知颜色。
- 当鼠标悬停在颜色块上时,应显示颜色名称。
- 颜色可以按已知颜色名称或按已知颜色的 ARGB 值进行排序。
- 当鼠标单击颜色块时,将显示已知颜色的 ARGB 值以及各个 ARGB 分量值。
- 应提供一个上下文菜单,允许用户执行排序、将工具置于最顶层,并允许将相应的颜色信息复制到剪贴板。
已知颜色调色板工具
已知颜色调色板工具基于微软作为 System.Drawing
程序集一部分提供的KnownColor 枚举。微软的枚举(除了系统颜色之外)等同于CSS 颜色名称。在枚举微软已知颜色名称时,会排除那些微软系统颜色。
// ************************** get_known_colors_from_Microsoft
// http://www.dreamincode.net/code/snippet1405.htm
private List < Color > get_known_colors_from_Microsoft ( )
{
List < Color > colors = new List<Color> ( );
string [ ] color_names =
Enum.GetNames ( typeof (
KnownColor ) );
foreach ( string color_name in color_names )
{
KnownColor known_color = ( KnownColor ) Enum.Parse (
typeof ( KnownColor ),
color_name );
if ( ( known_color > KnownColor.Transparent ) &&
( known_color < KnownColor.ButtonFace ) )
{
colors.Add ( Color.FromName ( color_name ) );
}
}
return ( colors );
}
颜色枚举后的第一个任务是创建两个面板,一个面板按名称显示颜色,另一个面板按 ARGB 显示颜色。这两个面板都会被创建然后隐藏。我创建了两个单独的面板来提高切换显示时的性能。
// ****************************** create_colors_by_name_panel
private void create_colors_by_name_panel ( )
{
NameComparer nc = new NameComparer ( );
known_colors.Sort ( nc );
colors_by_name_panel = populate_panel ( );
this.Controls.Add ( colors_by_name_panel );
colors_by_name_panel.Visible = false;
}
// ****************************** create_colors_by_ARGB_panel
private void create_colors_by_ARGB_panel ( )
{
ARGBComparer ac = new ARGBComparer ( );
known_colors.Sort ( ac );
colors_by_ARGB_panel = populate_panel ( );
this.Controls.Add ( colors_by_ARGB_panel );
colors_by_ARGB_panel.Visible = false;
}
实现了两个类,NameComparer
和 ARGBComparer
,用于执行比较。
// ******************************************* class NameComparer
public class NameComparer : IComparer < Color >
{
// ************************************************** Compare
public int Compare ( Color color_1,
Color color_2 )
{
if ( color_1 == null )
{
if ( color_2 == null )
{
// If color_1 is null and
// color_2 is null, they're
// equal
return ( 0 );
}
else
{
// If color_1 is null and
// color_2 is not null,
// color_2 is greater.
return ( -1 );
}
}
else
{
// If color_1 is not null...
if ( color_2 == null )
// ...and color_2 is null,
// color_1 is greater.
{
return ( 1 );
}
else
{
// ...and color_2 is not
// null, compare the names
// of the two colors
return ( color_1.Name.CompareTo (
color_2.Name ) );
}
}
}
} // class NameComparer
// ******************************************* class ARGBComparer
public class ARGBComparer : IComparer < Color >
{
// ************************************************** Compare
public int Compare ( Color color_1,
Color color_2 )
{
if ( color_1 == null )
{
if ( color_2 == null )
{
// If color_1 is null and
// color_2 is null, they're
// equal
return ( 0 );
}
else
{
// If color_1 is null and
// color_2 is not null,
// color_2 is greater.
return ( -1 );
}
}
else
{
// If color_1 is not null...
if ( color_2 == null )
// ...and color_2 is null,
// color_1 is greater.
{
return ( 1 );
}
else
{
// ...and color_2 is not
// null, compare the ARGBs
// of the two colors
uint ARGB_1;
uint ARGB_2;
ARGB_1 = Utilities.ColorToUIntARGB ( color_1 );
ARGB_2 = Utilities.ColorToUIntARGB ( color_2 );
return ( ARGB_1.CompareTo ( ARGB_2 ) );
}
}
}
} // class ARGBComparer
当已知颜色列表排序后,它将用于填充面板。
// ******************************************* populate_panel
private Panel populate_panel ( )
{
Point color_square_location;
Size color_square_size;
int column = 0;
Panel panel = new Panel ( );
panel.Location = new Point ( PANEL_LEFT, PANEL_TOP );
panel.Size = new Size ( PANEL_WIDTH, PANEL_HEIGHT );
color_square_location = new Point ( INITIAL_LEFT,
INITIAL_TOP );
color_square_size = new Size ( COLOR_SQUARE_EDGE,
COLOR_SQUARE_EDGE );
foreach ( Color color in known_colors )
{
Button color_square = new Button ( );
ToolTip tooltip = new ToolTip ( );
color_square.Location = color_square_location;
color_square.Size = color_square_size;
color_square.BackColor = color;
color_square.Click += new System.EventHandler (
color_square_BUT_Click );
tooltip.SetToolTip ( color_square, color.Name );
tooltip.AutomaticDelay = TOOLTIP_DELAY;
panel.Controls.Add ( color_square );
column++;
if ( column >= COLOR_SQUARES_PER_ROW )
{
column = 0;
color_square_location.X = INITIAL_LEFT;
color_square_location.Y +=
COLOR_SQUARE_EDGE + COLOR_SQUARE_SEPARATION;
}
else
{
color_square_location.X +=
COLOR_SQUARE_EDGE + COLOR_SQUARE_SEPARATION;
}
}
return ( panel );
}
在初始化时,变量 sort_by_name
为 true
,并且显示按名称排序的面板。
// ******************************************* initialize_GUI
private void initialize_GUI ( )
{
if ( sort_by_name )
{
byNameToolStripMenuItem.Checked = true;
sortByNameToolStripMenuItem.Checked = true;
byARGBToolStripMenuItem.Checked = false;
sortByARGBToolStripMenuItem.Checked = false;
colors_by_name_panel.Visible = true;
colors_by_ARGB_panel.Visible = false;
}
else
{
byNameToolStripMenuItem.Checked = false;
sortByNameToolStripMenuItem.Checked = false;
byARGBToolStripMenuItem.Checked = true;
sortByARGBToolStripMenuItem.Checked = true;
colors_by_name_panel.Visible = false;
colors_by_ARGB_panel.Visible = true;
}
}
如果用户切换显示,变量 sort_by_name
将变为 false
,并显示按 ARGB 排序的面板。
选择颜色时,将显示有关该颜色的信息。

一旦选择了一个颜色,无论是单击颜色块还是按 Ctrl-S,颜色信息都会被复制到剪贴板。对于已知颜色 DarkRed
,复制到剪贴板的信息是:
{Name=DarkRed,ARGB=(255,139,0,0)=#FF8B0000=(FF,8B,00,00)}
虽然传输到剪贴板与在 Microsoft Paint 中设置颜色不同,但它确实提供了一种捕获数据并将其复制到 Microsoft Paint 的方法。如果我能弄清楚如何对 Microsoft Paint 进行子类化,我将修改已知颜色调色板工具以直接与 Microsoft Paint 交互。任何关于此升级的建议都将不胜感激。
修订
正如一位读者指出的那样,工具开发时的屏幕分辨率可能与工具执行时的屏幕分辨率不同。在 1024x768 下看起来正常的内容,在其他分辨率下可能看起来不太好。更糟糕的是,当工具在更高分辨率下收缩时,该工具可能会变得无用。
为了解决这个问题,我在 800x600 的屏幕分辨率下重新开发了该工具。完成后,我添加了代码来初始化两个屏幕分辨率乘数,一个用于水平调整,另一个用于垂直调整。
// ************************ initialize_resolution_multipliers
private void initialize_resolution_multipliers ( )
{
if ( ( SystemInformation.PrimaryMonitorSize.Height >
CREATED_IN_SCREEN_HEIGHT ) ||
( SystemInformation.PrimaryMonitorSize.Width >
CREATED_IN_SCREEN_WIDTH ) )
{
screen_height_multiplier =
( float ) SystemInformation.
PrimaryMonitorSize.Height /
( float ) CREATED_IN_SCREEN_HEIGHT;
screen_height_multiplier *= 4.0F;
screen_height_multiplier /= 5.0F;
screen_width_multiplier =
( float ) SystemInformation.
PrimaryMonitorSize.Width /
( float ) CREATED_IN_SCREEN_WIDTH;
screen_width_multiplier *= 4.0F;
screen_width_multiplier /= 5.0F;
color_square_edge =
( int ) ( ( float ) color_square_edge *
screen_width_multiplier );
color_square_separation =
( int ) ( ( float ) color_square_separation *
screen_width_multiplier );
resolution_changed = true;
}
}
除了乘数之外,两个全局变量 color_square_edge
和 color_square_separation
被赋予了调整后的值。这两个变量替换了 populate_panel
方法(见上文)中的常量 COLOR_SQUARE_EDGE
和 COLOR_SQUARE_SEPARATION
。
一旦这些乘数被初始化(注意,如果执行分辨率为 800x600,两者都将是 1.0F),实际的调整将等待 Load
事件触发,该事件反过来执行 adjust_GUI_to_resolution
方法。
// ********************************** KnownColorsPalette_Load
private void KnownColorsPalette_Load ( object sender,
EventArgs e )
{
adjust_GUI_to_resolution ( );
}
如果执行分辨率与开发分辨率不同(即,变量 resolution_changed
为 true
),则 adjust_GUI_to_resolution
方法会修改每个控件的位置、大小和字体大小。
// ********************************* adjust_GUI_to_resolution
// http://cshark.wordpress.com/2009/06/01/
// how-to-change-form-size-depending-on-screen-resolution/
private void adjust_GUI_to_resolution ( )
{
if ( resolution_changed )
{
float font_size;
int height;
int width;
float x;
float y;
font_size = this.Font.Size *
screen_height_multiplier;
height = ( int ) ( ( float ) this.Height *
screen_height_multiplier );
width = ( int ) ( ( float ) this.Width *
screen_height_multiplier );
x = this.Location.X * screen_width_multiplier;
y = this.Location.Y * screen_height_multiplier;
this.Height = height;
this.Width = width;
this.Font = new Font ( this.Font.FontFamily,
font_size,
this.Font.Style );
foreach ( Control control in this.Controls )
{
font_size = control.Font.Size *
screen_height_multiplier;
height = ( int ) ( ( float ) control.Height *
screen_height_multiplier );
width = ( int ) ( ( float ) control.Width *
screen_height_multiplier );
x = control.Location.X * screen_width_multiplier;
y = control.Location.Y * screen_height_multiplier;
control.Width = ( int ) Math.Ceiling ( ( double ) width );
control.Height = ( int ) Math.Ceiling ( ( double ) height );
control.Location = new Point ( ( int ) x,
( int ) y );
control.Font = new Font ( control.Font.FontFamily,
( int ) font_size,
control.Font.Style );
}
}
}
工具提示和菜单项的字体大小存在一个问题,我仍在研究中。当我有了解决方案后,我将再次修改本文。
参考文献
- 使用颜色进行命中测试 Code Project
- KnownColor 枚举 .NET Framework 类库, MSDN
- X11 颜色名称 Wikipedia
- CSS 颜色名称, Refsnes Data, 2010
历史
- 2010/11/26 - 修订文章以回应读者意见并纠正排版和逻辑错误
- 2010/11/29 - 修改了工具,使其能够响应与开发分辨率不同的执行屏幕分辨率