1*3ac0a46fSAndroid Build Coastguard Worker# Copyright 2017 The PDFium Authors 2*3ac0a46fSAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 3*3ac0a46fSAndroid Build Coastguard Worker# found in the LICENSE file. 4*3ac0a46fSAndroid Build Coastguard Worker"""Compares pairs of page images and generates an HTML to look at differences. 5*3ac0a46fSAndroid Build Coastguard Worker""" 6*3ac0a46fSAndroid Build Coastguard Worker 7*3ac0a46fSAndroid Build Coastguard Workerimport functools 8*3ac0a46fSAndroid Build Coastguard Workerimport glob 9*3ac0a46fSAndroid Build Coastguard Workerimport multiprocessing 10*3ac0a46fSAndroid Build Coastguard Workerimport os 11*3ac0a46fSAndroid Build Coastguard Workerimport re 12*3ac0a46fSAndroid Build Coastguard Workerimport subprocess 13*3ac0a46fSAndroid Build Coastguard Workerimport sys 14*3ac0a46fSAndroid Build Coastguard Workerimport webbrowser 15*3ac0a46fSAndroid Build Coastguard Worker 16*3ac0a46fSAndroid Build Coastguard Workerfrom common import DirectoryFinder 17*3ac0a46fSAndroid Build Coastguard Worker 18*3ac0a46fSAndroid Build Coastguard Worker 19*3ac0a46fSAndroid Build Coastguard Workerdef GenerateOneDiffParallel(image_comparison, image): 20*3ac0a46fSAndroid Build Coastguard Worker return image_comparison.GenerateOneDiff(image) 21*3ac0a46fSAndroid Build Coastguard Worker 22*3ac0a46fSAndroid Build Coastguard Worker 23*3ac0a46fSAndroid Build Coastguard Workerclass ImageComparison: 24*3ac0a46fSAndroid Build Coastguard Worker """Compares pairs of page images and generates an HTML to look at differences. 25*3ac0a46fSAndroid Build Coastguard Worker 26*3ac0a46fSAndroid Build Coastguard Worker The images are all assumed to have the same name and be in two directories: 27*3ac0a46fSAndroid Build Coastguard Worker [output_path]/[two_labels[0]] and [output_path]/[two_labels[1]]. For example, 28*3ac0a46fSAndroid Build Coastguard Worker if output_path is "/tmp/images" and two_labels is ("before", "after"), 29*3ac0a46fSAndroid Build Coastguard Worker images in /tmp/images/before will be compared to /tmp/images/after. The HTML 30*3ac0a46fSAndroid Build Coastguard Worker produced will be in /tmp/images/compare.html and have relative links to these 31*3ac0a46fSAndroid Build Coastguard Worker images, so /tmp/images is self-contained and can be moved around or shared. 32*3ac0a46fSAndroid Build Coastguard Worker """ 33*3ac0a46fSAndroid Build Coastguard Worker 34*3ac0a46fSAndroid Build Coastguard Worker def __init__(self, build_dir, output_path, two_labels, num_workers, 35*3ac0a46fSAndroid Build Coastguard Worker threshold_fraction): 36*3ac0a46fSAndroid Build Coastguard Worker """Constructor. 37*3ac0a46fSAndroid Build Coastguard Worker 38*3ac0a46fSAndroid Build Coastguard Worker Args: 39*3ac0a46fSAndroid Build Coastguard Worker build_dir: Path to the build directory. 40*3ac0a46fSAndroid Build Coastguard Worker output_path: Path with the pngs and where the html will be created. 41*3ac0a46fSAndroid Build Coastguard Worker two_labels: Tuple of two strings that name the subdirectories in 42*3ac0a46fSAndroid Build Coastguard Worker output_path containing the images. 43*3ac0a46fSAndroid Build Coastguard Worker num_workers: Number of worker threads to start. 44*3ac0a46fSAndroid Build Coastguard Worker threshold_fraction: Minimum percentage (0.0 to 1.0) of pixels below which 45*3ac0a46fSAndroid Build Coastguard Worker an image is considered to have only small changes. They will not be 46*3ac0a46fSAndroid Build Coastguard Worker displayed on the HTML, only listed. 47*3ac0a46fSAndroid Build Coastguard Worker """ 48*3ac0a46fSAndroid Build Coastguard Worker self.build_dir = build_dir 49*3ac0a46fSAndroid Build Coastguard Worker self.output_path = output_path 50*3ac0a46fSAndroid Build Coastguard Worker self.two_labels = two_labels 51*3ac0a46fSAndroid Build Coastguard Worker self.num_workers = num_workers 52*3ac0a46fSAndroid Build Coastguard Worker self.threshold = threshold_fraction * 100 53*3ac0a46fSAndroid Build Coastguard Worker 54*3ac0a46fSAndroid Build Coastguard Worker def Run(self, open_in_browser): 55*3ac0a46fSAndroid Build Coastguard Worker """Runs the comparison and generates an HTML with the results. 56*3ac0a46fSAndroid Build Coastguard Worker 57*3ac0a46fSAndroid Build Coastguard Worker Returns: 58*3ac0a46fSAndroid Build Coastguard Worker Exit status. 59*3ac0a46fSAndroid Build Coastguard Worker """ 60*3ac0a46fSAndroid Build Coastguard Worker 61*3ac0a46fSAndroid Build Coastguard Worker # Running a test defines a number of attributes on the fly. 62*3ac0a46fSAndroid Build Coastguard Worker # pylint: disable=attribute-defined-outside-init 63*3ac0a46fSAndroid Build Coastguard Worker 64*3ac0a46fSAndroid Build Coastguard Worker if len(self.two_labels) != 2: 65*3ac0a46fSAndroid Build Coastguard Worker print('two_labels must be a tuple of length 2', file=sys.stderr) 66*3ac0a46fSAndroid Build Coastguard Worker return 1 67*3ac0a46fSAndroid Build Coastguard Worker 68*3ac0a46fSAndroid Build Coastguard Worker finder = DirectoryFinder(self.build_dir) 69*3ac0a46fSAndroid Build Coastguard Worker self.img_diff_bin = finder.ExecutablePath('pdfium_diff') 70*3ac0a46fSAndroid Build Coastguard Worker 71*3ac0a46fSAndroid Build Coastguard Worker html_path = os.path.join(self.output_path, 'compare.html') 72*3ac0a46fSAndroid Build Coastguard Worker 73*3ac0a46fSAndroid Build Coastguard Worker self.diff_path = os.path.join(self.output_path, 'diff') 74*3ac0a46fSAndroid Build Coastguard Worker if not os.path.exists(self.diff_path): 75*3ac0a46fSAndroid Build Coastguard Worker os.makedirs(self.diff_path) 76*3ac0a46fSAndroid Build Coastguard Worker 77*3ac0a46fSAndroid Build Coastguard Worker self.image_locations = ImageLocations(self.output_path, self.diff_path, 78*3ac0a46fSAndroid Build Coastguard Worker self.two_labels) 79*3ac0a46fSAndroid Build Coastguard Worker 80*3ac0a46fSAndroid Build Coastguard Worker difference = self._GenerateDiffs() 81*3ac0a46fSAndroid Build Coastguard Worker 82*3ac0a46fSAndroid Build Coastguard Worker small_changes = [] 83*3ac0a46fSAndroid Build Coastguard Worker 84*3ac0a46fSAndroid Build Coastguard Worker with open(html_path, 'w') as f: 85*3ac0a46fSAndroid Build Coastguard Worker f.write('<html><body>') 86*3ac0a46fSAndroid Build Coastguard Worker f.write('<table>') 87*3ac0a46fSAndroid Build Coastguard Worker for image in self.image_locations.Images(): 88*3ac0a46fSAndroid Build Coastguard Worker diff = difference[image] 89*3ac0a46fSAndroid Build Coastguard Worker if diff is None: 90*3ac0a46fSAndroid Build Coastguard Worker print('Failed to compare image %s' % image, file=sys.stderr) 91*3ac0a46fSAndroid Build Coastguard Worker elif diff > self.threshold: 92*3ac0a46fSAndroid Build Coastguard Worker self._WriteImageRows(f, image, diff) 93*3ac0a46fSAndroid Build Coastguard Worker else: 94*3ac0a46fSAndroid Build Coastguard Worker small_changes.append((image, diff)) 95*3ac0a46fSAndroid Build Coastguard Worker self._WriteSmallChanges(f, small_changes) 96*3ac0a46fSAndroid Build Coastguard Worker f.write('</table>') 97*3ac0a46fSAndroid Build Coastguard Worker f.write('</body></html>') 98*3ac0a46fSAndroid Build Coastguard Worker 99*3ac0a46fSAndroid Build Coastguard Worker if open_in_browser: 100*3ac0a46fSAndroid Build Coastguard Worker webbrowser.open(html_path) 101*3ac0a46fSAndroid Build Coastguard Worker 102*3ac0a46fSAndroid Build Coastguard Worker return 0 103*3ac0a46fSAndroid Build Coastguard Worker 104*3ac0a46fSAndroid Build Coastguard Worker def _GenerateDiffs(self): 105*3ac0a46fSAndroid Build Coastguard Worker """Runs a diff over all pairs of page images, producing diff images. 106*3ac0a46fSAndroid Build Coastguard Worker 107*3ac0a46fSAndroid Build Coastguard Worker As a side effect, the diff images will be saved to [output_path]/diff 108*3ac0a46fSAndroid Build Coastguard Worker with the same image name. 109*3ac0a46fSAndroid Build Coastguard Worker 110*3ac0a46fSAndroid Build Coastguard Worker Returns: 111*3ac0a46fSAndroid Build Coastguard Worker A dict mapping image names to percentage of pixels changes. 112*3ac0a46fSAndroid Build Coastguard Worker """ 113*3ac0a46fSAndroid Build Coastguard Worker difference = {} 114*3ac0a46fSAndroid Build Coastguard Worker pool = multiprocessing.Pool(self.num_workers) 115*3ac0a46fSAndroid Build Coastguard Worker worker_func = functools.partial(GenerateOneDiffParallel, self) 116*3ac0a46fSAndroid Build Coastguard Worker 117*3ac0a46fSAndroid Build Coastguard Worker try: 118*3ac0a46fSAndroid Build Coastguard Worker # The timeout is a workaround for http://bugs.python.org/issue8296 119*3ac0a46fSAndroid Build Coastguard Worker # which prevents KeyboardInterrupt from working. 120*3ac0a46fSAndroid Build Coastguard Worker one_year_in_seconds = 3600 * 24 * 365 121*3ac0a46fSAndroid Build Coastguard Worker worker_results = ( 122*3ac0a46fSAndroid Build Coastguard Worker pool.map_async( 123*3ac0a46fSAndroid Build Coastguard Worker worker_func, 124*3ac0a46fSAndroid Build Coastguard Worker self.image_locations.Images()).get(one_year_in_seconds)) 125*3ac0a46fSAndroid Build Coastguard Worker for worker_result in worker_results: 126*3ac0a46fSAndroid Build Coastguard Worker image, result = worker_result 127*3ac0a46fSAndroid Build Coastguard Worker difference[image] = result 128*3ac0a46fSAndroid Build Coastguard Worker except KeyboardInterrupt: 129*3ac0a46fSAndroid Build Coastguard Worker pool.terminate() 130*3ac0a46fSAndroid Build Coastguard Worker sys.exit(1) 131*3ac0a46fSAndroid Build Coastguard Worker else: 132*3ac0a46fSAndroid Build Coastguard Worker pool.close() 133*3ac0a46fSAndroid Build Coastguard Worker 134*3ac0a46fSAndroid Build Coastguard Worker pool.join() 135*3ac0a46fSAndroid Build Coastguard Worker 136*3ac0a46fSAndroid Build Coastguard Worker return difference 137*3ac0a46fSAndroid Build Coastguard Worker 138*3ac0a46fSAndroid Build Coastguard Worker def GenerateOneDiff(self, image): 139*3ac0a46fSAndroid Build Coastguard Worker """Runs a diff over one pair of images, producing a diff image. 140*3ac0a46fSAndroid Build Coastguard Worker 141*3ac0a46fSAndroid Build Coastguard Worker As a side effect, the diff image will be saved to [output_path]/diff 142*3ac0a46fSAndroid Build Coastguard Worker with the same image name. 143*3ac0a46fSAndroid Build Coastguard Worker 144*3ac0a46fSAndroid Build Coastguard Worker Args: 145*3ac0a46fSAndroid Build Coastguard Worker image: Page image to compare. 146*3ac0a46fSAndroid Build Coastguard Worker 147*3ac0a46fSAndroid Build Coastguard Worker Returns: 148*3ac0a46fSAndroid Build Coastguard Worker A tuple (image, diff), where image is the parameter and diff is the 149*3ac0a46fSAndroid Build Coastguard Worker percentage of pixels changed. 150*3ac0a46fSAndroid Build Coastguard Worker """ 151*3ac0a46fSAndroid Build Coastguard Worker try: 152*3ac0a46fSAndroid Build Coastguard Worker subprocess.check_output([ 153*3ac0a46fSAndroid Build Coastguard Worker self.img_diff_bin, 154*3ac0a46fSAndroid Build Coastguard Worker self.image_locations.Left(image), 155*3ac0a46fSAndroid Build Coastguard Worker self.image_locations.Right(image) 156*3ac0a46fSAndroid Build Coastguard Worker ]) 157*3ac0a46fSAndroid Build Coastguard Worker except subprocess.CalledProcessError as e: 158*3ac0a46fSAndroid Build Coastguard Worker percentage_change = float(re.findall(r'\d+\.\d+', e.output)[0]) 159*3ac0a46fSAndroid Build Coastguard Worker else: 160*3ac0a46fSAndroid Build Coastguard Worker return image, 0 161*3ac0a46fSAndroid Build Coastguard Worker 162*3ac0a46fSAndroid Build Coastguard Worker try: 163*3ac0a46fSAndroid Build Coastguard Worker subprocess.check_output([ 164*3ac0a46fSAndroid Build Coastguard Worker self.img_diff_bin, '--diff', 165*3ac0a46fSAndroid Build Coastguard Worker self.image_locations.Left(image), 166*3ac0a46fSAndroid Build Coastguard Worker self.image_locations.Right(image), 167*3ac0a46fSAndroid Build Coastguard Worker self.image_locations.Diff(image) 168*3ac0a46fSAndroid Build Coastguard Worker ]) 169*3ac0a46fSAndroid Build Coastguard Worker except subprocess.CalledProcessError as e: 170*3ac0a46fSAndroid Build Coastguard Worker return image, percentage_change 171*3ac0a46fSAndroid Build Coastguard Worker else: 172*3ac0a46fSAndroid Build Coastguard Worker print('Warning: Should have failed the previous diff.', file=sys.stderr) 173*3ac0a46fSAndroid Build Coastguard Worker return image, 0 174*3ac0a46fSAndroid Build Coastguard Worker 175*3ac0a46fSAndroid Build Coastguard Worker def _GetRelativePath(self, absolute_path): 176*3ac0a46fSAndroid Build Coastguard Worker return os.path.relpath(absolute_path, start=self.output_path) 177*3ac0a46fSAndroid Build Coastguard Worker 178*3ac0a46fSAndroid Build Coastguard Worker def _WriteImageRows(self, f, image, diff): 179*3ac0a46fSAndroid Build Coastguard Worker """Write table rows for a page image comparing its two versions. 180*3ac0a46fSAndroid Build Coastguard Worker 181*3ac0a46fSAndroid Build Coastguard Worker Args: 182*3ac0a46fSAndroid Build Coastguard Worker f: Open HTML file to write to. 183*3ac0a46fSAndroid Build Coastguard Worker image: Image file name. 184*3ac0a46fSAndroid Build Coastguard Worker diff: Percentage of different pixels. 185*3ac0a46fSAndroid Build Coastguard Worker """ 186*3ac0a46fSAndroid Build Coastguard Worker f.write('<tr><td colspan="2">') 187*3ac0a46fSAndroid Build Coastguard Worker f.write('%s (%.4f%% changed)' % (image, diff)) 188*3ac0a46fSAndroid Build Coastguard Worker f.write('</td></tr>') 189*3ac0a46fSAndroid Build Coastguard Worker 190*3ac0a46fSAndroid Build Coastguard Worker f.write('<tr>') 191*3ac0a46fSAndroid Build Coastguard Worker self._WritePageCompareTd( 192*3ac0a46fSAndroid Build Coastguard Worker f, self._GetRelativePath(self.image_locations.Left(image)), 193*3ac0a46fSAndroid Build Coastguard Worker self._GetRelativePath(self.image_locations.Right(image))) 194*3ac0a46fSAndroid Build Coastguard Worker self._WritePageTd(f, self._GetRelativePath( 195*3ac0a46fSAndroid Build Coastguard Worker self.image_locations.Diff(image))) 196*3ac0a46fSAndroid Build Coastguard Worker f.write('</tr>') 197*3ac0a46fSAndroid Build Coastguard Worker 198*3ac0a46fSAndroid Build Coastguard Worker def _WritePageTd(self, f, image_path): 199*3ac0a46fSAndroid Build Coastguard Worker """Write table column with a single image. 200*3ac0a46fSAndroid Build Coastguard Worker 201*3ac0a46fSAndroid Build Coastguard Worker Args: 202*3ac0a46fSAndroid Build Coastguard Worker f: Open HTML file to write to. 203*3ac0a46fSAndroid Build Coastguard Worker image_path: Path to image file. 204*3ac0a46fSAndroid Build Coastguard Worker """ 205*3ac0a46fSAndroid Build Coastguard Worker f.write('<td>') 206*3ac0a46fSAndroid Build Coastguard Worker f.write('<img src="%s">' % image_path) 207*3ac0a46fSAndroid Build Coastguard Worker f.write('</td>') 208*3ac0a46fSAndroid Build Coastguard Worker 209*3ac0a46fSAndroid Build Coastguard Worker def _WritePageCompareTd(self, f, normal_image_path, hover_image_path): 210*3ac0a46fSAndroid Build Coastguard Worker """Write table column for an image comparing its two versions. 211*3ac0a46fSAndroid Build Coastguard Worker 212*3ac0a46fSAndroid Build Coastguard Worker Args: 213*3ac0a46fSAndroid Build Coastguard Worker f: Open HTML file to write to. 214*3ac0a46fSAndroid Build Coastguard Worker normal_image_path: Path to image to be used in the "normal" state. 215*3ac0a46fSAndroid Build Coastguard Worker hover_image_path: Path to image to be used in the "hover" state. 216*3ac0a46fSAndroid Build Coastguard Worker """ 217*3ac0a46fSAndroid Build Coastguard Worker f.write('<td>') 218*3ac0a46fSAndroid Build Coastguard Worker f.write('<img src="%s" ' 219*3ac0a46fSAndroid Build Coastguard Worker 'onmouseover="this.src=\'%s\';" ' 220*3ac0a46fSAndroid Build Coastguard Worker 'onmouseout="this.src=\'%s\';">' % 221*3ac0a46fSAndroid Build Coastguard Worker (normal_image_path, hover_image_path, normal_image_path)) 222*3ac0a46fSAndroid Build Coastguard Worker f.write('</td>') 223*3ac0a46fSAndroid Build Coastguard Worker 224*3ac0a46fSAndroid Build Coastguard Worker def _WriteSmallChanges(self, f, small_changes): 225*3ac0a46fSAndroid Build Coastguard Worker """Write table rows for all images considered to have only small changes. 226*3ac0a46fSAndroid Build Coastguard Worker 227*3ac0a46fSAndroid Build Coastguard Worker Args: 228*3ac0a46fSAndroid Build Coastguard Worker f: Open HTML file to write to. 229*3ac0a46fSAndroid Build Coastguard Worker small_changes: List of (image, change) tuples, where image is the page 230*3ac0a46fSAndroid Build Coastguard Worker image and change is the percentage of pixels changed. 231*3ac0a46fSAndroid Build Coastguard Worker """ 232*3ac0a46fSAndroid Build Coastguard Worker for image, change in small_changes: 233*3ac0a46fSAndroid Build Coastguard Worker f.write('<tr><td colspan="2">') 234*3ac0a46fSAndroid Build Coastguard Worker if not change: 235*3ac0a46fSAndroid Build Coastguard Worker f.write('No change for: %s' % image) 236*3ac0a46fSAndroid Build Coastguard Worker else: 237*3ac0a46fSAndroid Build Coastguard Worker f.write('Small change of %.4f%% for: %s' % (change, image)) 238*3ac0a46fSAndroid Build Coastguard Worker f.write('</td></tr>') 239*3ac0a46fSAndroid Build Coastguard Worker 240*3ac0a46fSAndroid Build Coastguard Worker 241*3ac0a46fSAndroid Build Coastguard Workerclass ImageLocations: 242*3ac0a46fSAndroid Build Coastguard Worker """Contains the locations of input and output image files. 243*3ac0a46fSAndroid Build Coastguard Worker """ 244*3ac0a46fSAndroid Build Coastguard Worker 245*3ac0a46fSAndroid Build Coastguard Worker def __init__(self, output_path, diff_path, two_labels): 246*3ac0a46fSAndroid Build Coastguard Worker """Constructor. 247*3ac0a46fSAndroid Build Coastguard Worker 248*3ac0a46fSAndroid Build Coastguard Worker Args: 249*3ac0a46fSAndroid Build Coastguard Worker output_path: Path to directory with the pngs. 250*3ac0a46fSAndroid Build Coastguard Worker diff_path: Path to directory where the diffs will be generated. 251*3ac0a46fSAndroid Build Coastguard Worker two_labels: Tuple of two strings that name the subdirectories in 252*3ac0a46fSAndroid Build Coastguard Worker output_path containing the images. 253*3ac0a46fSAndroid Build Coastguard Worker """ 254*3ac0a46fSAndroid Build Coastguard Worker self.output_path = output_path 255*3ac0a46fSAndroid Build Coastguard Worker self.diff_path = diff_path 256*3ac0a46fSAndroid Build Coastguard Worker self.two_labels = two_labels 257*3ac0a46fSAndroid Build Coastguard Worker 258*3ac0a46fSAndroid Build Coastguard Worker self.left = self._FindImages(self.two_labels[0]) 259*3ac0a46fSAndroid Build Coastguard Worker self.right = self._FindImages(self.two_labels[1]) 260*3ac0a46fSAndroid Build Coastguard Worker 261*3ac0a46fSAndroid Build Coastguard Worker self.images = list(self.left.viewkeys() & self.right.viewkeys()) 262*3ac0a46fSAndroid Build Coastguard Worker 263*3ac0a46fSAndroid Build Coastguard Worker # Sort by pdf filename, then page number 264*3ac0a46fSAndroid Build Coastguard Worker def KeyFn(s): 265*3ac0a46fSAndroid Build Coastguard Worker pieces = s.rsplit('.', 2) 266*3ac0a46fSAndroid Build Coastguard Worker return (pieces[0], int(pieces[1])) 267*3ac0a46fSAndroid Build Coastguard Worker 268*3ac0a46fSAndroid Build Coastguard Worker self.images.sort(key=KeyFn) 269*3ac0a46fSAndroid Build Coastguard Worker self.diff = { 270*3ac0a46fSAndroid Build Coastguard Worker image: os.path.join(self.diff_path, image) for image in self.images 271*3ac0a46fSAndroid Build Coastguard Worker } 272*3ac0a46fSAndroid Build Coastguard Worker 273*3ac0a46fSAndroid Build Coastguard Worker def _FindImages(self, label): 274*3ac0a46fSAndroid Build Coastguard Worker """Traverses a dir and builds a dict of all page images to compare in it. 275*3ac0a46fSAndroid Build Coastguard Worker 276*3ac0a46fSAndroid Build Coastguard Worker Args: 277*3ac0a46fSAndroid Build Coastguard Worker label: name of subdirectory of output_path to traverse. 278*3ac0a46fSAndroid Build Coastguard Worker 279*3ac0a46fSAndroid Build Coastguard Worker Returns: 280*3ac0a46fSAndroid Build Coastguard Worker Dict mapping page image names to the path of the image file. 281*3ac0a46fSAndroid Build Coastguard Worker """ 282*3ac0a46fSAndroid Build Coastguard Worker image_path_matcher = os.path.join(self.output_path, label, '*.*.png') 283*3ac0a46fSAndroid Build Coastguard Worker image_paths = glob.glob(image_path_matcher) 284*3ac0a46fSAndroid Build Coastguard Worker 285*3ac0a46fSAndroid Build Coastguard Worker image_dict = { 286*3ac0a46fSAndroid Build Coastguard Worker os.path.split(image_path)[1]: image_path for image_path in image_paths 287*3ac0a46fSAndroid Build Coastguard Worker } 288*3ac0a46fSAndroid Build Coastguard Worker 289*3ac0a46fSAndroid Build Coastguard Worker return image_dict 290*3ac0a46fSAndroid Build Coastguard Worker 291*3ac0a46fSAndroid Build Coastguard Worker def Images(self): 292*3ac0a46fSAndroid Build Coastguard Worker """Returns a list of all page images present in both directories.""" 293*3ac0a46fSAndroid Build Coastguard Worker return self.images 294*3ac0a46fSAndroid Build Coastguard Worker 295*3ac0a46fSAndroid Build Coastguard Worker def Left(self, test_case): 296*3ac0a46fSAndroid Build Coastguard Worker """Returns the path for a page image in the first subdirectory.""" 297*3ac0a46fSAndroid Build Coastguard Worker return self.left[test_case] 298*3ac0a46fSAndroid Build Coastguard Worker 299*3ac0a46fSAndroid Build Coastguard Worker def Right(self, test_case): 300*3ac0a46fSAndroid Build Coastguard Worker """Returns the path for a page image in the second subdirectory.""" 301*3ac0a46fSAndroid Build Coastguard Worker return self.right[test_case] 302*3ac0a46fSAndroid Build Coastguard Worker 303*3ac0a46fSAndroid Build Coastguard Worker def Diff(self, test_case): 304*3ac0a46fSAndroid Build Coastguard Worker """Returns the path for a page diff image.""" 305*3ac0a46fSAndroid Build Coastguard Worker return self.diff[test_case] 306