1 /* 2 * Copyright 2013 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef SkDiffContext_DEFINED 9 #define SkDiffContext_DEFINED 10 11 #include "SkImageDiffer.h" 12 #include "SkString.h" 13 #include "SkTArray.h" 14 #include "SkTDArray.h" 15 #include "SkTLList.h" 16 #include "SkThread.h" 17 18 class SkWStream; 19 20 /** 21 * Collects records of diffs and outputs them as JSON. 22 */ 23 class SkDiffContext { 24 public: 25 SkDiffContext(); 26 ~SkDiffContext(); 27 setThreadCount(int threadCount)28 void setThreadCount(int threadCount) { fThreadCount = threadCount; } 29 30 /** 31 * Sets the directory within which to store alphaMasks (images that 32 * are transparent for each pixel that differs between baseline and test). 33 * 34 * If the directory does not exist yet, it will be created. 35 */ 36 void setAlphaMaskDir(const SkString& directory); 37 38 /** 39 * Sets the directory within which to store rgbDiffs (images showing the 40 * per-channel difference between baseline and test at each pixel). 41 * 42 * If the directory does not exist yet, it will be created. 43 */ 44 void setRgbDiffDir(const SkString& directory); 45 46 /** 47 * Sets the directory within which to store whiteDiffs (images showing white 48 * for each pixel that differs between baseline and test). 49 * 50 * If the directory does not exist yet, it will be created. 51 */ 52 void setWhiteDiffDir(const SkString& directory); 53 54 /** 55 * Modify the pattern used to generate commonName (= the 56 * basename of rgb/white diff files). 57 * 58 * - true: basename is a combination of the input file names. 59 * - false: basename is the common prefix of the input file names. 60 * 61 * For example, for: 62 * baselinePath=/tmp/dir/image-before.png 63 * testPath=/tmp/dir/image-after.png 64 * 65 * If setLongNames(true), commonName would be: 66 * image-before-png-vs-image-after-png.png 67 * 68 * If setLongNames(false), commonName would be: 69 * image-.png 70 */ 71 void setLongNames(const bool useLongNames); 72 73 /** 74 * Sets the differs to be used in each diff. Already started diffs will not retroactively use 75 * these. 76 * @param differs An array of differs to use. The array is copied, but not the differs 77 * themselves. 78 */ 79 void setDiffers(const SkTDArray<SkImageDiffer*>& differs); 80 81 /** 82 * Compares two directories of images with the given differ 83 * @param baselinePath The baseline directory's path 84 * @param testPath The test directory's path 85 */ 86 void diffDirectories(const char baselinePath[], const char testPath[]); 87 88 /** 89 * Compares two sets of images identified by glob style patterns with the given differ 90 * @param baselinePattern A pattern for baseline files 91 * @param testPattern A pattern for test files that matches each file of the baseline file 92 */ 93 void diffPatterns(const char baselinePattern[], const char testPattern[]); 94 95 /** 96 * Compares the images at the given paths 97 * @param baselinePath The baseline file path 98 * @param testPath The matching test file path 99 */ 100 void addDiff(const char* baselinePath, const char* testPath); 101 102 /** 103 * Output the records of each diff in JSON. 104 * 105 * The format of the JSON document is one top level array named "records". 106 * Each record in the array is an object with the following values: 107 * "commonName" : string containing the output filename (basename) 108 * depending on the value of 'longNames'. 109 * (see 'setLongNames' for an explanation and example). 110 * "baselinePath" : string containing the path to the baseline image 111 * "testPath" : string containing the path to the test image 112 * "differencePath" : (optional) string containing the path to an alpha 113 * mask of the pixel difference between the baseline 114 * and test images 115 * TODO(epoger): consider renaming this "alphaMaskPath" 116 * to distinguish from other difference types? 117 * "rgbDiffPath" : (optional) string containing the path to a bitmap 118 * showing per-channel differences between the 119 * baseline and test images at each pixel 120 * "whiteDiffPath" : (optional) string containing the path to a bitmap 121 * showing every pixel that differs between the 122 * baseline and test images as white 123 * 124 * They also have an array named "diffs" with each element being one diff record for the two 125 * images indicated in the above field. 126 * A diff record includes: 127 * "differName" : string name of the diff metric used 128 * "result" : numerical result of the diff 129 * 130 * Here is an example: 131 * 132 * { 133 * "records": [ 134 * { 135 * "commonName": "queue.png", 136 * "baselinePath": "/a/queue.png", 137 * "testPath": "/b/queue.png", 138 * "diffs": [ 139 * { 140 * "differName": "different_pixels", 141 * "result": 1, 142 * } 143 * ] 144 * } 145 * ] 146 * } 147 * 148 * @param stream The stream to output the diff to 149 * @param useJSONP True to adding padding to the JSON output to make it cross-site requestable. 150 */ 151 void outputRecords(SkWStream& stream, bool useJSONP); 152 153 /** 154 * Output the records score in csv format. 155 */ 156 void outputCsv(SkWStream& stream); 157 158 159 private: 160 struct DiffData { 161 const char* fDiffName; 162 SkImageDiffer::Result fResult; 163 }; 164 165 struct DiffRecord { 166 // TODO(djsollen): Some of these fields are required, while others are optional 167 // (e.g., fRgbDiffPath is only filled in if SkDifferentPixelsMetric 168 // was run). Figure out a way to note that. See http://skbug.com/2712 169 // ('allow skpdiff to report different sets of result fields for 170 // different comparison algorithms') 171 SkString fCommonName; 172 SkString fAlphaMaskPath; 173 SkString fRgbDiffPath; 174 SkString fWhiteDiffPath; 175 SkString fBaselinePath; 176 SkString fTestPath; 177 SkISize fSize; 178 int fMaxRedDiff; 179 int fMaxGreenDiff; 180 int fMaxBlueDiff; 181 SkTArray<DiffData> fDiffs; 182 }; 183 184 // Used to protect access to fRecords and ensure only one thread is 185 // adding new entries at a time. 186 SkMutex fRecordMutex; 187 188 // We use linked list for the records so that their pointers remain stable. A resizable array 189 // might change its pointers, which would make it harder for async diffs to record their 190 // results. 191 SkTLList<DiffRecord> fRecords; 192 193 SkImageDiffer** fDiffers; 194 int fDifferCount; 195 int fThreadCount; 196 197 SkString fAlphaMaskDir; 198 SkString fRgbDiffDir; 199 SkString fWhiteDiffDir; 200 bool longNames; 201 }; 202 203 #endif 204