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.
Will not be " |
| 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 // FIXME: This code is currently unreachable because we create an em
pty generator when |
| 60 // we fail to create a codec. |
| 61 SkDebugf("Codec could not be created for %s\n", skpName.c_str()); |
| 62 gSkpToUnknownCount[skpName]++; |
44 return; | 63 return; |
45 } | 64 } |
46 SkString ext; | 65 SkString ext; |
47 switch (codec->getEncodedFormat()) { | 66 switch (codec->getEncodedFormat()) { |
48 case SkEncodedFormat::kBMP_SkEncodedFormat: ext = "bmp"; break; | 67 case SkEncodedFormat::kBMP_SkEncodedFormat: ext = "bmp"; break; |
49 case SkEncodedFormat::kGIF_SkEncodedFormat: ext = "gif"; break; | 68 case SkEncodedFormat::kGIF_SkEncodedFormat: ext = "gif"; break; |
50 case SkEncodedFormat::kICO_SkEncodedFormat: ext = "ico"; break; | 69 case SkEncodedFormat::kICO_SkEncodedFormat: ext = "ico"; break; |
51 case SkEncodedFormat::kJPEG_SkEncodedFormat: ext = "jpg"; break; | 70 case SkEncodedFormat::kJPEG_SkEncodedFormat: ext = "jpg"; break; |
52 case SkEncodedFormat::kPNG_SkEncodedFormat: ext = "png"; break; | 71 case SkEncodedFormat::kPNG_SkEncodedFormat: ext = "png"; break; |
53 case SkEncodedFormat::kDNG_SkEncodedFormat: ext = "dng"; break; | 72 case SkEncodedFormat::kDNG_SkEncodedFormat: ext = "dng"; break; |
54 case SkEncodedFormat::kWBMP_SkEncodedFormat: ext = "wbmp"; break; | 73 case SkEncodedFormat::kWBMP_SkEncodedFormat: ext = "wbmp"; break; |
55 case SkEncodedFormat::kWEBP_SkEncodedFormat: ext = "webp"; break; | 74 case SkEncodedFormat::kWEBP_SkEncodedFormat: ext = "webp"; break; |
56 default: gUnknown++; return; | 75 default: |
| 76 // This should be unreachable because we cannot create a codec i
f we do not know |
| 77 // the image type. |
| 78 SkASSERT(false); |
57 } | 79 } |
58 | 80 |
59 SkString path; | 81 if (FLAGS_testDecode) { |
60 path.appendf("%s/%d.%s", gOutputDir, gKnown++, ext.c_str()); | 82 SkBitmap bitmap; |
| 83 SkImageInfo info = codec->getInfo().makeColorType(kN32_SkColorType); |
| 84 bitmap.allocPixels(info); |
| 85 if (SkCodec::kSuccess != codec->getPixels(info, bitmap.getPixels(),
bitmap.rowBytes())) |
| 86 { |
| 87 SkDebugf("Decoding failed for %s\n", skpName.c_str()); |
| 88 gSkpToUnknownCount[skpName]++; |
| 89 return; |
| 90 } |
| 91 } |
61 | 92 |
62 SkFILEWStream file(path.c_str()); | 93 if (FLAGS_writeImages) { |
63 file.write(ptr, len); | 94 SkString path; |
| 95 path.appendf("%s/%d.%s", gOutputDir, gKnown, ext.c_str()); |
64 | 96 |
65 SkDebugf("%s\n", path.c_str()); | 97 SkFILEWStream file(path.c_str()); |
| 98 file.write(ptr, len); |
| 99 |
| 100 SkDebugf("%s\n", path.c_str()); |
| 101 } |
| 102 gKnown++; |
66 } | 103 } |
67 | 104 |
68 bool onUseEncodedData(const void* ptr, size_t len) override { | 105 bool onUseEncodedData(const void* ptr, size_t len) override { |
69 this->sniff(ptr, len); | 106 this->sniff(ptr, len); |
70 return true; | 107 return true; |
71 } | 108 } |
72 SkData* onEncode(const SkPixmap&) override { return nullptr; } | 109 SkData* onEncode(const SkPixmap&) override { return nullptr; } |
73 }; | 110 }; |
74 | 111 |
75 | 112 |
76 int main(int argc, char** argv) { | 113 int main(int argc, char** argv) { |
77 SkCommandLineFlags::SetUsage( | 114 SkCommandLineFlags::SetUsage( |
78 "Usage: get_images_from_skps -s <dir of skps> -o <dir for output ima
ges>\n"); | 115 "Usage: get_images_from_skps -s <dir of skps> -o <dir for output ima
ges> --testDecode " |
| 116 "-j <output JSON path>\n"); |
79 | 117 |
80 SkCommandLineFlags::Parse(argc, argv); | 118 SkCommandLineFlags::Parse(argc, argv); |
81 const char* inputs = FLAGS_skps[0]; | 119 const char* inputs = FLAGS_skps[0]; |
82 gOutputDir = FLAGS_out[0]; | 120 gOutputDir = FLAGS_out[0]; |
83 | 121 |
84 if (!sk_isdir(inputs) || !sk_isdir(gOutputDir)) { | 122 if (!sk_isdir(inputs) || !sk_isdir(gOutputDir)) { |
85 SkCommandLineFlags::PrintUsage(); | 123 SkCommandLineFlags::PrintUsage(); |
86 return 1; | 124 return 1; |
87 } | 125 } |
88 | 126 |
89 SkOSFile::Iter iter(inputs, "skp"); | 127 SkOSFile::Iter iter(inputs, "skp"); |
90 for (SkString file; iter.next(&file); ) { | 128 for (SkString file; iter.next(&file); ) { |
91 SkAutoTDelete<SkStream> stream = | 129 SkAutoTDelete<SkStream> stream = |
92 SkStream::NewFromFile(SkOSPath::Join(inputs, file.c_str()).c_str
()); | 130 SkStream::NewFromFile(SkOSPath::Join(inputs, file.c_str()).c_str
()); |
93 sk_sp<SkPicture> picture(SkPicture::MakeFromStream(stream)); | 131 sk_sp<SkPicture> picture(SkPicture::MakeFromStream(stream)); |
94 | 132 |
95 SkDynamicMemoryWStream scratch; | 133 SkDynamicMemoryWStream scratch; |
96 Sniffer sniff; | 134 Sniffer sniff(file.c_str()); |
97 picture->serialize(&scratch, &sniff); | 135 picture->serialize(&scratch, &sniff); |
98 } | 136 } |
99 SkDebugf("%d known, %d unknown\n", gKnown, gUnknown); | 137 int totalUnknowns = 0; |
| 138 /** |
| 139 JSON results are written out in the following format: |
| 140 { |
| 141 "failures": { |
| 142 "skp1": 12, |
| 143 "skp4": 2, |
| 144 ... |
| 145 }, |
| 146 "totalFailures": 32, |
| 147 "totalSuccesses": 21, |
| 148 } |
| 149 */ |
| 150 Json::Value fRoot; |
| 151 for(auto it = gSkpToUnknownCount.cbegin(); it != gSkpToUnknownCount.cend();
++it) |
| 152 { |
| 153 SkDebugf("%s %d\n", it->first.c_str(), it->second); |
| 154 totalUnknowns += it->second; |
| 155 fRoot["failures"][it->first.c_str()] = it->second; |
| 156 } |
| 157 SkDebugf("%d known, %d unknown\n", gKnown, totalUnknowns); |
| 158 fRoot["totalFailures"] = totalUnknowns; |
| 159 fRoot["totalSuccesses"] = gKnown; |
| 160 if (totalUnknowns > 0 && !FLAGS_failuresJsonPath.isEmpty()) { |
| 161 SkDebugf("Writing failures to %s\n", FLAGS_failuresJsonPath[0]); |
| 162 SkFILEWStream stream(FLAGS_failuresJsonPath[0]); |
| 163 stream.writeText(Json::StyledWriter().write(fRoot).c_str()); |
| 164 stream.flush(); |
| 165 } |
100 | 166 |
101 return 0; | 167 return 0; |
102 } | 168 } |
OLD | NEW |