pax_global_header00006660000000000000000000000064142710221530014507gustar00rootroot0000000000000052 comment=2c4150a896c4eeffc904ad6bbf39962896c1c7e0 csscolorparser-0.1.3/000077500000000000000000000000001427102215300145545ustar00rootroot00000000000000csscolorparser-0.1.3/.github/000077500000000000000000000000001427102215300161145ustar00rootroot00000000000000csscolorparser-0.1.3/.github/FUNDING.yml000066400000000000000000000000441427102215300177270ustar00rootroot00000000000000ko_fi: mazznoer liberapay: mazznoer csscolorparser-0.1.3/.github/workflows/000077500000000000000000000000001427102215300201515ustar00rootroot00000000000000csscolorparser-0.1.3/.github/workflows/go.yml000066400000000000000000000012321427102215300212770ustar00rootroot00000000000000name: Go on: push: branches: [ master ] pull_request: branches: [ master ] jobs: build: name: Build runs-on: ubuntu-latest steps: - name: Set up Go 1.x uses: actions/setup-go@v2 with: go-version: ^1.13 - name: Check out code into the Go module directory uses: actions/checkout@v2 - name: Get dependencies run: | go get -v -t -d ./... if [ -f Gopkg.toml ]; then curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh dep ensure fi - name: Build run: go build -v ./... - name: Test run: go test -v ./... csscolorparser-0.1.3/.gitignore000066400000000000000000000004151427102215300165440ustar00rootroot00000000000000# Binaries for programs and plugins *.exe *.exe~ *.dll *.so *.dylib # Test binary, built with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out # Dependency directories (remove the comment below to include it) # vendor/ csscolorparser-0.1.3/.travis.yml000066400000000000000000000003211427102215300166610ustar00rootroot00000000000000language: go go: - 1.12.x - tip before_install: - go get -t -v ./... script: - go test -race -coverprofile=coverage.txt -covermode=atomic after_success: - bash <(curl -s https://codecov.io/bash) csscolorparser-0.1.3/LICENSE000066400000000000000000000020611427102215300155600ustar00rootroot00000000000000MIT License Copyright (c) 2020 Nor Khasyatillah Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. csscolorparser-0.1.3/README.md000066400000000000000000000047461427102215300160460ustar00rootroot00000000000000# Golang CSS Color Parser Library [![PkgGoDev](https://pkg.go.dev/badge/github.com/mazznoer/csscolorparser)](https://pkg.go.dev/github.com/mazznoer/csscolorparser) [![Build Status](https://travis-ci.org/mazznoer/csscolorparser.svg?branch=master)](https://travis-ci.org/mazznoer/csscolorparser) [![Build Status](https://github.com/mazznoer/csscolorparser/workflows/Go/badge.svg)](https://github.com/mazznoer/csscolorparser/actions) [![go report](https://goreportcard.com/badge/github.com/mazznoer/csscolorparser)](https://goreportcard.com/report/github.com/mazznoer/csscolorparser) [![codecov](https://codecov.io/gh/mazznoer/csscolorparser/branch/master/graph/badge.svg)](https://codecov.io/gh/mazznoer/csscolorparser) [![Lines of Code](https://tokei.rs/b1/github/mazznoer/csscolorparser?category=code)](https://github.com/mazznoer/csscolorparser) [Go](https://www.golang.org/) library for parsing CSS color string as defined in the W3C's [CSS Color Module Level 4](https://www.w3.org/TR/css-color-4/). ## Supported Color Format * [Named colors](https://www.w3.org/TR/css-color-4/#named-colors) * RGB hexadecimal (with and without `#` prefix) + Short format `#rgb` + Short format with alpha `#rgba` + Long format `#rrggbb` + Long format with alpha `#rrggbbaa` * `rgb()` and `rgba()` * `hsl()` and `hsla()` * `hwb()` * `hwba()`, `hsv()`, `hsva()` - not in CSS standard. Not yet supported: `lab()`, `lch()`. ### Example Color Format ``` transparent lime #0f0 #0f0f #00ff00 #00ff00ff rgb(0,255,0) rgb(0% 100% 0%) rgb(0 255 0 / 100%) rgba(0,255,0,1) hsl(120,100%,50%) hsl(120deg 100% 50%) hsl(-240 100% 50%) hsl(-240deg 100% 50%) hsl(0.3333turn 100% 50%) hsl(133.333grad 100% 50%) hsl(2.0944rad 100% 50%) hsla(120,100%,50%,100%) hwb(120 0% 0%) hwb(480deg 0% 0% / 100%) hsv(120,100%,100%) hsv(120deg 100% 100% / 100%) ``` ## Usage Examples ```go import "github.com/mazznoer/csscolorparser" ``` ```go c, err := csscolorparser.Parse("gold") if err != nil { panic(err) } fmt.Printf("R:%.3f, G:%.3f, B:%.3f, A:%.3f", c.R, c.G, c.B, c.A) // R:1.000, G:0.843, B:0.000, A:1.000 fmt.Println(c.RGBA255()) // 255 215 0 255 fmt.Println(c.HexString()) // #ffd700 fmt.Println(c.RGBString()) // rgb(255,215,0) ``` ## Try It Online * [Playground 1](https://play.golang.org/p/8KMIc1TLQB0) * [Playground 2](https://play.golang.org/p/7kb62KSARwa) ## Similar Projects * [csscolorparser](https://github.com/mazznoer/csscolorparser-rs) (Rust) * [csscolorparser](https://github.com/deanm/css-color-parser-js) (Javascript) csscolorparser-0.1.3/chromium_test.go000066400000000000000000000247531427102215300200000ustar00rootroot00000000000000package csscolorparser import "testing" func TestBrowserChromium(t *testing.T) { type testData struct { colorStr string r, g, b, a uint8 } // Randomly generated color string, parsed using Chromium 87.0.4280.66 data := []testData{ {"#13EF", 17, 51, 238, 255}, {"#b42f", 187, 68, 34, 255}, {"#49e97851", 73, 233, 120, 81}, {"#8C68B2E0", 140, 104, 178, 224}, {"#AE42B424", 174, 66, 180, 36}, {"#60b", 102, 0, 187, 255}, {"#9675E6EA", 150, 117, 230, 234}, {"#7858", 119, 136, 85, 136}, {"#f06", 255, 0, 102, 255}, {"#C82", 204, 136, 34, 255}, {"#70A8AA", 112, 168, 170, 255}, {"#198", 17, 153, 136, 255}, {"#bc94198b", 188, 148, 25, 139}, {"#FC3B98", 252, 59, 152, 255}, {"#541a3847", 84, 26, 56, 71}, {"#29A", 34, 153, 170, 255}, {"#4FA2DC", 79, 162, 220, 255}, {"#812", 136, 17, 34, 255}, {"#7A57AD0C", 122, 87, 173, 12}, {"#F74", 255, 119, 68, 255}, {"#ADB", 170, 221, 187, 255}, {"#774AD2B1", 119, 74, 210, 177}, {"#ECC", 238, 204, 204, 255}, {"#DCF724B3", 220, 247, 36, 179}, {"#716195", 113, 97, 149, 255}, {"#FC39", 255, 204, 51, 153}, {"#D3B", 221, 51, 187, 255}, {"#7795", 119, 119, 153, 85}, {"#387B", 51, 136, 119, 187}, {"#C3CE", 204, 51, 204, 238}, {"#BF88D793", 191, 136, 215, 147}, {"#D97C", 221, 153, 119, 204}, {"#401D", 68, 0, 17, 221}, {"#0daf68", 13, 175, 104, 255}, {"#C84E7484", 200, 78, 116, 132}, {"#284", 34, 136, 68, 255}, {"#248", 34, 68, 136, 255}, {"#3422AF", 52, 34, 175, 255}, {"#46E", 68, 102, 238, 255}, {"#2ec6d703", 46, 198, 215, 3}, {"#29F659", 41, 246, 89, 255}, {"#69355999", 105, 53, 89, 153}, {"#4099", 68, 0, 153, 153}, {"#44abea", 68, 171, 234, 255}, {"#0623B60A", 6, 35, 182, 10}, {"#4304F493", 67, 4, 244, 147}, {"#91176A", 145, 23, 106, 255}, {"#875994CF", 135, 89, 148, 207}, {"#806F", 136, 0, 102, 255}, {"#DD32", 221, 221, 51, 34}, {"rgb(105.927,150.994,15.104)", 106, 151, 15, 255}, {"rgb(10.837,152.535,154.317,0.568)", 11, 153, 154, 145}, {"rgb(237.623,156.627,211.140,-0.058)", 238, 157, 211, 0}, {"rgb(80.685,2.873,82.097,0.592)", 81, 3, 82, 151}, {"rgb(31.530,138.330,246.696)", 32, 138, 247, 255}, {"rgb(127.659,188.444,102.421)", 128, 188, 102, 255}, {"rgb(114.062,6.757,101.538)", 114, 7, 102, 255}, {"rgb(34.047,96.606,76.235,0.045)", 34, 97, 76, 11}, {"rgb(214.707,10.143,78.461)", 215, 10, 78, 255}, {"rgb(158.355,172.716,136.060)", 158, 173, 136, 255}, {"rgb(41.366,221.162,32.067,1.107)", 41, 221, 32, 255}, {"rgb(247.083,25.052,0.185)", 247, 25, 0, 255}, {"rgb(67.440,90.228,257.506)", 67, 90, 255, 255}, {"rgb(99.603,18.924,133.951)", 100, 19, 134, 255}, {"rgb(71.837,242.253,112.316)", 72, 242, 112, 255}, {"rgb(262.877,206.567,71.233)", 255, 207, 71, 255}, {"rgb(153.467,73.396,96.642,1.070)", 153, 73, 97, 255}, {"rgb(253.472,35.005,92.178,0.210)", 253, 35, 92, 54}, {"rgb(63.611,20.378,1.885)", 64, 20, 2, 255}, {"rgb(70.695,209.671,111.060)", 71, 210, 111, 255}, {"rgb(35.748,184.365,-3.144,-0.099)", 36, 184, 0, 0}, {"rgb(213.630,43.353,243.800,0.932)", 214, 43, 244, 238}, {"rgb(4.895,236.929,198.497,0.162)", 5, 237, 198, 41}, {"rgb(262.492,104.420,135.986)", 255, 104, 136, 255}, {"rgb(196.148,82.928,2.328,1.194)", 196, 83, 2, 255}, {"rgb(3.984,130.315,223.066)", 4, 130, 223, 255}, {"rgb(5.098,7.075,228.457)", 5, 7, 228, 255}, {"rgb(132.649,122.071,261.147)", 133, 122, 255, 255}, {"rgb(215.091,198.018,80.956,0.673)", 215, 198, 81, 172}, {"rgb(224.466,219.548,80.411)", 224, 220, 80, 255}, {"rgb(88.093,249.677,143.753)", 88, 250, 144, 255}, {"rgb(261.342,42.332,150.964,0.257)", 255, 42, 151, 66}, {"rgb(24.315,19.390,143.873)", 24, 19, 144, 255}, {"rgb(206.152,103.265,49.028)", 206, 103, 49, 255}, {"rgb(121.903,253.961,42.196,0.698)", 122, 254, 42, 178}, {"rgb(81.981,163.951,231.462)", 82, 164, 231, 255}, {"rgb(-9.058,143.858,233.204)", 0, 144, 233, 255}, {"rgb(192.509,117.856,-7.540)", 193, 118, 0, 255}, {"rgb(25.067,206.513,164.628)", 25, 207, 165, 255}, {"rgb(194.332,192.906,10.594,0.980)", 194, 193, 11, 250}, {"rgb(112.924,234.651,160.614)", 113, 235, 161, 255}, {"rgb(250.062,24.310,60.243)", 250, 24, 60, 255}, {"rgb(103.655,61.625,36.981)", 104, 62, 37, 255}, {"rgb(41.189,109.543,71.332)", 41, 110, 71, 255}, {"rgb(62.731,22.426,-1.441,0.018)", 63, 22, 0, 5}, {"rgb(260.117,262.267,234.967)", 255, 255, 235, 255}, {"rgb(4.026,-1.738,159.101)", 4, 0, 159, 255}, {"rgb(231.300,105.609,231.611,0.289)", 231, 106, 232, 74}, {"rgb(92.148,125.339,3.161)", 92, 125, 3, 255}, {"rgb(141.451,213.294,42.291)", 141, 213, 42, 255}, {"rgb(106.637%,63.245%,13.953%)", 255, 161, 36, 255}, {"rgb(36.891%,83.946%,-0.776%,-0.109)", 94, 214, 0, 0}, {"rgb(30.098%,57.177%,97.202%)", 77, 146, 248, 255}, {"rgb(20.348%,9.007%,50.198%)", 52, 23, 128, 255}, {"rgb(65.635%,38.597%,51.540%)", 167, 98, 131, 255}, {"rgb(82.140%,86.294%,74.226%)", 209, 220, 189, 255}, {"rgb(68.001%,43.582%,-8.031%,0.953)", 173, 111, 0, 243}, {"rgb(97.555%,88.344%,107.508%,1.067)", 249, 225, 255, 255}, {"rgb(103.833%,31.883%,106.519%,1.096)", 255, 81, 255, 255}, {"rgb(91.878%,77.833%,42.737%,1.036)", 234, 198, 109, 255}, {"rgb(-1.946%,104.666%,92.518%)", 0, 255, 236, 255}, {"rgb(-8.918%,43.768%,48.678%)", 0, 112, 124, 255}, {"rgb(22.344%,108.142%,25.588%,0.568)", 57, 255, 65, 145}, {"rgb(-4.792%,103.802%,25.728%,1.044)", 0, 255, 66, 255}, {"rgb(9.756%,-4.527%,55.095%)", 25, 0, 140, 255}, {"rgb(4.812%,102.908%,-9.392%)", 12, 255, 0, 255}, {"rgb(3.693%,104.465%,84.813%)", 9, 255, 216, 255}, {"rgb(29.187%,99.246%,53.246%)", 74, 253, 136, 255}, {"rgb(-7.354%,95.764%,105.057%)", 0, 244, 255, 255}, {"rgb(47.159%,48.044%,109.916%)", 120, 123, 255, 255}, {"rgb(45.759%,42.046%,91.989%)", 117, 107, 235, 255}, {"rgb(86.097%,91.214%,42.376%,0.086)", 220, 233, 108, 22}, {"rgb(13.127%,1.330%,40.329%)", 33, 3, 103, 255}, {"rgb(65.359%,88.567%,8.510%)", 167, 226, 22, 255}, {"rgb(63.728%,14.245%,39.191%)", 163, 36, 100, 255}, {"rgb(82.029%,70.333%,22.627%,0.130)", 209, 179, 58, 33}, {"rgb(-7.584%,24.596%,106.456%,0.540)", 0, 63, 255, 138}, {"rgb(34.295%,33.879%,25.945%)", 87, 86, 66, 255}, {"rgb(36.848%,55.483%,24.020%,0.215)", 94, 141, 61, 55}, {"rgb(34.615%,79.081%,96.135%,0.104)", 88, 202, 245, 27}, {"rgb(29.072%,76.973%,103.559%)", 74, 196, 255, 255}, {"rgb(-1.165%,18.030%,23.750%)", 0, 46, 61, 255}, {"rgb(23.834%,-4.078%,35.657%)", 61, 0, 91, 255}, {"rgb(10.751%,0.545%,73.270%)", 27, 1, 187, 255}, {"rgb(44.688%,9.295%,-1.679%)", 114, 24, 0, 255}, {"rgb(72.485%,65.899%,108.170%,0.917)", 185, 168, 255, 234}, {"rgb(34.422%,77.037%,93.107%)", 88, 196, 237, 255}, {"rgb(91.368%,55.279%,62.854%)", 233, 141, 160, 255}, {"rgb(102.434%,56.702%,33.212%)", 255, 145, 85, 255}, {"rgb(39.892%,87.191%,100.708%)", 102, 222, 255, 255}, {"rgb(65.042%,105.175%,5.622%)", 166, 255, 14, 255}, {"rgb(-5.767%,48.382%,-5.126%)", 0, 123, 0, 255}, {"rgb(17.665%,40.385%,80.169%)", 45, 103, 204, 255}, {"rgb(84.019%,-0.364%,9.859%,0.625)", 214, 0, 25, 159}, {"rgb(108.993%,100.397%,52.671%)", 255, 255, 134, 255}, {"rgb(19.223%,47.737%,51.318%)", 49, 122, 131, 255}, {"rgb(7.603%,70.494%,61.450%)", 19, 180, 157, 255}, {"rgb(10.202%,89.790%,78.516%)", 26, 229, 200, 255}, {"rgb(77.686%,97.221%,100.579%,0.246)", 198, 248, 255, 63}, {"rgb(-2.333%,11.540%,89.009%,0.802)", 0, 29, 227, 205}, {"hsl(303.505deg,40.607%,47.237%,-0.108)", 169, 72, 164, 0}, {"hsl(166.317grad,35.505%,61.623%,0.885)", 122, 192, 157, 226}, {"hsl(0.890turn,84.315%,-4.192%,0.733)", 0, 0, 0, 187}, {"hsl(4.367rad,26.559%,25.815%,1.025)", 54, 48, 83, 255}, {"hsl(129.011deg,24.599%,10.476%)", 20, 33, 22, 255}, {"hsl(0.132turn,18.948%,108.092%)", 255, 255, 255, 255}, {"hsl(6.366rad,86.281%,76.850%)", 247, 153, 145, 255}, {"hsl(0.025turn,9.070%,17.743%)", 49, 42, 41, 255}, {"hsl(346.054grad,22.344%,71.574%,-0.062)", 199, 166, 193, 0}, {"hsl(0.015turn,35.648%,92.027%)", 242, 229, 227, 255}, {"hsl(47.756grad,14.468%,86.803%)", 226, 223, 216, 255}, {"hsl(82.948deg,106.898%,51.390%,0.409)", 160, 255, 7, 104}, {"hsl(30.836deg,-6.307%,103.528%)", 255, 255, 255, 255}, {"hsl(43.265,70.201%,70.996%)", 233, 204, 129, 255}, {"hsl(128.089grad,69.628%,64.418%)", 111, 227, 101, 255}, {"hsl(32.213,84.179%,0.508%,0.967)", 2, 1, 0, 247}, {"hsl(243.278deg,107.466%,94.419%,-0.087)", 228, 227, 255, 0}, {"hsl(17.877,56.334%,102.965%,0.275)", 255, 255, 255, 70}, {"hsl(290.112,107.611%,108.356%)", 255, 255, 255, 255}, {"hsl(200.221grad,30.283%,11.069%)", 20, 37, 37, 255}, {"hsl(0.738turn,12.560%,3.624%,0.318)", 9, 8, 10, 81}, {"hsl(0.109turn,70.850%,74.131%,1.187)", 236, 203, 142, 255}, {"hsl(163.566,83.141%,36.520%)", 16, 171, 128, 255}, {"hsl(132.194,80.652%,105.081%,1.052)", 255, 255, 255, 255}, {"hsl(307.249deg,60.237%,26.132%)", 107, 26, 97, 255}, {"hsl(87.916grad,18.382%,-5.926%,0.725)", 0, 0, 0, 185}, {"hsl(0.923turn,22.762%,41.884%,1.001)", 131, 82, 105, 255}, {"hsl(316.684grad,55.930%,52.703%,0.661)", 168, 67, 202, 169}, {"hsl(0.939turn,57.243%,97.977%,1.009)", 253, 247, 249, 255}, {"hsl(-0.091turn,27.351%,92.166%)", 240, 230, 236, 255}, {"hsl(1.089turn,103.459%,55.996%,0.097)", 255, 150, 31, 25}, {"hsl(174.033deg,10.079%,29.391%)", 67, 83, 81, 255}, {"hsl(201.674,28.476%,8.261%)", 15, 23, 27, 255}, {"hsl(142.622deg,39.472%,90.933%,-0.126)", 223, 241, 230, 0}, {"hsl(4.658rad,107.070%,7.771%,0.600)", 18, 0, 40, 153}, {"hsl(4.880rad,80.889%,-9.699%,0.319)", 0, 0, 0, 81}, {"hsl(1.121rad,-5.569%,97.761%,1.084)", 249, 249, 249, 255}, {"hsl(262.036,5.324%,-4.960%,0.148)", 0, 0, 0, 38}, {"hsl(-0.455grad,41.379%,78.928%)", 224, 179, 179, 255}, {"hsl(0.390turn,105.835%,79.907%)", 153, 255, 187, 255}, {"hsl(0.347turn,-9.555%,33.512%)", 85, 85, 85, 255}, {"hsl(5.535rad,84.788%,36.228%)", 171, 14, 126, 255}, {"hsl(202.153,42.328%,57.768%)", 102, 159, 193, 255}, {"hsl(4.754rad,99.620%,30.456%,-0.115)", 84, 0, 155, 0}, {"hsl(0.703turn,-9.041%,64.426%,1.076)", 164, 164, 164, 255}, {"hsl(-0.020turn,22.850%,95.116%,0.123)", 245, 240, 240, 31}, {"hsl(403.987grad,42.191%,10.063%)", 36, 16, 15, 255}, {"hsl(0.104turn,49.789%,74.133%,0.198)", 222, 197, 156, 50}, {"hsl(0.088turn,32.001%,103.668%)", 255, 255, 255, 255}, {"hsl(53.662,57.956%,60.528%)", 213, 200, 96, 255}, } for i, d := range data { c, err := Parse(d.colorStr) if err != nil { t.Errorf("Parse error: %s", d.colorStr) continue } r, g, b, a := c.RGBA255() rgba := [4]uint8{r, g, b, a} out := [4]uint8{d.r, d.g, d.b, d.a} if rgba != out { t.Errorf("(%d) %s -> %v != %v", i, d.colorStr, out, rgba) } } } csscolorparser-0.1.3/colorparser.go000066400000000000000000000210651427102215300174420ustar00rootroot00000000000000// Package csscolorparser provides function for parsing CSS color string as defined in the W3C's CSS color module level 4. package csscolorparser import ( "fmt" "math" "strconv" "strings" ) // Inspired by https://github.com/deanm/css-color-parser-js // R, G, B, A values in the range 0..1 type Color struct { R, G, B, A float64 } // Implement the Go color.Color interface. func (c Color) RGBA() (r, g, b, a uint32) { r = uint32(c.R*c.A*65535 + 0.5) g = uint32(c.G*c.A*65535 + 0.5) b = uint32(c.B*c.A*65535 + 0.5) a = uint32(c.A*65535 + 0.5) return } // RGBA255 returns R, G, B, A values in the range 0..255 func (c Color) RGBA255() (r, g, b, a uint8) { r = uint8(c.R*255 + 0.5) g = uint8(c.G*255 + 0.5) b = uint8(c.B*255 + 0.5) a = uint8(c.A*255 + 0.5) return } // HexString returns CSS hexadecimal string. func (c Color) HexString() string { r, g, b, a := c.RGBA255() if a < 255 { return fmt.Sprintf("#%02x%02x%02x%02x", r, g, b, a) } return fmt.Sprintf("#%02x%02x%02x", r, g, b) } // RGBString returns CSS RGB string. func (c Color) RGBString() string { r, g, b, _ := c.RGBA255() if c.A < 1 { return fmt.Sprintf("rgba(%d,%d,%d,%v)", r, g, b, c.A) } return fmt.Sprintf("rgb(%d,%d,%d)", r, g, b) } // Name returns name of this color if its available. func (c Color) Name() (string, bool) { r, g, b, _ := c.RGBA255() rgb := [3]uint8{r, g, b} for k, v := range namedColors { if v == rgb { return k, true } } return "", false } // Implement the Go TextUnmarshaler interface func (c *Color) UnmarshalText(text []byte) error { col, err := Parse(string(text)) if err != nil { return err } c.R = col.R c.G = col.G c.B = col.B c.A = col.A return nil } // Implement the Go TextMarshaler interface func (c Color) MarshalText() ([]byte, error) { return []byte(c.HexString()), nil } var black = Color{0, 0, 0, 1} // Parse parses CSS color string and returns, if successful, a Color. func Parse(s string) (Color, error) { input := s s = strings.TrimSpace(strings.ToLower(s)) if s == "transparent" { return Color{0, 0, 0, 0}, nil } // Predefined name / keyword c, ok := namedColors[s] if ok { return Color{float64(c[0]) / 255, float64(c[1]) / 255, float64(c[2]) / 255, 1}, nil } // Hexadecimal if strings.HasPrefix(s, "#") { c, ok := parseHex(s[1:]) if ok { return c, nil } return black, fmt.Errorf("Invalid hex color, %s", input) } op := strings.Index(s, "(") if (op != -1) && strings.HasSuffix(s, ")") { fname := strings.TrimSpace(s[:op]) alpha := 1.0 okA := true s = s[op+1 : len(s)-1] s = strings.ReplaceAll(s, ",", " ") s = strings.ReplaceAll(s, "/", " ") params := strings.Fields(s) if fname == "rgb" || fname == "rgba" { if len(params) != 3 && len(params) != 4 { return black, fmt.Errorf("%s() format needs 3 or 4 parameters, %s", fname, input) } r, okR := parsePercentOr255(params[0]) g, okG := parsePercentOr255(params[1]) b, okB := parsePercentOr255(params[2]) if len(params) == 4 { alpha, okA = parsePercentOrFloat(params[3]) } if okR && okG && okB && okA { return Color{ clamp0_1(r), clamp0_1(g), clamp0_1(b), clamp0_1(alpha), }, nil } return black, fmt.Errorf("Wrong %s() components, %s", fname, input) } else if fname == "hsl" || fname == "hsla" { if len(params) != 3 && len(params) != 4 { return black, fmt.Errorf("%s() format needs 3 or 4 parameters, %s", fname, input) } h, okH := parseAngle(params[0]) s, okS := parsePercentOrFloat(params[1]) l, okL := parsePercentOrFloat(params[2]) if len(params) == 4 { alpha, okA = parsePercentOrFloat(params[3]) } if okH && okS && okL && okA { r, g, b := hslToRgb(normalizeAngle(h), clamp0_1(s), clamp0_1(l)) return Color{r, g, b, clamp0_1(alpha)}, nil } return black, fmt.Errorf("Wrong %s() components, %s", fname, input) } else if fname == "hwb" || fname == "hwba" { if len(params) != 3 && len(params) != 4 { return black, fmt.Errorf("hwb() format needs 3 or 4 parameters, %s", input) } H, okH := parseAngle(params[0]) W, okW := parsePercentOrFloat(params[1]) B, okB := parsePercentOrFloat(params[2]) if len(params) == 4 { alpha, okA = parsePercentOrFloat(params[3]) } if okH && okW && okB && okA { r, g, b := hwbToRgb(normalizeAngle(H), clamp0_1(W), clamp0_1(B)) return Color{r, g, b, clamp0_1(alpha)}, nil } return black, fmt.Errorf("Wrong hwb() components, %s", input) } else if fname == "hsv" || fname == "hsva" { if len(params) != 3 && len(params) != 4 { return black, fmt.Errorf("hsv() format needs 3 or 4 parameters, %s", input) } h, okH := parseAngle(params[0]) s, okS := parsePercentOrFloat(params[1]) v, okV := parsePercentOrFloat(params[2]) if len(params) == 4 { alpha, okA = parsePercentOrFloat(params[3]) } if okH && okS && okV && okA { r, g, b := hsvToRgb(normalizeAngle(h), clamp0_1(s), clamp0_1(v)) return Color{r, g, b, clamp0_1(alpha)}, nil } return black, fmt.Errorf("Wrong hsv() components, %s", input) } } // RGB hexadecimal format without '#' prefix c2, ok2 := parseHex(s) if ok2 { return c2, nil } return black, fmt.Errorf("Invalid color format, %s", input) } // https://stackoverflow.com/questions/54197913/parse-hex-string-to-image-color func parseHex(s string) (c Color, ok bool) { c.A = 1 ok = true hexToByte := func(b byte) byte { switch { case b >= '0' && b <= '9': return b - '0' case b >= 'a' && b <= 'f': return b - 'a' + 10 } ok = false return 0 } n := len(s) if n == 6 || n == 8 { c.R = float64(hexToByte(s[0])<<4+hexToByte(s[1])) / 255 c.G = float64(hexToByte(s[2])<<4+hexToByte(s[3])) / 255 c.B = float64(hexToByte(s[4])<<4+hexToByte(s[5])) / 255 if n == 8 { c.A = float64(hexToByte(s[6])<<4+hexToByte(s[7])) / 255 } } else if n == 3 || n == 4 { c.R = float64(hexToByte(s[0])*17) / 255 c.G = float64(hexToByte(s[1])*17) / 255 c.B = float64(hexToByte(s[2])*17) / 255 if n == 4 { c.A = float64(hexToByte(s[3])*17) / 255 } } else { ok = false } return } func modulo(x, y float64) float64 { return math.Mod(math.Mod(x, y)+y, y) } func hueToRgb(n1, n2, h float64) float64 { h = modulo(h, 6) if h < 1 { return n1 + ((n2 - n1) * h) } if h < 3 { return n2 } if h < 4 { return n1 + ((n2 - n1) * (4 - h)) } return n1 } // h = 0..360 // s, l = 0..1 // r, g, b = 0..1 func hslToRgb(h, s, l float64) (r, g, b float64) { if s == 0 { return l, l, l } var n2 float64 if l < 0.5 { n2 = l * (1 + s) } else { n2 = l + s - (l * s) } n1 := 2*l - n2 h /= 60 r = clamp0_1(hueToRgb(n1, n2, h+2)) g = clamp0_1(hueToRgb(n1, n2, h)) b = clamp0_1(hueToRgb(n1, n2, h-2)) return } func hwbToRgb(hue, white, black float64) (r, g, b float64) { if white+black >= 1 { gray := white / (white + black) return gray, gray, gray } r, g, b = hslToRgb(hue, 1, 0.5) r = r*(1-white-black) + white g = g*(1-white-black) + white b = b*(1-white-black) + white return } func hsvToHsl(H, S, V float64) (h, s, l float64) { h = H s = S l = (2 - S) * V / 2 if l != 0 { if l == 1 { s = 0 } else if l < 0.5 { s = S * V / (l * 2) } else { s = S * V / (2 - l*2) } } return } func hsvToRgb(H, S, V float64) (r, g, b float64) { h, s, l := hsvToHsl(H, S, V) return hslToRgb(h, s, l) } func clamp0_1(t float64) float64 { if t < 0 { return 0 } if t > 1 { return 1 } return t } func parseFloat(s string) (float64, bool) { f, err := strconv.ParseFloat(strings.TrimSpace(s), 64) return f, err == nil } func parsePercentOrFloat(s string) (float64, bool) { if strings.HasSuffix(s, "%") { f, ok := parseFloat(s[:len(s)-1]) if ok { return f / 100, true } return 0, false } return parseFloat(s) } func parsePercentOr255(s string) (float64, bool) { if strings.HasSuffix(s, "%") { f, ok := parseFloat(s[:len(s)-1]) if ok { return f / 100, true } return 0, false } f, ok := parseFloat(s) if ok { return f / 255, true } return 0, false } // Result angle in degrees (not normalized) func parseAngle(s string) (float64, bool) { if strings.HasSuffix(s, "deg") { return parseFloat(s[:len(s)-3]) } if strings.HasSuffix(s, "grad") { f, ok := parseFloat(s[:len(s)-4]) if ok { return f / 400 * 360, true } return 0, false } if strings.HasSuffix(s, "rad") { f, ok := parseFloat(s[:len(s)-3]) if ok { return f / math.Pi * 180, true } return 0, false } if strings.HasSuffix(s, "turn") { f, ok := parseFloat(s[:len(s)-4]) if ok { return f * 360, true } return 0, false } return parseFloat(s) } func normalizeAngle(t float64) float64 { t = math.Mod(t, 360) if t < 0 { t += 360 } return t } csscolorparser-0.1.3/colorparser_test.go000066400000000000000000000143701427102215300205020ustar00rootroot00000000000000package csscolorparser import ( "image/color" "strings" "testing" ) type rgba struct { r, g, b, a uint32 } func isColorEqual(c1, c2 color.Color) bool { r1, g1, b1, a1 := c1.RGBA() r2, g2, b2, a2 := c2.RGBA() a := rgba{r1, g1, b1, a1} b := rgba{r2, g2, b2, a2} if a == b { return true } return false } func equalStr(t *testing.T, a, b string) { if a != b { t.Errorf("%s != %s", a, b) } } func TestColor(t *testing.T) { a := Color{0, 0, 1, 1} equalStr(t, a.HexString(), "#0000ff") equalStr(t, a.RGBString(), "rgb(0,0,255)") b := Color{0, 0, 1, 0.5} equalStr(t, b.HexString(), "#0000ff80") equalStr(t, b.RGBString(), "rgba(0,0,255,0.5)") } func TestParseColor(t *testing.T) { type colorPair struct { in string out [4]uint8 } testData := []colorPair{ {"transparent", [4]uint8{0, 0, 0, 0}}, {"rebeccapurple", [4]uint8{102, 51, 153, 255}}, {"#ff00ff64", [4]uint8{255, 0, 255, 100}}, {"ff00ff64", [4]uint8{255, 0, 255, 100}}, {"rgb(247,179,99)", [4]uint8{247, 179, 99, 255}}, {"rgb(50% 50% 50%)", [4]uint8{128, 128, 128, 255}}, {"rgb(247,179,99,0.37)", [4]uint8{247, 179, 99, 94}}, {"hsl(270 0% 50%)", [4]uint8{128, 128, 128, 255}}, {"hwb(0 50% 50%)", [4]uint8{128, 128, 128, 255}}, {"hsv(0 0% 50%)", [4]uint8{128, 128, 128, 255}}, {"hsv(0 0% 100%)", [4]uint8{255, 255, 255, 255}}, {"hsv(0 0% 19%)", [4]uint8{48, 48, 48, 255}}, } for _, d := range testData { c, err := Parse(d.in) if err != nil { t.Errorf("Parse error: %s", d.in) continue } r, g, b, a := c.RGBA255() rgba := [4]uint8{r, g, b, a} if rgba != d.out { t.Errorf("%s -> %v != %v", d.in, d.out, rgba) } } } func TestNamedColors(t *testing.T) { for name, rgb := range namedColors { c, _ := Parse(name) r, g, b, _ := c.RGBA255() rgb_ := [3]uint8{r, g, b} if rgb_ != rgb { t.Errorf("%s != %s", rgb_, rgb) } if name == "aqua" || name == "cyan" || name == "fuchsia" || name == "magenta" { continue } if strings.Contains(name, "gray") || strings.Contains(name, "grey") { continue } name_, _ := c.Name() if name_ != name { t.Errorf("%s != %s", name_, name) } } data := [][2]string{ {"aliceblue", "#f0f8ff"}, {"bisque", "#ffe4c4"}, {"chartreuse", "#7fff00"}, {"coral", "#ff7f50"}, {"crimson", "#dc143c"}, {"dodgerblue", "#1e90ff"}, {"firebrick", "#b22222"}, {"gold", "#ffd700"}, {"hotpink", "#ff69b4"}, {"indigo", "#4b0082"}, {"lavender", "#e6e6fa"}, {"plum", "#dda0dd"}, {"salmon", "#fa8072"}, {"skyblue", "#87ceeb"}, {"tomato", "#ff6347"}, {"violet", "#ee82ee"}, {"yellowgreen", "#9acd32"}, } for _, d := range data { c, _ := Parse(d[0]) hex := c.HexString() if hex != d[1] { t.Errorf("%s != %s", hex, d[1]) } } } func TestEqualColorsBlack(t *testing.T) { data := []string{ "black", "#000", "#000f", "#000000", "#000000ff", "rgb(0,0,0)", "rgb(0% 0% 0%)", "rgb(0 0 0 100%)", "hsl(270,100%,0%)", "hwb(90 0% 100%)", "hwb(120deg 0% 100% 100%)", "hsv(120 100% 0%)", } black := color.NRGBA{0, 0, 0, 255} for _, d := range data { c, _ := Parse(d) if !isColorEqual(black, c) { t.Errorf("Not black, %s -> %v", d, c) break } } } func TestEqualColorsRed(t *testing.T) { data := []string{ "red", "#f00", "#f00f", "#ff0000", "#ff0000ff", "rgb(255,0,0)", "rgb(255 0 0)", "rgb(700, -99, 0)", // clamp to 0..255 "rgb(100% 0% 0%)", "rgb(200% -10% -100%)", // clamp to 0%..100% "rgb(255 0 0 100%)", "RGB( 255 , 0 , 0 )", "RGB( 255 0 0 )", "hsl(0,100%,50%)", "hsl(360 100% 50%)", "hwb(0 0% 0%)", "hwb(360deg 0% 0% 100%)", "hsv(0 100% 100%)", } red := color.NRGBA{255, 0, 0, 255} for _, d := range data { c, _ := Parse(d) if !isColorEqual(red, c) { t.Errorf("Not red, %s -> %v", d, c) break } } } func TestEqualColorsLime(t *testing.T) { data := []string{ "lime", "#0f0", "#0f0f", "#00ff00", "#00ff00ff", "rgb(0,255,0)", "rgb(0% 100% 0%)", "rgb(0 255 0 / 100%)", "rgba(0,255,0,1)", "hsl(120,100%,50%)", "hsl(120deg 100% 50%)", "hsl(-240 100% 50%)", "hsl(-240deg 100% 50%)", "hsl(0.3333turn 100% 50%)", "hsl(133.333grad 100% 50%)", "hsl(2.0944rad 100% 50%)", "hsla(120,100%,50%,100%)", "hwb(120 0% 0%)", "hwb(480deg 0% 0% / 100%)", "hsv(120 100% 100%)", } lime := [4]uint8{0, 255, 0, 255} for _, d := range data { c, _ := Parse(d) r, g, b, a := c.RGBA255() rgba := [4]uint8{r, g, b, a} if rgba != lime { t.Errorf("Not lime, %s -> %v", d, rgba) break } } } func TestEqualColorsLimeAlpha(t *testing.T) { data := []string{ "#00ff0080", "rgb(0,255,0,50%)", "rgb(0% 100% 0% / 0.5)", "rgba(0%,100%,0%,50%)", "hsl(120,100%,50%,0.5)", "hsl(120deg 100% 50% / 50%)", "hsla(120,100%,50%,0.5)", "hwb(120 0% 0% / 50%)", "hsv(120 100% 100% / 50%)", } limeAlpha := [4]uint8{0, 255, 0, 128} for _, d := range data { c, _ := Parse(d) r, g, b, a := c.RGBA255() rgba := [4]uint8{r, g, b, a} if rgba != limeAlpha { t.Errorf("Not lime 0.5 alpha, %s -> %v", d, rgba) break } } } func TestInvalidData(t *testing.T) { testData := []string{ "", "bloodred", "#78afzd", "#fffff", "rgb(0,255,8s)", "rgb(100%,z9%,75%)", "cmyk(1 0 0)", "rgba(0 0)", "hsl(90',100%,50%)", "hsl(deg 100% 50%)", "hsl(Xturn 100% 50%)", "hsl(Zgrad 100% 50%)", "hsl(180 1 x%)", "hsla(360)", "hwb(Xrad,50%,50%)", "hwb(270 0% 0% 0% 0%)", "hsv(120 100% 100% 1 50%)", "hsv(120 XXX 100%)", } for _, d := range testData { c, err := Parse(d) if err == nil { t.Errorf("It should fail, %s -> %v", d, c) } t.Log(err) } } func TestParseAngle(t *testing.T) { type pair struct { in string out float64 } testData := []pair{ {"360", 360}, {"127.356", 127.356}, {"+120deg", 120}, {"90deg", 90}, {"-127deg", -127}, {"100grad", 90}, {"1.5707963267948966rad", 90}, {"0.25turn", 90}, {"-0.25turn", -90}, } for _, s := range testData { d, ok := parseAngle(s.in) if !ok { t.Errorf("Parse error, %s", s.in) } if d != s.out { t.Errorf("%s -> %v != %v", s.in, d, s.out) } } } func TestNormalizeAngle(t *testing.T) { testData := [][2]float64{ {0, 0}, {360, 0}, {400, 40}, {1155, 75}, {-360, 0}, {-90, 270}, {-765, 315}, } for _, s := range testData { d := normalizeAngle(s[0]) if d != s[1] { t.Errorf("%v -> %v != %v", s[0], d, s[1]) } } } csscolorparser-0.1.3/example_test.go000066400000000000000000000014621427102215300176000ustar00rootroot00000000000000package csscolorparser_test import ( "fmt" "github.com/mazznoer/csscolorparser" ) func Example_namedColor() { c, err := csscolorparser.Parse("gold") if err != nil { panic(err) } fmt.Printf("R:%.3f, G:%.3f, B:%.3f, A:%.3f\n", c.R, c.G, c.B, c.A) fmt.Println(c.RGBA255()) fmt.Println(c.HexString()) fmt.Println(c.RGBString()) // Output: // R:1.000, G:0.843, B:0.000, A:1.000 // 255 215 0 255 // #ffd700 // rgb(255,215,0) } func Example_rgbColor() { c, err := csscolorparser.Parse("rgba(100%, 0%, 0%, 0.5)") if err != nil { panic(err) } fmt.Printf("R:%.3f, G:%.3f, B:%.3f, A:%.3f\n", c.R, c.G, c.B, c.A) fmt.Println(c.RGBA255()) fmt.Println(c.HexString()) fmt.Println(c.RGBString()) // Output: // R:1.000, G:0.000, B:0.000, A:0.500 // 255 0 0 128 // #ff000080 // rgba(255,0,0,0.5) } csscolorparser-0.1.3/firefox_test.go000066400000000000000000000246551427102215300176200ustar00rootroot00000000000000package csscolorparser import "testing" func TestBrowserFirefox(t *testing.T) { type testData struct { colorStr string r, g, b, a uint8 } // Randomly generated color string, parsed using Mozilla Firefox 84.0.2 data := []testData{ {"#817801", 129, 120, 1, 255}, {"#62D5", 102, 34, 221, 85}, {"#857D", 136, 85, 119, 221}, {"#8D0C5BBE", 141, 12, 91, 190}, {"#BD5", 187, 221, 85, 255}, {"#A64", 170, 102, 68, 255}, {"#8092", 136, 0, 153, 34}, {"#1C0FF87B", 28, 15, 248, 123}, {"#818FFE", 129, 143, 254, 255}, {"#1ed0ebea", 30, 208, 235, 234}, {"#0D5FCA67", 13, 95, 202, 103}, {"#C285F3", 194, 133, 243, 255}, {"#7D0D", 119, 221, 0, 221}, {"#E30", 238, 51, 0, 255}, {"#6e5dc4", 110, 93, 196, 255}, {"#389A", 51, 136, 153, 170}, {"#F1D", 255, 17, 221, 255}, {"#8BB5", 136, 187, 187, 85}, {"#3DAA", 51, 221, 170, 170}, {"#B1D88F42", 177, 216, 143, 66}, {"#793", 119, 153, 51, 255}, {"#55da", 85, 85, 221, 170}, {"#BE70C687", 190, 112, 198, 135}, {"#4FD", 68, 255, 221, 255}, {"#30D38748", 48, 211, 135, 72}, {"#878", 136, 119, 136, 255}, {"#AC0D", 170, 204, 0, 221}, {"#12E", 17, 34, 238, 255}, {"#0DD3", 0, 221, 221, 51}, {"#7F54C08F", 127, 84, 192, 143}, {"#6cc7cba0", 108, 199, 203, 160}, {"#E97933", 233, 121, 51, 255}, {"#9237", 153, 34, 51, 119}, {"#F1FB94BD", 241, 251, 148, 189}, {"#9a8", 153, 170, 136, 255}, {"#0fcb7f03", 15, 203, 127, 3}, {"#534603AF", 83, 70, 3, 175}, {"#ef4cfc11", 239, 76, 252, 17}, {"#5D16052C", 93, 22, 5, 44}, {"#090", 0, 153, 0, 255}, {"#bc1f653a", 188, 31, 101, 58}, {"#ED02A8", 237, 2, 168, 255}, {"#6dc", 102, 221, 204, 255}, {"#E2E9", 238, 34, 238, 153}, {"#77B69060", 119, 182, 144, 96}, {"#0953FC", 9, 83, 252, 255}, {"#09C", 0, 153, 204, 255}, {"#172aca", 23, 42, 202, 255}, {"#74c18f04", 116, 193, 143, 4}, {"#153B", 17, 85, 51, 187}, {"rgb(264.654,8.955,5.446)", 255, 9, 5, 255}, {"rgb(63.688,192.702,251.174,0.322)", 64, 193, 251, 82}, {"rgb(131.708,39.654,79.812,1.128)", 132, 40, 80, 255}, {"rgb(116.842,105.189,171.013)", 117, 105, 171, 255}, {"rgb(120.525,88.804,130.411,0.946)", 121, 89, 130, 241}, {"rgb(240.988,49.789,222.272,0.325)", 241, 50, 222, 83}, {"rgb(187.245,215.507,159.236)", 187, 216, 159, 255}, {"rgb(98.714,205.689,261.942)", 99, 206, 255, 255}, {"rgb(209.553,174.927,193.981)", 210, 175, 194, 255}, {"rgb(7.372,4.253,86.174,0.041)", 7, 4, 86, 10}, {"rgb(150.202,78.032,213.103,0.337)", 150, 78, 213, 86}, {"rgb(246.369,62.382,31.651)", 246, 62, 32, 255}, {"rgb(236.566,160.563,89.892)", 237, 161, 90, 255}, {"rgb(112.356,163.535,102.720,-0.042)", 112, 164, 103, 0}, {"rgb(35.219,244.481,202.782,0.493)", 35, 244, 203, 126}, {"rgb(232.189,255.053,111.323)", 232, 255, 111, 255}, {"rgb(109.771,118.748,181.671)", 110, 119, 182, 255}, {"rgb(92.105,105.280,144.175)", 92, 105, 144, 255}, {"rgb(18.643,213.863,186.733)", 19, 214, 187, 255}, {"rgb(3.754,214.128,20.735,1.158)", 4, 214, 21, 255}, {"rgb(234.259,224.675,206.049)", 234, 225, 206, 255}, {"rgb(-7.668,131.621,160.351,0.411)", 0, 132, 160, 105}, {"rgb(45.824,242.113,209.576)", 46, 242, 210, 255}, {"rgb(30.113,222.102,93.192)", 30, 222, 93, 255}, {"rgb(245.402,199.722,-8.903)", 245, 200, 0, 255}, {"rgb(106.884,234.873,44.912,0.572)", 107, 235, 45, 146}, {"rgb(76.730,168.471,90.981)", 77, 168, 91, 255}, {"rgb(197.334,-0.665,134.907,0.421)", 197, 0, 135, 107}, {"rgb(120.677,48.776,120.922)", 121, 49, 121, 255}, {"rgb(165.450,89.865,211.876)", 165, 90, 212, 255}, {"rgb(88.649,20.622,250.829)", 89, 21, 251, 255}, {"rgb(-3.239,112.321,33.676)", 0, 112, 34, 255}, {"rgb(211.846,130.462,175.005)", 212, 130, 175, 255}, {"rgb(154.051,122.824,-9.377)", 154, 123, 0, 255}, {"rgb(144.666,79.334,20.699,0.412)", 145, 79, 21, 105}, {"rgb(234.323,96.841,102.930,0.187)", 234, 97, 103, 48}, {"rgb(196.469,255.522,21.318,0.300)", 196, 255, 21, 77}, {"rgb(23.779,145.864,206.664)", 24, 146, 207, 255}, {"rgb(133.613,9.608,39.029)", 134, 10, 39, 255}, {"rgb(218.954,163.743,79.818)", 219, 164, 80, 255}, {"rgb(33.108,151.645,11.619,1.132)", 33, 152, 12, 255}, {"rgb(204.629,39.956,-4.544)", 205, 40, 0, 255}, {"rgb(123.245,255.852,24.856)", 123, 255, 25, 255}, {"rgb(90.894,-2.651,116.502,0.596)", 91, 0, 117, 152}, {"rgb(79.128,115.857,155.230)", 79, 116, 155, 255}, {"rgb(87.319,70.167,172.069,-0.033)", 87, 70, 172, 0}, {"rgb(48.049,235.369,171.190,0.534)", 48, 235, 171, 136}, {"rgb(15.808,223.023,81.102,-0.116)", 16, 223, 81, 0}, {"rgb(255.282,239.066,222.922)", 255, 239, 223, 255}, {"rgb(173.178,-7.708,29.095,1.177)", 173, 0, 29, 255}, {"rgb(-5.791%,-7.797%,44.772%)", 0, 0, 114, 255}, {"rgb(103.362%,86.514%,79.870%,0.467)", 255, 221, 204, 119}, {"rgb(79.920%,30.359%,66.318%)", 204, 77, 169, 255}, {"rgb(54.309%,48.762%,42.059%)", 138, 124, 107, 255}, {"rgb(89.114%,50.975%,80.230%,0.843)", 227, 130, 205, 215}, {"rgb(-2.707%,3.715%,26.256%,0.185)", 0, 9, 67, 47}, {"rgb(51.827%,102.172%,-0.876%,0.302)", 132, 255, 0, 77}, {"rgb(14.092%,63.162%,97.286%)", 36, 161, 248, 255}, {"rgb(20.757%,33.676%,26.518%)", 53, 86, 68, 255}, {"rgb(85.387%,32.861%,29.168%)", 218, 84, 74, 255}, {"rgb(20.322%,107.488%,-9.083%)", 52, 255, 0, 255}, {"rgb(9.805%,12.717%,78.073%)", 25, 32, 199, 255}, {"rgb(80.225%,-7.567%,91.104%)", 205, 0, 232, 255}, {"rgb(57.826%,66.957%,35.887%)", 147, 171, 92, 255}, {"rgb(-5.675%,36.883%,86.567%)", 0, 94, 221, 255}, {"rgb(96.884%,-7.570%,86.334%,0.539)", 247, 0, 220, 137}, {"rgb(109.872%,32.523%,-3.411%,1.081)", 255, 83, 0, 255}, {"rgb(31.101%,2.122%,41.198%)", 79, 5, 105, 255}, {"rgb(15.290%,88.533%,91.984%)", 39, 226, 235, 255}, {"rgb(43.254%,59.929%,88.796%)", 110, 153, 226, 255}, {"rgb(20.849%,65.810%,108.952%)", 53, 168, 255, 255}, {"rgb(107.764%,106.729%,5.219%,0.722)", 255, 255, 13, 184}, {"rgb(87.428%,12.272%,55.687%)", 223, 31, 142, 255}, {"rgb(66.030%,91.694%,36.578%)", 168, 234, 93, 255}, {"rgb(50.947%,70.496%,90.525%)", 130, 180, 231, 255}, {"rgb(20.316%,98.256%,21.624%)", 52, 251, 55, 255}, {"rgb(101.253%,97.684%,18.923%,0.982)", 255, 249, 48, 250}, {"rgb(73.848%,64.384%,24.685%)", 188, 164, 63, 255}, {"rgb(106.833%,104.707%,97.097%)", 255, 255, 248, 255}, {"rgb(0.219%,58.327%,64.714%)", 1, 149, 165, 255}, {"rgb(105.545%,54.528%,72.587%)", 255, 139, 185, 255}, {"rgb(15.832%,89.520%,67.361%)", 40, 228, 172, 255}, {"rgb(99.044%,-8.225%,107.718%,0.707)", 253, 0, 255, 180}, {"rgb(53.693%,23.908%,60.057%,-0.168)", 137, 61, 153, 0}, {"rgb(79.097%,41.894%,91.880%)", 202, 107, 234, 255}, {"rgb(75.495%,78.770%,40.656%,0.394)", 193, 201, 104, 100}, {"rgb(98.775%,87.084%,9.632%)", 252, 222, 25, 255}, {"rgb(7.499%,58.822%,37.091%,0.211)", 19, 150, 95, 54}, {"rgb(53.511%,45.547%,31.029%)", 136, 116, 79, 255}, {"rgb(103.106%,79.057%,60.671%)", 255, 202, 155, 255}, {"rgb(44.343%,52.743%,100.265%,-0.047)", 113, 134, 255, 0}, {"rgb(109.647%,58.782%,0.907%,0.718)", 255, 150, 2, 183}, {"rgb(24.882%,96.959%,43.001%,0.400)", 63, 247, 110, 102}, {"rgb(74.362%,41.983%,9.375%)", 190, 107, 24, 255}, {"rgb(46.816%,66.074%,108.821%)", 119, 168, 255, 255}, {"rgb(77.497%,89.829%,62.736%,-0.026)", 198, 229, 160, 0}, {"rgb(26.042%,65.488%,69.547%,0.348)", 66, 167, 177, 89}, {"rgb(23.342%,-0.633%,77.730%)", 60, 0, 198, 255}, {"rgb(33.015%,81.191%,78.615%)", 84, 207, 200, 255}, {"rgb(108.596%,93.998%,0.798%)", 255, 240, 2, 255}, {"hsl(237.711grad,88.536%,36.402%)", 11, 82, 175, 255}, {"hsl(281.434,105.519%,-5.626%)", 0, 0, 0, 255}, {"hsl(257.634deg,91.970%,34.848%)", 55, 7, 171, 255}, {"hsl(0.944turn,70.481%,50.217%)", 218, 39, 99, 255}, {"hsl(327.085deg,22.465%,-2.142%,-0.156)", 0, 0, 0, 0}, {"hsl(366.588deg,62.880%,50.057%,0.213)", 208, 65, 48, 54}, {"hsl(34.042,89.193%,33.385%)", 161, 95, 9, 255}, {"hsl(359.760,66.421%,97.192%)", 253, 243, 243, 255}, {"hsl(3.111grad,106.058%,21.159%)", 108, 5, 0, 255}, {"hsl(0.918rad,-9.357%,33.825%)", 86, 86, 86, 255}, {"hsl(37.202deg,96.433%,9.973%)", 50, 31, 1, 255}, {"hsl(2.694rad,56.805%,80.396%)", 177, 233, 209, 255}, {"hsl(369.063,52.881%,26.098%)", 102, 42, 31, 255}, {"hsl(142.665,70.616%,96.183%)", 238, 252, 244, 255}, {"hsl(266.585grad,98.461%,8.780%)", 0, 0, 44, 255}, {"hsl(0.292turn,89.098%,25.780%)", 36, 124, 7, 255}, {"hsl(-0.043turn,-9.603%,106.006%)", 255, 255, 255, 255}, {"hsl(135.985deg,29.099%,103.419%)", 255, 255, 255, 255}, {"hsl(293.828,52.597%,7.326%)", 26, 9, 29, 255}, {"hsl(309.911grad,74.581%,0.263%)", 1, 0, 1, 255}, {"hsl(1.676rad,91.390%,15.755%)", 33, 77, 3, 255}, {"hsl(350.968deg,33.726%,88.331%,0.471)", 235, 215, 218, 120}, {"hsl(353.287grad,-9.139%,89.568%)", 228, 228, 228, 255}, {"hsl(2.953rad,52.179%,10.657%,0.989)", 13, 41, 36, 252}, {"hsl(298.491,41.628%,64.058%)", 200, 125, 202, 255}, {"hsl(0.840turn,89.447%,73.390%,0.161)", 248, 126, 243, 41}, {"hsl(0.415turn,3.520%,74.963%)", 189, 193, 191, 255}, {"hsl(309.723deg,-2.498%,81.780%)", 209, 209, 209, 255}, {"hsl(346.595,27.379%,5.620%)", 18, 10, 12, 255}, {"hsl(0.345turn,28.417%,71.498%)", 162, 203, 165, 255}, {"hsl(-0.074turn,91.885%,16.669%)", 82, 3, 38, 255}, {"hsl(154.320deg,-5.633%,-4.799%,-0.005)", 0, 0, 0, 0}, {"hsl(5.983,-5.051%,50.117%)", 128, 128, 128, 255}, {"hsl(78.942deg,93.449%,108.614%)", 255, 255, 255, 255}, {"hsl(20.316deg,90.583%,20.504%)", 100, 37, 5, 255}, {"hsl(231.054grad,63.039%,82.668%)", 183, 213, 239, 255}, {"hsl(0.880turn,6.700%,10.668%)", 29, 25, 28, 255}, {"hsl(37.954grad,79.594%,68.066%,-0.063)", 238, 183, 109, 0}, {"hsl(193.327deg,59.120%,93.790%)", 230, 244, 249, 255}, {"hsl(143.684deg,30.652%,82.141%)", 196, 223, 207, 255}, {"hsl(134.726,4.308%,49.756%)", 121, 132, 124, 255}, {"hsl(0.277turn,-7.056%,25.211%)", 64, 64, 64, 255}, {"hsl(1.849deg,33.541%,58.253%,0.425)", 184, 115, 113, 108}, {"hsl(151.147,86.285%,-6.549%)", 0, 0, 0, 255}, {"hsl(0.226turn,107.942%,19.766%,0.533)", 65, 101, 0, 136}, {"hsl(351.807deg,51.829%,70.431%,-0.069)", 219, 141, 151, 0}, {"hsl(1.075turn,71.099%,71.695%)", 234, 178, 132, 255}, {"hsl(235.353,50.281%,96.254%)", 241, 241, 250, 255}, {"hsl(250.375deg,95.684%,91.300%)", 219, 212, 254, 255}, {"hsl(0.579turn,76.129%,22.968%)", 14, 61, 103, 255}, } for i, d := range data { c, err := Parse(d.colorStr) if err != nil { t.Errorf("Parse error: %s", d.colorStr) continue } r, g, b, a := c.RGBA255() rgba := [4]uint8{r, g, b, a} out := [4]uint8{d.r, d.g, d.b, d.a} if rgba != out { t.Errorf("(%d) %s -> %v != %v", i, d.colorStr, out, rgba) } } } csscolorparser-0.1.3/go.mod000066400000000000000000000000631427102215300156610ustar00rootroot00000000000000module github.com/mazznoer/csscolorparser go 1.15 csscolorparser-0.1.3/named_colors.go000066400000000000000000000137651427102215300175640ustar00rootroot00000000000000package csscolorparser var namedColors = map[string][3]uint8{ "aliceblue": {240, 248, 255}, "antiquewhite": {250, 235, 215}, "aqua": {0, 255, 255}, "aquamarine": {127, 255, 212}, "azure": {240, 255, 255}, "beige": {245, 245, 220}, "bisque": {255, 228, 196}, "black": {0, 0, 0}, "blanchedalmond": {255, 235, 205}, "blue": {0, 0, 255}, "blueviolet": {138, 43, 226}, "brown": {165, 42, 42}, "burlywood": {222, 184, 135}, "cadetblue": {95, 158, 160}, "chartreuse": {127, 255, 0}, "chocolate": {210, 105, 30}, "coral": {255, 127, 80}, "cornflowerblue": {100, 149, 237}, "cornsilk": {255, 248, 220}, "crimson": {220, 20, 60}, "cyan": {0, 255, 255}, "darkblue": {0, 0, 139}, "darkcyan": {0, 139, 139}, "darkgoldenrod": {184, 134, 11}, "darkgray": {169, 169, 169}, "darkgreen": {0, 100, 0}, "darkgrey": {169, 169, 169}, "darkkhaki": {189, 183, 107}, "darkmagenta": {139, 0, 139}, "darkolivegreen": {85, 107, 47}, "darkorange": {255, 140, 0}, "darkorchid": {153, 50, 204}, "darkred": {139, 0, 0}, "darksalmon": {233, 150, 122}, "darkseagreen": {143, 188, 143}, "darkslateblue": {72, 61, 139}, "darkslategray": {47, 79, 79}, "darkslategrey": {47, 79, 79}, "darkturquoise": {0, 206, 209}, "darkviolet": {148, 0, 211}, "deeppink": {255, 20, 147}, "deepskyblue": {0, 191, 255}, "dimgray": {105, 105, 105}, "dimgrey": {105, 105, 105}, "dodgerblue": {30, 144, 255}, "firebrick": {178, 34, 34}, "floralwhite": {255, 250, 240}, "forestgreen": {34, 139, 34}, "fuchsia": {255, 0, 255}, "gainsboro": {220, 220, 220}, "ghostwhite": {248, 248, 255}, "gold": {255, 215, 0}, "goldenrod": {218, 165, 32}, "gray": {128, 128, 128}, "green": {0, 128, 0}, "greenyellow": {173, 255, 47}, "grey": {128, 128, 128}, "honeydew": {240, 255, 240}, "hotpink": {255, 105, 180}, "indianred": {205, 92, 92}, "indigo": {75, 0, 130}, "ivory": {255, 255, 240}, "khaki": {240, 230, 140}, "lavender": {230, 230, 250}, "lavenderblush": {255, 240, 245}, "lawngreen": {124, 252, 0}, "lemonchiffon": {255, 250, 205}, "lightblue": {173, 216, 230}, "lightcoral": {240, 128, 128}, "lightcyan": {224, 255, 255}, "lightgoldenrodyellow": {250, 250, 210}, "lightgray": {211, 211, 211}, "lightgreen": {144, 238, 144}, "lightgrey": {211, 211, 211}, "lightpink": {255, 182, 193}, "lightsalmon": {255, 160, 122}, "lightseagreen": {32, 178, 170}, "lightskyblue": {135, 206, 250}, "lightslategray": {119, 136, 153}, "lightslategrey": {119, 136, 153}, "lightsteelblue": {176, 196, 222}, "lightyellow": {255, 255, 224}, "lime": {0, 255, 0}, "limegreen": {50, 205, 50}, "linen": {250, 240, 230}, "magenta": {255, 0, 255}, "maroon": {128, 0, 0}, "mediumaquamarine": {102, 205, 170}, "mediumblue": {0, 0, 205}, "mediumorchid": {186, 85, 211}, "mediumpurple": {147, 112, 219}, "mediumseagreen": {60, 179, 113}, "mediumslateblue": {123, 104, 238}, "mediumspringgreen": {0, 250, 154}, "mediumturquoise": {72, 209, 204}, "mediumvioletred": {199, 21, 133}, "midnightblue": {25, 25, 112}, "mintcream": {245, 255, 250}, "mistyrose": {255, 228, 225}, "moccasin": {255, 228, 181}, "navajowhite": {255, 222, 173}, "navy": {0, 0, 128}, "oldlace": {253, 245, 230}, "olive": {128, 128, 0}, "olivedrab": {107, 142, 35}, "orange": {255, 165, 0}, "orangered": {255, 69, 0}, "orchid": {218, 112, 214}, "palegoldenrod": {238, 232, 170}, "palegreen": {152, 251, 152}, "paleturquoise": {175, 238, 238}, "palevioletred": {219, 112, 147}, "papayawhip": {255, 239, 213}, "peachpuff": {255, 218, 185}, "peru": {205, 133, 63}, "pink": {255, 192, 203}, "plum": {221, 160, 221}, "powderblue": {176, 224, 230}, "purple": {128, 0, 128}, "rebeccapurple": {102, 51, 153}, "red": {255, 0, 0}, "rosybrown": {188, 143, 143}, "royalblue": {65, 105, 225}, "saddlebrown": {139, 69, 19}, "salmon": {250, 128, 114}, "sandybrown": {244, 164, 96}, "seagreen": {46, 139, 87}, "seashell": {255, 245, 238}, "sienna": {160, 82, 45}, "silver": {192, 192, 192}, "skyblue": {135, 206, 235}, "slateblue": {106, 90, 205}, "slategray": {112, 128, 144}, "slategrey": {112, 128, 144}, "snow": {255, 250, 250}, "springgreen": {0, 255, 127}, "steelblue": {70, 130, 180}, "tan": {210, 180, 140}, "teal": {0, 128, 128}, "thistle": {216, 191, 216}, "tomato": {255, 99, 71}, "turquoise": {64, 224, 208}, "violet": {238, 130, 238}, "wheat": {245, 222, 179}, "white": {255, 255, 255}, "whitesmoke": {245, 245, 245}, "yellow": {255, 255, 0}, "yellowgreen": {154, 205, 50}, }