ImagePairSet class; see its docstring below.
"""
+# System-level imports
+import posixpath
+
+# Local imports
import column
# Keys used within dictionary representation of ImagePairSet.
KEY__EXTRACOLUMNHEADERS = 'extraColumnHeaders'
KEY__IMAGEPAIRS = 'imagePairs'
KEY__IMAGESETS = 'imageSets'
-KEY__IMAGESETS__BASE_URL = 'baseUrl'
-KEY__IMAGESETS__DESCRIPTION = 'description'
+KEY__IMAGESETS__FIELD__BASE_URL = 'baseUrl'
+KEY__IMAGESETS__FIELD__DESCRIPTION = 'description'
+KEY__IMAGESETS__SET__DIFFS = 'diffs'
+KEY__IMAGESETS__SET__IMAGE_A = 'imageA'
+KEY__IMAGESETS__SET__IMAGE_B = 'imageB'
+KEY__IMAGESETS__SET__WHITEDIFFS = 'whiteDiffs'
DEFAULT_DESCRIPTIONS = ('setA', 'setB')
+DIFF_BASE_URL = '/static/generated-images'
class ImagePairSet(object):
self._extra_column_tallies = {} # maps column_id -> values
# -> instances_per_value
self._image_pair_dicts = []
+ self._image_base_url = None
+ self._diff_base_url = DIFF_BASE_URL
def add_image_pair(self, image_pair):
"""Adds an ImagePair; this may be repeated any number of times."""
# Special handling when we add the first ImagePair...
if not self._image_pair_dicts:
- self._base_url = image_pair.base_url
+ self._image_base_url = image_pair.base_url
- if image_pair.base_url != self._base_url:
+ if image_pair.base_url != self._image_base_url:
raise Exception('added ImagePair with base_url "%s" instead of "%s"' % (
- image_pair.base_url, self._base_url))
+ image_pair.base_url, self._image_base_url))
self._image_pair_dicts.append(image_pair.as_dict())
extra_columns_dict = image_pair.extra_columns_dict
if extra_columns_dict:
Uses the KEY__* constants as keys.
"""
+ key_description = KEY__IMAGESETS__FIELD__DESCRIPTION
+ key_base_url = KEY__IMAGESETS__FIELD__BASE_URL
return {
KEY__EXTRACOLUMNHEADERS: self._column_headers_as_dict(),
KEY__IMAGEPAIRS: self._image_pair_dicts,
- KEY__IMAGESETS: [{
- KEY__IMAGESETS__BASE_URL: self._base_url,
- KEY__IMAGESETS__DESCRIPTION: self._descriptions[0],
- }, {
- KEY__IMAGESETS__BASE_URL: self._base_url,
- KEY__IMAGESETS__DESCRIPTION: self._descriptions[1],
- }],
+ KEY__IMAGESETS: {
+ KEY__IMAGESETS__SET__IMAGE_A: {
+ key_description: self._descriptions[0],
+ key_base_url: self._image_base_url,
+ },
+ KEY__IMAGESETS__SET__IMAGE_B: {
+ key_description: self._descriptions[1],
+ key_base_url: self._image_base_url,
+ },
+ KEY__IMAGESETS__SET__DIFFS: {
+ key_description: 'color difference per channel',
+ key_base_url: posixpath.join(
+ self._diff_base_url, 'diffs'),
+ },
+ KEY__IMAGESETS__SET__WHITEDIFFS: {
+ key_description: 'differing pixels in white',
+ key_base_url: posixpath.join(
+ self._diff_base_url, 'whitediffs'),
+ },
+ },
}
IMAGEPAIR_2_AS_DICT,
IMAGEPAIR_3_AS_DICT,
],
- 'imageSets': [
- {
+ 'imageSets': {
+ 'imageA': {
'baseUrl': BASE_URL_1,
'description': SET_A_DESCRIPTION,
},
- {
+ 'imageB': {
'baseUrl': BASE_URL_1,
'description': SET_B_DESCRIPTION,
},
- ],
+ 'diffs': {
+ 'baseUrl': '/static/generated-images/diffs',
+ 'description': 'color difference per channel',
+ },
+ 'whiteDiffs': {
+ 'baseUrl': '/static/generated-images/whitediffs',
+ 'description': 'differing pixels in white',
+ },
+ },
}
image_pair_set = imagepairset.ImagePairSet(
# Keys used to link an image to a particular GM test.
# NOTE: Keep these in sync with static/constants.js
-REBASELINE_SERVER_SCHEMA_VERSION_NUMBER = 1
+REBASELINE_SERVER_SCHEMA_VERSION_NUMBER = 2
KEY__EXPECTATIONS__BUGS = gm_json.JSONKEY_EXPECTEDRESULTS_BUGS
KEY__EXPECTATIONS__IGNOREFAILURE = gm_json.JSONKEY_EXPECTEDRESULTS_IGNOREFAILURE
KEY__EXPECTATIONS__REVIEWED = gm_json.JSONKEY_EXPECTEDRESULTS_REVIEWED
now = int(time.time())
response_dict = {
results_mod.KEY__HEADER: {
+ results_mod.KEY__HEADER__SCHEMA_VERSION: (
+ results_mod.REBASELINE_SERVER_SCHEMA_VERSION_NUMBER),
results_mod.KEY__HEADER__IS_STILL_LOADING: True,
results_mod.KEY__HEADER__TIME_UPDATED: now,
results_mod.KEY__HEADER__TIME_NEXT_UPDATE_AVAILABLE: (
KEY__EXTRACOLUMNHEADERS: 'extraColumnHeaders',
KEY__IMAGEPAIRS: 'imagePairs',
KEY__IMAGESETS: 'imageSets',
- KEY__IMAGESETS__BASE_URL: 'baseUrl',
- KEY__IMAGESETS__DESCRIPTION: 'description',
+ KEY__IMAGESETS__FIELD__BASE_URL: 'baseUrl',
+ KEY__IMAGESETS__FIELD__DESCRIPTION: 'description',
+ KEY__IMAGESETS__SET__DIFFS: 'diffs',
+ KEY__IMAGESETS__SET__IMAGE_A: 'imageA',
+ KEY__IMAGESETS__SET__IMAGE_B: 'imageB',
+ KEY__IMAGESETS__SET__WHITEDIFFS: 'whiteDiffs',
// NOTE: Keep these in sync with ../results.py
- REBASELINE_SERVER_SCHEMA_VERSION_NUMBER: 1,
+ REBASELINE_SERVER_SCHEMA_VERSION_NUMBER: 2,
KEY__EXPECTATIONS__BUGS: 'bugs',
KEY__EXPECTATIONS__IGNOREFAILURE: 'ignore-failure',
KEY__EXPECTATIONS__REVIEWED: 'reviewed-by-human',
$scope.constants = constants;
$scope.windowTitle = "Loading GM Results...";
$scope.resultsToLoad = $location.search().resultsToLoad;
- $scope.loadingMessage = "Loading results from '" + $scope.resultsToLoad +
- "', please wait...";
+ $scope.loadingMessage = "please wait...";
/**
* On initial page load, load a full dictionary of results.
$http.get($scope.resultsToLoad).success(
function(data, status, header, config) {
var dataHeader = data[constants.KEY__HEADER];
- if (dataHeader[constants.KEY__HEADER__IS_STILL_LOADING]) {
+ if (dataHeader[constants.KEY__HEADER__SCHEMA_VERSION] !=
+ constants.REBASELINE_SERVER_SCHEMA_VERSION_NUMBER) {
+ $scope.loadingMessage = "ERROR: Got JSON file with schema version "
+ + dataHeader[constants.KEY__HEADER__SCHEMA_VERSION]
+ + " but expected schema version "
+ + constants.REBASELINE_SERVER_SCHEMA_VERSION_NUMBER;
+ } else if (dataHeader[constants.KEY__HEADER__IS_STILL_LOADING]) {
// Apply the server's requested reload delay to local time,
// so we will wait the right number of seconds regardless of clock
// skew between client and server.
var timeNow = new Date().getTime();
var timeToReload = timeNow + reloadDelayInSeconds * 1000;
$scope.loadingMessage =
- "Server is still loading results; will retry at " +
+ "server is still loading results; will retry at " +
$scope.localTimeString(timeToReload / 1000);
$timeout(
function(){location.reload();},
timeToReload - timeNow);
- } else if (dataHeader[constants.KEY__HEADER__SCHEMA_VERSION] !=
- constants.REBASELINE_SERVER_SCHEMA_VERSION_NUMBER) {
- $scope.loadingMessage = "ERROR: Got JSON file with schema version "
- + dataHeader[constants.KEY__HEADER__SCHEMA_VERSION]
- + " but expected schema version "
- + constants.REBASELINE_SERVER_SCHEMA_VERSION_NUMBER;
} else {
- $scope.loadingMessage = "Processing data, please wait...";
+ $scope.loadingMessage = "processing data, please wait...";
$scope.header = dataHeader;
$scope.extraColumnHeaders = data[constants.KEY__EXTRACOLUMNHEADERS];
}
).error(
function(data, status, header, config) {
- $scope.loadingMessage = "Failed to load results from '"
- + $scope.resultsToLoad + "'";
+ $scope.loadingMessage = "FAILED to load.";
$scope.windowTitle = "Failed to Load GM Results";
}
);
</a>
</h2>
- <em>
+ <em ng-show="!extraColumnHeaders"><!-- show until data is loaded -->
+ Loading results from <a href="{{resultsToLoad}}">{{resultsToLoad}}</a> ...
{{loadingMessage}}
</em>
</div>
<div ng-show="header[constants.KEY__HEADER__TIME_UPDATED]">
- Results current as of {{localTimeString(header[constants.KEY__HEADER__TIME_UPDATED])}}
+ Results from <a href="{{resultsToLoad}}">{{resultsToLoad}}</a> current as of {{localTimeString(header[constants.KEY__HEADER__TIME_UPDATED])}}
</div>
<div><!-- tabs -->
bugs
</th>
<th width="{{imageSize}}">
- {{imageSets[0][constants.KEY__IMAGESETS__DESCRIPTION]}}
+ {{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_A][constants.KEY__IMAGESETS__FIELD__DESCRIPTION]}}
</th>
<th width="{{imageSize}}">
- {{imageSets[1][constants.KEY__IMAGESETS__DESCRIPTION]}}
+ {{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_B][constants.KEY__IMAGESETS__FIELD__DESCRIPTION]}}
</th>
<th width="{{imageSize}}">
<input type="radio"
<!-- image A -->
<td valign="bottom" width="{{imageSize}}">
<div ng-if="imagePair[constants.KEY__IMAGE_A_URL] != null">
- <a href="{{imageSets[0][constants.KEY__IMAGESETS__BASE_URL]}}/{{imagePair[constants.KEY__IMAGE_A_URL]}}" target="_blank">View Image</a><br/>
+ <a href="{{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_A][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{imagePair[constants.KEY__IMAGE_A_URL]}}" target="_blank">View Image</a><br/>
<img ng-if="showThumbnails"
width="{{imageSize}}"
- src="{{imageSets[0][constants.KEY__IMAGESETS__BASE_URL]}}/{{imagePair[constants.KEY__IMAGE_A_URL]}}" />
+ src="{{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_A][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{imagePair[constants.KEY__IMAGE_A_URL]}}" />
</div>
<div ng-show="imagePair[constants.KEY__IMAGE_A_URL] == null"
style="text-align:center">
<!-- image B -->
<td valign="bottom" width="{{imageSize}}">
<div ng-if="imagePair[constants.KEY__IMAGE_B_URL] != null">
- <a href="{{imageSets[1][constants.KEY__IMAGESETS__BASE_URL]}}/{{imagePair[constants.KEY__IMAGE_B_URL]}}" target="_blank">View Image</a><br/>
+ <a href="{{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_B][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{imagePair[constants.KEY__IMAGE_B_URL]}}" target="_blank">View Image</a><br/>
<img ng-if="showThumbnails"
width="{{imageSize}}"
- src="{{imageSets[1][constants.KEY__IMAGESETS__BASE_URL]}}/{{imagePair[constants.KEY__IMAGE_B_URL]}}" />
+ src="{{imageSets[constants.KEY__IMAGESETS__SET__IMAGE_B][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{imagePair[constants.KEY__IMAGE_B_URL]}}" />
</div>
<div ng-show="imagePair[constants.KEY__IMAGE_B_URL] == null"
style="text-align:center">
{{imagePair[constants.KEY__DIFFERENCE_DATA][constants.KEY__DIFFERENCE_DATA__PERCENT_DIFF_PIXELS].toFixed(4)}}%
({{imagePair[constants.KEY__DIFFERENCE_DATA][constants.KEY__DIFFERENCE_DATA__NUM_DIFF_PIXELS]}})
<br/>
- <a href="/static/generated-images/whitediffs/{{getImageDiffRelativeUrl(imagePair)}}" target="_blank">View Image</a><br/>
+ <a href="{{imageSets[constants.KEY__IMAGESETS__SET__WHITEDIFFS][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{getImageDiffRelativeUrl(imagePair)}}" target="_blank">View Image</a><br/>
<img ng-if="showThumbnails"
width="{{imageSize}}"
- src="/static/generated-images/whitediffs/{{getImageDiffRelativeUrl(imagePair)}}" />
+ src="{{imageSets[constants.KEY__IMAGESETS__SET__WHITEDIFFS][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{getImageDiffRelativeUrl(imagePair)}}" />
</div>
<div ng-show="!imagePair[constants.KEY__IS_DIFFERENT]"
style="text-align:center">
{{imagePair[constants.KEY__DIFFERENCE_DATA][constants.KEY__DIFFERENCE_DATA__PERCEPTUAL_DIFF].toFixed(4)}}%
{{imagePair[constants.KEY__DIFFERENCE_DATA][constants.KEY__DIFFERENCE_DATA__MAX_DIFF_PER_CHANNEL]}}
<br/>
- <a href="/static/generated-images/diffs/{{getImageDiffRelativeUrl(imagePair)}}" target="_blank">View Image</a><br/>
+ <a href="{{imageSets[constants.KEY__IMAGESETS__SET__DIFFS][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{getImageDiffRelativeUrl(imagePair)}}" target="_blank">View Image</a><br/>
<img ng-if="showThumbnails"
ng-style="{backgroundColor: pixelDiffBgColor}"
width="{{imageSize}}"
- src="/static/generated-images/diffs/{{getImageDiffRelativeUrl(imagePair)}}"/>
+ src="{{imageSets[constants.KEY__IMAGESETS__SET__DIFFS][constants.KEY__IMAGESETS__FIELD__BASE_URL]}}/{{getImageDiffRelativeUrl(imagePair)}}" />
</div>
<div ng-show="!imagePair[constants.KEY__IS_DIFFERENT]"
style="text-align:center">
"dataHash": "2099241024256114776",
"isEditable": false,
"isExported": true,
- "schemaVersion": 1,
+ "schemaVersion": 2,
"timeNextUpdateAvailable": null,
"timeUpdated": 12345678,
"type": "all"
"isDifferent": false
}
],
- "imageSets": [
- {
+ "imageSets": {
+ "diffs": {
+ "baseUrl": "/static/generated-images/diffs",
+ "description": "color difference per channel"
+ },
+ "imageA": {
"baseUrl": "http://chromium-skia-gm.commondatastorage.googleapis.com/gm",
"description": "expected image"
},
- {
+ "imageB": {
"baseUrl": "http://chromium-skia-gm.commondatastorage.googleapis.com/gm",
"description": "actual image"
+ },
+ "whiteDiffs": {
+ "baseUrl": "/static/generated-images/whitediffs",
+ "description": "differing pixels in white"
}
- ]
+ }
}
\ No newline at end of file