Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2013 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """Module that outputs an JSON summary containing the comparision of images.""" | 6 """Module that outputs an JSON summary containing the comparision of images.""" |
| 7 | 7 |
| 8 import json | 8 import json |
| 9 import optparse | 9 import optparse |
| 10 import os | 10 import os |
| 11 import posixpath | 11 import posixpath |
| 12 import re | |
| 12 import sys | 13 import sys |
| 13 import traceback | 14 import traceback |
| 14 | 15 |
| 15 sys.path.append( | 16 sys.path.append( |
| 16 os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir)) | 17 os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir)) |
| 17 import json_summary_constants | 18 import json_summary_constants |
| 18 | 19 |
| 20 # TODO(epoger): These constants must be kept in sync with the ones in | |
| 21 # https://skia.googlesource.com/skia/+/master/tools/PictureRenderer.cpp | |
| 22 JSONKEY_IMAGE_CHECKSUMALGORITHM = 'checksumAlgorithm' | |
| 23 JSONKEY_IMAGE_CHECKSUMVALUE = 'checksumValue' | |
| 24 JSONKEY_IMAGE_FILEPATH = 'filepath' | |
| 25 | |
| 19 | 26 |
| 20 def WriteJsonSummary(img_root, nopatch_json, nopatch_images_base_url, | 27 def WriteJsonSummary(img_root, nopatch_json, nopatch_images_base_url, |
| 21 withpatch_json, withpatch_images_base_url, | 28 withpatch_json, withpatch_images_base_url, |
| 22 output_file_path, gs_output_dir, gs_skp_dir, slave_num, | 29 output_file_path, gs_output_dir, gs_skp_dir, slave_num, |
| 23 additions_to_sys_path): | 30 additions_to_sys_path): |
| 24 """Outputs the JSON summary of image comparisions. | 31 """Outputs the JSON summary of image comparisions. |
| 25 | 32 |
| 26 Args: | 33 Args: |
| 27 img_root: (str) The root directory on local disk where we store all images. | 34 img_root: (str) The root directory on local disk where we store all images. |
| 28 nopatch_json: (str) Location of the nopatch render_pictures JSON summary | 35 nopatch_json: (str) Location of the nopatch render_pictures JSON summary |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 51 | 58 |
| 52 # Modules from skia's gm/ and gm/rebaseline_server/ dirs. | 59 # Modules from skia's gm/ and gm/rebaseline_server/ dirs. |
| 53 try: | 60 try: |
| 54 import gm_json | 61 import gm_json |
| 55 import imagediffdb | 62 import imagediffdb |
| 56 except ImportError: | 63 except ImportError: |
| 57 print 'sys.path is [%s]' % sys.path | 64 print 'sys.path is [%s]' % sys.path |
| 58 traceback.print_exc() | 65 traceback.print_exc() |
| 59 raise Exception('You need to add gm/ and gm/rebaseline_server to sys.path') | 66 raise Exception('You need to add gm/ and gm/rebaseline_server to sys.path') |
| 60 | 67 |
| 61 files_to_checksums_nopatch = GetFilesAndChecksums(gm_json, nopatch_json) | 68 all_image_descriptions_nopatch = GetImageDescriptions(gm_json, nopatch_json) |
| 62 files_to_checksums_withpatch = GetFilesAndChecksums(gm_json, withpatch_json) | 69 all_image_descriptions_withpatch = GetImageDescriptions( |
| 70 gm_json, withpatch_json) | |
| 63 | 71 |
| 64 assert len(files_to_checksums_nopatch) == len(files_to_checksums_withpatch), ( | 72 assert (len(all_image_descriptions_nopatch) == |
| 65 'Number of images in both JSON summary files are different') | 73 len(all_image_descriptions_withpatch)), \ |
| 66 assert files_to_checksums_nopatch.keys() == \ | 74 'Number of images in the two JSON summary files are different' |
| 67 files_to_checksums_withpatch.keys(), ( | 75 assert (all_image_descriptions_nopatch.keys() == |
| 68 'File names in both JSON summary files are different') | 76 all_image_descriptions_withpatch.keys()), \ |
| 77 'SKP filenames in the two JSON summary files are different' | |
| 69 | 78 |
| 70 # Compare checksums in both directories and output differences. | 79 # Compare checksums in both directories and output differences. |
| 71 file_differences = [] | 80 file_differences = [] |
| 72 slave_dict = { | 81 slave_dict = { |
| 73 json_summary_constants.JSONKEY_SKPS_LOCATION: gs_skp_dir, | 82 json_summary_constants.JSONKEY_SKPS_LOCATION: gs_skp_dir, |
| 74 json_summary_constants.JSONKEY_FAILED_FILES: file_differences, | 83 json_summary_constants.JSONKEY_FAILED_FILES: file_differences, |
| 75 json_summary_constants.JSONKEY_FILES_LOCATION_NOPATCH: posixpath.join( | 84 json_summary_constants.JSONKEY_FILES_LOCATION_NOPATCH: posixpath.join( |
| 76 gs_output_dir, 'slave%s' % slave_num, 'nopatch-images'), | 85 gs_output_dir, 'slave%s' % slave_num, 'nopatch-images'), |
| 77 json_summary_constants.JSONKEY_FILES_LOCATION_WITHPATCH: posixpath.join( | 86 json_summary_constants.JSONKEY_FILES_LOCATION_WITHPATCH: posixpath.join( |
| 78 gs_output_dir, 'slave%s' % slave_num, 'withpatch-images'), | 87 gs_output_dir, 'slave%s' % slave_num, 'withpatch-images'), |
| 79 json_summary_constants.JSONKEY_FILES_LOCATION_DIFFS: posixpath.join( | 88 json_summary_constants.JSONKEY_FILES_LOCATION_DIFFS: posixpath.join( |
| 80 gs_output_dir, 'slave%s' % slave_num, 'diffs'), | 89 gs_output_dir, 'slave%s' % slave_num, 'diffs'), |
| 81 json_summary_constants.JSONKEY_FILES_LOCATION_WHITE_DIFFS: posixpath.join( | 90 json_summary_constants.JSONKEY_FILES_LOCATION_WHITE_DIFFS: posixpath.join( |
| 82 gs_output_dir, 'slave%s' % slave_num, 'whitediffs') | 91 gs_output_dir, 'slave%s' % slave_num, 'whitediffs') |
| 83 } | 92 } |
| 84 json_summary = { | 93 json_summary = { |
| 85 'slave%s' % slave_num: slave_dict | 94 'slave%s' % slave_num: slave_dict |
| 86 } | 95 } |
| 87 | 96 |
| 88 image_diff_db = imagediffdb.ImageDiffDB(storage_root=img_root) | 97 image_diff_db = imagediffdb.ImageDiffDB(storage_root=img_root) |
| 89 for filename in files_to_checksums_nopatch: | 98 for skp_file_and_tile in all_image_descriptions_nopatch: |
| 90 algo_nopatch, checksum_nopatch = files_to_checksums_nopatch[filename] | 99 image_desc_nopatch = all_image_descriptions_nopatch[skp_file_and_tile] |
| 91 algo_withpatch, checksum_withpatch = files_to_checksums_withpatch[filename] | 100 image_desc_withpatch = all_image_descriptions_withpatch[skp_file_and_tile] |
| 92 assert algo_nopatch == algo_withpatch, 'Different checksum algorithms found' | 101 |
| 102 algo_nopatch = image_desc_nopatch[JSONKEY_IMAGE_CHECKSUMALGORITHM] | |
| 103 algo_withpatch = image_desc_withpatch[JSONKEY_IMAGE_CHECKSUMALGORITHM] | |
| 104 assert algo_nopatch == algo_withpatch, 'Different checksum algorithms' | |
| 105 | |
| 106 imagefile_nopatch = image_desc_nopatch[JSONKEY_IMAGE_FILEPATH] | |
| 107 imagefile_withpatch = image_desc_withpatch[JSONKEY_IMAGE_FILEPATH] | |
| 108 assert imagefile_nopatch == imagefile_withpatch, 'Different imagefile names' | |
| 109 | |
| 110 checksum_nopatch = image_desc_nopatch[JSONKEY_IMAGE_CHECKSUMVALUE] | |
| 111 checksum_withpatch = image_desc_withpatch[JSONKEY_IMAGE_CHECKSUMVALUE] | |
| 93 if checksum_nopatch != checksum_withpatch: | 112 if checksum_nopatch != checksum_withpatch: |
| 94 # TODO(epoger): It seems silly that we add this DiffRecord to ImageDiffDB | 113 # TODO(epoger): It seems silly that we add this DiffRecord to ImageDiffDB |
| 95 # and then pull it out again right away, but this is a stepping-stone | 114 # and then pull it out again right away, but this is a stepping-stone |
| 96 # to using ImagePairSet instead of replicating its behavior here. | 115 # to using ImagePairSet instead of replicating its behavior here. |
| 97 image_locator_base = os.path.splitext(filename)[0] | 116 image_locator_base = os.path.splitext(imagefile_nopatch)[0] |
| 98 image_locator_nopatch = image_locator_base + '_nopatch' | 117 image_locator_nopatch = image_locator_base + '_nopatch' |
| 99 image_locator_withpatch = image_locator_base + '_withpatch' | 118 image_locator_withpatch = image_locator_base + '_withpatch' |
| 100 image_diff_db.add_image_pair( | 119 image_diff_db.add_image_pair( |
| 101 expected_image_url=posixpath.join(nopatch_images_base_url, filename), | 120 expected_image_url=posixpath.join( |
| 121 nopatch_images_base_url, skp_file_and_tile), | |
| 102 expected_image_locator=image_locator_nopatch, | 122 expected_image_locator=image_locator_nopatch, |
| 103 actual_image_url=posixpath.join(withpatch_images_base_url, filename), | 123 actual_image_url=posixpath.join( |
| 124 withpatch_images_base_url, skp_file_and_tile), | |
| 104 actual_image_locator=image_locator_withpatch) | 125 actual_image_locator=image_locator_withpatch) |
| 105 diff_record = image_diff_db.get_diff_record( | 126 diff_record = image_diff_db.get_diff_record( |
| 106 expected_image_locator=image_locator_nopatch, | 127 expected_image_locator=image_locator_nopatch, |
| 107 actual_image_locator=image_locator_withpatch) | 128 actual_image_locator=image_locator_withpatch) |
| 108 file_differences.append({ | 129 file_differences.append({ |
| 109 json_summary_constants.JSONKEY_FILE_NAME: filename, | 130 json_summary_constants.JSONKEY_FILE_NAME: imagefile_nopatch, |
| 110 json_summary_constants.JSONKEY_SKP_LOCATION: posixpath.join( | 131 json_summary_constants.JSONKEY_SKP_LOCATION: posixpath.join( |
| 111 gs_skp_dir, GetSkpFileName(filename)), | 132 gs_skp_dir, GetSkpFileName(skp_file_and_tile)), |
| 112 json_summary_constants.JSONKEY_NUM_PIXELS_DIFFERING: | 133 json_summary_constants.JSONKEY_NUM_PIXELS_DIFFERING: |
| 113 diff_record.get_num_pixels_differing(), | 134 diff_record.get_num_pixels_differing(), |
| 114 json_summary_constants.JSONKEY_PERCENT_PIXELS_DIFFERING: | 135 json_summary_constants.JSONKEY_PERCENT_PIXELS_DIFFERING: |
| 115 diff_record.get_percent_pixels_differing(), | 136 diff_record.get_percent_pixels_differing(), |
| 116 json_summary_constants.JSONKEY_WEIGHTED_DIFF_MEASURE: | 137 json_summary_constants.JSONKEY_WEIGHTED_DIFF_MEASURE: |
| 117 diff_record.get_weighted_diff_measure(), | 138 diff_record.get_weighted_diff_measure(), |
| 118 json_summary_constants.JSONKEY_MAX_DIFF_PER_CHANNEL: | 139 json_summary_constants.JSONKEY_MAX_DIFF_PER_CHANNEL: |
| 119 diff_record.get_max_diff_per_channel(), | 140 diff_record.get_max_diff_per_channel(), |
| 120 json_summary_constants.JSONKEY_PERCEPTUAL_DIFF: | 141 json_summary_constants.JSONKEY_PERCEPTUAL_DIFF: |
| 121 diff_record.get_perceptual_difference(), | 142 diff_record.get_perceptual_difference(), |
| 122 }) | 143 }) |
| 123 if file_differences: | 144 if file_differences: |
| 124 slave_dict[json_summary_constants.JSONKEY_FAILED_FILES_COUNT] = len( | 145 slave_dict[json_summary_constants.JSONKEY_FAILED_FILES_COUNT] = len( |
| 125 file_differences) | 146 file_differences) |
| 126 with open(output_file_path, 'w') as f: | 147 with open(output_file_path, 'w') as f: |
| 127 f.write(json.dumps(json_summary, indent=4, sort_keys=True)) | 148 f.write(json.dumps(json_summary, indent=4, sort_keys=True)) |
| 128 | 149 |
| 129 | 150 |
| 130 def GetSkpFileName(img_file_name): | 151 def GetSkpFileName(skp_file_and_tile): |
| 131 """Determine the SKP file name from the image's file name.""" | 152 """Determine the SKP file name from the combined skpFile and tile string.""" |
| 132 # TODO(rmistry): The below relies too much on the current output of render | 153 # TODO(rmistry): The below relies too much on the current output of render |
| 133 # pictures to determine the root SKP. | 154 # pictures to determine the root SKP. |
| 134 return '%s_.skp' % '_'.join(img_file_name.split('_')[:-1]) | 155 return re.sub('-tile\d+$', '', skp_file_and_tile) |
|
epoger
2014/04/07 22:08:01
This still relies on a "magic" conversion algorith
| |
| 135 | 156 |
| 136 | 157 |
| 137 def GetFilesAndChecksums(gm_json_mod, json_location): | 158 def GetImageDescriptions(gm_json_mod, json_location): |
| 138 """Reads the JSON summary and returns dict of files to checksums.""" | 159 """Reads the JSON summary and returns {SkpFileName: ImageDescription} dict. |
| 160 | |
| 161 Each ImageDescription is a dict of this form: | |
| 162 { | |
| 163 JSONKEY_IMAGE_CHECKSUMALGORITHM: blah, | |
| 164 JSONKEY_IMAGE_CHECKSUMVALUE: blah, | |
| 165 JSONKEY_IMAGE_FILEPATH: blah, | |
| 166 } | |
| 167 """ | |
| 139 data = gm_json_mod.LoadFromFile(json_location) | 168 data = gm_json_mod.LoadFromFile(json_location) |
| 140 if data: | 169 if data: |
| 141 return data[gm_json_mod.JSONKEY_ACTUALRESULTS][ | 170 return data[gm_json_mod.JSONKEY_ACTUALRESULTS][ |
| 142 gm_json_mod.JSONKEY_ACTUALRESULTS_NOCOMPARISON] | 171 gm_json_mod.JSONKEY_ACTUALRESULTS_NOCOMPARISON] |
| 143 else: | 172 else: |
| 144 return {} | 173 return {} |
| 145 | 174 |
| 146 | 175 |
| 147 if '__main__' == __name__: | 176 if '__main__' == __name__: |
| 148 option_parser = optparse.OptionParser() | 177 option_parser = optparse.OptionParser() |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 192 option_parser.error( | 221 option_parser.error( |
| 193 'Must specify img_root, nopatch_json, nopatch_images_base_url, ' | 222 'Must specify img_root, nopatch_json, nopatch_images_base_url, ' |
| 194 'withpatch_json, withpatch_images_base_url, output_file_path, ' | 223 'withpatch_json, withpatch_images_base_url, output_file_path, ' |
| 195 'gs_output_dir, gs_skp_dir, and slave_num.') | 224 'gs_output_dir, gs_skp_dir, and slave_num.') |
| 196 | 225 |
| 197 WriteJsonSummary(options.img_root, options.nopatch_json, | 226 WriteJsonSummary(options.img_root, options.nopatch_json, |
| 198 options.nopatch_images_base_url, options.withpatch_json, | 227 options.nopatch_images_base_url, options.withpatch_json, |
| 199 options.withpatch_images_base_url, options.output_file_path, | 228 options.withpatch_images_base_url, options.output_file_path, |
| 200 options.gs_output_dir, options.gs_skp_dir, options.slave_num, | 229 options.gs_output_dir, options.gs_skp_dir, options.slave_num, |
| 201 options.add_to_sys_path) | 230 options.add_to_sys_path) |
| OLD | NEW |