我想在API中添加一个选项,让用户指定某种东西的颜色。我希望它能接受合理的颜色表示,可能包括十六进制表示和各种CSS颜色。乍一看,ColorTranslator.FromHtml()
似乎是我需要的,但经过一点实验,我不太确定。
MSDN文档读起来不小心,似乎建议ColorTranslator.FromHtml()
应该支持CSS颜色规范。然而,它似乎并不支持CSS提供的每一种语法。例如,这将引发一个异常:
// "rgb(255 is not a valid value for Int32"
Color c = ColorTranslator.FromHtml("rgb(255,255,255)");
其他颜色的解析与这里的CSS规则不同。8位十六进制代码被解释为AARGGBB,而不是RRGGBBAA:
Color c = ColorTranslator.FromHtml("#aabbccdd");
// 187, 204, 221, 170
Console.WriteLine($"{c.R}, {c.G}, {c.B}, {c.A}");
4位十六进制代码被解释为RRGG(蓝色部分为零),而不是RGBA:
Color c = ColorTranslator.FromHtml("#abcd");
// 0, 171, 205, 0
Console.WriteLine($"{c.R}, {c.G}, {c.B}, {c.A}");
为什么会存在这些偏差,该方法到底支持什么?只是因为该方法是旧的,冻结在旧版本的CSS中,但添加了一些与最近的CSS标准冲突的扩展吗?
我不能告诉你为什么,但我可以告诉你支持什么。
如果你阅读来源,你可以看到颜色是如何处理的,本质上是:
#771122
作为#RRGGBB
处理#712
作为#RGB
处理LightGrey
转换为LightGray
- 诸如
highlighttext
之类的任何系统颜色名称都被转换为特定的颜色 - 任何其他颜色名称都将使用
Color.FromName
创建(我认为)
我想,这是在你所指的大多数东西都存在于规范中之前的一段时间。
如果将来有人需要这个。手动将HTML/CSS颜色解析为Color?(可为null的颜色)可能需要翻译成C#。可能需要添加对更多格式的支持,但我认为这涵盖了99%网络样式的典型基本情况。
''' <summary>
''' Named groups "r", "g", "b".
''' </summary>
Private Shared Regex_Html_RRGGBB As New Regex("^#(?<r>[0-9a-f][0-9a-f])(?<g>[0-9a-f][0-9a-f])(?<b>[0-9a-f][0-9a-f])$", RegexOptions.ExplicitCapture Or RegexOptions.IgnoreCase Or RegexOptions.Compiled)
''' <summary>
''' Named groups "r", "g", "b".
''' </summary>
Private Shared Regex_Html_RGB As New Regex("^#(?<r>[0-9a-f])(?<g>[0-9a-f])(?<b>[0-9a-f])$", RegexOptions.ExplicitCapture Or RegexOptions.IgnoreCase Or RegexOptions.Compiled)
''' <summary>
''' Named groups "r", "g", "b".
''' </summary>
Private Shared Regex_Html_RGB_funct As New Regex("^rgb((?<r>[0-255]{1,3})[t ]*,[t ]*(?<g>[0-255]{1,3})[t ]*,[t ]*(?<b>[0-255]{1,3}))$", RegexOptions.ExplicitCapture Or RegexOptions.IgnoreCase Or RegexOptions.Compiled)
''' <summary>
''' Named groups "r", "g", "b", "a" where A is only 0-1 range decimal.
''' </summary>
Private Shared Regex_Html_RGBA_funct As New Regex("^rgba((?<r>[0-255]{1,3})[t ]*,[t ]*(?<g>[0-255]{1,3})[t ]*,[t ]*(?<b>[0-255]{1,3}),[t ]*(?<a>[0-1][.]{0,1}[0-9]{0,9}))$", RegexOptions.ExplicitCapture Or RegexOptions.IgnoreCase Or RegexOptions.Compiled)
''' <summary>
''' Reverse convertion from css format color to drawing color.
''' Supported formats #RRGGBB, #RGB, rgb(i,i,i), rgba(i,i,i,d), Named Colors.
''' Returns Nothing on failure.
''' </summary>
''' <param name="value"></param>
Public Shared Function FromHtmlColor(value As String) As Color?
If value.IsNullOrWhitespace Then
Return Nothing
Else ' must parse
' color translator doesn't account for transparancy.
' must check manually first.
Dim m As Match
m = Regex_Html_RGBA_funct.Match(value)
If m.Success Then
Dim r As Integer = ToRange(0, ToInt(m.Groups("r").Value), 255)
Dim g As Integer = ToRange(0, ToInt(m.Groups("g").Value), 255)
Dim b As Integer = ToRange(0, ToInt(m.Groups("b").Value), 255)
Dim a As Integer = ToRange(0, ToInt(255 * ToDbl(m.Groups("a").Value)), 255) ' convert 0-1 to 0-255.
Return Color.FromArgb(a, r, g, b)
End If
m = Regex_Html_RRGGBB.Match(value)
If m.Success Then
Dim r As Integer = Convert.ToInt32(m.Groups("r").Value, 16)
Dim g As Integer = Convert.ToInt32(m.Groups("g").Value, 16)
Dim b As Integer = Convert.ToInt32(m.Groups("b").Value, 16)
Return Color.FromArgb(r, g, b)
End If
m = Regex_Html_RGB_funct.Match(value)
If m.Success Then
Dim r As Integer = ToRange(0, ToInt(m.Groups("r").Value), 255)
Dim g As Integer = ToRange(0, ToInt(m.Groups("g").Value), 255)
Dim b As Integer = ToRange(0, ToInt(m.Groups("b").Value), 255)
Return Color.FromArgb(r, g, b)
End If
m = Regex_Html_RGB.Match(value) ' #rgb that needs values doubled before conversion.
If m.Success Then
Dim r As Integer = Convert.ToInt32(m.Groups("r").Value & m.Groups("r").Value, 16) ' double up each character for "#rgb"
Dim g As Integer = Convert.ToInt32(m.Groups("g").Value & m.Groups("g").Value, 16)
Dim b As Integer = Convert.ToInt32(m.Groups("b").Value & m.Groups("b").Value, 16)
Return Color.FromArgb(r, g, b)
End If
Try ' color translator as final fallback (this supports very little surprisingly
Return Drawing.ColorTranslator.FromHtml(value)
Catch ex As Exception
' ignore.
End Try
Return Nothing
End If
End Function
基于该方法被称为FromHtml()
而不是FromCss()
的事实,该方法"偏离"CSS标准的原因可能是因为它一开始甚至没有尝试实现CSS。它到底支持什么?同样,根据方法名称,该方法似乎是对HTML颜色的广告支持。
对于那些不熟悉这两种语言的人来说,HTML和CSS是两种不同的语言,它们对颜色值的表示法并不完全相同。它们唯一的共同点是许多预定义的颜色名称,以及十六进制表示法。事实上,任何给定的方法都能正确地将6位十六进制代码解释为RGB颜色,这并不意味着该方法与CSS有任何关系。同样,HTML接受十六进制代码作为颜色值这一事实并不意味着它与CSS兼容。
举个例子:HTML没有rgb()
函数表示法。HTML没有8位十六进制代码(它们被简单地视为6位十六进制码,忽略任何尾随数字)。HTML没有4位十六进制代码(它们被简单地视为6位十六进制码,并填充前4位)。
在CSS中,8位和4位十六进制代码仅在CSS-color-4中有效,这是一个相对较新的标准,与您链接到的标准相同。另一方面,这种方法已经存在多年了。一些浏览器可以声称实现了以后标准化的功能(WebKit尤其臭名昭著,但IE5经常被认为普及了后来的box-sizing
属性),但要说这种方法也能做到这一点,那就太夸张了。