Chromium Code Reviews| Index: tools/skimage_main.cpp |
| diff --git a/tools/skimage_main.cpp b/tools/skimage_main.cpp |
| index af9b4adea27b9dc1534ab5e654d535e836a2fcc3..db4ee7595867d5b7502e7836dab016da6c821937 100644 |
| --- a/tools/skimage_main.cpp |
| +++ b/tools/skimage_main.cpp |
| @@ -6,7 +6,9 @@ |
| */ |
| #include "SkBitmap.h" |
| +#include "SkColorPriv.h" |
| #include "SkCommandLineFlags.h" |
| +#include "SkData.h" |
| #include "SkGraphics.h" |
| #include "SkImageDecoder.h" |
| #include "SkImageEncoder.h" |
| @@ -15,46 +17,55 @@ |
| #include "SkTArray.h" |
| #include "SkTemplates.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::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 (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 +74,146 @@ 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 bool write_bitmap(const char outName[], SkBitmap* bm) { |
| + SkBitmap* bmPtr; |
|
epoger
2013/04/23 16:03:41
or, rather than creating this additional SkBitmap*
scroggo
2013/04/24 18:00:05
Done.
|
| + SkBitmap bitmap8888; |
| + if (SkBitmap::kARGB_8888_Config == bm->config()) { |
| + bmPtr = bm; |
| + } else { |
| + if (!bm->copyTo(&bitmap8888, SkBitmap::kARGB_8888_Config)) { |
| + return false; |
| + } |
| + bmPtr = &bitmap8888; |
| + } |
| + // FIXME: This forces all pixels to be opaque, like the many implementations |
| + // of force_all_opaque. These should be unified if they cannot be eliminated. |
| + SkAutoLockPixels lock(*bmPtr); |
| + for (int y = 0; y < bmPtr->height(); y++) { |
| + for (int x = 0; x < bmPtr->width(); x++) { |
| + *bmPtr->getAddr32(x, y) |= (SK_A32_MASK << SK_A32_SHIFT); |
| + } |
| + } |
| + return SkImageEncoder::EncodeFile(outName, *bmPtr, SkImageEncoder::kPNG_Type, 100); |
| +} |
| + |
| +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. |
| + SkImageDecoder::Format format = codec->getFormat(); |
| + if (SkImageDecoder::kMultiple_Formats == format |
| + || SkImageDecoder::kUnknown_Format == format) { |
| + if (stream.rewind()) { |
| + format = codec->getFormat(&stream); |
| + } |
| + } else { |
| + SkASSERT(!stream.rewind() || codec->getFormat(&stream) == format); |
| + } |
| + SkImageEncoder::Type type = format_to_type(format); |
| + 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"); |
| + if (write_bitmap(outPath.c_str(), &bitmap)) { |
| + 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 +226,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 +276,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); |
| - 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; |
| } |