Chromium Code Reviews| Index: tools/skimage_main.cpp |
| diff --git a/tools/skimage_main.cpp b/tools/skimage_main.cpp |
| index af9b4adea27b9dc1534ab5e654d535e836a2fcc3..afa1f78407f79560ef88414e67364a688a94c8f4 100644 |
| --- a/tools/skimage_main.cpp |
| +++ b/tools/skimage_main.cpp |
| @@ -7,6 +7,7 @@ |
| #include "SkBitmap.h" |
| #include "SkCommandLineFlags.h" |
| +#include "SkData.h" |
| #include "SkGraphics.h" |
| #include "SkImageDecoder.h" |
| #include "SkImageEncoder.h" |
| @@ -14,47 +15,61 @@ |
| #include "SkStream.h" |
| #include "SkTArray.h" |
| #include "SkTemplates.h" |
| - |
| +#include "picture_utils.h" |
| DEFINE_string2(readPath, r, "", "Folder(s) and files to decode images. Required."); |
| DEFINE_string2(writePath, w, "", "Write rendered images into this directory."); |
| +DEFINE_bool(reencode, true, "Reencode the images to test encoding."); |
| -// Store the names of the filenames to report later which ones failed, succeeded, and were |
| -// invalid. |
| -static SkTArray<SkString, false> invalids; |
| -static SkTArray<SkString, false> nocodecs; |
| -static SkTArray<SkString, false> failures; |
| -static SkTArray<SkString, false> successes; |
| +struct Format { |
| + SkImageEncoder::Type fType; |
| + SkImageDecoder::Format fFormat; |
| + const char* fSuffix; |
| +}; |
| -static bool decodeFile(SkBitmap* bitmap, const char srcPath[]) { |
| - SkFILEStream stream(srcPath); |
| - if (!stream.isValid()) { |
| - invalids.push_back().set(srcPath); |
| - return false; |
| - } |
| +static const Format gFormats[] = { |
| + { SkImageEncoder::kUnknown_Type, SkImageDecoder::kUnknown_Format, "" }, |
| + { SkImageEncoder::kBMP_Type, SkImageDecoder::kBMP_Format, ".bmp" }, |
| + { SkImageEncoder::kGIF_Type, SkImageDecoder::kGIF_Format, ".gif" }, |
| + { SkImageEncoder::kICO_Type, SkImageDecoder::kICO_Format, ".ico" }, |
| + { SkImageEncoder::kJPEG_Type, SkImageDecoder::kJPEG_Format, ".jpg" }, |
| + { SkImageEncoder::kPNG_Type, SkImageDecoder::kPNG_Format, ".png" }, |
| + { SkImageEncoder::kWBMP_Type, SkImageDecoder::kWBMP_Format, ".wbmp" }, |
| + { SkImageEncoder::kWEBP_Type, SkImageDecoder::kWEBP_Format, ".webp" } |
| +}; |
| - SkImageDecoder* codec = SkImageDecoder::Factory(&stream); |
| - if (NULL == codec) { |
| - nocodecs.push_back().set(srcPath); |
| - return false; |
| +static SkImageEncoder::Type format_to_type(SkImageDecoder::Format format) { |
| + for (size_t i = 0; i < SK_ARRAY_COUNT(gFormats); i++) { |
| + if (gFormats[i].fFormat == format) { |
| + return gFormats[i].fType; |
| + } |
| } |
| + return SkImageEncoder::kUnknown_Type; |
| +} |
| - SkAutoTDelete<SkImageDecoder> ad(codec); |
| - |
| - stream.rewind(); |
| - if (!codec->decode(&stream, bitmap, SkBitmap::kARGB_8888_Config, |
| - SkImageDecoder::kDecodePixels_Mode)) { |
| - failures.push_back().set(srcPath); |
| - return false; |
| +static const char* suffix_for_type(SkImageEncoder::Type type) { |
| + for (size_t i = 0; i < SK_ARRAY_COUNT(gFormats); i++) { |
| + if (gFormats[i].fType == type) { |
| + return gFormats[i].fSuffix; |
| + } |
| } |
| - |
| - successes.push_back().printf("%s [%d %d]", srcPath, bitmap->width(), bitmap->height()); |
| - return true; |
| + return ""; |
| } |
| -/////////////////////////////////////////////////////////////////////////////// |
| +static SkImageEncoder::Type guess_type_from_suffix(const char suffix[]) { |
| + for (size_t i = 0; i < SK_ARRAY_COUNT(gFormats); i++) { |
| + if (SkImageEncoder::kUnknown_Type == gFormats[i].fType) { |
| + continue; |
| + } |
| + if (strcmp(suffix, gFormats[i].fSuffix) == 0) { |
| + return gFormats[i].fType; |
| + } |
| + } |
| + return SkImageEncoder::kUnknown_Type; |
| +} |
| -static void make_outname(SkString* dst, const char outDir[], const char src[]) { |
| +static void make_outname(SkString* dst, const char outDir[], const char src[], |
| + const char suffix[]) { |
| dst->set(outDir); |
| const char* start = strrchr(src, '/'); |
| if (start) { |
| @@ -63,17 +78,116 @@ static void make_outname(SkString* dst, const char outDir[], const char src[]) { |
| start = src; |
| } |
| dst->append(start); |
| - if (!dst->endsWith(".png")) { |
| + if (!dst->endsWith(suffix)) { |
| const char* cstyleDst = dst->c_str(); |
| const char* dot = strrchr(cstyleDst, '.'); |
| if (dot != NULL) { |
| int32_t index = SkToS32(dot - cstyleDst); |
| dst->remove(index, dst->size() - index); |
| } |
| - dst->append(".png"); |
| + dst->append(suffix); |
| + } |
| +} |
| + |
| +// Store the names of the filenames to report later which ones failed, succeeded, and were |
| +// invalid. |
| +static SkTArray<SkString, false> gInvalidStreams; |
| +static SkTArray<SkString, false> gMissingCodecs; |
| +static SkTArray<SkString, false> gDecodeFailures; |
| +static SkTArray<SkString, false> gEncodeFailures; |
| +static SkTArray<SkString, false> gSuccessfulDecodes; |
| + |
| +static void decodeFileAndWrite(const char srcPath[], const SkString* writePath) { |
| + SkBitmap bitmap; |
| + SkFILEStream stream(srcPath); |
| + if (!stream.isValid()) { |
| + gInvalidStreams.push_back().set(srcPath); |
| + return; |
| + } |
| + |
| + SkImageDecoder* codec = SkImageDecoder::Factory(&stream); |
| + if (NULL == codec) { |
| + gMissingCodecs.push_back().set(srcPath); |
| + return; |
| + } |
| + |
| + SkAutoTDelete<SkImageDecoder> ad(codec); |
| + |
| + stream.rewind(); |
| + if (!codec->decode(&stream, &bitmap, SkBitmap::kARGB_8888_Config, |
| + SkImageDecoder::kDecodePixels_Mode)) { |
| + gDecodeFailures.push_back().set(srcPath); |
| + return; |
| + } |
| + |
| + gSuccessfulDecodes.push_back().printf("%s [%d %d]", srcPath, bitmap.width(), bitmap.height()); |
| + |
| + if (FLAGS_reencode) { |
| + // Encode to the format the file was originally in, or PNG if the encoder for the same |
| + // format is unavailable. |
| + SkImageEncoder::Type type = format_to_type(codec->getFormat()); |
| + if (SkImageEncoder::kUnknown_Type == type) { |
| + const char* dot = strrchr(srcPath, '.'); |
| + if (NULL != dot) { |
| + type = guess_type_from_suffix(dot); |
| + } |
| + if (SkImageEncoder::kUnknown_Type == type) { |
| + SkDebugf("Could not determine type for '%s'\n", srcPath); |
| + type = SkImageEncoder::kPNG_Type; |
| + } |
| + } |
| + |
| + SkImageEncoder* encoder = SkImageEncoder::Create(type); |
| + if (NULL == encoder) { |
| + type = SkImageEncoder::kPNG_Type; |
| + encoder = SkImageEncoder::Create(type); |
| + SkASSERT(encoder); |
| + } |
| + SkAutoTDelete<SkImageEncoder> ade(encoder); |
| + // Encode to a stream. |
| + SkDynamicMemoryWStream wStream; |
| + if (!encoder->encodeStream(&wStream, bitmap, 100)) { |
| + gEncodeFailures.push_back().printf("Failed to reencode %s to type '%s'", srcPath, |
| + suffix_for_type(type)); |
| + return; |
| + } |
| + |
| + SkAutoTUnref<SkData> data(wStream.copyToData()); |
| + if (writePath != NULL && type != SkImageEncoder::kPNG_Type) { |
| + // Write the encoded data to a file. Do not write to PNG, which will be written later, |
| + // regardless of the input format. |
| + SkString outPath; |
| + make_outname(&outPath, writePath->c_str(), srcPath, suffix_for_type(type)); |
| + SkFILEWStream file(outPath.c_str()); |
| + if(file.write(data->data(), data->size())) { |
| + gSuccessfulDecodes.push_back().appendf("\twrote %s", outPath.c_str()); |
| + } else { |
| + gEncodeFailures.push_back().printf("Failed to write %s", outPath.c_str()); |
| + } |
| + } |
| + // Ensure that the reencoded data can still be decoded. |
| + SkMemoryStream memStream(data); |
| + SkBitmap redecodedBitmap; |
| + if (!SkImageDecoder::DecodeStream(&memStream, &redecodedBitmap)) { |
| + gDecodeFailures.push_back().printf("Failed to redecode %s after reencoding to '%s'", |
| + srcPath, suffix_for_type(type)); |
| + } |
| + } |
| + |
| + if (writePath != NULL) { |
| + SkString outPath; |
| + make_outname(&outPath, writePath->c_str(), srcPath, ".png"); |
| + sk_tools::force_all_opaque(bitmap); |
| + if (SkImageEncoder::EncodeFile(outPath.c_str(), bitmap, SkImageEncoder::kPNG_Type, 100)) { |
| + gSuccessfulDecodes.push_back().appendf("\twrote %s", outPath.c_str()); |
| + } else { |
| + gEncodeFailures.push_back().set(outPath); |
| + } |
| } |
| } |
| +/////////////////////////////////////////////////////////////////////////////// |
| + |
| // If strings is not empty, print title, followed by each string on its own line starting |
| // with a tab. |
| static void print_strings(const char* title, const SkTArray<SkString, false>& strings) { |
| @@ -86,18 +200,6 @@ static void print_strings(const char* title, const SkTArray<SkString, false>& st |
| } |
| } |
| -static void decodeFileAndWrite(const char filePath[], const SkString* writePath) { |
| - SkBitmap bitmap; |
| - if (decodeFile(&bitmap, filePath)) { |
| - if (writePath != NULL) { |
| - SkString outPath; |
| - make_outname(&outPath, writePath->c_str(), filePath); |
| - successes.push_back().appendf("\twrote %s", outPath.c_str()); |
| - SkImageEncoder::EncodeFile(outPath.c_str(), bitmap, SkImageEncoder::kPNG_Type, 100); |
| - } |
| - } |
| -} |
| - |
| int tool_main(int argc, char** argv); |
| int tool_main(int argc, char** argv) { |
| SkCommandLineFlags::SetUsage("Decode files, and optionally write the results to files."); |
| @@ -148,10 +250,11 @@ int tool_main(int argc, char** argv) { |
| // Add some space, since codecs may print warnings without newline. |
| SkDebugf("\n\n"); |
| - print_strings("Invalid files", invalids); |
|
epoger
2013/04/19 21:35:16
I have to give the previous author style points fo
scroggo
2013/04/19 22:12:01
Haha, that would be me. Thanks ;)
|
| - print_strings("Missing codec", nocodecs); |
| - print_strings("Failed to decode", failures); |
| - print_strings("Decoded", successes); |
| + print_strings("Invalid files", gInvalidStreams); |
| + print_strings("Missing codec", gMissingCodecs); |
| + print_strings("Failed to decode", gDecodeFailures); |
| + print_strings("Failed to encode", gEncodeFailures); |
| + print_strings("Decoded", gSuccessfulDecodes); |
| return 0; |
| } |