blob: a4b0cea9d3cb78488f2ff6bac61b4d84c3448dd6 [file] [log] [blame]
// Copyright 2021 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 imgcmp is a package for common code related to image comparisons.
package imgcmp
import (
"context"
"image"
"image/color"
"image/png"
"os"
"chromiumos/tast/errors"
"chromiumos/tast/local/colorcmp"
)
// CountPixelsWithDiff returns how many pixels in the specified color are contained in image with max diff.
func CountPixelsWithDiff(image image.Image, clr color.Color, colorMaxDiff uint8) int {
rect := image.Bounds()
numPixels := 0
for y := rect.Min.Y; y < rect.Max.Y; y++ {
for x := rect.Min.X; x < rect.Max.X; x++ {
if colorcmp.ColorsMatch(image.At(x, y), clr, colorMaxDiff) {
numPixels++
}
}
}
return numPixels
}
// CountPixels returns how many pixels in the specified color are contained in image.
func CountPixels(image image.Image, clr color.Color) int {
// TODO(ricardoq): At least on Eve, Nocturne, Caroline, Kevin and Dru the color
// in black flashes is RGBA(0,0,0,255). But it might be possible that on certain
// devices the color is slightly different. In that case we should adjust the colorMaxDiff.
return CountPixelsWithDiff(image, clr, 0)
}
// CountBrighterPixels takes two same size image, return how many pixels in
// countImage brighter than baseImage.
func CountBrighterPixels(baseImage, countImage image.Image) (int, error) {
rect := baseImage.Bounds()
if rect != countImage.Bounds() {
return 0, errors.New("two images have different size")
}
numPixels := 0
for y := rect.Min.Y; y < rect.Max.Y; y++ {
for x := rect.Min.X; x < rect.Max.X; x++ {
if colorcmp.Brighter(countImage.At(x, y), baseImage.At(x, y)) {
numPixels++
}
}
}
return numPixels, nil
}
// CountDiffPixels takes two images of the same size, and returns how many pixels are different.
func CountDiffPixels(imageA, imageB image.Image, threshold uint8) (int, error) {
rect := imageA.Bounds()
if rect != imageB.Bounds() {
return 0, errors.Errorf("the images have different sizes; imageA=%v, imageB=%v", imageA.Bounds(), imageB.Bounds())
}
numPixels := 0
for y := rect.Min.Y; y < rect.Max.Y; y++ {
for x := rect.Min.X; x < rect.Max.X; x++ {
if !colorcmp.ColorsMatch(imageB.At(x, y), imageA.At(x, y), threshold) {
numPixels++
}
}
}
return numPixels, nil
}
// DumpImageToPNG saves the image to path.
func DumpImageToPNG(ctx context.Context, image *image.Image, path string) error {
fd, err := os.Create(path)
if err != nil {
return err
}
defer fd.Close()
return png.Encode(fd, *image)
}