Add image decoding mode to DM.
This is meant to supplant skimage. BUG=skia:3235 Review URL: https://codereview.chromium.org/802793002
This commit is contained in:
parent
9880607151
commit
f6139f7c38
54
dm/DM.cpp
54
dm/DM.cpp
@ -18,6 +18,7 @@
|
||||
#include "DMCpuGMTask.h"
|
||||
#include "DMGpuGMTask.h"
|
||||
#include "DMGpuSupport.h"
|
||||
#include "DMImageTask.h"
|
||||
#include "DMJsonWriter.h"
|
||||
#include "DMPDFTask.h"
|
||||
#include "DMReporter.h"
|
||||
@ -50,6 +51,7 @@ DEFINE_bool(gms, true, "Run GMs?");
|
||||
DEFINE_bool(tests, true, "Run tests?");
|
||||
DEFINE_bool(reportUsedChars, false, "Output test font construction data to be pasted into"
|
||||
" create_test_font.cpp.");
|
||||
DEFINE_string(images, "resources", "Path to directory containing images to decode.");
|
||||
|
||||
__SK_FORCE_IMAGE_DECODER_LINKING;
|
||||
|
||||
@ -119,16 +121,21 @@ static void kick_off_tests(const SkTDArray<TestRegistry::Factory>& tests,
|
||||
}
|
||||
}
|
||||
|
||||
static void find_skps(SkTArray<SkString>* skps) {
|
||||
if (FLAGS_skps.isEmpty()) {
|
||||
static void find_files(const char* dir,
|
||||
const char* suffixes[],
|
||||
size_t num_suffixes,
|
||||
SkTArray<SkString>* files) {
|
||||
if (0 == strcmp(dir, "")) {
|
||||
return;
|
||||
}
|
||||
|
||||
SkOSFile::Iter it(FLAGS_skps[0], ".skp");
|
||||
SkString filename;
|
||||
while (it.next(&filename)) {
|
||||
if (!SkCommandLineFlags::ShouldSkip(FLAGS_match, filename.c_str())) {
|
||||
skps->push_back(SkOSPath::Join(FLAGS_skps[0], filename.c_str()));
|
||||
for (size_t i = 0; i < num_suffixes; i++) {
|
||||
SkOSFile::Iter it(dir, suffixes[i]);
|
||||
while (it.next(&filename)) {
|
||||
if (!SkCommandLineFlags::ShouldSkip(FLAGS_match, filename.c_str())) {
|
||||
files->push_back(SkOSPath::Join(dir, filename.c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -155,6 +162,22 @@ static void kick_off_skps(const SkTArray<SkString>& skps,
|
||||
}
|
||||
}
|
||||
|
||||
static void kick_off_images(const SkTArray<SkString>& images,
|
||||
DM::Reporter* reporter,
|
||||
DM::TaskRunner* tasks) {
|
||||
for (int i = 0; i < images.count(); i++) {
|
||||
SkAutoTUnref<SkData> image(SkData::NewFromFileName(images[i].c_str()));
|
||||
if (!image) {
|
||||
SkDebugf("Could not read %s.\n", images[i].c_str());
|
||||
exit(1);
|
||||
}
|
||||
SkString filename = SkOSPath::Basename(images[i].c_str());
|
||||
tasks->add(SkNEW_ARGS(DM::ImageTask, (reporter, tasks, image, filename)));
|
||||
tasks->add(SkNEW_ARGS(DM::ImageTask, (reporter, tasks, image, filename, 5/*subsets*/)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void report_failures(const SkTArray<SkString>& failures) {
|
||||
if (failures.count() == 0) {
|
||||
return;
|
||||
@ -217,17 +240,28 @@ int dm_main() {
|
||||
append_matching_factories<Test>(TestRegistry::Head(), &tests);
|
||||
}
|
||||
|
||||
SkTArray<SkString> skps;
|
||||
find_skps(&skps);
|
||||
|
||||
SkDebugf("%d GMs x %d configs, %d tests, %d pictures\n",
|
||||
gms.count(), configs.count(), tests.count(), skps.count());
|
||||
SkTArray<SkString> skps;
|
||||
if (!FLAGS_skps.isEmpty()) {
|
||||
const char* suffixes[] = { "skp" };
|
||||
find_files(FLAGS_skps[0], suffixes, SK_ARRAY_COUNT(suffixes), &skps);
|
||||
}
|
||||
|
||||
SkTArray<SkString> images;
|
||||
if (!FLAGS_images.isEmpty()) {
|
||||
const char* suffixes[] = { "bmp", "gif", "jpg", "png", "webp", "ktx", "astc" };
|
||||
find_files(FLAGS_images[0], suffixes, SK_ARRAY_COUNT(suffixes), &images);
|
||||
}
|
||||
|
||||
SkDebugf("%d GMs x %d configs, %d tests, %d pictures, %d images\n",
|
||||
gms.count(), configs.count(), tests.count(), skps.count(), images.count());
|
||||
DM::Reporter reporter;
|
||||
|
||||
DM::TaskRunner tasks;
|
||||
kick_off_tests(tests, &reporter, &tasks);
|
||||
kick_off_gms(gms, configs, gpuAPI, &reporter, &tasks);
|
||||
kick_off_skps(skps, &reporter, &tasks);
|
||||
kick_off_images(images, &reporter, &tasks);
|
||||
tasks.wait();
|
||||
|
||||
DM::JsonWriter::DumpJson();
|
||||
|
78
dm/DMImageTask.cpp
Normal file
78
dm/DMImageTask.cpp
Normal file
@ -0,0 +1,78 @@
|
||||
#include "DMImageTask.h"
|
||||
#include "DMUtil.h"
|
||||
#include "DMWriteTask.h"
|
||||
#include "SkImageDecoder.h"
|
||||
#include "SkRandom.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace DM {
|
||||
|
||||
// This converts file names like "mandrill_128.r11.ktx" into
|
||||
// "mandrill-128-r11_ktx" or "mandrill-128-r11-5-subsets_ktx".
|
||||
static SkString task_name(SkString filename, int subsets) {
|
||||
const char* ext = strrchr(filename.c_str(), '.');
|
||||
SkString name(filename.c_str(), ext - filename.c_str());
|
||||
if (subsets > 0) {
|
||||
name.appendf("_%d_subsets", subsets);
|
||||
}
|
||||
name = FileToTaskName(name); // Promote any stray '.' in the filename to '_'.
|
||||
name.append(ext); // Tack on the extension, including the '.'.
|
||||
return FileToTaskName(name); // Promote that last '.' to '_', other '_' to '-'.
|
||||
}
|
||||
|
||||
ImageTask::ImageTask(Reporter* r, TaskRunner* t, const SkData* encoded, SkString name, int subsets)
|
||||
: CpuTask(r, t)
|
||||
, fEncoded(SkRef(encoded))
|
||||
, fName(task_name(name, subsets))
|
||||
, fSubsets(subsets) {}
|
||||
|
||||
void ImageTask::draw() {
|
||||
if (fSubsets == 0) {
|
||||
// Decoding the whole image is considerably simpler than decoding subsets!
|
||||
SkBitmap bitmap;
|
||||
if (!SkImageDecoder::DecodeMemory(fEncoded->data(), fEncoded->size(), &bitmap)) {
|
||||
return this->fail("Can't DecodeMemory");
|
||||
}
|
||||
this->spawnChild(SkNEW_ARGS(WriteTask, (*this, "image", bitmap)));
|
||||
return;
|
||||
}
|
||||
|
||||
SkMemoryStream stream(fEncoded->data(), fEncoded->size());
|
||||
SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(&stream));
|
||||
if (!decoder) {
|
||||
return this->fail("Can't find good decoder.");
|
||||
}
|
||||
|
||||
int w,h;
|
||||
if (!decoder->buildTileIndex(&stream, &w, &h) || w*h == 1) {
|
||||
return; // Subset decoding is not always supported.
|
||||
}
|
||||
|
||||
SkBitmap composite;
|
||||
composite.allocN32Pixels(w,h); // We're lazy here and just always use native 8888.
|
||||
composite.eraseColor(SK_ColorTRANSPARENT);
|
||||
SkCanvas canvas(composite);
|
||||
|
||||
SkRandom rand;
|
||||
for (int i = 0; i < fSubsets; i++) {
|
||||
SkIRect rect;
|
||||
do {
|
||||
rect.fLeft = rand.nextULessThan(w);
|
||||
rect.fTop = rand.nextULessThan(h);
|
||||
rect.fRight = rand.nextULessThan(w);
|
||||
rect.fBottom = rand.nextULessThan(h);
|
||||
rect.sort();
|
||||
} while (rect.isEmpty());
|
||||
|
||||
SkBitmap subset;
|
||||
if (!decoder->decodeSubset(&subset, rect, kN32_SkColorType)) {
|
||||
return this->fail("Could not decode subset.");
|
||||
}
|
||||
canvas.drawBitmap(subset, SkIntToScalar(rect.fLeft), SkIntToScalar(rect.fTop));
|
||||
}
|
||||
canvas.flush();
|
||||
this->spawnChild(SkNEW_ARGS(WriteTask, (*this, "image", composite)));
|
||||
}
|
||||
|
||||
} // namespace DM
|
30
dm/DMImageTask.h
Normal file
30
dm/DMImageTask.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef DMImageTask_DEFINED
|
||||
#define DMImageTask_DEFINED
|
||||
|
||||
#include "DMReporter.h"
|
||||
#include "DMTask.h"
|
||||
#include "DMTaskRunner.h"
|
||||
#include "SkData.h"
|
||||
#include "SkString.h"
|
||||
|
||||
// Decode an image into its natural bitmap, perhaps decoding random subsets.
|
||||
|
||||
namespace DM {
|
||||
|
||||
class ImageTask : public CpuTask {
|
||||
public:
|
||||
ImageTask(Reporter*, TaskRunner*, const SkData*, SkString name, int subsets = 0);
|
||||
|
||||
void draw() SK_OVERRIDE;
|
||||
bool shouldSkip() const SK_OVERRIDE { return false; }
|
||||
SkString name() const SK_OVERRIDE { return fName; }
|
||||
|
||||
private:
|
||||
SkAutoTUnref<const SkData> fEncoded;
|
||||
const SkString fName;
|
||||
int fSubsets;
|
||||
};
|
||||
|
||||
} // namespace DM
|
||||
|
||||
#endif // DMImageTask_DEFINED
|
@ -60,8 +60,9 @@ WriteTask::WriteTask(const Task& parent,
|
||||
}
|
||||
|
||||
void WriteTask::makeDirOrFail(SkString dir) {
|
||||
if (!sk_mkdir(dir.c_str())) {
|
||||
this->fail();
|
||||
// This can be a little racy, so if it fails check to see if someone else succeeded.
|
||||
if (!sk_mkdir(dir.c_str()) && !sk_isdir(dir.c_str())) {
|
||||
this->fail("Can't make directory.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,6 +93,19 @@ static SkString get_md5(SkStreamAsset* stream) {
|
||||
return get_md5_string(&hasher);
|
||||
}
|
||||
|
||||
static bool encode_png(const SkBitmap& src, SkFILEWStream* file) {
|
||||
SkBitmap bm;
|
||||
// We can't encode A8 bitmaps as PNGs. Convert them to 8888 first.
|
||||
if (src.info().colorType() == kAlpha_8_SkColorType) {
|
||||
if (!src.copyTo(&bm, kN32_SkColorType)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
bm = src;
|
||||
}
|
||||
return SkImageEncoder::EncodeStream(file, bm, SkImageEncoder::kPNG_Type, 100);
|
||||
}
|
||||
|
||||
void WriteTask::draw() {
|
||||
SkString md5;
|
||||
{
|
||||
@ -153,7 +167,7 @@ void WriteTask::draw() {
|
||||
}
|
||||
|
||||
bool ok = fData ? write_asset(fData, &file)
|
||||
: SkImageEncoder::EncodeStream(&file, fBitmap, SkImageEncoder::kPNG_Type, 100);
|
||||
: encode_png(fBitmap, &file);
|
||||
if (!ok) {
|
||||
return this->fail("Can't write to file.");
|
||||
}
|
||||
|
@ -32,6 +32,7 @@
|
||||
'../dm/DMCpuGMTask.cpp',
|
||||
'../dm/DMGpuGMTask.cpp',
|
||||
'../dm/DMPDFRasterizeTask.cpp',
|
||||
'../dm/DMImageTask.cpp',
|
||||
'../dm/DMJsonWriter.cpp',
|
||||
'../dm/DMPDFTask.cpp',
|
||||
'../dm/DMPipeTask.cpp',
|
||||
|
Loading…
Reference in New Issue
Block a user