Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkBitmap.h" | |
| 8 #include "SkCodec.h" | 9 #include "SkCodec.h" |
| 9 #include "SkCommandLineFlags.h" | 10 #include "SkCommandLineFlags.h" |
| 10 #include "SkData.h" | 11 #include "SkData.h" |
| 12 #include "SkJSONCPP.h" | |
| 11 #include "SkMD5.h" | 13 #include "SkMD5.h" |
| 12 #include "SkOSFile.h" | 14 #include "SkOSFile.h" |
| 13 #include "SkPicture.h" | 15 #include "SkPicture.h" |
| 14 #include "SkPixelSerializer.h" | 16 #include "SkPixelSerializer.h" |
| 15 #include "SkStream.h" | 17 #include "SkStream.h" |
| 16 #include "SkTHash.h" | 18 #include "SkTHash.h" |
| 17 | 19 |
| 20 | |
| 21 #include <map> | |
| 22 | |
| 18 DEFINE_string2(skps, s, "skps", "A path to a directory of skps."); | 23 DEFINE_string2(skps, s, "skps", "A path to a directory of skps."); |
| 19 DEFINE_string2(out, o, "img-out", "A path to an output directory."); | 24 DEFINE_string2(out, o, "img-out", "A path to an output directory."); |
| 25 DEFINE_bool(testDecode, false, "Indicates if we want to test that the images dec ode successfully."); | |
| 26 DEFINE_bool(writeImages, true, "Indicates if we want to write out images."); | |
| 27 DEFINE_string2(failuresJsonPath, j, "", | |
| 28 "Dump SKP and count of unknown images to the specified JSON file. Wll not be " | |
|
msarett
2016/04/25 15:29:53
nit: *Will
rmistry
2016/04/25 17:11:45
Oops. Done.
| |
| 29 "written anywhere if empty."); | |
| 20 | 30 |
| 21 static int gKnown; | 31 static int gKnown; |
| 22 static int gUnknown; | |
| 23 static const char* gOutputDir; | 32 static const char* gOutputDir; |
| 33 static std::map<std::string, unsigned int> gSkpToUnknownCount = {}; | |
| 24 | 34 |
| 25 static SkTHashSet<SkMD5::Digest> gSeen; | 35 static SkTHashSet<SkMD5::Digest> gSeen; |
| 26 | 36 |
| 27 struct Sniffer : public SkPixelSerializer { | 37 struct Sniffer : public SkPixelSerializer { |
| 28 | 38 |
| 39 std::string skpName; | |
| 40 | |
| 41 Sniffer(std::string name) { | |
| 42 skpName = name; | |
| 43 } | |
| 44 | |
| 29 void sniff(const void* ptr, size_t len) { | 45 void sniff(const void* ptr, size_t len) { |
| 30 SkMD5 md5; | 46 SkMD5 md5; |
| 31 md5.write(ptr, len); | 47 md5.write(ptr, len); |
| 32 SkMD5::Digest digest; | 48 SkMD5::Digest digest; |
| 33 md5.finish(digest); | 49 md5.finish(digest); |
| 34 | 50 |
| 35 if (gSeen.contains(digest)) { | 51 if (gSeen.contains(digest)) { |
| 36 return; | 52 return; |
| 37 } | 53 } |
| 38 gSeen.add(digest); | 54 gSeen.add(digest); |
| 39 | 55 |
| 40 SkAutoTUnref<SkData> data(SkData::NewWithoutCopy(ptr, len)); | 56 SkAutoTUnref<SkData> data(SkData::NewWithoutCopy(ptr, len)); |
| 41 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(data)); | 57 SkAutoTDelete<SkCodec> codec(SkCodec::NewFromData(data)); |
| 42 if (!codec) { | 58 if (!codec) { |
| 43 gUnknown++; | 59 SkDebugf("Codec could not be created for %s\n", skpName.c_str()); |
|
msarett
2016/04/25 15:29:53
I believe this is unreachable... Looks like we cr
rmistry
2016/04/25 17:11:45
Done.
| |
| 60 gSkpToUnknownCount[skpName]++; | |
| 44 return; | 61 return; |
| 45 } | 62 } |
| 46 SkString ext; | 63 SkString ext; |
| 47 switch (codec->getEncodedFormat()) { | 64 switch (codec->getEncodedFormat()) { |
| 48 case SkEncodedFormat::kBMP_SkEncodedFormat: ext = "bmp"; break; | 65 case SkEncodedFormat::kBMP_SkEncodedFormat: ext = "bmp"; break; |
| 49 case SkEncodedFormat::kGIF_SkEncodedFormat: ext = "gif"; break; | 66 case SkEncodedFormat::kGIF_SkEncodedFormat: ext = "gif"; break; |
| 50 case SkEncodedFormat::kICO_SkEncodedFormat: ext = "ico"; break; | 67 case SkEncodedFormat::kICO_SkEncodedFormat: ext = "ico"; break; |
| 51 case SkEncodedFormat::kJPEG_SkEncodedFormat: ext = "jpg"; break; | 68 case SkEncodedFormat::kJPEG_SkEncodedFormat: ext = "jpg"; break; |
| 52 case SkEncodedFormat::kPNG_SkEncodedFormat: ext = "png"; break; | 69 case SkEncodedFormat::kPNG_SkEncodedFormat: ext = "png"; break; |
| 53 case SkEncodedFormat::kDNG_SkEncodedFormat: ext = "dng"; break; | 70 case SkEncodedFormat::kDNG_SkEncodedFormat: ext = "dng"; break; |
| 54 case SkEncodedFormat::kWBMP_SkEncodedFormat: ext = "wbmp"; break; | 71 case SkEncodedFormat::kWBMP_SkEncodedFormat: ext = "wbmp"; break; |
| 55 case SkEncodedFormat::kWEBP_SkEncodedFormat: ext = "webp"; break; | 72 case SkEncodedFormat::kWEBP_SkEncodedFormat: ext = "webp"; break; |
| 56 default: gUnknown++; return; | 73 default: |
| 74 SkDebugf("Unrecognized encoded format for %s\n", skpName.c_str() ); | |
|
msarett
2016/04/25 15:29:53
I think this is also unreachable - just because we
rmistry
2016/04/25 17:11:45
Done.
| |
| 75 gSkpToUnknownCount[skpName]++; | |
| 76 return; | |
| 57 } | 77 } |
| 58 | 78 |
| 59 SkString path; | 79 if (FLAGS_testDecode) { |
| 60 path.appendf("%s/%d.%s", gOutputDir, gKnown++, ext.c_str()); | 80 SkBitmap bitmap; |
| 81 SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType); | |
| 82 bitmap.allocPixels(info); | |
| 83 if (SkCodec::kSuccess != codec->getPixels(info, bitmap.getPixels(), bitmap.rowBytes())) | |
|
msarett
2016/04/25 15:29:53
Our dm tests treat kSuccess and kIncompleteInput a
rmistry
2016/04/25 17:11:45
k, lets leave this in for now. I am guessing we wi
| |
| 84 { | |
| 85 SkDebugf("Decoding failed for %s\n", skpName.c_str()); | |
| 86 gSkpToUnknownCount[skpName]++; | |
| 87 return; | |
| 88 } | |
| 89 } | |
| 61 | 90 |
| 62 SkFILEWStream file(path.c_str()); | 91 if (FLAGS_writeImages) { |
| 63 file.write(ptr, len); | 92 SkString path; |
| 93 path.appendf("%s/%d.%s", gOutputDir, gKnown, ext.c_str()); | |
| 64 | 94 |
| 65 SkDebugf("%s\n", path.c_str()); | 95 SkFILEWStream file(path.c_str()); |
| 96 file.write(ptr, len); | |
| 97 | |
| 98 SkDebugf("%s\n", path.c_str()); | |
| 99 } | |
| 100 gKnown++; | |
| 66 } | 101 } |
| 67 | 102 |
| 68 bool onUseEncodedData(const void* ptr, size_t len) override { | 103 bool onUseEncodedData(const void* ptr, size_t len) override { |
| 69 this->sniff(ptr, len); | 104 this->sniff(ptr, len); |
| 70 return true; | 105 return true; |
| 71 } | 106 } |
| 72 SkData* onEncode(const SkPixmap&) override { return nullptr; } | 107 SkData* onEncode(const SkPixmap&) override { return nullptr; } |
| 73 }; | 108 }; |
| 74 | 109 |
| 75 | 110 |
| 76 int main(int argc, char** argv) { | 111 int main(int argc, char** argv) { |
| 77 SkCommandLineFlags::SetUsage( | 112 SkCommandLineFlags::SetUsage( |
| 78 "Usage: get_images_from_skps -s <dir of skps> -o <dir for output ima ges>\n"); | 113 "Usage: get_images_from_skps -s <dir of skps> -o <dir for output ima ges> --testDecode " |
| 114 "-j <output JSON path>\n"); | |
| 79 | 115 |
| 80 SkCommandLineFlags::Parse(argc, argv); | 116 SkCommandLineFlags::Parse(argc, argv); |
| 81 const char* inputs = FLAGS_skps[0]; | 117 const char* inputs = FLAGS_skps[0]; |
| 82 gOutputDir = FLAGS_out[0]; | 118 gOutputDir = FLAGS_out[0]; |
| 83 | 119 |
| 84 if (!sk_isdir(inputs) || !sk_isdir(gOutputDir)) { | 120 if (!sk_isdir(inputs) || !sk_isdir(gOutputDir)) { |
| 85 SkCommandLineFlags::PrintUsage(); | 121 SkCommandLineFlags::PrintUsage(); |
| 86 return 1; | 122 return 1; |
| 87 } | 123 } |
| 88 | 124 |
| 89 SkOSFile::Iter iter(inputs, "skp"); | 125 SkOSFile::Iter iter(inputs, "skp"); |
| 90 for (SkString file; iter.next(&file); ) { | 126 for (SkString file; iter.next(&file); ) { |
| 91 SkAutoTDelete<SkStream> stream = | 127 SkAutoTDelete<SkStream> stream = |
| 92 SkStream::NewFromFile(SkOSPath::Join(inputs, file.c_str()).c_str ()); | 128 SkStream::NewFromFile(SkOSPath::Join(inputs, file.c_str()).c_str ()); |
| 93 sk_sp<SkPicture> picture(SkPicture::MakeFromStream(stream)); | 129 sk_sp<SkPicture> picture(SkPicture::MakeFromStream(stream)); |
| 94 | 130 |
| 95 SkDynamicMemoryWStream scratch; | 131 SkDynamicMemoryWStream scratch; |
| 96 Sniffer sniff; | 132 Sniffer sniff(file.c_str()); |
| 97 picture->serialize(&scratch, &sniff); | 133 picture->serialize(&scratch, &sniff); |
| 98 } | 134 } |
| 99 SkDebugf("%d known, %d unknown\n", gKnown, gUnknown); | 135 int totalUnknowns = 0; |
| 136 /** | |
| 137 JSON results are written out in the following format: | |
| 138 { | |
| 139 "failures": { | |
| 140 "skp1": 12, | |
| 141 "skp4": 2, | |
| 142 ... | |
| 143 }, | |
| 144 "totalFailures": 32, | |
| 145 "totalSuccesses": 21, | |
| 146 } | |
| 147 */ | |
| 148 Json::Value fRoot; | |
| 149 for(auto it = gSkpToUnknownCount.cbegin(); it != gSkpToUnknownCount.cend(); ++it) | |
| 150 { | |
| 151 SkDebugf("%s %d\n", it->first.c_str(), it->second); | |
| 152 totalUnknowns += it->second; | |
| 153 fRoot["failures"][it->first.c_str()] = it->second; | |
| 154 } | |
| 155 SkDebugf("%d known, %d unknown\n", gKnown, totalUnknowns); | |
| 156 fRoot["totalFailures"] = totalUnknowns; | |
| 157 fRoot["totalSuccesses"] = gKnown; | |
| 158 if (totalUnknowns > 0 && !FLAGS_failuresJsonPath.isEmpty()) { | |
| 159 SkDebugf("Writing failures to %s\n", FLAGS_failuresJsonPath[0]); | |
| 160 SkFILEWStream stream(FLAGS_failuresJsonPath[0]); | |
| 161 stream.writeText(Json::StyledWriter().write(fRoot).c_str()); | |
| 162 stream.flush(); | |
| 163 } | |
| 100 | 164 |
| 101 return 0; | 165 return 0; |
| 102 } | 166 } |
| OLD | NEW |