| 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");
|
|
|
|
|