├── .gitignore ├── .goreleaser.yml ├── .travis.yml ├── LICENSE ├── README.md ├── cmd └── palitra │ └── palitra.go ├── cssNamesToHex.go ├── helpers.go ├── images └── screenshot.jpg ├── palitra.go ├── palitra_test.go ├── test_images └── venice.jpg └── types.go /.gitignore: -------------------------------------------------------------------------------- 1 | .env -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | project_name: palitra 2 | before: 3 | hooks: 4 | # 5 | builds: 6 | - 7 | # Path to main package 8 | main: ./cmd/palitra/palitra.go 9 | 10 | # Name for the binary final name 11 | binary: palitra 12 | 13 | # Custom environment variables to be set during the builds 14 | env: 15 | - CGO_ENABLED=0 16 | 17 | # GOOS list to build for 18 | goos: 19 | - darwin 20 | - windows 21 | - linux 22 | 23 | # GOARCH to build for 24 | goarch: 25 | - amd64 26 | archive: 27 | replacements: 28 | darwin: Darwin 29 | linux: Linux 30 | windows: Windows 31 | amd64: x86_64 32 | checksum: 33 | name_template: 'checksums.txt' 34 | snapshot: 35 | name_template: "{{ .Tag }}-next" 36 | changelog: 37 | sort: asc 38 | filters: 39 | exclude: 40 | - '^docs:' 41 | - '^test:' 42 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.8 5 | - 1.9 6 | 7 | script: go test -v -bench=. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2017 Alberto Schiabel 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # palitra 2 | 3 | [![Build Status](https://travis-ci.org/jkomyno/palitra.svg?branch=master)](https://travis-ci.org/jkomyno/palitra) [![GoDoc](https://godoc.org/github.com/jkomyno/palitra?status.svg)](https://godoc.org/github.com/jkomyno/palitra) [![Go Report Card](https://goreportcard.com/badge/github.com/jkomyno/palitra)](https://goreportcard.com/report/github.com/jkomyno/palitra) 4 | 5 | ![Example image](./images/screenshot.jpg) 6 | 7 | # Description 8 | 9 | Utility that finds the N most frequent colors in a picture, approximated to CSS3 color names. 10 | Palitra is available both as a plain library, and as a CLI tool (which also supports input from `stdin`, via pipe). 11 | **It requires Go 1.8**. 12 | 13 | ## Install 14 | 15 | You can download the library with `go get`: 16 | 17 | ```bash 18 | $ go get github.com/jkomyno/palitra 19 | ``` 20 | 21 | If you want to use the CLI tool, then you can type the following to install it in your environment. 22 | 23 | ```bash 24 | $ go install github.com/jkomyno/palitra/cmd/palitra 25 | ``` 26 | 27 | ## Usage 28 | 29 | ### CLI 30 | 31 | This guide assumes that `palitra` is installed globally. 32 | 33 | Here's how `palitra --help` looks like: 34 | 35 | ```bash 36 | Usage of C:\Work\GoWorkspace\bin\palitra.exe: 37 | -img string 38 | the name of the image file to get colors from 39 | -n int 40 | the number of the most dominant CSS3 colors to extract (default 3) 41 | -r uint 42 | the resized width to process the image quicker (default 75) 43 | ``` 44 | 45 | If you're ok with the default values, then you can simply pipe an image to palitra. Example: 46 | 47 | ```bash 48 | $ cat ./test_images/venice.jpg | palitra 49 | ``` 50 | 51 | The result should look like the following: 52 | ```bash 53 | 1) lightpink: 10.48% 54 | 2) lightslategrey: 9.97% 55 | 3) dimgrey: 9.61% 56 | 57 | Completed in 679.7955ms ✨ 58 | ``` 59 | 60 | If not, you can manually specify the parameters as you like: 61 | 62 | ```bash 63 | $ palitra -img ./test_images/venice.jpg -n 5 -r 50 64 | ``` 65 | 66 | The result should look like the following: 67 | ```bash 68 | 1) lightpink: 10.34% 69 | 2) dimgrey: 10.04% 70 | 3) lightslategrey: 9.93% 71 | 4) silver: 9.15% 72 | 5) darkslategrey: 8.81% 73 | 74 | Completed in 290.7805ms ✨ 75 | ``` 76 | 77 | ### Library 78 | 79 | For the library usage, please refer to [godoc](https://godoc.org/github.com/jkomyno/palitra). 80 | You can import the library in the following way: 81 | 82 | ```go 83 | import "github.com/jkomyno/palitra" 84 | ``` 85 | 86 | ## Testing 87 | 88 | ``` bash 89 | $ go test -v -bench=. 90 | ``` 91 | 92 | ## License 93 | 94 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. -------------------------------------------------------------------------------- /cmd/palitra/palitra.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "image" 7 | _ "image/jpeg" 8 | _ "image/png" 9 | "io" 10 | "log" 11 | "os" 12 | "time" 13 | 14 | "github.com/jkomyno/palitra" 15 | ) 16 | 17 | var ( 18 | inputImageName = flag.String("img", "", "the name of the image file to get colors from") 19 | paletteLimit = flag.Int("n", 3, "the number of the most dominant CSS3 colors to extract") 20 | resizeWidth = flag.Uint("r", 75, "the resized width to process the image quicker") 21 | ) 22 | 23 | // supportsStdin returns true if os.Stdin is interactive 24 | func supportsStdin() bool { 25 | fileInfo, err := os.Stdin.Stat() 26 | if err != nil { 27 | return false 28 | } 29 | return fileInfo.Mode()&(os.ModeCharDevice|os.ModeCharDevice) != 0 30 | } 31 | 32 | // showSpinner is a simple loader to display the user that palitra is processing 33 | func showSpinner() { 34 | for { // while true 35 | for _, r := range `⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏` { 36 | fmt.Printf("\r%c %s", r, "Calculating colors") 37 | time.Sleep(100 * time.Millisecond) 38 | } 39 | } 40 | } 41 | 42 | func timeTrack(start time.Time) { 43 | elapsed := time.Since(start) 44 | fmt.Printf("\nCompleted in %s ✨", elapsed) 45 | } 46 | 47 | func printPaletteList(palette []palitra.ColorPercentageT) { 48 | fmt.Printf("\r") 49 | for i, val := range palette { 50 | fmt.Printf("%d) %s: %s%s\n", i+1, val.Color, val.Percentage, "%") 51 | } 52 | } 53 | 54 | func executeCommand(img image.Image) { 55 | defer timeTrack(time.Now()) 56 | palette := palitra.GetPalette(img, *paletteLimit, *resizeWidth) 57 | printPaletteList(palette) 58 | } 59 | 60 | func init() { 61 | flag.Parse() 62 | } 63 | 64 | func main() { 65 | // handle inputImageName 66 | 67 | if supportsStdin() && *inputImageName == "" { 68 | flag.Usage() 69 | fmt.Fprintln(os.Stderr, "Supports reading image from stdin") 70 | os.Exit(1) 71 | } 72 | 73 | var imageReader io.Reader 74 | imageReader = os.Stdin 75 | if *inputImageName != "" { 76 | f, err := os.Open(*inputImageName) 77 | if err != nil { 78 | log.Fatalf("Reading input file: %s", err) 79 | } 80 | 81 | defer f.Close() 82 | imageReader = f 83 | } 84 | 85 | if img, _, err := image.Decode(imageReader); err != nil { 86 | fmt.Fprintln(os.Stderr, "error parsing", err) 87 | os.Exit(1) 88 | } else { 89 | go showSpinner() 90 | executeCommand(img) 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /cssNamesToHex.go: -------------------------------------------------------------------------------- 1 | package palitra 2 | 3 | // I've used a pair struct instead of a map due to the fact that maps get accessed 4 | // randomly in range loops in Golang 5 | // List adapted from: 6 | // https://github.com/jyotiska/go-webcolors/blob/master/go-webcolors.go#L40 7 | var cssColorPair = []pair{ 8 | {"aliceblue", "#f0f8ff"}, 9 | {"antiquewhite", "#faebd7"}, 10 | {"aqua", "#00ffff"}, 11 | {"aquamarine", "#7fffd4"}, 12 | {"azure", "#f0ffff"}, 13 | {"beige", "#f5f5dc"}, 14 | {"bisque", "#ffe4c4"}, 15 | {"black", "#000000"}, 16 | {"blanchedalmond", "#ffebcd"}, 17 | {"blue", "#0000ff"}, 18 | {"blueviolet", "#8a2be2"}, 19 | {"brown", "#a52a2a"}, 20 | {"burlywood", "#deb887"}, 21 | {"cadetblue", "#5f9ea0"}, 22 | {"chartreuse", "#7fff00"}, 23 | {"chocolate", "#d2691e"}, 24 | {"coral", "#ff7f50"}, 25 | {"cornflowerblue", "#6495ed"}, 26 | {"cornsilk", "#fff8dc"}, 27 | {"crimson", "#dc143c"}, 28 | {"cyan", "#00ffff"}, 29 | {"darkblue", "#00008b"}, 30 | {"darkcyan", "#008b8b"}, 31 | {"darkgoldenrod", "#b8860b"}, 32 | {"darkgray", "#a9a9a9"}, 33 | {"darkgrey", "#a9a9a9"}, 34 | {"darkgreen", "#006400"}, 35 | {"darkkhaki", "#bdb76b"}, 36 | {"darkmagenta", "#8b008b"}, 37 | {"darkolivegreen", "#556b2f"}, 38 | {"darkorange", "#ff8c00"}, 39 | {"darkorchid", "#9932cc"}, 40 | {"darkred", "#8b0000"}, 41 | {"darksalmon", "#e9967a"}, 42 | {"darkseagreen", "#8fbc8f"}, 43 | {"darkslateblue", "#483d8b"}, 44 | {"darkslategray", "#2f4f4f"}, 45 | {"darkslategrey", "#2f4f4f"}, 46 | {"darkturquoise", "#00ced1"}, 47 | {"darkviolet", "#9400d3"}, 48 | {"deeppink", "#ff1493"}, 49 | {"deepskyblue", "#00bfff"}, 50 | {"dimgray", "#696969"}, 51 | {"dimgrey", "#696969"}, 52 | {"dodgerblue", "#1e90ff"}, 53 | {"firebrick", "#b22222"}, 54 | {"floralwhite", "#fffaf0"}, 55 | {"forestgreen", "#228b22"}, 56 | {"fuchsia", "#ff00ff"}, 57 | {"gainsboro", "#dcdcdc"}, 58 | {"ghostwhite", "#f8f8ff"}, 59 | {"gold", "#ffd700"}, 60 | {"goldenrod", "#daa520"}, 61 | {"gray", "#808080"}, 62 | {"grey", "#808080"}, 63 | {"green", "#008000"}, 64 | {"greenyellow", "#adff2f"}, 65 | {"honeydew", "#f0fff0"}, 66 | {"hotpink", "#ff69b4"}, 67 | {"indianred", "#cd5c5c"}, 68 | {"indigo", "#4b0082"}, 69 | {"ivory", "#fffff0"}, 70 | {"khaki", "#f0e68c"}, 71 | {"lavender", "#e6e6fa"}, 72 | {"lavenderblush", "#fff0f5"}, 73 | {"lawngreen", "#7cfc00"}, 74 | {"lemonchiffon", "#fffacd"}, 75 | {"lightblue", "#add8e6"}, 76 | {"lightcoral", "#f08080"}, 77 | {"lightcyan", "#e0ffff"}, 78 | {"lightgoldenrodyellow", "#fafad2"}, 79 | {"lightgray", "#d3d3d3"}, 80 | {"lightgrey", "#d3d3d3"}, 81 | {"lightgreen", "#90ee90"}, 82 | {"lightpink", "#ffb6c1"}, 83 | {"lightsalmon", "#ffa07a"}, 84 | {"lightseagreen", "#20b2aa"}, 85 | {"lightskyblue", "#87cefa"}, 86 | {"lightslategray", "#778899"}, 87 | {"lightslategrey", "#778899"}, 88 | {"lightsteelblue", "#b0c4de"}, 89 | {"lightyellow", "#ffffe0"}, 90 | {"lime", "#00ff00"}, 91 | {"limegreen", "#32cd32"}, 92 | {"linen", "#faf0e6"}, 93 | {"magenta", "#ff00ff"}, 94 | {"maroon", "#800000"}, 95 | {"mediumaquamarine", "#66cdaa"}, 96 | {"mediumblue", "#0000cd"}, 97 | {"mediumorchid", "#ba55d3"}, 98 | {"mediumpurple", "#9370d8"}, 99 | {"mediumseagreen", "#3cb371"}, 100 | {"mediumslateblue", "#7b68ee"}, 101 | {"mediumspringgreen", "#00fa9a"}, 102 | {"mediumturquoise", "#48d1cc"}, 103 | {"mediumvioletred", "#c71585"}, 104 | {"midnightblue", "#191970"}, 105 | {"mintcream", "#f5fffa"}, 106 | {"mistyrose", "#ffe4e1"}, 107 | {"moccasin", "#ffe4b5"}, 108 | {"navajowhite", "#ffdead"}, 109 | {"navy", "#000080"}, 110 | {"oldlace", "#fdf5e6"}, 111 | {"olive", "#808000"}, 112 | {"olivedrab", "#6b8e23"}, 113 | {"orange", "#ffa500"}, 114 | {"orangered", "#ff4500"}, 115 | {"orchid", "#da70d6"}, 116 | {"palegoldenrod", "#eee8aa"}, 117 | {"palegreen", "#98fb98"}, 118 | {"paleturquoise", "#afeeee"}, 119 | {"palevioletred", "#d87093"}, 120 | {"papayawhip", "#ffefd5"}, 121 | {"peachpuff", "#ffdab9"}, 122 | {"peru", "#cd853f"}, 123 | {"pink", "#ffc0cb"}, 124 | {"plum", "#dda0dd"}, 125 | {"powderblue", "#b0e0e6"}, 126 | {"purple", "#800080"}, 127 | {"red", "#ff0000"}, 128 | {"rosybrown", "#bc8f8f"}, 129 | {"royalblue", "#4169e1"}, 130 | {"saddlebrown", "#8b4513"}, 131 | {"salmon", "#fa8072"}, 132 | {"sandybrown", "#f4a460"}, 133 | {"seagreen", "#2e8b57"}, 134 | {"seashell", "#fff5ee"}, 135 | {"sienna", "#a0522d"}, 136 | {"silver", "#c0c0c0"}, 137 | {"skyblue", "#87ceeb"}, 138 | {"slateblue", "#6a5acd"}, 139 | {"slategray", "#708090"}, 140 | {"slategrey", "#708090"}, 141 | {"snow", "#fffafa"}, 142 | {"springgreen", "#00ff7f"}, 143 | {"steelblue", "#4682b4"}, 144 | {"tan", "#d2b48c"}, 145 | {"teal", "#008080"}, 146 | {"thistle", "#d8bfd8"}, 147 | {"tomato", "#ff6347"}, 148 | {"turquoise", "#40e0d0"}, 149 | {"violet", "#ee82ee"}, 150 | {"wheat", "#f5deb3"}, 151 | {"white", "#ffffff"}, 152 | {"whitesmoke", "#f5f5f5"}, 153 | {"yellow", "#ffff00"}, 154 | {"yellowgreen", "#9acd32"}, 155 | } 156 | -------------------------------------------------------------------------------- /helpers.go: -------------------------------------------------------------------------------- 1 | package palitra 2 | 3 | import ( 4 | "fmt" 5 | "image" 6 | "image/color" 7 | "math" 8 | "sort" 9 | 10 | webColors "github.com/jyotiska/go-webcolors" 11 | "github.com/nfnt/resize" 12 | ) 13 | 14 | // l2Norm returns the Euclidean distance between two colors 15 | func l2Norm(currentColor rgbT, cssColor []int) int { 16 | r := cssColor[0] - currentColor[0] 17 | g := cssColor[1] - currentColor[1] 18 | b := cssColor[2] - currentColor[2] 19 | 20 | return int(math.Sqrt(float64(r*r + g*g + b*b))) 21 | } 22 | 23 | // getApproximatedCSSColor returns the nearest approximated CSS3 color of the color 24 | // passed as parameter 25 | func getApproximatedCSSColor(currentColor rgbT) string { 26 | approximateColors := make(map[int]string) 27 | 28 | for _, c := range cssColorPair { 29 | rgb := webColors.HexToRGB(c.hex) 30 | approximateColors[l2Norm(currentColor, rgb)] = c.color 31 | } 32 | 33 | keys := make([]int, 0, len(approximateColors)) 34 | for key := range approximateColors { 35 | keys = append(keys, key) 36 | } 37 | sort.Ints(keys) 38 | 39 | return approximateColors[keys[0]] 40 | } 41 | 42 | // min returs the minimum value between `a` and `b` 43 | func min(a, b int) int { 44 | if a < b { 45 | return a 46 | } 47 | 48 | return b 49 | } 50 | 51 | // resizeImage resizes an image adapting the aspect ration to a specified width 52 | func resizeImage(img image.Image, width uint) image.Image { 53 | // height set to 0 -> adapts aspect ratio to specified width 54 | return resize.Resize(width, 0, img, resize.Lanczos3) 55 | } 56 | 57 | // getImageDim returns the horizontal and vertical dimensions of an image, in pixels 58 | func getImageDim(img image.Image) *imageDim { 59 | maxBound := img.Bounds().Max 60 | return &imageDim{ 61 | horizontalPixels: maxBound.X, 62 | verticalPixels: maxBound.Y, 63 | } 64 | } 65 | 66 | // getRGBTuple, given a single pixel, returns its RGB color 67 | func getRGBTuple(pixel color.Color) rgbT { 68 | red, green, blue, _ := pixel.RGBA() 69 | rgbTuple := rgbT{int(red / 255), int(green / 255), int(blue / 255)} 70 | return rgbTuple 71 | } 72 | 73 | // sortMap sorts `colorMap` by its value property 74 | func sortMap(colorMap map[string]int) []colorMapT { 75 | var sortedColorMap []colorMapT 76 | 77 | for key, value := range colorMap { 78 | sortedColorMap = append(sortedColorMap, colorMapT{ 79 | key, 80 | value, 81 | }) 82 | } 83 | 84 | sort.Slice(sortedColorMap, func(i, j int) bool { 85 | return sortedColorMap[i].value > sortedColorMap[j].value 86 | }) 87 | 88 | return sortedColorMap 89 | } 90 | 91 | // getPaletteWithPercentage returns a maximum of `paletteLimit` combinations of approximated color 92 | // and percentage. The percentage represents how much an approximation of that color appears in 93 | // the original image, and for convenience is expressed as string. 94 | func getPaletteWithPercentage(palette []colorMapT, paletteLimit int, totalPixels float64) []ColorPercentageT { 95 | size := min(paletteLimit, len(palette)) 96 | paletteWithPercentage := make([]ColorPercentageT, size) 97 | var currPalette colorMapT 98 | 99 | for i := 0; i < size; i++ { 100 | currPalette = palette[i] 101 | paletteWithPercentage[i] = ColorPercentageT{ 102 | Color: currPalette.key, 103 | Percentage: fmt.Sprintf("%.2f", (float64(currPalette.value)/totalPixels)*100), 104 | } 105 | } 106 | 107 | return paletteWithPercentage 108 | } 109 | -------------------------------------------------------------------------------- /images/screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jkomyno/palitra/cd8f50f6e5d998657c2136a0a6bf7a1491a567ff/images/screenshot.jpg -------------------------------------------------------------------------------- /palitra.go: -------------------------------------------------------------------------------- 1 | package palitra 2 | 3 | import "image" 4 | 5 | // getColorMap populates a map of approximated colors, given the color of a single 6 | // pixel. To enhance performance, it does so in a concurrent fashion, using channels and 7 | // an anonymous goroutine. 8 | // It returns the color map and the total number of pixels of the image `img`. 9 | func getColorMap(img image.Image) (map[string]int, int) { 10 | colorMap := make(map[string]int) 11 | dims := getImageDim(img) 12 | totalPixels := dims.horizontalPixels * dims.verticalPixels 13 | 14 | approxColorResponseChan := make(chan string, totalPixels) 15 | defer close(approxColorResponseChan) 16 | 17 | for i := 0; i < dims.horizontalPixels; i++ { 18 | for j := 0; j < dims.verticalPixels; j++ { 19 | pixel := img.At(i, j) 20 | rgbTuple := getRGBTuple(pixel) 21 | 22 | go func(rgb rgbT) { 23 | approxColorResponseChan <- getApproximatedCSSColor(rgb) 24 | }(rgbTuple) 25 | } 26 | } 27 | 28 | for k := 0; k < totalPixels; k++ { 29 | colorName := <-approxColorResponseChan 30 | _, exists := colorMap[colorName] 31 | 32 | if exists { 33 | colorMap[colorName]++ 34 | } else { 35 | colorMap[colorName] = 1 36 | } 37 | } 38 | 39 | return colorMap, totalPixels 40 | } 41 | 42 | // GetPalette returns an array of `paletteLen` colors, given an image `img`. To enhance 43 | // performance, a `resizeWidth` param is required. 44 | func GetPalette(img image.Image, paletteLimit int, resizeWidth uint) []ColorPercentageT { 45 | resizedImg := resizeImage(img, resizeWidth) 46 | colorMap, totalPixels := getColorMap(resizedImg) 47 | 48 | palette := sortMap(colorMap) 49 | paletteWithPercentage := getPaletteWithPercentage(palette, paletteLimit, float64(totalPixels)) 50 | return paletteWithPercentage 51 | } 52 | -------------------------------------------------------------------------------- /palitra_test.go: -------------------------------------------------------------------------------- 1 | package palitra_test 2 | 3 | import ( 4 | "image" 5 | _ "image/jpeg" 6 | _ "image/png" 7 | "os" 8 | "testing" 9 | 10 | "github.com/jkomyno/palitra" 11 | "github.com/stretchr/testify/assert" 12 | ) 13 | 14 | var testImg image.Image 15 | 16 | func handleError(err error) { 17 | if err != nil { 18 | panic(err) 19 | } 20 | } 21 | 22 | func init() { 23 | imageReader, err := os.Open("./test_images/venice.jpg") 24 | handleError(err) 25 | defer imageReader.Close() 26 | 27 | testImg, _, err = image.Decode(imageReader) 28 | handleError(err) 29 | } 30 | 31 | func TestGetPalette(t *testing.T) { 32 | colorMap1 := palitra.GetPalette(testImg, 3, 75) 33 | expectedMap1 := []palitra.ColorPercentageT{{ 34 | Color: "lightpink", 35 | Percentage: "10.48", 36 | }, { 37 | Color: "lightslategrey", 38 | Percentage: "9.97", 39 | }, { 40 | Color: "dimgrey", 41 | Percentage: "9.61", 42 | }} 43 | for i := range colorMap1 { 44 | assert.Equal(t, expectedMap1[i], colorMap1[i]) 45 | } 46 | 47 | colorMap2 := palitra.GetPalette(testImg, 4, 75) 48 | expectedMap2 := append(expectedMap1, palitra.ColorPercentageT{ 49 | Color: "silver", 50 | Percentage: "9.36", 51 | }) 52 | 53 | for i := range colorMap2 { 54 | assert.Equal(t, expectedMap2[i], colorMap2[i]) 55 | } 56 | 57 | colorMap3 := palitra.GetPalette(testImg, 5, 75) 58 | expectedMap3 := append(expectedMap2, palitra.ColorPercentageT{ 59 | Color: "darkslategrey", 60 | Percentage: "8.79", 61 | }) 62 | 63 | for i := range colorMap3 { 64 | assert.Equal(t, expectedMap3[i], colorMap3[i]) 65 | } 66 | } 67 | 68 | // Benchmark nanoid generator 69 | func BenchmarkGetPalette(b *testing.B) { 70 | 71 | for n := 0; n < b.N; n++ { 72 | palitra.GetPalette(testImg, 3, 75) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /test_images/venice.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jkomyno/palitra/cd8f50f6e5d998657c2136a0a6bf7a1491a567ff/test_images/venice.jpg -------------------------------------------------------------------------------- /types.go: -------------------------------------------------------------------------------- 1 | package palitra 2 | 3 | type imageDim struct { 4 | horizontalPixels int 5 | verticalPixels int 6 | } 7 | 8 | type rgbT [3]int 9 | 10 | type colorMapT struct { 11 | key string 12 | value int 13 | } 14 | 15 | // pair is a simple key value struct, which links a color with its hex representation 16 | type pair struct { 17 | color string 18 | hex string 19 | } 20 | 21 | // ColorPercentageT is a struct which contains the approximated CSS3 color `Color` and its 22 | // spread in the image, expressed as `Percentage`% 23 | type ColorPercentageT struct { 24 | Color string `json:"color"` 25 | Percentage string `json:"percentage"` 26 | } 27 | --------------------------------------------------------------------------------