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

Unified Diff: tools/skimage_main.cpp

Issue 26297004: More work to integrate skimage with rebaseline tools. (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Rebase Created 7 years, 2 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 | « tools/rebaseline.py ('k') | tools/tests/skimage/input/bad-images/empty-results.json » ('j') | 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 5b8f09548535069b5f8c347cb12c1b24992bbd82..f5a2b3d738a6dce5709a8bbd8525849e5e364fcd 100644
--- a/tools/skimage_main.cpp
+++ b/tools/skimage_main.cpp
@@ -31,6 +31,8 @@ DEFINE_bool(reencode, true, "Reencode the images to test encoding.");
DEFINE_int32(sampleSize, 1, "Set the sampleSize for decoding.");
DEFINE_bool(skip, false, "Skip writing zeroes.");
DEFINE_bool(testSubsetDecoding, true, "Test decoding subsets of images.");
+DEFINE_bool(writeChecksumBasedFilenames, false, "When writing out actual images, use checksum-"
+ "based filenames, as rebaseline.py will use when downloading them from Google Storage");
DEFINE_string2(writePath, w, "", "Write rendered images into this directory.");
struct Format {
@@ -80,15 +82,7 @@ static void make_outname(SkString* dst, const char outDir[], const char src[],
const char suffix[]) {
SkString basename = SkOSPath::SkBasename(src);
dst->set(SkOSPath::SkPathJoin(outDir, basename.c_str()));
- if (!dst->endsWith(suffix)) {
- const char* cstyleDst = dst->c_str();
- const char* dot = strrchr(cstyleDst, '.');
- if (dot != NULL) {
- int32_t index = SkToS32(dot - cstyleDst);
- dst->remove(index, dst->size() - index);
- }
- dst->append(suffix);
- }
+ dst->append(suffix);
}
// Store the names of the filenames to report later which ones failed, succeeded, and were
@@ -129,8 +123,44 @@ static SkBitmap::Config gPrefConfig(SkBitmap::kNo_Config);
// previously written using createExpectationsPath.
SkAutoTUnref<skiagm::JsonExpectationsSource> gJsonExpectations;
-static bool write_bitmap(const char outName[], const SkBitmap& bm) {
- if (SkImageEncoder::EncodeFile(outName, bm, SkImageEncoder::kPNG_Type, 100)) {
+/**
+ * Encode the bitmap to a file, written one of two ways, depending on
+ * FLAGS_writeChecksumBasedFilenames. If true, the final image will be
+ * written to:
+ * outDir/hashType/src/digestValue.png
+ * If false, the final image will be written out to:
+ * outDir/src.png
+ * The function returns whether the file was successfully written.
+ */
+static bool write_bitmap(const char outDir[], const char src[],
+ const skiagm::BitmapAndDigest& bitmapAndDigest) {
+ SkString filename;
+ if (FLAGS_writeChecksumBasedFilenames) {
+ // First create the directory for the hashtype.
+ const SkString hashType = bitmapAndDigest.fDigest.getHashType();
+ const SkString hashDir = SkOSPath::SkPathJoin(outDir, hashType.c_str());
+ if (!sk_mkdir(hashDir.c_str())) {
+ return false;
+ }
+
+ // Now create the name of the folder specific to this image.
+ SkString basename = SkOSPath::SkBasename(src);
+ const SkString imageDir = SkOSPath::SkPathJoin(hashDir.c_str(), basename.c_str());
+ if (!sk_mkdir(imageDir.c_str())) {
+ return false;
+ }
+
+ // Name the file <digest>.png
+ SkString checksumBasedName = bitmapAndDigest.fDigest.getDigestValue();
+ checksumBasedName.append(".png");
+
+ filename = SkOSPath::SkPathJoin(imageDir.c_str(), checksumBasedName.c_str());
+ } else {
+ make_outname(&filename, outDir, src, ".png");
+ }
+
+ const SkBitmap& bm = bitmapAndDigest.fBitmap;
+ if (SkImageEncoder::EncodeFile(filename.c_str(), bm, SkImageEncoder::kPNG_Type, 100)) {
return true;
}
@@ -145,7 +175,7 @@ static bool write_bitmap(const char outName[], const SkBitmap& bm) {
if (!bm.copyTo(&bm8888, SkBitmap::kARGB_8888_Config)) {
return false;
}
- return SkImageEncoder::EncodeFile(outName, bm8888, SkImageEncoder::kPNG_Type, 100);
+ return SkImageEncoder::EncodeFile(filename.c_str(), bm8888, SkImageEncoder::kPNG_Type, 100);
}
/**
@@ -189,27 +219,47 @@ static SkIRect generate_random_rect(SkRandom* rand, int32_t maxX, int32_t maxY)
return rect;
}
+/**
+ * Return a string which includes the name of the file and the preferred config,
+ * as specified by "--config". The resulting string will match the pattern of
+ * gm_json.py's IMAGE_FILENAME_PATTERN: "filename_config.png"
+ */
+static SkString create_json_key(const char* filename) {
+ SkASSERT(FLAGS_config.count() == 1);
+ return SkStringPrintf("%s_%s.png", filename, FLAGS_config[0]);
+}
+
// Stored expectations to be written to a file if createExpectationsPath is specified.
static Json::Value gExpectationsToWrite;
/**
- * If expectations are to be recorded, record the bitmap expectations into global
+ * If expectations are to be recorded, record the bitmap expectations into the global
* expectations array.
+ * As is the case with reading expectations, the key used will combine the filename
+ * parameter with the preferred config, as specified by "--config", matching the
+ * pattern of gm_json.py's IMAGE_FILENAME_PATTERN: "filename_config.png"
*/
-static void write_expectations(const SkBitmap& bitmap, const char* filename) {
+static void write_expectations(const skiagm::BitmapAndDigest& bitmapAndDigest,
+ const char* filename) {
+ const SkString name_config = create_json_key(filename);
if (!FLAGS_createExpectationsPath.isEmpty()) {
// Creates an Expectations object, and add it to the list to write.
- skiagm::Expectations expectation(bitmap);
+ skiagm::Expectations expectation(bitmapAndDigest);
Json::Value value = expectation.asJsonValue();
- gExpectationsToWrite[filename] = value;
+ gExpectationsToWrite[name_config.c_str()] = value;
}
}
/**
- * Compare against an expectation for this filename, if there is one.
- * @param digest GmResultDigest, computed from the decoded bitmap, to compare to the
- * expectation.
- * @param filename String used to find the expected value.
+ * If --readExpectationsPath is set, compare this bitmap to the json expectations
+ * provided.
+ *
+ * @param digest GmResultDigest, computed from the decoded bitmap, to compare to
+ * the existing expectation.
+ * @param filename String used to find the expected value. Will be combined with the
+ * preferred config, as specified by "--config", to match the pattern of
+ * gm_json.py's IMAGE_FILENAME_PATTERN: "filename_config.png". The resulting
+ * key will be used to find the proper expectations.
* @param failureArray Array to add a failure message to on failure.
* @param missingArray Array to add failure message to when missing image
* expectation.
@@ -228,6 +278,11 @@ static bool compare_to_expectations_if_necessary(const skiagm::GmResultDigest& d
SkTArray<SkString, false>* failureArray,
SkTArray<SkString, false>* missingArray,
SkTArray<SkString, false>* ignoreArray) {
+ // For both writing and reading, the key for this entry will include the name
+ // of the file and the pref config, matching the pattern of gm_json.py's
+ // IMAGE_FILENAME_PATTERN: "name_config.png"
+ const SkString name_config = create_json_key(filename);
+
if (!digest.isValid()) {
if (failureArray != NULL) {
failureArray->push_back().printf("decoded %s, but could not create a GmResultDigest.",
@@ -240,7 +295,7 @@ static bool compare_to_expectations_if_necessary(const skiagm::GmResultDigest& d
return false;
}
- skiagm::Expectations jsExpectation = gJsonExpectations->get(filename);
+ skiagm::Expectations jsExpectation = gJsonExpectations->get(name_config.c_str());
if (jsExpectation.empty()) {
if (missingArray != NULL) {
missingArray->push_back().printf("decoded %s, but could not find expectation.",
@@ -266,72 +321,83 @@ static bool compare_to_expectations_if_necessary(const skiagm::GmResultDigest& d
/**
* Helper function to write a bitmap subset to a file. Only called if subsets were created
- * and a writePath was provided. Creates a subdirectory called 'subsets' and writes a PNG to
- * that directory. Also creates a subdirectory called 'extracted' and writes a bitmap created
- * using extractSubset to a PNG in that directory. Both files will represent the same
- * subrectangle and have the same name for comparison.
+ * and a writePath was provided. Behaves differently depending on
+ * FLAGS_writeChecksumBasedFilenames. If true:
+ * Writes the image to a PNG file named according to the digest hash, as described in
+ * write_bitmap.
+ * If false:
+ * Creates a subdirectory called 'subsets' and writes a PNG to that directory. Also
+ * creates a subdirectory called 'extracted' and writes a bitmap created using
+ * extractSubset to a PNG in that directory. Both files will represent the same
+ * subrectangle and have the same name for convenient comparison. In this case, the
+ * digest is ignored.
+ *
* @param writePath Parent directory to hold the folders for the PNG files to write. Must
* not be NULL.
- * @param filename Basename of the original file. Used to name the new files. Must not be
- * NULL.
- * @param subsetDim String representing the dimensions of the subset. Used to name the new
- * files. Must not be NULL.
- * @param bitmapFromDecodeSubset Pointer to SkBitmap created by SkImageDecoder::DecodeSubset,
- * using rect as the area to decode.
+ * @param subsetName Basename of the original file, with the dimensions of the subset tacked
+ * on. Used to name the new file/folder.
+ * @param bitmapAndDigestFromDecodeSubset SkBitmap (with digest) created by
+ * SkImageDecoder::DecodeSubset, using rect as the area to decode.
* @param rect Rectangle of the area decoded into bitmapFromDecodeSubset. Used to call
* extractSubset on originalBitmap to create a bitmap with the same dimensions/pixels as
* bitmapFromDecodeSubset (assuming decodeSubset worked properly).
* @param originalBitmap SkBitmap decoded from the same stream as bitmapFromDecodeSubset,
* using SkImageDecoder::decode to get the entire image. Used to create a PNG file for
- * comparison to the PNG created by bitmapFromDecodeSubset.
+ * comparison to the PNG created by bitmapAndDigestFromDecodeSubset's bitmap.
* @return bool Whether the function succeeded at drawing the decoded subset and the extracted
* subset to files.
*/
-static bool write_subset(const char* writePath, const char* filename, const char* subsetDim,
- SkBitmap* bitmapFromDecodeSubset, SkIRect rect,
- const SkBitmap& originalBitmap) {
+static bool write_subset(const char* writePath, const SkString& subsetName,
+ const skiagm::BitmapAndDigest bitmapAndDigestFromDecodeSubset,
+ SkIRect rect, const SkBitmap& originalBitmap) {
// All parameters must be valid.
SkASSERT(writePath != NULL);
- SkASSERT(filename != NULL);
- SkASSERT(subsetDim != NULL);
- SkASSERT(bitmapFromDecodeSubset != NULL);
-
- // Create a subdirectory to hold the results of decodeSubset.
- SkString dir = SkOSPath::SkPathJoin(writePath, "subsets");
- if (!sk_mkdir(dir.c_str())) {
- gFailedSubsetDecodes.push_back().printf("Successfully decoded %s from %s, but failed to "
- "create a directory to write to.", subsetDim,
- filename);
- return false;
- }
- // Write the subset to a file whose name includes the dimensions.
- SkString suffix = SkStringPrintf("_%s.png", subsetDim);
- SkString outPath;
- make_outname(&outPath, dir.c_str(), filename, suffix.c_str());
- SkAssertResult(write_bitmap(outPath.c_str(), *bitmapFromDecodeSubset));
- gSuccessfulSubsetDecodes.push_back().printf("\twrote %s", outPath.c_str());
-
- // Also use extractSubset from the original for visual comparison.
- // Write the result to a file in a separate subdirectory.
- SkBitmap extractedSubset;
- if (!originalBitmap.extractSubset(&extractedSubset, rect)) {
- gFailedSubsetDecodes.push_back().printf("Successfully decoded %s from %s, but failed to "
- "extract a similar subset for comparison.",
- subsetDim, filename);
- return false;
+ SkString subsetPath;
+ if (FLAGS_writeChecksumBasedFilenames) {
+ subsetPath.set(writePath);
+ } else {
+ // Create a subdirectory to hold the results of decodeSubset.
+ subsetPath = SkOSPath::SkPathJoin(writePath, "subsets");
+ if (!sk_mkdir(subsetPath.c_str())) {
+ gFailedSubsetDecodes.push_back().printf("Successfully decoded subset %s, but "
+ "failed to create a directory to write to.",
+ subsetName.c_str());
+ return false;
+ }
}
+ SkAssertResult(write_bitmap(subsetPath.c_str(), subsetName.c_str(),
+ bitmapAndDigestFromDecodeSubset));
+ gSuccessfulSubsetDecodes.push_back().printf("\twrote %s", subsetName.c_str());
+
+ if (!FLAGS_writeChecksumBasedFilenames) {
+ // FIXME: The goal of extracting the subset is for visual comparison/using skdiff/skpdiff.
+ // Currently disabling for writeChecksumBasedFilenames since it will be trickier to
+ // determine which files to compare.
+
+ // Also use extractSubset from the original for visual comparison.
+ // Write the result to a file in a separate subdirectory.
+ SkBitmap extractedSubset;
+ if (!originalBitmap.extractSubset(&extractedSubset, rect)) {
+ gFailedSubsetDecodes.push_back().printf("Successfully decoded subset %s, but failed "
+ "to extract a similar subset for comparison.",
+ subsetName.c_str());
+ return false;
+ }
- SkString dirExtracted = SkOSPath::SkPathJoin(writePath, "extracted");
- if (!sk_mkdir(dirExtracted.c_str())) {
- gFailedSubsetDecodes.push_back().printf("Successfully decoded %s from %s, but failed to "
- "create a directory for extractSubset comparison.",
- subsetDim, filename);
- return false;
- }
+ SkString dirExtracted = SkOSPath::SkPathJoin(writePath, "extracted");
+ if (!sk_mkdir(dirExtracted.c_str())) {
+ gFailedSubsetDecodes.push_back().printf("Successfully decoded subset%s, but failed "
+ "to create a directory for extractSubset "
+ "comparison.",
+ subsetName.c_str());
+ return false;
+ }
- make_outname(&outPath, dirExtracted.c_str(), filename, suffix.c_str());
- SkAssertResult(write_bitmap(outPath.c_str(), extractedSubset));
+ skiagm::BitmapAndDigest bitmapAndDigestFromExtractSubset(extractedSubset);
+ SkAssertResult(write_bitmap(dirExtracted.c_str(), subsetName.c_str(),
+ bitmapAndDigestFromExtractSubset));
+ }
return true;
}
@@ -397,6 +463,21 @@ static void test_stream_without_length(const char srcPath[], SkImageDecoder* cod
}
#endif // defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX)
+/**
+ * Replace all instances of oldChar with newChar in str.
+ * TODO: Add this function to SkString and write tests for it.
+ */
+static void replace_char(SkString* str, const char oldChar, const char newChar) {
+ if (NULL == str) {
+ return;
+ }
+ for (size_t i = 0; i < str->size(); ++i) {
+ if (oldChar == str->operator[](i)) {
+ str->operator[](i) = newChar;
+ }
+ }
+}
+
static void decodeFileAndWrite(const char srcPath[], const SkString* writePath) {
SkBitmap bitmap;
SkFILEStream stream(srcPath);
@@ -419,12 +500,18 @@ static void decodeFileAndWrite(const char srcPath[], const SkString* writePath)
// Create a string representing just the filename itself, for use in json expectations.
SkString basename = SkOSPath::SkBasename(srcPath);
+ // Replace '_' with '-', so that the names can fit gm_json.py's IMAGE_FILENAME_PATTERN
+ replace_char(&basename, '_', '-');
+ // Replace '.' with '-', so the output filename can still retain the original file extension,
+ // but still end up with only one '.', which denotes the actual extension of the final file.
+ replace_char(&basename, '.', '-');
const char* filename = basename.c_str();
if (!codec->decode(&stream, &bitmap, gPrefConfig,
SkImageDecoder::kDecodePixels_Mode)) {
if (NULL != gJsonExpectations.get()) {
- skiagm::Expectations jsExpectations = gJsonExpectations->get(filename);
+ const SkString name_config = create_json_key(filename);
+ skiagm::Expectations jsExpectations = gJsonExpectations->get(name_config.c_str());
if (jsExpectations.ignoreFailure()) {
// This is a known failure.
gKnownFailures.push_back().appendf(
@@ -462,40 +549,34 @@ static void decodeFileAndWrite(const char srcPath[], const SkString* writePath)
}
}
- skiagm::GmResultDigest digest(bitmap);
- if (compare_to_expectations_if_necessary(digest, filename,
- &gDecodeFailures,
- &gMissingExpectations,
- &gKnownFailures)) {
+ skiagm::BitmapAndDigest bitmapAndDigest(bitmap);
+ if (compare_to_expectations_if_necessary(bitmapAndDigest.fDigest, filename, &gDecodeFailures,
+ &gMissingExpectations, &gKnownFailures)) {
gSuccessfulDecodes.push_back().printf("%s [%d %d]", srcPath, bitmap.width(),
bitmap.height());
} else if (!FLAGS_mismatchPath.isEmpty()) {
- SkString outPath;
- make_outname(&outPath, FLAGS_mismatchPath[0], srcPath, ".png");
- if (write_bitmap(outPath.c_str(), bitmap)) {
- gSuccessfulDecodes.push_back().appendf("\twrote %s", outPath.c_str());
+ if (write_bitmap(FLAGS_mismatchPath[0], filename, bitmapAndDigest)) {
+ gSuccessfulDecodes.push_back().appendf("\twrote %s", filename);
} else {
- gEncodeFailures.push_back().set(outPath);
+ gEncodeFailures.push_back().set(filename);
}
}
// FIXME: This test could be run on windows/mac once we remove their dependence on
// getLength. See https://code.google.com/p/skia/issues/detail?id=1570
#if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX)
- test_stream_without_length(srcPath, codec, digest);
+ test_stream_without_length(srcPath, codec, bitmapAndDigest.fDigest);
#endif
if (writePath != NULL) {
- SkString outPath;
- make_outname(&outPath, writePath->c_str(), srcPath, ".png");
- if (write_bitmap(outPath.c_str(), bitmap)) {
- gSuccessfulDecodes.push_back().appendf("\twrote %s", outPath.c_str());
+ if (write_bitmap(writePath->c_str(), filename, bitmapAndDigest)) {
+ gSuccessfulDecodes.push_back().appendf("\twrote %s", filename);
} else {
- gEncodeFailures.push_back().set(outPath);
+ gEncodeFailures.push_back().set(filename);
}
}
- write_expectations(bitmap, filename);
+ write_expectations(bitmapAndDigest, filename);
if (FLAGS_testSubsetDecoding) {
SkDEBUGCODE(bool couldRewind =) stream.rewind();
@@ -514,9 +595,9 @@ 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, gPrefConfig)) {
- SkString subsetName = SkStringPrintf("%s_%s", filename, subsetDim.c_str());
- skiagm::GmResultDigest subsetDigest(bitmapFromDecodeSubset);
- if (compare_to_expectations_if_necessary(subsetDigest,
+ SkString subsetName = SkStringPrintf("%s-%s", filename, subsetDim.c_str());
+ skiagm::BitmapAndDigest subsetBitmapAndDigest(bitmapFromDecodeSubset);
+ if (compare_to_expectations_if_necessary(subsetBitmapAndDigest.fDigest,
subsetName.c_str(),
&gFailedSubsetDecodes,
&gMissingSubsetExpectations,
@@ -524,14 +605,15 @@ static void decodeFileAndWrite(const char srcPath[], const SkString* writePath)
gSuccessfulSubsetDecodes.push_back().printf("Decoded subset %s from %s",
subsetDim.c_str(), srcPath);
} else if (!FLAGS_mismatchPath.isEmpty()) {
- write_subset(FLAGS_mismatchPath[0], filename, subsetDim.c_str(),
- &bitmapFromDecodeSubset, rect, bitmap);
+ write_subset(FLAGS_mismatchPath[0], subsetName,
+ subsetBitmapAndDigest, rect, bitmap);
}
- write_expectations(bitmapFromDecodeSubset, subsetName.c_str());
+ write_expectations(subsetBitmapAndDigest, subsetName.c_str());
+
if (writePath != NULL) {
- write_subset(writePath->c_str(), filename, subsetDim.c_str(),
- &bitmapFromDecodeSubset, rect, bitmap);
+ write_subset(writePath->c_str(), subsetName,
+ subsetBitmapAndDigest, rect, bitmap);
}
} else {
gFailedSubsetDecodes.push_back().printf("Failed to decode region %s from %s",
@@ -587,7 +669,7 @@ static void decodeFileAndWrite(const char srcPath[], const SkString* writePath)
if (writePath != NULL && type != SkImageEncoder::kPNG_Type) {
// Write the encoded data to a file. Do not write to PNG, which was already written.
SkString outPath;
- make_outname(&outPath, writePath->c_str(), srcPath, suffix_for_type(type));
+ make_outname(&outPath, writePath->c_str(), filename, suffix_for_type(type));
SkFILEWStream file(outPath.c_str());
if(file.write(data->data(), data->size())) {
gSuccessfulDecodes.push_back().appendf("\twrote %s", outPath.c_str());
« no previous file with comments | « tools/rebaseline.py ('k') | tools/tests/skimage/input/bad-images/empty-results.json » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698