Test decoding and output failures to JSON in get_images_from_skps.

Testing for decoding was copy pasted from msarett's CL https://codereview.chromium.org/1828323002/

BUG=skia:4981
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1844713003

Review URL: https://codereview.chromium.org/1844713003
diff --git a/gyp/tools.gyp b/gyp/tools.gyp
index cd92233..1f38ef8 100644
--- a/gyp/tools.gyp
+++ b/gyp/tools.gyp
@@ -278,6 +278,7 @@
       ],
       'dependencies': [
         'flags.gyp:flags',
+        'jsoncpp.gyp:jsoncpp',
         'skia_lib.gyp:skia_lib',
       ],
     },
diff --git a/tools/get_images_from_skps.cpp b/tools/get_images_from_skps.cpp
index e6bb6e2..f963b9a 100644
--- a/tools/get_images_from_skps.cpp
+++ b/tools/get_images_from_skps.cpp
@@ -5,9 +5,11 @@
  * found in the LICENSE file.
  */
 
+#include "SkBitmap.h"
 #include "SkCodec.h"
 #include "SkCommandLineFlags.h"
 #include "SkData.h"
+#include "SkJSONCPP.h"
 #include "SkMD5.h"
 #include "SkOSFile.h"
 #include "SkPicture.h"
@@ -15,17 +17,31 @@
 #include "SkStream.h"
 #include "SkTHash.h"
 
+
+#include <map>
+
 DEFINE_string2(skps, s, "skps", "A path to a directory of skps.");
 DEFINE_string2(out, o, "img-out", "A path to an output directory.");
+DEFINE_bool(testDecode, false, "Indicates if we want to test that the images decode successfully.");
+DEFINE_bool(writeImages, true, "Indicates if we want to write out images.");
+DEFINE_string2(failuresJsonPath, j, "",
+               "Dump SKP and count of unknown images to the specified JSON file. Will not be "
+               "written anywhere if empty.");
 
 static int gKnown;
-static int gUnknown;
 static const char* gOutputDir;
+static std::map<std::string, unsigned int> gSkpToUnknownCount = {};
 
 static SkTHashSet<SkMD5::Digest> gSeen;
 
 struct Sniffer : public SkPixelSerializer {
 
+    std::string skpName;
+
+    Sniffer(std::string name) {
+        skpName = name;
+    }
+
     void sniff(const void* ptr, size_t len) {
         SkMD5 md5;
         md5.write(ptr, len);
@@ -40,7 +56,10 @@
         SkAutoTUnref<SkData> data(SkData::NewWithoutCopy(ptr, len));
         SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(data));
         if (!codec) {
-            gUnknown++;
+            // FIXME: This code is currently unreachable because we create an empty generator when
+            //        we fail to create a codec.
+            SkDebugf("Codec could not be created for %s\n", skpName.c_str());
+            gSkpToUnknownCount[skpName]++;
             return;
         }
         SkString ext;
@@ -53,16 +72,34 @@
             case SkEncodedFormat::kDNG_SkEncodedFormat:  ext =  "dng"; break;
             case SkEncodedFormat::kWBMP_SkEncodedFormat: ext = "wbmp"; break;
             case SkEncodedFormat::kWEBP_SkEncodedFormat: ext = "webp"; break;
-            default: gUnknown++; return;
+            default:
+                // This should be unreachable because we cannot create a codec if we do not know
+                // the image type.
+                SkASSERT(false);
         }
 
-        SkString path;
-        path.appendf("%s/%d.%s", gOutputDir, gKnown++, ext.c_str());
+        if (FLAGS_testDecode) {
+            SkBitmap bitmap;
+            SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType);
+            bitmap.allocPixels(info);
+            if (SkCodec::kSuccess != codec->getPixels(info, bitmap.getPixels(),  bitmap.rowBytes()))
+            {
+                SkDebugf("Decoding failed for %s\n", skpName.c_str());
+                gSkpToUnknownCount[skpName]++;
+                return;
+            }
+        }
 
-        SkFILEWStream file(path.c_str());
-        file.write(ptr, len);
+        if (FLAGS_writeImages) {
+            SkString path;
+            path.appendf("%s/%d.%s", gOutputDir, gKnown, ext.c_str());
 
-        SkDebugf("%s\n", path.c_str());
+            SkFILEWStream file(path.c_str());
+            file.write(ptr, len);
+
+            SkDebugf("%s\n", path.c_str());
+        }
+        gKnown++;
     }
 
     bool onUseEncodedData(const void* ptr, size_t len) override {
@@ -75,7 +112,8 @@
 
 int main(int argc, char** argv) {
     SkCommandLineFlags::SetUsage(
-            "Usage: get_images_from_skps -s <dir of skps> -o <dir for output images>\n");
+            "Usage: get_images_from_skps -s <dir of skps> -o <dir for output images> --testDecode "
+            "-j <output JSON path>\n");
 
     SkCommandLineFlags::Parse(argc, argv);
     const char* inputs = FLAGS_skps[0];
@@ -93,10 +131,38 @@
         sk_sp<SkPicture> picture(SkPicture::MakeFromStream(stream));
 
         SkDynamicMemoryWStream scratch;
-        Sniffer sniff;
+        Sniffer sniff(file.c_str());
         picture->serialize(&scratch, &sniff);
     }
-    SkDebugf("%d known, %d unknown\n", gKnown, gUnknown);
+    int totalUnknowns = 0;
+    /**
+     JSON results are written out in the following format:
+     {
+       "failures": {
+         "skp1": 12,
+         "skp4": 2,
+         ...
+       },
+       "totalFailures": 32,
+       "totalSuccesses": 21,
+     }
+     */
+    Json::Value fRoot;
+    for(auto it = gSkpToUnknownCount.cbegin(); it != gSkpToUnknownCount.cend(); ++it)
+    {
+        SkDebugf("%s %d\n", it->first.c_str(), it->second);
+        totalUnknowns += it->second;
+        fRoot["failures"][it->first.c_str()] = it->second;
+    }
+    SkDebugf("%d known, %d unknown\n", gKnown, totalUnknowns);
+    fRoot["totalFailures"] = totalUnknowns;
+    fRoot["totalSuccesses"] = gKnown;
+    if (totalUnknowns > 0 && !FLAGS_failuresJsonPath.isEmpty()) {
+        SkDebugf("Writing failures to %s\n", FLAGS_failuresJsonPath[0]);
+        SkFILEWStream stream(FLAGS_failuresJsonPath[0]);
+        stream.writeText(Json::StyledWriter().write(fRoot).c_str());
+        stream.flush();
+    }
 
     return 0;
 }