OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright 2014 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 * TODO(epoger): Combine this with gm/gm_expectations.cpp, or eliminate one of t
he two. |
| 8 */ |
| 9 |
| 10 #include "SkBitmap.h" |
| 11 #include "SkBitmapHasher.h" |
| 12 #include "SkData.h" |
| 13 #include "SkDataUtils.h" |
| 14 #include "SkJSONCPP.h" |
| 15 #include "SkOSFile.h" |
| 16 #include "SkStream.h" |
| 17 #include "SkTypes.h" |
| 18 |
| 19 #include "image_expectations.h" |
| 20 |
| 21 /* |
| 22 * TODO(epoger): Similar constants are already maintained in 2 other places: |
| 23 * gm/gm_json.py and gm/gm_expectations.cpp. We shouldn't add yet a third place. |
| 24 * Figure out a way to share the definitions instead. |
| 25 * |
| 26 * Note that, as of https://codereview.chromium.org/226293002 , the JSON |
| 27 * schema used here has started to differ from the one in gm_expectations.cpp . |
| 28 * So the best thing to do is, once render_pictures JSON file format has stabili
zed, |
| 29 * change GM over to using this file and remove gm/gm_expectations.cpp. |
| 30 * |
| 31 * TODO(epoger): Make constant strings consistent instead of mixing hypenated an
d camel-caps. |
| 32 */ |
| 33 const static char kJsonKey_ActualResults[] = "actual-results"; |
| 34 const static char kJsonKey_ExpectedResults[] = "expected-results"; |
| 35 const static char kJsonKey_Header[] = "header"; |
| 36 const static char kJsonKey_Header_Type[] = "type"; |
| 37 const static char kJsonKey_Header_Revision[] = "revision"; |
| 38 const static char kJsonKey_Image_ChecksumAlgorithm[] = "checksumAlgorithm"; |
| 39 const static char kJsonKey_Image_ChecksumValue[] = "checksumValue"; |
| 40 const static char kJsonKey_Image_ComparisonResult[] = "comparisonResult"; |
| 41 const static char kJsonKey_Image_Filepath[] = "filepath"; |
| 42 const static char kJsonKey_Image_IgnoreFailure[] = "ignoreFailure"; |
| 43 const static char kJsonKey_Source_TiledImages[] = "tiled-images"; |
| 44 const static char kJsonKey_Source_WholeImage[] = "whole-image"; |
| 45 // Values (not keys) that are written out by this JSON generator |
| 46 const static char kJsonValue_Header_Type[] = "ChecksummedImages"; |
| 47 const static int kJsonValue_Header_Revision = 1; |
| 48 const static char kJsonValue_Image_ChecksumAlgorithm_Bitmap64bitMD5[] = "bitmap-
64bitMD5"; |
| 49 const static char kJsonValue_Image_ComparisonResult_Failed[] = "failed"; |
| 50 const static char kJsonValue_Image_ComparisonResult_FailureIgnored[] = "failure-
ignored"; |
| 51 const static char kJsonValue_Image_ComparisonResult_NoComparison[] = "no-compari
son"; |
| 52 const static char kJsonValue_Image_ComparisonResult_Succeeded[] = "succeeded"; |
| 53 |
| 54 namespace sk_tools { |
| 55 |
| 56 // ImageDigest class... |
| 57 |
| 58 ImageDigest::ImageDigest(const SkBitmap &bitmap) { |
| 59 if (!SkBitmapHasher::ComputeDigest(bitmap, &fHashValue)) { |
| 60 SkFAIL("unable to compute image digest"); |
| 61 } |
| 62 } |
| 63 |
| 64 ImageDigest::ImageDigest(const SkString &hashType, uint64_t hashValue) { |
| 65 if (!hashType.equals(kJsonValue_Image_ChecksumAlgorithm_Bitmap64bitMD5))
{ |
| 66 SkFAIL((SkString("unsupported hashType ")+=hashType).c_str()); |
| 67 } else { |
| 68 fHashValue = hashValue; |
| 69 } |
| 70 } |
| 71 |
| 72 SkString ImageDigest::getHashType() const { |
| 73 // TODO(epoger): The current implementation assumes that the |
| 74 // result digest is always of type kJsonValue_Image_ChecksumAlgorithm_Bi
tmap64bitMD5 . |
| 75 return SkString(kJsonValue_Image_ChecksumAlgorithm_Bitmap64bitMD5); |
| 76 } |
| 77 |
| 78 uint64_t ImageDigest::getHashValue() const { |
| 79 return fHashValue; |
| 80 } |
| 81 |
| 82 // BitmapAndDigest class... |
| 83 |
| 84 BitmapAndDigest::BitmapAndDigest(const SkBitmap &bitmap) : |
| 85 fBitmap(bitmap), fEPOGERImageDigest(bitmap) { |
| 86 } |
| 87 |
| 88 const ImageDigest *BitmapAndDigest::getImageDigestPtr() { |
| 89 return &fEPOGERImageDigest; |
| 90 } |
| 91 |
| 92 const SkBitmap *BitmapAndDigest::getBitmapPtr() const { |
| 93 return &fBitmap; |
| 94 } |
| 95 |
| 96 // ImageResultsSummary class... |
| 97 |
| 98 bool ImageResultsSummary::readExpectationsFile(const char *jsonPath) { |
| 99 if (Parse(jsonPath, &fExpectedJsonRoot)) { |
| 100 fExpectedResults = fExpectedJsonRoot[kJsonKey_ExpectedResults]; |
| 101 return true; |
| 102 } else { |
| 103 return false; |
| 104 } |
| 105 } |
| 106 |
| 107 void ImageResultsSummary::add(const char *sourceName, const char *fileName, |
| 108 const ImageDigest &digest, const int *tileNumb
er) { |
| 109 // Get expectation, if any. |
| 110 Json::Value expectedImage; |
| 111 if (!fExpectedResults.isNull()) { |
| 112 if (NULL == tileNumber) { |
| 113 // EPOGER: before committing, add a unittest to exercise what ha
ppens if |
| 114 // we don't have an expectation for a single sourceName/wholeIma
ge. |
| 115 expectedImage = fExpectedResults[sourceName][kJsonKey_Source_Who
leImage]; |
| 116 } else { |
| 117 // EPOGER: before committing, add a unittest to exercise what ha
ppens if |
| 118 // we don't have an expectation for a single sourceName/tiledIma
ge. |
| 119 expectedImage = fExpectedResults[sourceName][kJsonKey_Source_Til
edImages] |
| 120 [*tileNumber]; |
| 121 } |
| 122 } |
| 123 |
| 124 // Fill in info about the actual result itself. |
| 125 Json::Value actualChecksumAlgorithm = digest.getHashType().c_str(); |
| 126 Json::Value actualChecksumValue = Json::UInt64(digest.getHashValue()); |
| 127 Json::Value actualImage; |
| 128 actualImage[kJsonKey_Image_ChecksumAlgorithm] = actualChecksumAlgorithm; |
| 129 actualImage[kJsonKey_Image_ChecksumValue] = actualChecksumValue; |
| 130 actualImage[kJsonKey_Image_Filepath] = fileName; |
| 131 |
| 132 // Compare against expectedImage to fill in comparisonResult. |
| 133 Json::Value comparisonResult = kJsonValue_Image_ComparisonResult_NoCompa
rison; |
| 134 if (!expectedImage.isNull()) { |
| 135 if ((actualChecksumAlgorithm == expectedImage[kJsonKey_Image_Checksu
mAlgorithm]) && |
| 136 (actualChecksumValue == expectedImage[kJsonKey_Image_ChecksumVal
ue])) { |
| 137 comparisonResult = kJsonValue_Image_ComparisonResult_Succeeded; |
| 138 } else if (expectedImage[kJsonKey_Image_IgnoreFailure] == true) { |
| 139 comparisonResult = kJsonValue_Image_ComparisonResult_FailureIgno
red; |
| 140 } else { |
| 141 comparisonResult = kJsonValue_Image_ComparisonResult_Failed; |
| 142 } |
| 143 } |
| 144 actualImage[kJsonKey_Image_ComparisonResult] = comparisonResult; |
| 145 |
| 146 // Add this actual result to our collection. |
| 147 if (NULL == tileNumber) { |
| 148 fActualResults[sourceName][kJsonKey_Source_WholeImage] = actualImage
; |
| 149 } else { |
| 150 fActualResults[sourceName][kJsonKey_Source_TiledImages][*tileNumber]
= actualImage; |
| 151 } |
| 152 } |
| 153 |
| 154 void ImageResultsSummary::writeToFile(const char *filename) const { |
| 155 Json::Value header; |
| 156 header[kJsonKey_Header_Type] = kJsonValue_Header_Type; |
| 157 header[kJsonKey_Header_Revision] = kJsonValue_Header_Revision; |
| 158 Json::Value root; |
| 159 root[kJsonKey_Header] = header; |
| 160 root[kJsonKey_ActualResults] = fActualResults; |
| 161 std::string jsonStdString = root.toStyledString(); |
| 162 SkFILEWStream stream(filename); |
| 163 stream.write(jsonStdString.c_str(), jsonStdString.length()); |
| 164 } |
| 165 |
| 166 /*static*/ bool ImageResultsSummary::Parse(const char *jsonPath, Json::Value
*jsonRoot) { |
| 167 SkFILEStream inFile(jsonPath); |
| 168 if (!inFile.isValid()) { |
| 169 SkDebugf("unable to read JSON file %s\n", jsonPath); |
| 170 return false; |
| 171 } |
| 172 |
| 173 SkAutoDataUnref dataRef(SkDataUtils::ReadFileIntoSkData(inFile)); |
| 174 if (NULL == dataRef.get()) { |
| 175 SkDebugf("error reading JSON file %s\n", jsonPath); |
| 176 return false; |
| 177 } |
| 178 |
| 179 const char *bytes = reinterpret_cast<const char *>(dataRef.get()->data()
); |
| 180 size_t size = dataRef.get()->size(); |
| 181 Json::Reader reader; |
| 182 if (!reader.parse(bytes, bytes+size, *jsonRoot)) { |
| 183 SkDebugf("error parsing JSON file %s\n", jsonPath); |
| 184 return false; |
| 185 } |
| 186 |
| 187 return true; |
| 188 } |
| 189 |
| 190 } // namespace sk_tools |
OLD | NEW |