Home | History | Annotate | Download | only in tools
      1 /*
      2  * Copyright 2012 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "LazyDecodeBitmap.h"
      9 #include "CopyTilesRenderer.h"
     10 #include "SkBitmap.h"
     11 #include "SkDevice.h"
     12 #include "SkCommandLineFlags.h"
     13 #include "SkGraphics.h"
     14 #include "SkImageDecoder.h"
     15 #include "SkImageEncoder.h"
     16 #include "SkMath.h"
     17 #include "SkOSFile.h"
     18 #include "SkPicture.h"
     19 #include "SkStream.h"
     20 #include "SkString.h"
     21 #include "PictureRenderer.h"
     22 #include "PictureRenderingFlags.h"
     23 #include "picture_utils.h"
     24 
     25 // Flags used by this file, alphabetically:
     26 DEFINE_int32(clone, 0, "Clone the picture n times before rendering.");
     27 DECLARE_bool(deferImageDecoding);
     28 DEFINE_int32(maxComponentDiff, 256, "Maximum diff on a component, 0 - 256. Components that differ "
     29              "by more than this amount are considered errors, though all diffs are reported. "
     30              "Requires --validate.");
     31 DECLARE_string(readPath);
     32 DEFINE_bool(writeEncodedImages, false, "Any time the skp contains an encoded image, write it to a "
     33             "file rather than decoding it. Requires writePath to be set. Skips drawing the full "
     34             "skp to a file. Not compatible with deferImageDecoding.");
     35 DEFINE_string2(writePath, w, "", "Directory to write the rendered images.");
     36 DEFINE_bool(writeWholeImage, false, "In tile mode, write the entire rendered image to a "
     37             "file, instead of an image for each tile.");
     38 DEFINE_bool(validate, false, "Verify that the rendered image contains the same pixels as "
     39             "the picture rendered in simple mode. When used in conjunction with --bbh, results "
     40             "are validated against the picture rendered in the same mode, but without the bbh.");
     41 
     42 DEFINE_bool(bench_record, false, "If true, drop into an infinite loop of recording the picture.");
     43 
     44 static void make_output_filepath(SkString* path, const SkString& dir,
     45                                  const SkString& name) {
     46     sk_tools::make_filepath(path, dir, name);
     47     // Remove ".skp"
     48     path->remove(path->size() - 4, 4);
     49 }
     50 
     51 ////////////////////////////////////////////////////////////////////////////////////////////////////
     52 
     53 /**
     54  *  Table for translating from format of data to a suffix.
     55  */
     56 struct Format {
     57     SkImageDecoder::Format  fFormat;
     58     const char*             fSuffix;
     59 };
     60 static const Format gFormats[] = {
     61     { SkImageDecoder::kBMP_Format, ".bmp" },
     62     { SkImageDecoder::kGIF_Format, ".gif" },
     63     { SkImageDecoder::kICO_Format, ".ico" },
     64     { SkImageDecoder::kJPEG_Format, ".jpg" },
     65     { SkImageDecoder::kPNG_Format, ".png" },
     66     { SkImageDecoder::kWBMP_Format, ".wbmp" },
     67     { SkImageDecoder::kWEBP_Format, ".webp" },
     68     { SkImageDecoder::kUnknown_Format, "" },
     69 };
     70 
     71 /**
     72  *  Get an appropriate suffix for an image format.
     73  */
     74 static const char* get_suffix_from_format(SkImageDecoder::Format format) {
     75     for (size_t i = 0; i < SK_ARRAY_COUNT(gFormats); i++) {
     76         if (gFormats[i].fFormat == format) {
     77             return gFormats[i].fSuffix;
     78         }
     79     }
     80     return "";
     81 }
     82 
     83 /**
     84  *  Base name for an image file created from the encoded data in an skp.
     85  */
     86 static SkString gInputFileName;
     87 
     88 /**
     89  *  Number to be appended to the image file name so that it is unique.
     90  */
     91 static uint32_t gImageNo;
     92 
     93 /**
     94  *  Set up the name for writing encoded data to a file.
     95  *  Sets gInputFileName to name, minus any extension ".*"
     96  *  Sets gImageNo to 0, so images from file "X.skp" will
     97  *  look like "X_<gImageNo>.<suffix>", beginning with 0
     98  *  for each new skp.
     99  */
    100 static void reset_image_file_base_name(const SkString& name) {
    101     gImageNo = 0;
    102     // Remove ".skp"
    103     const char* cName = name.c_str();
    104     const char* dot = strrchr(cName, '.');
    105     if (dot != NULL) {
    106         gInputFileName.set(cName, dot - cName);
    107     } else {
    108         gInputFileName.set(name);
    109     }
    110 }
    111 
    112 /**
    113  *  Write the raw encoded bitmap data to a file.
    114  */
    115 static bool write_image_to_file(const void* buffer, size_t size, SkBitmap* bitmap) {
    116     SkASSERT(!FLAGS_writePath.isEmpty());
    117     SkMemoryStream memStream(buffer, size);
    118     SkString outPath;
    119     SkImageDecoder::Format format = SkImageDecoder::GetStreamFormat(&memStream);
    120     SkString name = SkStringPrintf("%s_%d%s", gInputFileName.c_str(), gImageNo++,
    121                                    get_suffix_from_format(format));
    122     SkString dir(FLAGS_writePath[0]);
    123     sk_tools::make_filepath(&outPath, dir, name);
    124     SkFILEWStream fileStream(outPath.c_str());
    125     if (!(fileStream.isValid() && fileStream.write(buffer, size))) {
    126         SkDebugf("Failed to write encoded data to \"%s\"\n", outPath.c_str());
    127     }
    128     // Put in a dummy bitmap.
    129     return SkImageDecoder::DecodeStream(&memStream, bitmap, SkBitmap::kNo_Config,
    130                                         SkImageDecoder::kDecodeBounds_Mode);
    131 }
    132 
    133 ////////////////////////////////////////////////////////////////////////////////////////////////////
    134 
    135 static bool render_picture(const SkString& inputPath, const SkString* outputDir,
    136                            sk_tools::PictureRenderer& renderer,
    137                            SkBitmap** out) {
    138     SkString inputFilename;
    139     sk_tools::get_basename(&inputFilename, inputPath);
    140 
    141     SkFILEStream inputStream;
    142     inputStream.setPath(inputPath.c_str());
    143     if (!inputStream.isValid()) {
    144         SkDebugf("Could not open file %s\n", inputPath.c_str());
    145         return false;
    146     }
    147 
    148     SkPicture::InstallPixelRefProc proc;
    149     if (FLAGS_deferImageDecoding) {
    150         proc = &sk_tools::LazyDecodeBitmap;
    151     } else if (FLAGS_writeEncodedImages) {
    152         SkASSERT(!FLAGS_writePath.isEmpty());
    153         reset_image_file_base_name(inputFilename);
    154         proc = &write_image_to_file;
    155     } else {
    156         proc = &SkImageDecoder::DecodeMemory;
    157     }
    158 
    159     SkDebugf("deserializing... %s\n", inputPath.c_str());
    160 
    161     SkPicture* picture = SkPicture::CreateFromStream(&inputStream, proc);
    162 
    163     if (NULL == picture) {
    164         SkDebugf("Could not read an SkPicture from %s\n", inputPath.c_str());
    165         return false;
    166     }
    167 
    168     while (FLAGS_bench_record) {
    169         const int kRecordFlags = 0;
    170         SkPicture other;
    171         picture->draw(other.beginRecording(picture->width(), picture->height(), kRecordFlags));
    172         other.endRecording();
    173     }
    174 
    175     for (int i = 0; i < FLAGS_clone; ++i) {
    176         SkPicture* clone = picture->clone();
    177         SkDELETE(picture);
    178         picture = clone;
    179     }
    180 
    181     SkDebugf("drawing... [%i %i] %s\n", picture->width(), picture->height(),
    182              inputPath.c_str());
    183 
    184     renderer.init(picture);
    185     renderer.setup();
    186 
    187     SkString* outputPath = NULL;
    188     if (NULL != outputDir && outputDir->size() > 0 && !FLAGS_writeEncodedImages) {
    189         outputPath = SkNEW(SkString);
    190         make_output_filepath(outputPath, *outputDir, inputFilename);
    191     }
    192 
    193     bool success = renderer.render(outputPath, out);
    194     if (outputPath) {
    195         if (!success) {
    196             SkDebugf("Could not write to file %s\n", outputPath->c_str());
    197         }
    198         SkDELETE(outputPath);
    199     }
    200 
    201     renderer.end();
    202 
    203     SkDELETE(picture);
    204     return success;
    205 }
    206 
    207 static inline int getByte(uint32_t value, int index) {
    208     SkASSERT(0 <= index && index < 4);
    209     return (value >> (index * 8)) & 0xFF;
    210 }
    211 
    212 static int MaxByteDiff(uint32_t v1, uint32_t v2) {
    213     return SkMax32(SkMax32(abs(getByte(v1, 0) - getByte(v2, 0)), abs(getByte(v1, 1) - getByte(v2, 1))),
    214                    SkMax32(abs(getByte(v1, 2) - getByte(v2, 2)), abs(getByte(v1, 3) - getByte(v2, 3))));
    215 }
    216 
    217 namespace {
    218 class AutoRestoreBbhType {
    219 public:
    220     AutoRestoreBbhType() {
    221         fRenderer = NULL;
    222         fSavedBbhType = sk_tools::PictureRenderer::kNone_BBoxHierarchyType;
    223     }
    224 
    225     void set(sk_tools::PictureRenderer* renderer,
    226              sk_tools::PictureRenderer::BBoxHierarchyType bbhType) {
    227         fRenderer = renderer;
    228         fSavedBbhType = renderer->getBBoxHierarchyType();
    229         renderer->setBBoxHierarchyType(bbhType);
    230     }
    231 
    232     ~AutoRestoreBbhType() {
    233         if (NULL != fRenderer) {
    234             fRenderer->setBBoxHierarchyType(fSavedBbhType);
    235         }
    236     }
    237 
    238 private:
    239     sk_tools::PictureRenderer* fRenderer;
    240     sk_tools::PictureRenderer::BBoxHierarchyType fSavedBbhType;
    241 };
    242 }
    243 
    244 static bool render_picture(const SkString& inputPath, const SkString* outputDir,
    245                            sk_tools::PictureRenderer& renderer) {
    246     int diffs[256] = {0};
    247     SkBitmap* bitmap = NULL;
    248     bool success = render_picture(inputPath,
    249         FLAGS_writeWholeImage ? NULL : outputDir,
    250         renderer,
    251         FLAGS_validate || FLAGS_writeWholeImage ? &bitmap : NULL);
    252 
    253     if (!success || ((FLAGS_validate || FLAGS_writeWholeImage) && bitmap == NULL)) {
    254         SkDebugf("Failed to draw the picture.\n");
    255         SkDELETE(bitmap);
    256         return false;
    257     }
    258 
    259     if (FLAGS_validate) {
    260         SkBitmap* referenceBitmap = NULL;
    261         sk_tools::PictureRenderer* referenceRenderer;
    262         // If the renderer uses a BBoxHierarchy, then the reference renderer
    263         // will be the same renderer, without the bbh.
    264         AutoRestoreBbhType arbbh;
    265         if (sk_tools::PictureRenderer::kNone_BBoxHierarchyType !=
    266             renderer.getBBoxHierarchyType()) {
    267             referenceRenderer = &renderer;
    268             referenceRenderer->ref();  // to match auto unref below
    269             arbbh.set(referenceRenderer, sk_tools::PictureRenderer::kNone_BBoxHierarchyType);
    270         } else {
    271             referenceRenderer = SkNEW(sk_tools::SimplePictureRenderer);
    272         }
    273         SkAutoTUnref<sk_tools::PictureRenderer> aurReferenceRenderer(referenceRenderer);
    274 
    275         success = render_picture(inputPath, NULL, *referenceRenderer,
    276                                  &referenceBitmap);
    277 
    278         if (!success || NULL == referenceBitmap || NULL == referenceBitmap->getPixels()) {
    279             SkDebugf("Failed to draw the reference picture.\n");
    280             SkDELETE(bitmap);
    281             SkDELETE(referenceBitmap);
    282             return false;
    283         }
    284 
    285         if (success && (bitmap->width() != referenceBitmap->width())) {
    286             SkDebugf("Expected image width: %i, actual image width %i.\n",
    287                      referenceBitmap->width(), bitmap->width());
    288             SkDELETE(bitmap);
    289             SkDELETE(referenceBitmap);
    290             return false;
    291         }
    292         if (success && (bitmap->height() != referenceBitmap->height())) {
    293             SkDebugf("Expected image height: %i, actual image height %i",
    294                      referenceBitmap->height(), bitmap->height());
    295             SkDELETE(bitmap);
    296             SkDELETE(referenceBitmap);
    297             return false;
    298         }
    299 
    300         for (int y = 0; success && y < bitmap->height(); y++) {
    301             for (int x = 0; success && x < bitmap->width(); x++) {
    302                 int diff = MaxByteDiff(*referenceBitmap->getAddr32(x, y),
    303                                        *bitmap->getAddr32(x, y));
    304                 SkASSERT(diff >= 0 && diff <= 255);
    305                 diffs[diff]++;
    306 
    307                 if (diff > FLAGS_maxComponentDiff) {
    308                     SkDebugf("Expected pixel at (%i %i) exceedds maximum "
    309                                  "component diff of %i: 0x%x, actual 0x%x\n",
    310                              x, y, FLAGS_maxComponentDiff,
    311                              *referenceBitmap->getAddr32(x, y),
    312                              *bitmap->getAddr32(x, y));
    313                     SkDELETE(bitmap);
    314                     SkDELETE(referenceBitmap);
    315                     return false;
    316                 }
    317             }
    318         }
    319         SkDELETE(referenceBitmap);
    320 
    321         for (int i = 1; i <= 255; ++i) {
    322             if(diffs[i] > 0) {
    323                 SkDebugf("Number of pixels with max diff of %i is %i\n", i, diffs[i]);
    324             }
    325         }
    326     }
    327 
    328     if (FLAGS_writeWholeImage) {
    329         sk_tools::force_all_opaque(*bitmap);
    330         if (NULL != outputDir && FLAGS_writeWholeImage) {
    331             SkString inputFilename;
    332             sk_tools::get_basename(&inputFilename, inputPath);
    333             SkString outputPath;
    334             make_output_filepath(&outputPath, *outputDir, inputFilename);
    335             outputPath.append(".png");
    336             if (!SkImageEncoder::EncodeFile(outputPath.c_str(), *bitmap,
    337                                             SkImageEncoder::kPNG_Type, 100)) {
    338                 SkDebugf("Failed to draw the picture.\n");
    339                 success = false;
    340             }
    341         }
    342     }
    343     SkDELETE(bitmap);
    344 
    345     return success;
    346 }
    347 
    348 
    349 static int process_input(const char* input, const SkString* outputDir,
    350                          sk_tools::PictureRenderer& renderer) {
    351     SkOSFile::Iter iter(input, "skp");
    352     SkString inputFilename;
    353     int failures = 0;
    354     SkDebugf("process_input, %s\n", input);
    355     if (iter.next(&inputFilename)) {
    356         do {
    357             SkString inputPath;
    358             SkString inputAsSkString(input);
    359             sk_tools::make_filepath(&inputPath, inputAsSkString, inputFilename);
    360             if (!render_picture(inputPath, outputDir, renderer)) {
    361                 ++failures;
    362             }
    363         } while(iter.next(&inputFilename));
    364     } else if (SkStrEndsWith(input, ".skp")) {
    365         SkString inputPath(input);
    366         if (!render_picture(inputPath, outputDir, renderer)) {
    367             ++failures;
    368         }
    369     } else {
    370         SkString warning;
    371         warning.printf("Warning: skipping %s\n", input);
    372         SkDebugf(warning.c_str());
    373     }
    374     return failures;
    375 }
    376 
    377 int tool_main(int argc, char** argv);
    378 int tool_main(int argc, char** argv) {
    379     SkCommandLineFlags::SetUsage("Render .skp files.");
    380     SkCommandLineFlags::Parse(argc, argv);
    381 
    382     if (FLAGS_readPath.isEmpty()) {
    383         SkDebugf(".skp files or directories are required.\n");
    384         exit(-1);
    385     }
    386 
    387     if (FLAGS_maxComponentDiff < 0 || FLAGS_maxComponentDiff > 256) {
    388         SkDebugf("--maxComponentDiff must be between 0 and 256\n");
    389         exit(-1);
    390     }
    391 
    392     if (FLAGS_maxComponentDiff != 256 && !FLAGS_validate) {
    393         SkDebugf("--maxComponentDiff requires --validate\n");
    394         exit(-1);
    395     }
    396 
    397     if (FLAGS_clone < 0) {
    398         SkDebugf("--clone must be >= 0. Was %i\n", FLAGS_clone);
    399         exit(-1);
    400     }
    401 
    402     if (FLAGS_writeEncodedImages) {
    403         if (FLAGS_writePath.isEmpty()) {
    404             SkDebugf("--writeEncodedImages requires --writePath\n");
    405             exit(-1);
    406         }
    407         if (FLAGS_deferImageDecoding) {
    408             SkDebugf("--writeEncodedImages is not compatible with --deferImageDecoding\n");
    409             exit(-1);
    410         }
    411     }
    412 
    413     SkString errorString;
    414     SkAutoTUnref<sk_tools::PictureRenderer> renderer(parseRenderer(errorString,
    415                                                                    kRender_PictureTool));
    416     if (errorString.size() > 0) {
    417         SkDebugf("%s\n", errorString.c_str());
    418     }
    419 
    420     if (renderer.get() == NULL) {
    421         exit(-1);
    422     }
    423 
    424     SkAutoGraphics ag;
    425 
    426     SkString outputDir;
    427     if (FLAGS_writePath.count() == 1) {
    428         outputDir.set(FLAGS_writePath[0]);
    429     }
    430 
    431     int failures = 0;
    432     for (int i = 0; i < FLAGS_readPath.count(); i ++) {
    433         failures += process_input(FLAGS_readPath[i], &outputDir, *renderer.get());
    434     }
    435     if (failures != 0) {
    436         SkDebugf("Failed to render %i pictures.\n", failures);
    437         return 1;
    438     }
    439 #if SK_SUPPORT_GPU
    440 #if GR_CACHE_STATS
    441     if (renderer->isUsingGpuDevice()) {
    442         GrContext* ctx = renderer->getGrContext();
    443 
    444         ctx->printCacheStats();
    445     }
    446 #endif
    447 #endif
    448     return 0;
    449 }
    450 
    451 #if !defined SK_BUILD_FOR_IOS
    452 int main(int argc, char * const argv[]) {
    453     return tool_main(argc, (char**) argv);
    454 }
    455 #endif
    456