blob: 4256d59f6f767da23da343cd80776d7ab3ecaae9 [file] [log] [blame]
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Package colorcmp supports comparing colors.
package colorcmp
import (
"fmt"
"image"
"image/color"
)
// RGB returns a fully-opaque color.Color based on the supplied components.
func RGB(r, g, b uint8) color.Color {
return color.NRGBA{R: r, G: g, B: b, A: 0xff}
}
// ColorStr converts clr to 8-bit-per-channel, non-pre-alpha-multiplied RGBA and
// returns either a "#rrggbb" representation if it's fully opaque or "#rrggbbaa" otherwise.
func ColorStr(clr color.Color) string {
nrgba := toNRGBA(clr)
if nrgba.A == 0xff {
return fmt.Sprintf("#%02x%02x%02x", nrgba.R, nrgba.G, nrgba.B)
}
return fmt.Sprintf("#%02x%02x%02x%02x", nrgba.R, nrgba.G, nrgba.B, nrgba.A)
}
// toNRGBA converts clr to a color.NRGBA.
func toNRGBA(clr color.Color) color.NRGBA {
return color.NRGBAModel.Convert(clr).(color.NRGBA)
}
// DominantColor returns the color that occupies the largest number of pixels
// in the passed in image. It also returns the ratio of that pixel to the number
// of overall pixels in the image.
func DominantColor(im image.Image) (clr color.Color, ratio float64) {
counts := map[color.NRGBA]int{}
box := im.Bounds()
for x := box.Min.X; x < box.Max.X; x++ {
for y := box.Min.Y; y < box.Max.Y; y++ {
counts[toNRGBA(im.At(x, y))]++
}
}
var bestClr color.NRGBA
bestCnt := 0
for clr, cnt := range counts {
if cnt > bestCnt {
bestClr = clr
bestCnt = cnt
}
}
return bestClr, float64(bestCnt) / float64(box.Dx()*box.Dy())
}
// ColorsMatch takes two colors and returns whether or not each component is within
// maxDiff of each other after conversion to 8-bit-per-channel, non-alpha-premultiplied RGBA.
func ColorsMatch(a, b color.Color, maxDiff uint8) bool {
an := toNRGBA(a)
bn := toNRGBA(b)
allowed := int(maxDiff)
near := func(x, y uint8) bool {
d := int(x) - int(y)
return -allowed <= d && d <= allowed
}
return near(an.R, bn.R) && near(an.G, bn.G) && near(an.B, bn.B) && near(an.A, bn.A)
}
// Brighter takes two colors and returns whether color a brighter than color b
// by gray scale comparison.
func Brighter(a, b color.Color) bool {
ag := color.GrayModel.Convert(a).(color.Gray).Y
bg := color.GrayModel.Convert(b).(color.Gray).Y
return ag > bg
}