diff options
-rw-r--r-- | gyp/tools.gyp | 14 | ||||
-rw-r--r-- | tools/render_pictures_main.cpp | 129 | ||||
-rw-r--r-- | tools/test_pictures.py | 130 |
3 files changed, 273 insertions, 0 deletions
diff --git a/gyp/tools.gyp b/gyp/tools.gyp index 349b0e068e..04356c690e 100644 --- a/gyp/tools.gyp +++ b/gyp/tools.gyp @@ -18,6 +18,7 @@ 'skdiff', 'skhello', 'skimage', + 'render_pictures', ], }, { @@ -62,6 +63,19 @@ 'utils.gyp:utils', ], }, + { + 'target_name': 'render_pictures', + 'type': 'executable', + 'sources': [ + '../tools/render_pictures_main.cpp', + ], + 'dependencies': [ + 'core.gyp:core', + 'images.gyp:images', + 'ports.gyp:ports', + ], + }, + ], } diff --git a/tools/render_pictures_main.cpp b/tools/render_pictures_main.cpp new file mode 100644 index 0000000000..0e7232e2dc --- /dev/null +++ b/tools/render_pictures_main.cpp @@ -0,0 +1,129 @@ +/* + * Copyright 2012 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 "SkCanvas.h" +#include "SkColorPriv.h" +#include "SkImageEncoder.h" +#include "SkOSFile.h" +#include "SkPicture.h" +#include "SkStream.h" +#include "SkString.h" + + +static void usage(const char* argv0) { + SkDebugf("SkPicture rendering tool\n"); + SkDebugf("\n" +"Usage: \n" +" %s <inputDir> <outputDir> \n\n" +, argv0); + SkDebugf( +" inputDir: directory to read the serialized SkPicture files.\n"); + SkDebugf( +" outputDir: directory to write the rendered images.\n"); +} + +static void make_filepath(SkString* path, const char* dir, + const SkString& name) { + size_t len = strlen(dir); + path->set(dir); + if (0 < len && '/' != dir[len - 1]) { + path->append("/"); + } + path->append(name); +} + +static void open_picture_stream(const char* inputDir, + const SkString& inputFilename, + SkFILEStream* inputStream) { + SkString inputPath; + make_filepath(&inputPath, inputDir, inputFilename); + inputStream->setPath(inputPath.c_str()); + if (!inputStream->isValid()) { + SkDebugf("Could not open file %s\n", inputPath.c_str()); + } +} + +static void make_output_filepath(SkString* path, const char* dir, + const SkString& name) { + make_filepath(path, dir, name); + path->remove(path->size() - 3, 3); + path->append("png"); +} + +static void setup_bitmap(SkPicture& picture, SkBitmap* bitmap) { + bitmap->setConfig(SkBitmap::kARGB_8888_Config, picture.width(), + picture.height()); + bitmap->allocPixels(); + bitmap->eraseColor(0); +} + +static void generate_image_from_picture(SkPicture& pict, SkBitmap* bitmap) { + setup_bitmap(pict, bitmap); + SkCanvas canvas(*bitmap); + canvas.drawPicture(pict); +} + +/* since PNG insists on unpremultiplying our alpha, we take no precision chances + and force all pixels to be 100% opaque, otherwise on compare we may not get + a perfect match. + */ +static void force_all_opaque(const SkBitmap& bitmap) { + SkAutoLockPixels lock(bitmap); + for (int y = 0; y < bitmap.height(); y++) { + for (int x = 0; x < bitmap.width(); x++) { + *bitmap.getAddr32(x, y) |= (SK_A32_MASK << SK_A32_SHIFT); + } + } +} + +static bool write_bitmap(const SkString& path, const SkBitmap& bitmap) { + SkBitmap copy; + bitmap.copyTo(©, SkBitmap::kARGB_8888_Config); + force_all_opaque(copy); + return SkImageEncoder::EncodeFile(path.c_str(), copy, + SkImageEncoder::kPNG_Type, 100); +} + +static void write_output(const char* outputDir, const SkString& inputFilename, + const SkBitmap& bitmap) { + SkString outputPath; + make_output_filepath(&outputPath, outputDir, inputFilename); + bool isWritten = write_bitmap(outputPath, bitmap); + if (!isWritten) { + SkDebugf("Could not write to file %s\n", outputPath.c_str()); + } +} + +static void render_picture(const char* inputDir, const char* outputDir, + const SkString& inputFilename) { + SkFILEStream inputStream; + open_picture_stream(inputDir, inputFilename, &inputStream); + SkPicture picture(&inputStream); + SkBitmap bitmap; + generate_image_from_picture(picture, &bitmap); + write_output(outputDir, inputFilename, bitmap); +} + +int main(int argc, char* const argv[]) { + const char* inputDir; + const char* outputDir; + if (argc != 3) { + usage(argv[0]); + } + + inputDir = argv[1]; + outputDir = argv[2]; + + SkOSFile::Iter iter(inputDir, "skp"); + SkString inputFilename; + + while(iter.next(&inputFilename)) { + render_picture(inputDir, outputDir, inputFilename); + } +} diff --git a/tools/test_pictures.py b/tools/test_pictures.py new file mode 100644 index 0000000000..253bf4e50d --- /dev/null +++ b/tools/test_pictures.py @@ -0,0 +1,130 @@ +''' +Compares the rendererings of serialized SkPictures to expected images. + +Launch with --help to see more information. + + +Copyright 2012 Google Inc. + +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +''' +# common Python modules +import os +import optparse +import sys +import shutil +import tempfile + +USAGE_STRING = 'Usage: %s inputDir expectedDir [renderDir [diffDir]]' +HELP_STRING = ''' + +Compares the renderings of serialized SkPicture files in inputDir with the +images in expectedDir. +''' + +def RunCommand(command): + """Run a command. + + @param command the command as a single string + """ + print 'running command [%s]...' % command + os.system(command) + + +def FindPathToProgram(program): + """Return path to an existing program binary, or raise an exception if we + cannot find one. + + @param program the name of the program that is being looked for + """ + trunk_path = os.path.abspath(os.path.join(os.path.dirname(__file__), + os.pardir)) + possible_paths = [os.path.join(trunk_path, 'out', 'Release', program), + os.path.join(trunk_path, 'out', 'Debug', program)] + for try_path in possible_paths: + if os.path.isfile(try_path): + return try_path + raise Exception('cannot find %s in paths %s; maybe you need to ' + 'build %s?' % (program, possible_paths, program)) + + +def RenderImages(input_dir, render_dir): + """Renders the serialized SkPictures. + + Uses the render_pictures program to do the rendering. + + @param input_dir the location to read the serlialized SkPictures + @param render_dir the location to write out the rendered images + """ + renderer_path = FindPathToProgram('render_pictures') + RunCommand('%s %s %s' % (renderer_path, input_dir, render_dir)) + + +def DiffImages(expected_dir, comparison_dir, diff_dir): + """Diffs the rendered SkPicture images with the baseline images. + + Uses the skdiff program to do the diffing. + + @param expected_dir the location of the baseline images. + @param comparison_dir the location of the images to comapre with the + baseline + @param diff_dir the location to write out the diff results + """ + skdiff_path = FindPathToProgram('skdiff') + RunCommand('%s %s %s %s' % + (skdiff_path, expected_dir, comparison_dir, diff_dir)) + + +def Cleanup(options, render_dir, diff_dir): + """Deletes any temporary folders and files created. + + @param options The OptionParser object that parsed if render_dir or diff_dir + was set + @param render_dir the directory where the rendered images were written + @param diff_dir the directory where the diff results were written + """ + if (not options.render_dir): + if (os.path.isdir(render_dir)): + shutil.rmtree(render_dir) + if (not options.diff_dir): + if (os.path.isdir(diff_dir)): + shutil.rmtree(diff_dir) + + +def Main(args): + """Allow other scripts to call this script with fake command-line args. + + @param The commandline argument list + """ + parser = optparse.OptionParser(USAGE_STRING % '%prog' + HELP_STRING) + parser.add_option('--render_dir', dest='render_dir', + help = ("specify the location to output the rendered files." + " Default is a temp directory.")) + parser.add_option('--diff_dir', dest='diff_dir', + help = ("specify the location to output the diff files." + " Default is a temp directory.")) + + options, arguments = parser.parse_args(args) + + input_dir = arguments[1] + expected_dir = arguments[2] + + if (options.render_dir): + render_dir = options.render_dir + else: + render_dir = tempfile.mkdtemp() + + if (options.diff_dir): + diff_dir = options.diff_dir + else: + diff_dir = tempfile.mkdtemp() + + try: + RenderImages(input_dir, render_dir) + DiffImages(expected_dir, render_dir, diff_dir) + finally: + Cleanup(options, render_dir, diff_dir) + +if __name__ == '__main__': + Main(sys.argv) |