将十六进制字符串解析为图像/颜色

如何将Web 颜色格式(3 或 6 个十六进制数字)中的 RGB 颜色解析为Colorfrom image/color?go 有内置的解析器吗?我希望能够解析两种格式#XXXXXX#XXX颜色格式。 color文档对此只字不提: https: //golang.org/pkg/image/color/ 但这个任务很常见,所以我相信 go 有一些功能(我只是没有找到)。

呼唤远方
浏览 202回答 3
3回答

米琪卡哇伊

前言:我在 中发布了此实用程序(2.Fast 解决方案)github.com/icza/gox,请参阅colorx.ParseHexColor()。1.优雅的解决方案这是另一个使用fmt.Sscanf(). 它当然不是最快的解决方案,但它很优雅。它直接扫描到结构的字段中color.RGBA:func ParseHexColor(s string) (c color.RGBA, err error) {    c.A = 0xff    switch len(s) {    case 7:        _, err = fmt.Sscanf(s, "#%02x%02x%02x", &c.R, &c.G, &c.B)    case 4:        _, err = fmt.Sscanf(s, "#%1x%1x%1x", &c.R, &c.G, &c.B)        // Double the hex digits:        c.R *= 17        c.G *= 17        c.B *= 17    default:        err = fmt.Errorf("invalid length, must be 7 or 4")    }    return}测试它:hexCols := []string{    "#112233",    "#123",    "#000233",    "#023",    "invalid",    "#abcd",    "#-12",}for _, hc := range hexCols {    c, err := ParseHexColor(hc)    fmt.Printf("%-7s = %3v, %v\n", hc, c, err)}输出(在Go Playground上尝试):#112233 = { 17  34  51 255}, <nil>#123    = { 17  34  51 255}, <nil>#000233 = {  0   2  51 255}, <nil>#023    = {  0  34  51 255}, <nil>invalid = {  0   0   0 255}, input does not match format#abcd   = {  0   0   0 255}, invalid length, must be 7 or 4#-12    = {  0   0   0 255}, expected integer2.快速解决如果性能确实很重要,fmt.Sscanf()那是一个非常糟糕的选择。它需要一个实现必须解析的格式字符串,并根据它解析输入,并使用反射将结果存储到指向的值中。由于任务基本上只是“解析”一个十六进制值,我们可以做得更好。我们甚至不必调用通用的十六进制解析库(例如encoding/hex),我们可以自己完成。我们甚至不必将输入视为 a string,甚至不必将其视为一系列runes,我们可能会降低到将其视为一系列字节的级别。是的,Go 在内存中将值存储为 UTF-8 字节序列,但如果输入是有效的颜色字符串,则其所有字节必须在1 对 1 映射到字节string的范围内。0..127如果不是这种情况,输入将已经无效,我们将检测到这一点,但在这种情况下我们返回什么颜色应该无关紧要(无关紧要)。现在让我们看一个快速的实现:var errInvalidFormat = errors.New("invalid format")func ParseHexColorFast(s string) (c color.RGBA, err error) {    c.A = 0xff    if s[0] != '#' {        return c, errInvalidFormat    }    hexToByte := func(b byte) byte {        switch {        case b >= '0' && b <= '9':            return b - '0'        case b >= 'a' && b <= 'f':            return b - 'a' + 10        case b >= 'A' && b <= 'F':            return b - 'A' + 10        }        err = errInvalidFormat        return 0    }    switch len(s) {    case 7:        c.R = hexToByte(s[1])<<4 + hexToByte(s[2])        c.G = hexToByte(s[3])<<4 + hexToByte(s[4])        c.B = hexToByte(s[5])<<4 + hexToByte(s[6])    case 4:        c.R = hexToByte(s[1]) * 17        c.G = hexToByte(s[2]) * 17        c.B = hexToByte(s[3]) * 17    default:        err = errInvalidFormat    }    return}使用与第一个示例相同的输入对其进行测试,输出为(在Go Playground上尝试):#112233 = { 17  34  51 255}, <nil>#123    = { 17  34  51 255}, <nil>#000233 = {  0   2  51 255}, <nil>#023    = {  0  34  51 255}, <nil>invalid = {  0   0   0 255}, invalid format#abcd   = {  0   0   0 255}, invalid format#-12    = {  0  17  34 255}, invalid format3. 基准让我们对这两个解决方案进行基准测试。基准测试代码将包括使用长格式和短格式调用它们。排除错误情况。func BenchmarkParseHexColor(b *testing.B) {    for i := 0; i < b.N; i++ {        ParseHexColor("#112233")        ParseHexColor("#123")    }}func BenchmarkParseHexColorFast(b *testing.B) {    for i := 0; i < b.N; i++ {        ParseHexColorFast("#112233")        ParseHexColorFast("#123")    }}以下是基准测试结果:go test -bench . -benchmemBenchmarkParseHexColor-4         500000     2557 ns/op      144 B/op    9 allocs/opBenchmarkParseHexColorFast-4   100000000      10.3 ns/op      0 B/op    0 allocs/op正如我们所见,“快速”解决方案大约快250 倍并且不使用分配(与“优雅”解决方案不同)。

炎炎设计

RGBA 颜色只有 4 个字节,红色、绿色、蓝色和 alpha 通道各一个。对于三个或六个十六进制数字,字母字节通常隐含为 0xFF(AABBCC被认为与 一样AABBCCFF,按原样ABC)。因此解析颜色字符串就像对其进行规范化一样简单,使其具有“RRGGBBAA”(4 个十六进制编码字节)的形式,然后对其进行解码:package mainimport (&nbsp; &nbsp; "encoding/hex"&nbsp; &nbsp; "fmt"&nbsp; &nbsp; "image/color"&nbsp; &nbsp; "log")func main() {&nbsp; &nbsp; colorStr := "102030FF"&nbsp; &nbsp; colorStr, err := normalize(colorStr)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; log.Fatal(err)&nbsp; &nbsp; }&nbsp; &nbsp; b, err := hex.DecodeString(colorStr)&nbsp; &nbsp; if err != nil {&nbsp; &nbsp; &nbsp; &nbsp; log.Fatal(err)&nbsp; &nbsp; }&nbsp; &nbsp; color := color.RGBA{b[0], b[1], b[2], b[3]}&nbsp; &nbsp; fmt.Println(color) // Output: {16 32 48 255}}func normalize(colorStr string) (string, error) {&nbsp; &nbsp; // left as an exercise for the reader&nbsp; &nbsp; return colorStr, nil}在操场上试试:https ://play.golang.org/p/aCX-vyfMG4G

MMMHUHU

您可以使用将任意 2 个十六进制数字转换为整数strconv.ParseUintstrconv.ParseUint(str, 16, 8)指示16基数 16(十六进制),8 指示位数,在本例中为一个字节。您可以使用它来将每 2 个字符解析为它们的组件https://play.golang.org/p/B56B8_NvnVRfunc ParseHexColor(v string) (out color.RGBA, err error) {    if len(v) != 7 {        return out, errors.New("hex color must be 7 characters")    }    if v[0] != '#' {        return out, errors.New("hex color must start with '#'")    }    var red, redError = strconv.ParseUint(v[1:3], 16, 8)    if redError != nil {        return out, errors.New("red component invalid")    }    out.R = uint8(red)    var green, greenError = strconv.ParseUint(v[3:5], 16, 8)    if greenError != nil {        return out, errors.New("green component invalid")    }    out.G = uint8(green)    var blue, blueError = strconv.ParseUint(v[5:7], 16, 8)    if blueError != nil {        return out, errors.New("blue component invalid")    }    out.B = uint8(blue)    return}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go