Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(159)

Unified Diff: tools/skimage_main.cpp

Issue 14670021: Write/compare against expectations in skimage tool. (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Instead of appending a string of potentially infinite length, append a single character. Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « gyp/tools.gyp ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/skimage_main.cpp
diff --git a/tools/skimage_main.cpp b/tools/skimage_main.cpp
index b545af3edb8e67dc1152759fb69498d77c29fbd2..2041f7bbcc5a4991fc81791519b65f4de86ea068 100644
--- a/tools/skimage_main.cpp
+++ b/tools/skimage_main.cpp
@@ -5,7 +5,9 @@
* found in the LICENSE file.
*/
+#include "gm_expectations.h"
#include "SkBitmap.h"
+#include "SkBitmapHasher.h"
#include "SkColorPriv.h"
#include "SkCommandLineFlags.h"
#include "SkData.h"
@@ -18,7 +20,9 @@
#include "SkTArray.h"
#include "SkTemplates.h"
+DEFINE_string(createExpectationsPath, "", "Path to write JSON expectations.");
DEFINE_string2(readPath, r, "", "Folder(s) and files to decode images. Required.");
+DEFINE_string(readExpectationsPath, "", "Path to read JSON expectations from.");
DEFINE_string2(writePath, w, "", "Write rendered images into this directory.");
DEFINE_bool(reencode, true, "Reencode the images to test encoding.");
DEFINE_bool(testSubsetDecoding, true, "Test decoding subsets of images.");
@@ -97,6 +101,10 @@ static SkTArray<SkString, false> gSuccessfulDecodes;
static SkTArray<SkString, false> gSuccessfulSubsetDecodes;
static SkTArray<SkString, false> gFailedSubsetDecodes;
+// Expections read from a file specified by readExpectationsPath. The expectations must have been
+// previously written using createExpectationsPath.
+SkAutoTUnref<skiagm::JsonExpectationsSource> gJsonExpectations;
+
static bool write_bitmap(const char outName[], SkBitmap* bm) {
SkBitmap bitmap8888;
if (SkBitmap::kARGB_8888_Config != bm->config()) {
@@ -157,6 +165,79 @@ static SkIRect generate_random_rect(SkRandom* rand, int32_t maxX, int32_t maxY)
return rect;
}
+// Stored expectations to be written to a file if createExpectationsPath is specified.
+static Json::Value gExpectationsToWrite;
+
+/**
+ * If expectations are to be recorded, record the expected checksum of bitmap into global
+ * expectations array.
+ */
+static void write_expectations(const SkBitmap& bitmap, const char* filename) {
+ if (!FLAGS_createExpectationsPath.isEmpty()) {
+ // Creates an Expectations object, and add it to the list to write.
+ skiagm::Expectations expectation(bitmap);
+ Json::Value value = expectation.asJsonValue();
+ gExpectationsToWrite[filename] = value;
+ }
+}
+
+/**
+ * Return the name of the file, ignoring the directory structure.
+ * Does not create a new string.
+ * @param fullPath Full path to the file.
+ * @return string The basename of the file - anything beyond the final slash, or the full name
+ * if there is no slash.
+ * TODO: Might this be useful as a utility function in SkOSFile? Would it be more appropriate to
+ * create a new string?
+ */
+static const char* SkBasename(const char* fullPath) {
+ const char* filename = strrchr(fullPath, SkPATH_SEPARATOR);
+ if (NULL == filename || ++filename == '\0') {
+ filename = fullPath;
+ }
+ return filename;
+}
+
+/**
+ * Compare against an expectation for this filename, if there is one.
+ * @param bitmap SkBitmap to compare to the expected value.
+ * @param filename String used to find the expected value.
+ * @return bool True if the bitmap matched the expectation, or if there was no expectation. False
+ * if there was an expecation that the bitmap did not match, or if an expectation could not be
+ * computed from an expectation.
+ */
+static bool compare_to_expectations_if_necessary(const SkBitmap& bitmap, const char* filename,
+ SkTArray<SkString, false>* failureArray) {
+ if (NULL == gJsonExpectations.get()) {
+ return true;
+ }
+
+ skiagm::Expectations jsExpectation = gJsonExpectations->get(filename);
+ if (jsExpectation.empty()) {
+ return true;
+ }
+
+ SkHashDigest checksum;
+ if (!SkBitmapHasher::ComputeDigest(bitmap, &checksum)) {
+ if (failureArray != NULL) {
+ failureArray->push_back().printf("decoded %s, but could not create a checksum.",
+ filename);
+ }
+ return false;
+ }
+
+ if (jsExpectation.match(checksum)) {
+ return true;
+ }
+
+ if (failureArray != NULL) {
+ failureArray->push_back().printf("decoded %s, but the result does not match "
+ "expectations.",
+ filename);
+ }
+ return false;
+}
+
static void decodeFileAndWrite(const char srcPath[], const SkString* writePath) {
SkBitmap bitmap;
SkFILEStream stream(srcPath);
@@ -180,7 +261,15 @@ static void decodeFileAndWrite(const char srcPath[], const SkString* writePath)
return;
}
- gSuccessfulDecodes.push_back().printf("%s [%d %d]", srcPath, bitmap.width(), bitmap.height());
+ // Create a string representing just the filename itself, for use in json expectations.
+ const char* filename = SkBasename(srcPath);
+
+ if (compare_to_expectations_if_necessary(bitmap, filename, &gDecodeFailures)) {
+ gSuccessfulDecodes.push_back().printf("%s [%d %d]", srcPath, bitmap.width(),
+ bitmap.height());
+ }
+
+ write_expectations(bitmap, filename);
if (FLAGS_testSubsetDecoding) {
SkDEBUGCODE(bool couldRewind =) stream.rewind();
@@ -199,8 +288,16 @@ static void decodeFileAndWrite(const char srcPath[], const SkString* writePath)
SkString subsetDim = SkStringPrintf("[%d,%d,%d,%d]", rect.fLeft, rect.fTop,
rect.fRight, rect.fBottom);
if (codec->decodeSubset(&bitmapFromDecodeSubset, rect, SkBitmap::kNo_Config)) {
- gSuccessfulSubsetDecodes.push_back().printf("Decoded subset %s from %s",
- subsetDim.c_str(), srcPath);
+ SkString subsetName = SkStringPrintf("%s_%s", filename, subsetDim.c_str());
+ if (compare_to_expectations_if_necessary(bitmapFromDecodeSubset,
+ subsetName.c_str(),
+ &gFailedSubsetDecodes)) {
+ gSuccessfulSubsetDecodes.push_back().printf("Decoded subset %s from %s",
+ subsetDim.c_str(), srcPath);
+ }
+
+ write_expectations(bitmapFromDecodeSubset, subsetName.c_str());
+
if (writePath != NULL) {
// Write the region to a file whose name includes the dimensions.
SkString suffix = SkStringPrintf("_%s.png", subsetDim.c_str());
@@ -322,6 +419,17 @@ static bool print_strings(const char* title, const SkTArray<SkString, false>& st
return false;
}
+/**
+ * If directory is non null and does not end with a path separator, append one.
+ * @param directory SkString representing the path to a directory. If the last character is not a
+ * path separator (specific to the current OS), append one.
+ */
+static void append_path_separator_if_necessary(SkString* directory) {
+ if (directory != NULL && directory->c_str()[directory->size() - 1] != SkPATH_SEPARATOR) {
+ directory->appendf("%c", SkPATH_SEPARATOR);
+ }
+}
+
int tool_main(int argc, char** argv);
int tool_main(int argc, char** argv) {
SkCommandLineFlags::SetUsage("Decode files, and optionally write the results to files.");
@@ -335,14 +443,17 @@ int tool_main(int argc, char** argv) {
SkAutoGraphics ag;
+ if (!FLAGS_readExpectationsPath.isEmpty()) {
+ gJsonExpectations.reset(SkNEW_ARGS(skiagm::JsonExpectationsSource,
+ (FLAGS_readExpectationsPath[0])));
+ }
+
SkString outDir;
SkString* outDirPtr;
if (FLAGS_writePath.count() == 1) {
outDir.set(FLAGS_writePath[0]);
- if (outDir.c_str()[outDir.size() - 1] != '/') {
- outDir.append("/");
- }
+ append_path_separator_if_necessary(&outDir);
outDirPtr = &outDir;
} else {
outDirPtr = NULL;
@@ -356,9 +467,7 @@ int tool_main(int argc, char** argv) {
SkString filename;
if (iter.next(&filename)) {
SkString directory(FLAGS_readPath[i]);
- if (directory[directory.size() - 1] != '/') {
- directory.append("/");
- }
+ append_path_separator_if_necessary(&directory);
do {
SkString fullname(directory);
fullname.append(filename);
@@ -369,6 +478,18 @@ int tool_main(int argc, char** argv) {
}
}
+ if (!FLAGS_createExpectationsPath.isEmpty()) {
+ // Use an empty value for everything besides expectations, since the reader only cares
+ // about the expectations.
+ Json::Value nullValue;
+ Json::Value root = skiagm::CreateJsonTree(gExpectationsToWrite, nullValue, nullValue,
+ nullValue, nullValue);
+ std::string jsonStdString = root.toStyledString();
+ SkString path = SkStringPrintf("%s%cresults.json", FLAGS_createExpectationsPath[0],
+ SkPATH_SEPARATOR);
+ SkFILEWStream stream(path.c_str());
+ stream.write(jsonStdString.c_str(), jsonStdString.length());
+ }
// Add some space, since codecs may print warnings without newline.
SkDebugf("\n\n");
« no previous file with comments | « gyp/tools.gyp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698