blob: 1b382dadff81bd25116a81f14852d8d8c408ae06 [file] [log] [blame]
# Copyright 2015 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.
import errno
from PIL import Image
import logging
import subprocess
import tempfile
from autotest_lib.client.cros.image_comparison import comparison_result
from import method_logger
class PdiffImageComparer(object):
Compares two images using ChromeOS' perceptualdiff binary.
def compare(self, golden_img_path, test_img_path, box=None):
Compares a test image against the specified golden image using the
terminal tool 'perceptualdiff'.
@param golden_img_path: path, complete path to a golden image.
@param test_img_path: path, complete path to a test image.
@param box: int tuple, left, upper, right, lower pixel coordinates.
Defines the rectangular boundary within which to compare.
@return: int, number of pixels that are different.
@raise : Whatever _pdiff_compare raises.
if not box:
return self._pdiff_compare(golden_img_path, test_img_path)
ext = '.png'
tmp_golden_img_file = tempfile.NamedTemporaryFile(suffix=ext)
tmp_test_img_file = tempfile.NamedTemporaryFile(suffix=ext)
with tmp_golden_img_file, tmp_test_img_file:
tmp_golden_img_path =
tmp_test_img_path =
return self._pdiff_compare(tmp_golden_img_path, tmp_test_img_path)
def _pdiff_compare(self, golden_img_path, test_img_path):
Invokes perceptualdiff using subprocess tools.
@param golden_img_path: path, complete path to a golden image.
@param test_img_path: path, complete path to a test image.
@return: int, number of pixels that are different.
@raise ValueError if image dimensions are not the same.
@raise OSError: if file does not exist or can not be opened.
# TODO mussa: Could downsampling the images be good for us?
tmp_diff_file = tempfile.NamedTemporaryFile(suffix='.png', delete=False)
args = ['perceptualdiff', golden_img_path, test_img_path, '-output',]
logging.debug("Start process with args : " + str(args))
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output = p.communicate()
logging.debug('output of perceptual diff command is')
stdoutdata = output[0]
mismatch_error = "Image dimensions do not match"
diff_message = "Images are visibly different"
filenotfound_message = "Cannot open"
#TODO(dhaddock): Check for image not created
if p.returncode == 0:
# pdiff exited with 0, images were the same
return comparison_result.ComparisonResult(0, '', None)
if mismatch_error in stdoutdata:
raise ValueError("pdiff says: " + stdoutdata)
if diff_message in stdoutdata:
diff_pixels = [int(s) for s in stdoutdata.split() if s.isdigit()][0]
return comparison_result.ComparisonResult(int(diff_pixels), '',
if filenotfound_message in stdoutdata:
raise OSError(errno.ENOENT, "pdiff says: " + stdoutdata)
raise RuntimeError("Unknown result from pdiff: "
"Output : " + stdoutdata)
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):