render_pictures_main.cpp revision 163c84ba5026907fea7b4f4bdcf8b16c13103adc
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 "SkBitmap.h"
9#include "SkCanvas.h"
10#include "SkDevice.h"
11#include "SkGraphics.h"
12#include "SkMath.h"
13#include "SkOSFile.h"
14#include "SkPicture.h"
15#include "SkStream.h"
16#include "SkString.h"
17#include "SkTArray.h"
18#include "PictureRenderer.h"
19#include "picture_utils.h"
20
21static void usage(const char* argv0) {
22    SkDebugf("SkPicture rendering tool\n");
23    SkDebugf("\n"
24"Usage: \n"
25"     %s <input>... <outputDir> \n"
26"     [--mode pipe | pow2tile minWidth height[%] | simple\n"
27"         | tile width[%] height[%]]\n"
28"     [--device bitmap"
29#if SK_SUPPORT_GPU
30" | gpu"
31#endif
32"]"
33, argv0);
34    SkDebugf("\n\n");
35    SkDebugf(
36"     input:     A list of directories and files to use as input. Files are\n"
37"                expected to have the .skp extension.\n\n");
38    SkDebugf(
39"     outputDir: directory to write the rendered images.\n\n");
40    SkDebugf(
41"     --mode pipe | pow2tile minWidth height[%] | simple\n"
42"          | tile width[%] height[%]: Run in the corresponding mode.\n"
43"                                     Default is simple.\n");
44    SkDebugf(
45"                     pipe, Render using a SkGPipe.\n");
46    SkDebugf(
47"                     pow2tile minWidth height[%], Creates tiles with widths\n"
48"                                                  that are all a power of two\n"
49"                                                  such that they minimize the\n"
50"                                                  amount of wasted tile space.\n"
51"                                                  minWidth is the minimum width\n"
52"                                                  of these tiles and must be a\n"
53"                                                  power of two. A simple render\n"
54"                                                  is done with these tiles.\n");
55    SkDebugf(
56"                     simple, Render using the default rendering method.\n");
57    SkDebugf(
58"                     tile width[%] height[%], Do a simple render using tiles\n"
59"                                              with the given dimensions.\n");
60    SkDebugf("\n");
61    SkDebugf(
62"     --device bitmap"
63#if SK_SUPPORT_GPU
64" | gpu"
65#endif
66": Use the corresponding device. Default is bitmap.\n");
67    SkDebugf(
68"                     bitmap, Render to a bitmap.\n");
69#if SK_SUPPORT_GPU
70    SkDebugf(
71"                     gpu, Render to the GPU.\n");
72#endif
73}
74
75static void make_output_filepath(SkString* path, const SkString& dir,
76                                 const SkString& name) {
77    sk_tools::make_filepath(path, dir, name);
78    path->remove(path->size() - 3, 3);
79    path->append("png");
80}
81
82static void write_output(const SkString& outputDir, const SkString& inputFilename,
83                         const sk_tools::PictureRenderer& renderer) {
84    SkString outputPath;
85    make_output_filepath(&outputPath, outputDir, inputFilename);
86    bool isWritten = renderer.write(outputPath);
87    if (!isWritten) {
88        SkDebugf("Could not write to file %s\n", outputPath.c_str());
89    }
90}
91
92static void render_picture(const SkString& inputPath, const SkString& outputDir,
93                           sk_tools::PictureRenderer& renderer) {
94    SkString inputFilename;
95    sk_tools::get_basename(&inputFilename, inputPath);
96
97    SkFILEStream inputStream;
98    inputStream.setPath(inputPath.c_str());
99    if (!inputStream.isValid()) {
100        SkDebugf("Could not open file %s\n", inputPath.c_str());
101        return;
102    }
103
104    SkPicture picture(&inputStream);
105
106    SkDebugf("drawing... [%i %i] %s\n", picture.width(), picture.height(),
107             inputPath.c_str());
108    renderer.init(&picture);
109
110    renderer.render(true);
111
112    renderer.resetState();
113
114    write_output(outputDir, inputFilename, renderer);
115
116    renderer.end();
117}
118
119static void process_input(const SkString& input, const SkString& outputDir,
120                          sk_tools::PictureRenderer& renderer) {
121    SkOSFile::Iter iter(input.c_str(), "skp");
122    SkString inputFilename;
123
124    if (iter.next(&inputFilename)) {
125        do {
126            SkString inputPath;
127            sk_tools::make_filepath(&inputPath, input, inputFilename);
128            render_picture(inputPath, outputDir, renderer);
129        } while(iter.next(&inputFilename));
130    } else {
131        SkString inputPath(input);
132        render_picture(inputPath, outputDir, renderer);
133    }
134}
135
136static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>* inputs,
137                              sk_tools::PictureRenderer*& renderer){
138    const char* argv0 = argv[0];
139    char* const* stop = argv + argc;
140
141    sk_tools::PictureRenderer::SkDeviceTypes deviceType =
142        sk_tools::PictureRenderer::kBitmap_DeviceType;
143
144    for (++argv; argv < stop; ++argv) {
145        if (0 == strcmp(*argv, "--mode")) {
146            SkDELETE(renderer);
147
148            ++argv;
149            if (argv >= stop) {
150                SkDebugf("Missing mode for --mode\n");
151                usage(argv0);
152                exit(-1);
153            }
154
155            if (0 == strcmp(*argv, "pipe")) {
156                renderer = SkNEW(sk_tools::PipePictureRenderer);
157            } else if (0 == strcmp(*argv, "simple")) {
158                renderer = SkNEW(sk_tools::SimplePictureRenderer);
159            } else if ((0 == strcmp(*argv, "tile")) || (0 == strcmp(*argv, "pow2tile"))) {
160                char* mode = *argv;
161                bool isPowerOf2Mode = false;
162
163                if (0 == strcmp(*argv, "pow2tile")) {
164                    isPowerOf2Mode = true;
165                }
166
167                sk_tools::TiledPictureRenderer* tileRenderer =
168                    SkNEW(sk_tools::TiledPictureRenderer);
169                ++argv;
170                if (argv >= stop) {
171                    SkDELETE(tileRenderer);
172                    SkDebugf("Missing width for --mode %s\n", mode);
173                    usage(argv0);
174                    exit(-1);
175                }
176
177                if (isPowerOf2Mode) {
178                    int minWidth = atoi(*argv);
179
180                    if (!SkIsPow2(minWidth) || minWidth <= 0) {
181                        SkDELETE(tileRenderer);
182                        SkDebugf("--mode %s must be given a width"
183                                 " value that is a power of two\n", mode);
184                        exit(-1);
185                    }
186
187                    tileRenderer->setTileMinPowerOf2Width(minWidth);
188                } else if (sk_tools::is_percentage(*argv)) {
189                    tileRenderer->setTileWidthPercentage(atof(*argv));
190                    if (!(tileRenderer->getTileWidthPercentage() > 0)) {
191                        SkDELETE(tileRenderer);
192                        SkDebugf("--mode %s must be given a width percentage > 0\n", mode);
193                        exit(-1);
194                    }
195                } else {
196                    tileRenderer->setTileWidth(atoi(*argv));
197                    if (!(tileRenderer->getTileWidth() > 0)) {
198                        SkDELETE(tileRenderer);
199                        SkDebugf("--mode %s must be given a width > 0\n", mode);
200                        exit(-1);
201                    }
202                }
203
204                ++argv;
205                if (argv >= stop) {
206                    SkDELETE(tileRenderer);
207                    SkDebugf("Missing height for --mode %s\n", mode);
208                    usage(argv0);
209                    exit(-1);
210                }
211
212                if (sk_tools::is_percentage(*argv)) {
213                    tileRenderer->setTileHeightPercentage(atof(*argv));
214                    if (!(tileRenderer->getTileHeightPercentage() > 0)) {
215                        SkDELETE(tileRenderer);
216                        SkDebugf(
217                            "--mode %s must be given a height percentage > 0\n", mode);
218                        exit(-1);
219                    }
220                } else {
221                    tileRenderer->setTileHeight(atoi(*argv));
222                    if (!(tileRenderer->getTileHeight() > 0)) {
223                        SkDELETE(tileRenderer);
224                        SkDebugf("--mode %s must be given a height > 0\n", mode);
225                        exit(-1);
226                    }
227                }
228
229                renderer = tileRenderer;
230            } else {
231                SkDebugf("%s is not a valid mode for --mode\n", *argv);
232                usage(argv0);
233                exit(-1);
234            }
235        } else if (0 == strcmp(*argv, "--device")) {
236            ++argv;
237            if (argv >= stop) {
238                SkDebugf("Missing mode for --deivce\n");
239                usage(argv0);
240                exit(-1);
241            }
242
243            if (0 == strcmp(*argv, "bitmap")) {
244                deviceType = sk_tools::PictureRenderer::kBitmap_DeviceType;
245            }
246#if SK_SUPPORT_GPU
247            else if (0 == strcmp(*argv, "gpu")) {
248                deviceType = sk_tools::PictureRenderer::kGPU_DeviceType;
249            }
250#endif
251            else {
252                SkDebugf("%s is not a valid mode for --device\n", *argv);
253                usage(argv0);
254                exit(-1);
255            }
256
257        } else if ((0 == strcmp(*argv, "-h")) || (0 == strcmp(*argv, "--help"))) {
258            SkDELETE(renderer);
259            usage(argv0);
260            exit(-1);
261        } else {
262            inputs->push_back(SkString(*argv));
263        }
264    }
265
266    if (inputs->count() < 2) {
267        SkDELETE(renderer);
268        usage(argv0);
269        exit(-1);
270    }
271
272    if (NULL == renderer) {
273        renderer = SkNEW(sk_tools::SimplePictureRenderer);
274    }
275
276    renderer->setDeviceType(deviceType);
277}
278
279int main(int argc, char* const argv[]) {
280    SkGraphics::Init();
281    SkTArray<SkString> inputs;
282    sk_tools::PictureRenderer* renderer = NULL;
283
284    parse_commandline(argc, argv, &inputs, renderer);
285    SkString outputDir = inputs[inputs.count() - 1];
286    SkASSERT(renderer);
287
288    for (int i = 0; i < inputs.count() - 1; i ++) {
289        process_input(inputs[i], outputDir, *renderer);
290    }
291
292#if SK_SUPPORT_GPU
293#if GR_CACHE_STATS
294    if (renderer->isUsingGpuDevice()) {
295        GrContext* ctx = renderer->getGrContext();
296
297        ctx->printCacheStats();
298    }
299#endif
300#endif
301
302    SkDELETE(renderer);
303    SkGraphics::Term();
304}
305