/*static*/ bool SkBitmapHasher::ComputeDigestInternal(const SkBitmap& bitmap, uint64_t *result) { SkMD5 out; // start with the x/y dimensions write_int32_to_buffer(SkToU32(bitmap.width()), &out); write_int32_to_buffer(SkToU32(bitmap.height()), &out); // add all the pixel data SkAutoTDelete<SkImageEncoder> enc(CreateARGBImageEncoder()); if (!enc->encodeStream(&out, bitmap, SkImageEncoder::kDefaultQuality)) { return false; } SkMD5::Digest digest; out.finish(digest); *result = first_8_bytes_as_uint64(digest.data); return true; }
static void Run(Task* task) { SkString name = task->src->name(); // We'll skip drawing this Src/Sink pair if: // - the Src vetoes the Sink; // - this Src / Sink combination is on the blacklist; // - it's a dry run. SkString note(task->src->veto(task->sink->flags()) ? " (veto)" : ""); SkString whyBlacklisted = is_blacklisted(task->sink.tag, task->src.tag, task->src.options, name.c_str()); if (!whyBlacklisted.isEmpty()) { note.appendf(" (--blacklist %s)", whyBlacklisted.c_str()); } SkString log; WallTimer timer; timer.start(); if (!FLAGS_dryRun && note.isEmpty()) { SkBitmap bitmap; SkDynamicMemoryWStream stream; if (FLAGS_pre_log) { SkDebugf("\nRunning %s->%s", name.c_str(), task->sink.tag); } start(task->sink.tag, task->src.tag, task->src.options, name.c_str()); Error err = task->sink->draw(*task->src, &bitmap, &stream, &log); if (!err.isEmpty()) { timer.end(); if (err.isFatal()) { fail(SkStringPrintf("%s %s %s %s: %s", task->sink.tag, task->src.tag, task->src.options, name.c_str(), err.c_str())); } else { note.appendf(" (skipped: %s)", err.c_str()); } done(timer.fWall, task->sink.tag, task->src.tag, task->src.options, name, note, log); return; } SkAutoTDelete<SkStreamAsset> data(stream.detachAsStream()); SkString md5; if (!FLAGS_writePath.isEmpty() || !FLAGS_readPath.isEmpty()) { SkMD5 hash; if (data->getLength()) { hash.writeStream(data, data->getLength()); data->rewind(); } else { // If we're BGRA (Linux, Windows), swizzle over to RGBA (Mac, Android). // This helps eliminate multiple 0-pixel-diff hashes on gold.skia.org. // (Android's general slow speed breaks the tie arbitrarily in RGBA's favor.) // We might consider promoting 565 to RGBA too. if (bitmap.colorType() == kBGRA_8888_SkColorType) { SkBitmap swizzle; SkAssertResult(bitmap.copyTo(&swizzle, kRGBA_8888_SkColorType)); hash.write(swizzle.getPixels(), swizzle.getSize()); } else { hash.write(bitmap.getPixels(), bitmap.getSize()); } } SkMD5::Digest digest; hash.finish(digest); for (int i = 0; i < 16; i++) { md5.appendf("%02x", digest.data[i]); } } if (!FLAGS_readPath.isEmpty() && !gGold.contains(Gold(task->sink.tag, task->src.tag, task->src.options, name, md5))) { fail(SkStringPrintf("%s not found for %s %s %s %s in %s", md5.c_str(), task->sink.tag, task->src.tag, task->src.options, name.c_str(), FLAGS_readPath[0])); } if (!FLAGS_writePath.isEmpty()) { const char* ext = task->sink->fileExtension(); if (data->getLength()) { WriteToDisk(*task, md5, ext, data, data->getLength(), nullptr); SkASSERT(bitmap.drawsNothing()); } else if (!bitmap.drawsNothing()) { WriteToDisk(*task, md5, ext, nullptr, 0, &bitmap); } } } timer.end(); done(timer.fWall, task->sink.tag, task->src.tag, task->src.options, name, note, log); }
static SkString get_md5(const void* ptr, size_t len) { SkMD5 hasher; hasher.write(ptr, len); return get_md5_string(&hasher); }
static void Run(const Task& task) { SkString name = task.src->name(); SkString log; if (!FLAGS_dryRun) { SkBitmap bitmap; SkDynamicMemoryWStream stream; start(task.sink.tag.c_str(), task.src.tag.c_str(), task.src.options.c_str(), name.c_str()); Error err = task.sink->draw(*task.src, &bitmap, &stream, &log); if (!log.isEmpty()) { info("%s %s %s %s:\n%s\n", task.sink.tag.c_str() , task.src.tag.c_str() , task.src.options.c_str() , name.c_str() , log.c_str()); } if (!err.isEmpty()) { if (err.isFatal()) { fail(SkStringPrintf("%s %s %s %s: %s", task.sink.tag.c_str(), task.src.tag.c_str(), task.src.options.c_str(), name.c_str(), err.c_str())); } else { done(task.sink.tag.c_str(), task.src.tag.c_str(), task.src.options.c_str(), name.c_str()); return; } } // We're likely switching threads here, so we must capture by value, [=] or [foo,bar]. SkStreamAsset* data = stream.detachAsStream(); gDefinitelyThreadSafeWork.add([task,name,bitmap,data]{ SkAutoTDelete<SkStreamAsset> ownedData(data); // Why doesn't the copy constructor do this when we have pre-locked pixels? bitmap.lockPixels(); SkString md5; if (!FLAGS_writePath.isEmpty() || !FLAGS_readPath.isEmpty()) { SkMD5 hash; if (data->getLength()) { hash.writeStream(data, data->getLength()); data->rewind(); } else { // If we're BGRA (Linux, Windows), swizzle over to RGBA (Mac, Android). // This helps eliminate multiple 0-pixel-diff hashes on gold.skia.org. // (Android's general slow speed breaks the tie arbitrarily in RGBA's favor.) // We might consider promoting 565 to RGBA too. if (bitmap.colorType() == kBGRA_8888_SkColorType) { SkBitmap swizzle; SkAssertResult(bitmap.copyTo(&swizzle, kRGBA_8888_SkColorType)); hash.write(swizzle.getPixels(), swizzle.getSize()); } else { hash.write(bitmap.getPixels(), bitmap.getSize()); } } SkMD5::Digest digest; hash.finish(digest); for (int i = 0; i < 16; i++) { md5.appendf("%02x", digest.data[i]); } } if (!FLAGS_readPath.isEmpty() && !gGold.contains(Gold(task.sink.tag, task.src.tag, task.src.options, name, md5))) { fail(SkStringPrintf("%s not found for %s %s %s %s in %s", md5.c_str(), task.sink.tag.c_str(), task.src.tag.c_str(), task.src.options.c_str(), name.c_str(), FLAGS_readPath[0])); } if (!FLAGS_writePath.isEmpty()) { const char* ext = task.sink->fileExtension(); if (data->getLength()) { WriteToDisk(task, md5, ext, data, data->getLength(), nullptr); SkASSERT(bitmap.drawsNothing()); } else if (!bitmap.drawsNothing()) { WriteToDisk(task, md5, ext, nullptr, 0, &bitmap); } } }); } done(task.sink.tag.c_str(), task.src.tag.c_str(), task.src.options.c_str(), name.c_str()); }
static void Run(Task* task) { SkString name = task->src->name(); SkString note; SkString whyBlacklisted = is_blacklisted(task->sink.tag, task->src.tag, task->src.options, name.c_str()); if (!whyBlacklisted.isEmpty()) { note.appendf(" (--blacklist %s)", whyBlacklisted.c_str()); } SkString log; WallTimer timer; timer.start(); if (!FLAGS_dryRun && whyBlacklisted.isEmpty()) { SkBitmap bitmap; SkDynamicMemoryWStream stream; start(task->sink.tag, task->src.tag, task->src.options, name.c_str()); Error err = task->sink->draw(*task->src, &bitmap, &stream, &log); if (!err.isEmpty()) { timer.end(); if (err.isFatal()) { fail(SkStringPrintf("%s %s %s %s: %s", task->sink.tag, task->src.tag, task->src.options, name.c_str(), err.c_str())); } else { note.appendf(" (skipped: %s)", err.c_str()); } done(timer.fWall, task->sink.tag, task->src.tag, task->src.options, name, note, log); return; } SkAutoTDelete<SkStreamAsset> data(stream.detachAsStream()); SkString md5; if (!FLAGS_writePath.isEmpty() || !FLAGS_readPath.isEmpty()) { SkMD5 hash; if (data->getLength()) { hash.writeStream(data, data->getLength()); data->rewind(); } else { hash.write(bitmap.getPixels(), bitmap.getSize()); } SkMD5::Digest digest; hash.finish(digest); for (int i = 0; i < 16; i++) { md5.appendf("%02x", digest.data[i]); } } if (!FLAGS_readPath.isEmpty() && !gGold.contains(Gold(task->sink.tag, task->src.tag, task->src.options, name, md5))) { fail(SkStringPrintf("%s not found for %s %s %s %s in %s", md5.c_str(), task->sink.tag, task->src.tag, task->src.options, name.c_str(), FLAGS_readPath[0])); } if (!FLAGS_writePath.isEmpty()) { const char* ext = task->sink->fileExtension(); if (data->getLength()) { WriteToDisk(*task, md5, ext, data, data->getLength(), NULL); SkASSERT(bitmap.drawsNothing()); } else if (!bitmap.drawsNothing()) { WriteToDisk(*task, md5, ext, NULL, 0, &bitmap); } } } timer.end(); done(timer.fWall, task->sink.tag, task->src.tag, task->src.options, name, note, log); }