Updates for the skimage tool.

Allow passing files or folders on the command line.

Group the output to show all successes together, all failures
together, etc.

When writing a new png, do not make its file type ".png.png"
if the original was a png.

Force linking for JPEG decoder.

Use SkCommandLineFlags.

Review URL: https://codereview.chromium.org/14089002

git-svn-id: http://skia.googlecode.com/svn/trunk@8615 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/tools/skimage_main.cpp b/tools/skimage_main.cpp
index 53cc6b3..dc5bdd4 100644
--- a/tools/skimage_main.cpp
+++ b/tools/skimage_main.cpp
@@ -1,27 +1,41 @@
-
 /*
  * Copyright 2011 Google Inc.
  *
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
+
 #include "SkBitmap.h"
+#include "SkCommandLineFlags.h"
 #include "SkGraphics.h"
 #include "SkImageDecoder.h"
 #include "SkImageEncoder.h"
+#include "SkOSFile.h"
 #include "SkStream.h"
+#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.");
+
+// 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;
+
 static bool decodeFile(SkBitmap* bitmap, const char srcPath[]) {
     SkFILEStream stream(srcPath);
     if (!stream.isValid()) {
-        SkDebugf("ERROR: bad filename <%s>\n", srcPath);
+        invalids.push_back().set(srcPath);
         return false;
     }
 
     SkImageDecoder* codec = SkImageDecoder::Factory(&stream);
     if (NULL == codec) {
-        SkDebugf("ERROR: no codec found for <%s>\n", srcPath);
+        nocodecs.push_back().set(srcPath);
         return false;
     }
 
@@ -30,18 +44,16 @@
     stream.rewind();
     if (!codec->decode(&stream, bitmap, SkBitmap::kARGB_8888_Config,
                        SkImageDecoder::kDecodePixels_Mode)) {
-        SkDebugf("ERROR: codec failed for <%s>\n", srcPath);
+        failures.push_back().set(srcPath);
         return false;
     }
+
+    successes.push_back().printf("%s [%d %d]", srcPath, bitmap->width(), bitmap->height());
     return true;
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
-static void show_help() {
-    SkDebugf("usage: skiamge [-o out-dir] inputfiles...\n");
-}
-
 static void make_outname(SkString* dst, const char outDir[], const char src[]) {
     dst->set(outDir);
     const char* start = strrchr(src, '/');
@@ -51,58 +63,106 @@
         start = src;
     }
     dst->append(start);
-    dst->append(".png");
+    if (!dst->endsWith(".png")) {
+        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");
+    }
+}
+
+// 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) {
+    if (strings.count() > 0) {
+        SkDebugf("%s:\n", title);
+        for (int i = 0; i < strings.count(); i++) {
+            SkDebugf("\t%s\n", strings[i].c_str());
+        }
+        SkDebugf("\n");
+    }
+}
+
+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.");
+    SkCommandLineFlags::Parse(argc, argv);
+
+    if (FLAGS_readPath.count() < 1) {
+        SkDebugf("Folder(s) or image(s) to decode are required.\n");
+        return -1;
+    }
+
+
     SkAutoGraphics ag;
-    int i, outDirIndex = 0;
+
     SkString outDir;
+    SkString* outDirPtr;
 
-    for (i = 1; i < argc; i++) {
-        if (!strcmp(argv[i], "-help")) {
-            show_help();
-            return 0;
+    if (FLAGS_writePath.count() == 1) {
+        outDir.set(FLAGS_writePath[0]);
+        if (outDir.c_str()[outDir.size() - 1] != '/') {
+            outDir.append("/");
         }
-        if (!strcmp(argv[i], "-o")) {
-            if (i == argc-1) {
-                SkDebugf("ERROR: -o needs a following filename\n");
-                return -1;
+        outDirPtr = &outDir;
+    } else {
+        outDirPtr = NULL;
+    }
+
+    for (int i = 0; i < FLAGS_readPath.count(); i++) {
+        if (strlen(FLAGS_readPath[i]) < 1) {
+            break;
+        }
+        SkOSFile::Iter iter(FLAGS_readPath[i]);
+        SkString filename;
+        if (iter.next(&filename)) {
+            SkString directory(FLAGS_readPath[i]);
+            if (directory[directory.size() - 1] != '/') {
+                directory.append("/");
             }
-            outDirIndex = i;
-            outDir.set(argv[i+1]);
-            if (outDir.c_str()[outDir.size() - 1] != '/') {
-                outDir.append("/");
-            }
-            i += 1; // skip the out dir name
+            do {
+                SkString fullname(directory);
+                fullname.append(filename);
+                decodeFileAndWrite(fullname.c_str(), outDirPtr);
+            } while (iter.next(&filename));
+        } else {
+            decodeFileAndWrite(FLAGS_readPath[i], outDirPtr);
         }
     }
 
-    for (i = 1; i < argc; i++) {
-        if (i == outDirIndex) {
-            i += 1; // skip this and the next entry
-            continue;
-        }
+    // Add some space, since codecs may print warnings without newline.
+    SkDebugf("\n\n");
 
-        SkBitmap bitmap;
-        if (decodeFile(&bitmap, argv[i])) {
-            if (outDirIndex) {
-                SkString outPath;
-                make_outname(&outPath, outDir.c_str(), argv[i]);
-                SkDebugf("  writing %s\n", outPath.c_str());
-                SkImageEncoder::EncodeFile(outPath.c_str(), bitmap,
-                                           SkImageEncoder::kPNG_Type, 100);
-            } else {
-                SkDebugf("  decoded %s [%d %d]\n", argv[i], bitmap.width(),
-                         bitmap.height());
-            }
-        }
-    }
+    print_strings("Invalid files", invalids);
+    print_strings("Missing codec", nocodecs);
+    print_strings("Failed to decode", failures);
+    print_strings("Decoded", successes);
 
     return 0;
 }
 
+void forceLinking();
+
+void forceLinking() {
+    SkDEBUGCODE(SkImageDecoder *creator = ) CreateJPEGImageDecoder();
+    SkASSERT(creator);
+}
+
 #if !defined SK_BUILD_FOR_IOS
 int main(int argc, char * const argv[]) {
     return tool_main(argc, (char**) argv);