亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

將十六進制字符串解析為圖像/顏色

將十六進制字符串解析為圖像/顏色

Go
呼喚遠方 2023-06-01 15:15:30
如何將Web 顏色格式(3 或 6 個十六進制數字)中的 RGB 顏色解析為Colorfrom?image/color?go 有內置的解析器嗎?我希望能夠解析兩種格式#XXXXXX和#XXX顏色格式。?color文檔對此只字不提: https:?//golang.org/pkg/image/color/?但這個任務很常見,所以我相信 go 有一些功能(我只是沒有找到)。
查看完整描述

3 回答

?
米琪卡哇伊

TA貢獻1998條經驗 獲得超6個贊

前言:我在 中發布了此實用程序(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 integer

2.快速解決

如果性能確實很重要,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 format

3. 基準

讓我們對這兩個解決方案進行基準測試。基準測試代碼將包括使用長格式和短格式調用它們。排除錯誤情況。


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 . -benchmem


BenchmarkParseHexColor-4? ? ? ? ?500000? ? ?2557 ns/op? ? ? 144 B/op? ? 9 allocs/op

BenchmarkParseHexColorFast-4? ?100000000? ? ? 10.3 ns/op? ? ? 0 B/op? ? 0 allocs/op

正如我們所見,“快速”解決方案大約快250 倍并且不使用分配(與“優雅”解決方案不同)。


查看完整回答
反對 回復 2023-06-01
?
炎炎設計

TA貢獻1808條經驗 獲得超4個贊

RGBA 顏色只有 4 個字節,紅色、綠色、藍色和 alpha 通道各一個。對于三個或六個十六進制數字,字母字節通常隱含為 0xFF(AABBCC被認為與 一樣AABBCCFF,按原樣ABC)。


因此解析顏色字符串就像對其進行規范化一樣簡單,使其具有“RRGGBBAA”(4 個十六進制編碼字節)的形式,然后對其進行解碼:


package main


import (

    "encoding/hex"

    "fmt"

    "image/color"

    "log"

)


func main() {

    colorStr := "102030FF"


    colorStr, err := normalize(colorStr)

    if err != nil {

        log.Fatal(err)

    }


    b, err := hex.DecodeString(colorStr)

    if err != nil {

        log.Fatal(err)

    }


    color := color.RGBA{b[0], b[1], b[2], b[3]}


    fmt.Println(color) // Output: {16 32 48 255}

}


func normalize(colorStr string) (string, error) {

    // left as an exercise for the reader

    return colorStr, nil

}

在操場上試試:https ://play.golang.org/p/aCX-vyfMG4G


查看完整回答
反對 回復 2023-06-01
?
MMMHUHU

TA貢獻1834條經驗 獲得超8個贊

您可以使用將任意 2 個十六進制數字轉換為整數strconv.ParseUint

strconv.ParseUint(str,?16,?8)

指示16基數 16(十六進制),8 指示位數,在本例中為一個字節。

您可以使用它來將每 2 個字符解析為它們的組件

https://play.golang.org/p/B56B8_NvnVR

func 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

}


查看完整回答
反對 回復 2023-06-01
  • 3 回答
  • 0 關注
  • 168 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號