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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « tools/rebaseline.py ('k') | tools/tests/skimage/input/bad-images/empty-results.json » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2011 Google Inc. 2 * Copyright 2011 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 "gm_expectations.h" 8 #include "gm_expectations.h"
9 #include "SkBitmap.h" 9 #include "SkBitmap.h"
10 #include "SkColorPriv.h" 10 #include "SkColorPriv.h"
(...skipping 13 matching lines...) Expand all
24 24
25 DEFINE_string(config, "None", "Preferred config to decode into. [None|8888|565|A 8]"); 25 DEFINE_string(config, "None", "Preferred config to decode into. [None|8888|565|A 8]");
26 DEFINE_string(createExpectationsPath, "", "Path to write JSON expectations."); 26 DEFINE_string(createExpectationsPath, "", "Path to write JSON expectations.");
27 DEFINE_string(mismatchPath, "", "Folder to write mismatched images to."); 27 DEFINE_string(mismatchPath, "", "Folder to write mismatched images to.");
28 DEFINE_string2(readPath, r, "", "Folder(s) and files to decode images. Required. "); 28 DEFINE_string2(readPath, r, "", "Folder(s) and files to decode images. Required. ");
29 DEFINE_string(readExpectationsPath, "", "Path to read JSON expectations from."); 29 DEFINE_string(readExpectationsPath, "", "Path to read JSON expectations from.");
30 DEFINE_bool(reencode, true, "Reencode the images to test encoding."); 30 DEFINE_bool(reencode, true, "Reencode the images to test encoding.");
31 DEFINE_int32(sampleSize, 1, "Set the sampleSize for decoding."); 31 DEFINE_int32(sampleSize, 1, "Set the sampleSize for decoding.");
32 DEFINE_bool(skip, false, "Skip writing zeroes."); 32 DEFINE_bool(skip, false, "Skip writing zeroes.");
33 DEFINE_bool(testSubsetDecoding, true, "Test decoding subsets of images."); 33 DEFINE_bool(testSubsetDecoding, true, "Test decoding subsets of images.");
34 DEFINE_bool(writeChecksumBasedFilenames, false, "When writing out actual images , use checksum-"
35 "based filenames, as rebaseline.py will use when downloading them fr om Google Storage");
34 DEFINE_string2(writePath, w, "", "Write rendered images into this directory."); 36 DEFINE_string2(writePath, w, "", "Write rendered images into this directory.");
35 37
36 struct Format { 38 struct Format {
37 SkImageEncoder::Type fType; 39 SkImageEncoder::Type fType;
38 SkImageDecoder::Format fFormat; 40 SkImageDecoder::Format fFormat;
39 const char* fSuffix; 41 const char* fSuffix;
40 }; 42 };
41 43
42 static const Format gFormats[] = { 44 static const Format gFormats[] = {
43 { SkImageEncoder::kBMP_Type, SkImageDecoder::kBMP_Format, ".bmp" }, 45 { SkImageEncoder::kBMP_Type, SkImageDecoder::kBMP_Format, ".bmp" },
(...skipping 29 matching lines...) Expand all
73 return gFormats[i].fFormat; 75 return gFormats[i].fFormat;
74 } 76 }
75 } 77 }
76 return SkImageDecoder::kUnknown_Format; 78 return SkImageDecoder::kUnknown_Format;
77 } 79 }
78 80
79 static void make_outname(SkString* dst, const char outDir[], const char src[], 81 static void make_outname(SkString* dst, const char outDir[], const char src[],
80 const char suffix[]) { 82 const char suffix[]) {
81 SkString basename = SkOSPath::SkBasename(src); 83 SkString basename = SkOSPath::SkBasename(src);
82 dst->set(SkOSPath::SkPathJoin(outDir, basename.c_str())); 84 dst->set(SkOSPath::SkPathJoin(outDir, basename.c_str()));
83 if (!dst->endsWith(suffix)) { 85 dst->append(suffix);
84 const char* cstyleDst = dst->c_str();
85 const char* dot = strrchr(cstyleDst, '.');
86 if (dot != NULL) {
87 int32_t index = SkToS32(dot - cstyleDst);
88 dst->remove(index, dst->size() - index);
89 }
90 dst->append(suffix);
91 }
92 } 86 }
93 87
94 // Store the names of the filenames to report later which ones failed, succeeded , and were 88 // Store the names of the filenames to report later which ones failed, succeeded , and were
95 // invalid. 89 // invalid.
96 // FIXME: Add more arrays, for more specific types of errors, and make the outpu t simpler. 90 // FIXME: Add more arrays, for more specific types of errors, and make the outpu t simpler.
97 // If each array holds one type of error, the output can change from: 91 // If each array holds one type of error, the output can change from:
98 // 92 //
99 // Failures: 93 // Failures:
100 // <image> failed for such and such reason 94 // <image> failed for such and such reason
101 // <image> failed for some different reason 95 // <image> failed for some different reason
(...skipping 20 matching lines...) Expand all
122 // For files that are expected to fail. 116 // For files that are expected to fail.
123 static SkTArray<SkString, false> gKnownFailures; 117 static SkTArray<SkString, false> gKnownFailures;
124 static SkTArray<SkString, false> gKnownSubsetFailures; 118 static SkTArray<SkString, false> gKnownSubsetFailures;
125 119
126 static SkBitmap::Config gPrefConfig(SkBitmap::kNo_Config); 120 static SkBitmap::Config gPrefConfig(SkBitmap::kNo_Config);
127 121
128 // Expections read from a file specified by readExpectationsPath. The expectatio ns must have been 122 // Expections read from a file specified by readExpectationsPath. The expectatio ns must have been
129 // previously written using createExpectationsPath. 123 // previously written using createExpectationsPath.
130 SkAutoTUnref<skiagm::JsonExpectationsSource> gJsonExpectations; 124 SkAutoTUnref<skiagm::JsonExpectationsSource> gJsonExpectations;
131 125
132 static bool write_bitmap(const char outName[], const SkBitmap& bm) { 126 /**
133 if (SkImageEncoder::EncodeFile(outName, bm, SkImageEncoder::kPNG_Type, 100)) { 127 * Encode the bitmap to a file, written one of two ways, depending on
128 * FLAGS_writeChecksumBasedFilenames. If true, the final image will be
129 * written to:
130 * outDir/hashType/src/digestValue.png
131 * If false, the final image will be written out to:
132 * outDir/src.png
133 * The function returns whether the file was successfully written.
134 */
135 static bool write_bitmap(const char outDir[], const char src[],
136 const skiagm::BitmapAndDigest& bitmapAndDigest) {
137 SkString filename;
138 if (FLAGS_writeChecksumBasedFilenames) {
139 // First create the directory for the hashtype.
140 const SkString hashType = bitmapAndDigest.fDigest.getHashType();
141 const SkString hashDir = SkOSPath::SkPathJoin(outDir, hashType.c_str());
142 if (!sk_mkdir(hashDir.c_str())) {
143 return false;
144 }
145
146 // Now create the name of the folder specific to this image.
147 SkString basename = SkOSPath::SkBasename(src);
148 const SkString imageDir = SkOSPath::SkPathJoin(hashDir.c_str(), basename .c_str());
149 if (!sk_mkdir(imageDir.c_str())) {
150 return false;
151 }
152
153 // Name the file <digest>.png
154 SkString checksumBasedName = bitmapAndDigest.fDigest.getDigestValue();
155 checksumBasedName.append(".png");
156
157 filename = SkOSPath::SkPathJoin(imageDir.c_str(), checksumBasedName.c_st r());
158 } else {
159 make_outname(&filename, outDir, src, ".png");
160 }
161
162 const SkBitmap& bm = bitmapAndDigest.fBitmap;
163 if (SkImageEncoder::EncodeFile(filename.c_str(), bm, SkImageEncoder::kPNG_Ty pe, 100)) {
134 return true; 164 return true;
135 } 165 }
136 166
137 if (bm.config() == SkBitmap::kARGB_8888_Config) { 167 if (bm.config() == SkBitmap::kARGB_8888_Config) {
138 // First attempt at encoding failed, and the bitmap was already 8888. Ma king 168 // First attempt at encoding failed, and the bitmap was already 8888. Ma king
139 // a copy is not going to help. 169 // a copy is not going to help.
140 return false; 170 return false;
141 } 171 }
142 172
143 // Encoding failed. Copy to 8888 and try again. 173 // Encoding failed. Copy to 8888 and try again.
144 SkBitmap bm8888; 174 SkBitmap bm8888;
145 if (!bm.copyTo(&bm8888, SkBitmap::kARGB_8888_Config)) { 175 if (!bm.copyTo(&bm8888, SkBitmap::kARGB_8888_Config)) {
146 return false; 176 return false;
147 } 177 }
148 return SkImageEncoder::EncodeFile(outName, bm8888, SkImageEncoder::kPNG_Type , 100); 178 return SkImageEncoder::EncodeFile(filename.c_str(), bm8888, SkImageEncoder:: kPNG_Type, 100);
149 } 179 }
150 180
151 /** 181 /**
152 * Return a random SkIRect inside the range specified. 182 * Return a random SkIRect inside the range specified.
153 * @param rand Random number generator. 183 * @param rand Random number generator.
154 * @param maxX Exclusive maximum x-coordinate. SkIRect's fLeft and fRight will be 184 * @param maxX Exclusive maximum x-coordinate. SkIRect's fLeft and fRight will be
155 * in the range [0, maxX) 185 * in the range [0, maxX)
156 * @param maxY Exclusive maximum y-coordinate. SkIRect's fTop and fBottom will be 186 * @param maxY Exclusive maximum y-coordinate. SkIRect's fTop and fBottom will be
157 * in the range [0, maxY) 187 * in the range [0, maxY)
158 * @return SkIRect Non-empty, non-degenerate rectangle. 188 * @return SkIRect Non-empty, non-degenerate rectangle.
(...skipping 23 matching lines...) Expand all
182 rect.fTop--; 212 rect.fTop--;
183 } else { 213 } else {
184 rect.fBottom++; 214 rect.fBottom++;
185 // Again, this must be in range. 215 // Again, this must be in range.
186 SkASSERT(rect.fBottom < maxY); 216 SkASSERT(rect.fBottom < maxY);
187 } 217 }
188 } 218 }
189 return rect; 219 return rect;
190 } 220 }
191 221
222 /**
223 * Return a string which includes the name of the file and the preferred config ,
224 * as specified by "--config". The resulting string will match the pattern of
225 * gm_json.py's IMAGE_FILENAME_PATTERN: "filename_config.png"
226 */
227 static SkString create_json_key(const char* filename) {
228 SkASSERT(FLAGS_config.count() == 1);
229 return SkStringPrintf("%s_%s.png", filename, FLAGS_config[0]);
230 }
231
192 // Stored expectations to be written to a file if createExpectationsPath is spec ified. 232 // Stored expectations to be written to a file if createExpectationsPath is spec ified.
193 static Json::Value gExpectationsToWrite; 233 static Json::Value gExpectationsToWrite;
194 234
195 /** 235 /**
196 * If expectations are to be recorded, record the bitmap expectations into glob al 236 * If expectations are to be recorded, record the bitmap expectations into the global
197 * expectations array. 237 * expectations array.
238 * As is the case with reading expectations, the key used will combine the file name
239 * parameter with the preferred config, as specified by "--config", matching th e
240 * pattern of gm_json.py's IMAGE_FILENAME_PATTERN: "filename_config.png"
198 */ 241 */
199 static void write_expectations(const SkBitmap& bitmap, const char* filename) { 242 static void write_expectations(const skiagm::BitmapAndDigest& bitmapAndDigest,
243 const char* filename) {
244 const SkString name_config = create_json_key(filename);
200 if (!FLAGS_createExpectationsPath.isEmpty()) { 245 if (!FLAGS_createExpectationsPath.isEmpty()) {
201 // Creates an Expectations object, and add it to the list to write. 246 // Creates an Expectations object, and add it to the list to write.
202 skiagm::Expectations expectation(bitmap); 247 skiagm::Expectations expectation(bitmapAndDigest);
203 Json::Value value = expectation.asJsonValue(); 248 Json::Value value = expectation.asJsonValue();
204 gExpectationsToWrite[filename] = value; 249 gExpectationsToWrite[name_config.c_str()] = value;
205 } 250 }
206 } 251 }
207 252
208 /** 253 /**
209 * Compare against an expectation for this filename, if there is one. 254 * If --readExpectationsPath is set, compare this bitmap to the json expectatio ns
210 * @param digest GmResultDigest, computed from the decoded bitmap, to compare t o the 255 * provided.
211 * expectation. 256 *
212 * @param filename String used to find the expected value. 257 * @param digest GmResultDigest, computed from the decoded bitmap, to compare t o
258 * the existing expectation.
259 * @param filename String used to find the expected value. Will be combined wit h the
260 * preferred config, as specified by "--config", to match the pattern of
261 * gm_json.py's IMAGE_FILENAME_PATTERN: "filename_config.png". The resul ting
262 * key will be used to find the proper expectations.
213 * @param failureArray Array to add a failure message to on failure. 263 * @param failureArray Array to add a failure message to on failure.
214 * @param missingArray Array to add failure message to when missing image 264 * @param missingArray Array to add failure message to when missing image
215 * expectation. 265 * expectation.
216 * @param ignoreArray Array to add failure message to when the image does not m atch 266 * @param ignoreArray Array to add failure message to when the image does not m atch
217 * the expectation, but this is a failure we can ignore. 267 * the expectation, but this is a failure we can ignore.
218 * @return bool True in any of these cases: 268 * @return bool True in any of these cases:
219 * - the bitmap matches the expectation. 269 * - the bitmap matches the expectation.
220 * False in any of these cases: 270 * False in any of these cases:
221 * - there is no expectations file. 271 * - there is no expectations file.
222 * - there is an expectations file, but no expectation for this bitmap. 272 * - there is an expectations file, but no expectation for this bitmap.
223 * - there is an expectation for this bitmap, but it did not ma tch. 273 * - there is an expectation for this bitmap, but it did not ma tch.
224 * - expectation could not be computed from the bitmap. 274 * - expectation could not be computed from the bitmap.
225 */ 275 */
226 static bool compare_to_expectations_if_necessary(const skiagm::GmResultDigest& d igest, 276 static bool compare_to_expectations_if_necessary(const skiagm::GmResultDigest& d igest,
227 const char* filename, 277 const char* filename,
228 SkTArray<SkString, false>* fail ureArray, 278 SkTArray<SkString, false>* fail ureArray,
229 SkTArray<SkString, false>* miss ingArray, 279 SkTArray<SkString, false>* miss ingArray,
230 SkTArray<SkString, false>* igno reArray) { 280 SkTArray<SkString, false>* igno reArray) {
281 // For both writing and reading, the key for this entry will include the nam e
282 // of the file and the pref config, matching the pattern of gm_json.py's
283 // IMAGE_FILENAME_PATTERN: "name_config.png"
284 const SkString name_config = create_json_key(filename);
285
231 if (!digest.isValid()) { 286 if (!digest.isValid()) {
232 if (failureArray != NULL) { 287 if (failureArray != NULL) {
233 failureArray->push_back().printf("decoded %s, but could not create a GmResultDigest.", 288 failureArray->push_back().printf("decoded %s, but could not create a GmResultDigest.",
234 filename); 289 filename);
235 } 290 }
236 return false; 291 return false;
237 } 292 }
238 293
239 if (NULL == gJsonExpectations.get()) { 294 if (NULL == gJsonExpectations.get()) {
240 return false; 295 return false;
241 } 296 }
242 297
243 skiagm::Expectations jsExpectation = gJsonExpectations->get(filename); 298 skiagm::Expectations jsExpectation = gJsonExpectations->get(name_config.c_st r());
244 if (jsExpectation.empty()) { 299 if (jsExpectation.empty()) {
245 if (missingArray != NULL) { 300 if (missingArray != NULL) {
246 missingArray->push_back().printf("decoded %s, but could not find exp ectation.", 301 missingArray->push_back().printf("decoded %s, but could not find exp ectation.",
247 filename); 302 filename);
248 } 303 }
249 return false; 304 return false;
250 } 305 }
251 306
252 if (jsExpectation.match(digest)) { 307 if (jsExpectation.match(digest)) {
253 return true; 308 return true;
254 } 309 }
255 310
256 if (jsExpectation.ignoreFailure()) { 311 if (jsExpectation.ignoreFailure()) {
257 ignoreArray->push_back().printf("%s does not match expectation, but this is known.", 312 ignoreArray->push_back().printf("%s does not match expectation, but this is known.",
258 filename); 313 filename);
259 } else if (failureArray != NULL) { 314 } else if (failureArray != NULL) {
260 failureArray->push_back().printf("decoded %s, but the result does not ma tch " 315 failureArray->push_back().printf("decoded %s, but the result does not ma tch "
261 "expectations.", 316 "expectations.",
262 filename); 317 filename);
263 } 318 }
264 return false; 319 return false;
265 } 320 }
266 321
267 /** 322 /**
268 * Helper function to write a bitmap subset to a file. Only called if subsets w ere created 323 * Helper function to write a bitmap subset to a file. Only called if subsets w ere created
269 * and a writePath was provided. Creates a subdirectory called 'subsets' and wr ites a PNG to 324 * and a writePath was provided. Behaves differently depending on
270 * that directory. Also creates a subdirectory called 'extracted' and writes a bitmap created 325 * FLAGS_writeChecksumBasedFilenames. If true:
271 * using extractSubset to a PNG in that directory. Both files will represent th e same 326 * Writes the image to a PNG file named according to the digest hash, as de scribed in
272 * subrectangle and have the same name for comparison. 327 * write_bitmap.
328 * If false:
329 * Creates a subdirectory called 'subsets' and writes a PNG to that directo ry. Also
330 * creates a subdirectory called 'extracted' and writes a bitmap created us ing
331 * extractSubset to a PNG in that directory. Both files will represent the same
332 * subrectangle and have the same name for convenient comparison. In this c ase, the
333 * digest is ignored.
334 *
273 * @param writePath Parent directory to hold the folders for the PNG files to w rite. Must 335 * @param writePath Parent directory to hold the folders for the PNG files to w rite. Must
274 * not be NULL. 336 * not be NULL.
275 * @param filename Basename of the original file. Used to name the new files. M ust not be 337 * @param subsetName Basename of the original file, with the dimensions of the subset tacked
276 * NULL. 338 * on. Used to name the new file/folder.
277 * @param subsetDim String representing the dimensions of the subset. Used to n ame the new 339 * @param bitmapAndDigestFromDecodeSubset SkBitmap (with digest) created by
278 * files. Must not be NULL. 340 * SkImageDecoder::DecodeSubset, using rect as the area to decode.
279 * @param bitmapFromDecodeSubset Pointer to SkBitmap created by SkImageDecoder: :DecodeSubset,
280 * using rect as the area to decode.
281 * @param rect Rectangle of the area decoded into bitmapFromDecodeSubset. Used to call 341 * @param rect Rectangle of the area decoded into bitmapFromDecodeSubset. Used to call
282 * extractSubset on originalBitmap to create a bitmap with the same dimensi ons/pixels as 342 * extractSubset on originalBitmap to create a bitmap with the same dimensi ons/pixels as
283 * bitmapFromDecodeSubset (assuming decodeSubset worked properly). 343 * bitmapFromDecodeSubset (assuming decodeSubset worked properly).
284 * @param originalBitmap SkBitmap decoded from the same stream as bitmapFromDec odeSubset, 344 * @param originalBitmap SkBitmap decoded from the same stream as bitmapFromDec odeSubset,
285 * using SkImageDecoder::decode to get the entire image. Used to create a P NG file for 345 * using SkImageDecoder::decode to get the entire image. Used to create a P NG file for
286 * comparison to the PNG created by bitmapFromDecodeSubset. 346 * comparison to the PNG created by bitmapAndDigestFromDecodeSubset's bitma p.
287 * @return bool Whether the function succeeded at drawing the decoded subset an d the extracted 347 * @return bool Whether the function succeeded at drawing the decoded subset an d the extracted
288 * subset to files. 348 * subset to files.
289 */ 349 */
290 static bool write_subset(const char* writePath, const char* filename, const char * subsetDim, 350 static bool write_subset(const char* writePath, const SkString& subsetName,
291 SkBitmap* bitmapFromDecodeSubset, SkIRect rect, 351 const skiagm::BitmapAndDigest bitmapAndDigestFromDecod eSubset,
292 const SkBitmap& originalBitmap) { 352 SkIRect rect, const SkBitmap& originalBitmap) {
293 // All parameters must be valid. 353 // All parameters must be valid.
294 SkASSERT(writePath != NULL); 354 SkASSERT(writePath != NULL);
295 SkASSERT(filename != NULL);
296 SkASSERT(subsetDim != NULL);
297 SkASSERT(bitmapFromDecodeSubset != NULL);
298 355
299 // Create a subdirectory to hold the results of decodeSubset. 356 SkString subsetPath;
300 SkString dir = SkOSPath::SkPathJoin(writePath, "subsets"); 357 if (FLAGS_writeChecksumBasedFilenames) {
301 if (!sk_mkdir(dir.c_str())) { 358 subsetPath.set(writePath);
302 gFailedSubsetDecodes.push_back().printf("Successfully decoded %s from %s , but failed to " 359 } else {
303 "create a directory to write to. ", subsetDim, 360 // Create a subdirectory to hold the results of decodeSubset.
304 filename); 361 subsetPath = SkOSPath::SkPathJoin(writePath, "subsets");
305 return false; 362 if (!sk_mkdir(subsetPath.c_str())) {
363 gFailedSubsetDecodes.push_back().printf("Successfully decoded subset %s, but "
364 "failed to create a director y to write to.",
365 subsetName.c_str());
366 return false;
367 }
306 } 368 }
369 SkAssertResult(write_bitmap(subsetPath.c_str(), subsetName.c_str(),
370 bitmapAndDigestFromDecodeSubset));
371 gSuccessfulSubsetDecodes.push_back().printf("\twrote %s", subsetName.c_str() );
307 372
308 // Write the subset to a file whose name includes the dimensions. 373 if (!FLAGS_writeChecksumBasedFilenames) {
309 SkString suffix = SkStringPrintf("_%s.png", subsetDim); 374 // FIXME: The goal of extracting the subset is for visual comparison/usi ng skdiff/skpdiff.
310 SkString outPath; 375 // Currently disabling for writeChecksumBasedFilenames since it will be trickier to
311 make_outname(&outPath, dir.c_str(), filename, suffix.c_str()); 376 // determine which files to compare.
312 SkAssertResult(write_bitmap(outPath.c_str(), *bitmapFromDecodeSubset));
313 gSuccessfulSubsetDecodes.push_back().printf("\twrote %s", outPath.c_str());
314 377
315 // Also use extractSubset from the original for visual comparison. 378 // Also use extractSubset from the original for visual comparison.
316 // Write the result to a file in a separate subdirectory. 379 // Write the result to a file in a separate subdirectory.
317 SkBitmap extractedSubset; 380 SkBitmap extractedSubset;
318 if (!originalBitmap.extractSubset(&extractedSubset, rect)) { 381 if (!originalBitmap.extractSubset(&extractedSubset, rect)) {
319 gFailedSubsetDecodes.push_back().printf("Successfully decoded %s from %s , but failed to " 382 gFailedSubsetDecodes.push_back().printf("Successfully decoded subset %s, but failed "
320 "extract a similar subset for co mparison.", 383 "to extract a similar subset for comparison.",
321 subsetDim, filename); 384 subsetName.c_str());
322 return false; 385 return false;
386 }
387
388 SkString dirExtracted = SkOSPath::SkPathJoin(writePath, "extracted");
389 if (!sk_mkdir(dirExtracted.c_str())) {
390 gFailedSubsetDecodes.push_back().printf("Successfully decoded subset %s, but failed "
391 "to create a directory for e xtractSubset "
392 "comparison.",
393 subsetName.c_str());
394 return false;
395 }
396
397 skiagm::BitmapAndDigest bitmapAndDigestFromExtractSubset(extractedSubset );
398 SkAssertResult(write_bitmap(dirExtracted.c_str(), subsetName.c_str(),
399 bitmapAndDigestFromExtractSubset));
323 } 400 }
324
325 SkString dirExtracted = SkOSPath::SkPathJoin(writePath, "extracted");
326 if (!sk_mkdir(dirExtracted.c_str())) {
327 gFailedSubsetDecodes.push_back().printf("Successfully decoded %s from %s , but failed to "
328 "create a directory for extractS ubset comparison.",
329 subsetDim, filename);
330 return false;
331 }
332
333 make_outname(&outPath, dirExtracted.c_str(), filename, suffix.c_str());
334 SkAssertResult(write_bitmap(outPath.c_str(), extractedSubset));
335 return true; 401 return true;
336 } 402 }
337 403
338 // FIXME: This test could be run on windows/mac once we remove their dependence on 404 // FIXME: This test could be run on windows/mac once we remove their dependence on
339 // getLength. See https://code.google.com/p/skia/issues/detail?id=1570 405 // getLength. See https://code.google.com/p/skia/issues/detail?id=1570
340 #if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX) 406 #if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX)
341 407
342 /** 408 /**
343 * Dummy class for testing to ensure that a stream without a length decodes the same 409 * Dummy class for testing to ensure that a stream without a length decodes the same
344 * as a stream with a length. 410 * as a stream with a length.
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
390 "a digest\n", srcPath); 456 "a digest\n", srcPath);
391 return; 457 return;
392 } 458 }
393 if (!lengthLessDigest.equals(digest)) { 459 if (!lengthLessDigest.equals(digest)) {
394 gDecodeFailures.push_back().appendf("Without using getLength, %s did not match digest " 460 gDecodeFailures.push_back().appendf("Without using getLength, %s did not match digest "
395 "that uses getLength\n", srcPath); 461 "that uses getLength\n", srcPath);
396 } 462 }
397 } 463 }
398 #endif // defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX) 464 #endif // defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX)
399 465
466 /**
467 * Replace all instances of oldChar with newChar in str.
468 * TODO: Add this function to SkString and write tests for it.
469 */
470 static void replace_char(SkString* str, const char oldChar, const char newChar) {
471 if (NULL == str) {
472 return;
473 }
474 for (size_t i = 0; i < str->size(); ++i) {
475 if (oldChar == str->operator[](i)) {
476 str->operator[](i) = newChar;
477 }
478 }
479 }
480
400 static void decodeFileAndWrite(const char srcPath[], const SkString* writePath) { 481 static void decodeFileAndWrite(const char srcPath[], const SkString* writePath) {
401 SkBitmap bitmap; 482 SkBitmap bitmap;
402 SkFILEStream stream(srcPath); 483 SkFILEStream stream(srcPath);
403 if (!stream.isValid()) { 484 if (!stream.isValid()) {
404 gInvalidStreams.push_back().set(srcPath); 485 gInvalidStreams.push_back().set(srcPath);
405 return; 486 return;
406 } 487 }
407 488
408 SkImageDecoder* codec = SkImageDecoder::Factory(&stream); 489 SkImageDecoder* codec = SkImageDecoder::Factory(&stream);
409 if (NULL == codec) { 490 if (NULL == codec) {
410 gMissingCodecs.push_back().set(srcPath); 491 gMissingCodecs.push_back().set(srcPath);
411 return; 492 return;
412 } 493 }
413 494
414 SkAutoTDelete<SkImageDecoder> ad(codec); 495 SkAutoTDelete<SkImageDecoder> ad(codec);
415 496
416 codec->setSkipWritingZeroes(FLAGS_skip); 497 codec->setSkipWritingZeroes(FLAGS_skip);
417 codec->setSampleSize(FLAGS_sampleSize); 498 codec->setSampleSize(FLAGS_sampleSize);
418 stream.rewind(); 499 stream.rewind();
419 500
420 // Create a string representing just the filename itself, for use in json ex pectations. 501 // Create a string representing just the filename itself, for use in json ex pectations.
421 SkString basename = SkOSPath::SkBasename(srcPath); 502 SkString basename = SkOSPath::SkBasename(srcPath);
503 // Replace '_' with '-', so that the names can fit gm_json.py's IMAGE_FILENA ME_PATTERN
504 replace_char(&basename, '_', '-');
505 // Replace '.' with '-', so the output filename can still retain the origina l file extension,
506 // but still end up with only one '.', which denotes the actual extension of the final file.
507 replace_char(&basename, '.', '-');
422 const char* filename = basename.c_str(); 508 const char* filename = basename.c_str();
423 509
424 if (!codec->decode(&stream, &bitmap, gPrefConfig, 510 if (!codec->decode(&stream, &bitmap, gPrefConfig,
425 SkImageDecoder::kDecodePixels_Mode)) { 511 SkImageDecoder::kDecodePixels_Mode)) {
426 if (NULL != gJsonExpectations.get()) { 512 if (NULL != gJsonExpectations.get()) {
427 skiagm::Expectations jsExpectations = gJsonExpectations->get(filenam e); 513 const SkString name_config = create_json_key(filename);
514 skiagm::Expectations jsExpectations = gJsonExpectations->get(name_co nfig.c_str());
428 if (jsExpectations.ignoreFailure()) { 515 if (jsExpectations.ignoreFailure()) {
429 // This is a known failure. 516 // This is a known failure.
430 gKnownFailures.push_back().appendf( 517 gKnownFailures.push_back().appendf(
431 "failed to decode %s, which is a known failure.", srcPath); 518 "failed to decode %s, which is a known failure.", srcPath);
432 return; 519 return;
433 } 520 }
434 if (jsExpectations.empty()) { 521 if (jsExpectations.empty()) {
435 // This is a failure, but it is a new file. Mark it as missing, with 522 // This is a failure, but it is a new file. Mark it as missing, with
436 // a note that it should be marked failing. 523 // a note that it should be marked failing.
437 gMissingExpectations.push_back().appendf( 524 gMissingExpectations.push_back().appendf(
(...skipping 17 matching lines...) Expand all
455 gDecodeFailures.push_back() = failure; 542 gDecodeFailures.push_back() = failure;
456 } else { 543 } else {
457 // Now check that the bounds match: 544 // Now check that the bounds match:
458 if (dim.width() != bitmap.width() || dim.height() != bitmap.height() ) { 545 if (dim.width() != bitmap.width() || dim.height() != bitmap.height() ) {
459 SkString failure = SkStringPrintf("bounds do not match for %s", srcPath); 546 SkString failure = SkStringPrintf("bounds do not match for %s", srcPath);
460 gDecodeFailures.push_back() = failure; 547 gDecodeFailures.push_back() = failure;
461 } 548 }
462 } 549 }
463 } 550 }
464 551
465 skiagm::GmResultDigest digest(bitmap); 552 skiagm::BitmapAndDigest bitmapAndDigest(bitmap);
466 if (compare_to_expectations_if_necessary(digest, filename, 553 if (compare_to_expectations_if_necessary(bitmapAndDigest.fDigest, filename, &gDecodeFailures,
467 &gDecodeFailures, 554 &gMissingExpectations, &gKnownFailu res)) {
468 &gMissingExpectations,
469 &gKnownFailures)) {
470 gSuccessfulDecodes.push_back().printf("%s [%d %d]", srcPath, bitmap.widt h(), 555 gSuccessfulDecodes.push_back().printf("%s [%d %d]", srcPath, bitmap.widt h(),
471 bitmap.height()); 556 bitmap.height());
472 } else if (!FLAGS_mismatchPath.isEmpty()) { 557 } else if (!FLAGS_mismatchPath.isEmpty()) {
473 SkString outPath; 558 if (write_bitmap(FLAGS_mismatchPath[0], filename, bitmapAndDigest)) {
474 make_outname(&outPath, FLAGS_mismatchPath[0], srcPath, ".png"); 559 gSuccessfulDecodes.push_back().appendf("\twrote %s", filename);
475 if (write_bitmap(outPath.c_str(), bitmap)) {
476 gSuccessfulDecodes.push_back().appendf("\twrote %s", outPath.c_str() );
477 } else { 560 } else {
478 gEncodeFailures.push_back().set(outPath); 561 gEncodeFailures.push_back().set(filename);
479 } 562 }
480 } 563 }
481 564
482 // FIXME: This test could be run on windows/mac once we remove their dependence on 565 // FIXME: This test could be run on windows/mac once we remove their dependence on
483 // getLength. See https://code.google.com/p/skia/issues/detail?id=1570 566 // getLength. See https://code.google.com/p/skia/issues/detail?id=1570
484 #if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX) 567 #if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX)
485 test_stream_without_length(srcPath, codec, digest); 568 test_stream_without_length(srcPath, codec, bitmapAndDigest.fDigest);
486 #endif 569 #endif
487 570
488 if (writePath != NULL) { 571 if (writePath != NULL) {
489 SkString outPath; 572 if (write_bitmap(writePath->c_str(), filename, bitmapAndDigest)) {
490 make_outname(&outPath, writePath->c_str(), srcPath, ".png"); 573 gSuccessfulDecodes.push_back().appendf("\twrote %s", filename);
491 if (write_bitmap(outPath.c_str(), bitmap)) {
492 gSuccessfulDecodes.push_back().appendf("\twrote %s", outPath.c_str() );
493 } else { 574 } else {
494 gEncodeFailures.push_back().set(outPath); 575 gEncodeFailures.push_back().set(filename);
495 } 576 }
496 } 577 }
497 578
498 write_expectations(bitmap, filename); 579 write_expectations(bitmapAndDigest, filename);
499 580
500 if (FLAGS_testSubsetDecoding) { 581 if (FLAGS_testSubsetDecoding) {
501 SkDEBUGCODE(bool couldRewind =) stream.rewind(); 582 SkDEBUGCODE(bool couldRewind =) stream.rewind();
502 SkASSERT(couldRewind); 583 SkASSERT(couldRewind);
503 int width, height; 584 int width, height;
504 // Build the tile index for decoding subsets. If the image is 1x1, skip subset 585 // Build the tile index for decoding subsets. If the image is 1x1, skip subset
505 // decoding since there are no smaller subsets. 586 // decoding since there are no smaller subsets.
506 if (codec->buildTileIndex(&stream, &width, &height) && width > 1 && heig ht > 1) { 587 if (codec->buildTileIndex(&stream, &width, &height) && width > 1 && heig ht > 1) {
507 SkASSERT(bitmap.width() == width && bitmap.height() == height); 588 SkASSERT(bitmap.width() == width && bitmap.height() == height);
508 // Call decodeSubset multiple times: 589 // Call decodeSubset multiple times:
509 SkRandom rand(0); 590 SkRandom rand(0);
510 for (int i = 0; i < 5; i++) { 591 for (int i = 0; i < 5; i++) {
511 SkBitmap bitmapFromDecodeSubset; 592 SkBitmap bitmapFromDecodeSubset;
512 // FIXME: Come up with a more representative set of rectangles. 593 // FIXME: Come up with a more representative set of rectangles.
513 SkIRect rect = generate_random_rect(&rand, width, height); 594 SkIRect rect = generate_random_rect(&rand, width, height);
514 SkString subsetDim = SkStringPrintf("[%d,%d,%d,%d]", rect.fLeft, rect.fTop, 595 SkString subsetDim = SkStringPrintf("[%d,%d,%d,%d]", rect.fLeft, rect.fTop,
515 rect.fRight, rect.fBottom); 596 rect.fRight, rect.fBottom);
516 if (codec->decodeSubset(&bitmapFromDecodeSubset, rect, gPrefConf ig)) { 597 if (codec->decodeSubset(&bitmapFromDecodeSubset, rect, gPrefConf ig)) {
517 SkString subsetName = SkStringPrintf("%s_%s", filename, subs etDim.c_str()); 598 SkString subsetName = SkStringPrintf("%s-%s", filename, subs etDim.c_str());
518 skiagm::GmResultDigest subsetDigest(bitmapFromDecodeSubset); 599 skiagm::BitmapAndDigest subsetBitmapAndDigest(bitmapFromDeco deSubset);
519 if (compare_to_expectations_if_necessary(subsetDigest, 600 if (compare_to_expectations_if_necessary(subsetBitmapAndDige st.fDigest,
520 subsetName.c_str(), 601 subsetName.c_str(),
521 &gFailedSubsetDecod es, 602 &gFailedSubsetDecod es,
522 &gMissingSubsetExpe ctations, 603 &gMissingSubsetExpe ctations,
523 &gKnownSubsetFailur es)) { 604 &gKnownSubsetFailur es)) {
524 gSuccessfulSubsetDecodes.push_back().printf("Decoded sub set %s from %s", 605 gSuccessfulSubsetDecodes.push_back().printf("Decoded sub set %s from %s",
525 subsetDim.c_str(), srcPath); 606 subsetDim.c_str(), srcPath);
526 } else if (!FLAGS_mismatchPath.isEmpty()) { 607 } else if (!FLAGS_mismatchPath.isEmpty()) {
527 write_subset(FLAGS_mismatchPath[0], filename, subsetDim. c_str(), 608 write_subset(FLAGS_mismatchPath[0], subsetName,
528 &bitmapFromDecodeSubset, rect, bitmap); 609 subsetBitmapAndDigest, rect, bitmap);
529 } 610 }
530 611
531 write_expectations(bitmapFromDecodeSubset, subsetName.c_str( )); 612 write_expectations(subsetBitmapAndDigest, subsetName.c_str() );
613
532 if (writePath != NULL) { 614 if (writePath != NULL) {
533 write_subset(writePath->c_str(), filename, subsetDim.c_s tr(), 615 write_subset(writePath->c_str(), subsetName,
534 &bitmapFromDecodeSubset, rect, bitmap); 616 subsetBitmapAndDigest, rect, bitmap);
535 } 617 }
536 } else { 618 } else {
537 gFailedSubsetDecodes.push_back().printf("Failed to decode re gion %s from %s", 619 gFailedSubsetDecodes.push_back().printf("Failed to decode re gion %s from %s",
538 subsetDim.c_str(), s rcPath); 620 subsetDim.c_str(), s rcPath);
539 } 621 }
540 } 622 }
541 } 623 }
542 } 624 }
543 625
544 // Do not attempt to re-encode A8, since our image encoders do not support e ncoding to A8. 626 // Do not attempt to re-encode A8, since our image encoders do not support e ncoding to A8.
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
580 if (!encoder->encodeStream(&wStream, bitmap, 100)) { 662 if (!encoder->encodeStream(&wStream, bitmap, 100)) {
581 gEncodeFailures.push_back().printf("Failed to reencode %s to type '% s'", srcPath, 663 gEncodeFailures.push_back().printf("Failed to reencode %s to type '% s'", srcPath,
582 suffix_for_type(type)); 664 suffix_for_type(type));
583 return; 665 return;
584 } 666 }
585 667
586 SkAutoTUnref<SkData> data(wStream.copyToData()); 668 SkAutoTUnref<SkData> data(wStream.copyToData());
587 if (writePath != NULL && type != SkImageEncoder::kPNG_Type) { 669 if (writePath != NULL && type != SkImageEncoder::kPNG_Type) {
588 // Write the encoded data to a file. Do not write to PNG, which was already written. 670 // Write the encoded data to a file. Do not write to PNG, which was already written.
589 SkString outPath; 671 SkString outPath;
590 make_outname(&outPath, writePath->c_str(), srcPath, suffix_for_type( type)); 672 make_outname(&outPath, writePath->c_str(), filename, suffix_for_type (type));
591 SkFILEWStream file(outPath.c_str()); 673 SkFILEWStream file(outPath.c_str());
592 if(file.write(data->data(), data->size())) { 674 if(file.write(data->data(), data->size())) {
593 gSuccessfulDecodes.push_back().appendf("\twrote %s", outPath.c_s tr()); 675 gSuccessfulDecodes.push_back().appendf("\twrote %s", outPath.c_s tr());
594 } else { 676 } else {
595 gEncodeFailures.push_back().printf("Failed to write %s", outPath .c_str()); 677 gEncodeFailures.push_back().printf("Failed to write %s", outPath .c_str());
596 } 678 }
597 } 679 }
598 // Ensure that the reencoded data can still be decoded. 680 // Ensure that the reencoded data can still be decoded.
599 SkMemoryStream memStream(data); 681 SkMemoryStream memStream(data);
600 SkBitmap redecodedBitmap; 682 SkBitmap redecodedBitmap;
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
749 print_strings("Known failures", gKnownFailures); 831 print_strings("Known failures", gKnownFailures);
750 832
751 return failed ? -1 : 0; 833 return failed ? -1 : 0;
752 } 834 }
753 835
754 #if !defined SK_BUILD_FOR_IOS 836 #if !defined SK_BUILD_FOR_IOS
755 int main(int argc, char * const argv[]) { 837 int main(int argc, char * const argv[]) {
756 return tool_main(argc, (char**) argv); 838 return tool_main(argc, (char**) argv);
757 } 839 }
758 #endif 840 #endif
OLDNEW
« 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