blob: ab20e3f9ed4a4f740a12c3672f5912682d83c07c [file] [log] [blame]
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +00001/*
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
robertphillips@google.com801cee12012-10-19 19:06:11 +00008#include "SkDevice.h"
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +00009#include "SkGraphics.h"
robertphillips@google.com4e4d75b2012-11-12 18:03:19 +000010#include "SkImageDecoder.h"
robertphillips@google.com801cee12012-10-19 19:06:11 +000011#include "SkImageEncoder.h"
djsollen@google.coma09e8832012-11-13 18:50:33 +000012#include "SkOSFile.h"
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +000013#include "SkPicture.h"
robertphillips@google.com801cee12012-10-19 19:06:11 +000014#include "SkPicturePlayback.h"
15#include "SkPictureRecord.h"
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +000016#include "SkStream.h"
djsollen@google.coma09e8832012-11-13 18:50:33 +000017#include "picture_utils.h"
robertphillips@google.comd3d377f2012-12-07 20:56:13 +000018#include "path_utils.h"
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +000019
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +000020static void usage() {
robertphillips@google.comd3d377f2012-12-07 20:56:13 +000021 SkDebugf("Usage: filter -i inFile [-o outFile] [--input-dir path] [--output-dir path]\n");
22 SkDebugf(" [-p pathFile] [-t textureDir] [-h|--help]\n\n");
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +000023 SkDebugf(" -i inFile : file to file.\n");
24 SkDebugf(" -o outFile : result of filtering.\n");
djsollen@google.coma09e8832012-11-13 18:50:33 +000025 SkDebugf(" --input-dir : process all files in dir with .skp extension.\n");
26 SkDebugf(" --output-dir : results of filtering the input dir.\n");
robertphillips@google.comd3d377f2012-12-07 20:56:13 +000027 SkDebugf(" -p pathFile : file in which to place compileable path data.\n");
djsollen@google.coma09e8832012-11-13 18:50:33 +000028 SkDebugf(" -t textureDir : directory in which to place textures. (only available w/ single file)\n");
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +000029 SkDebugf(" -h|--help : Show this help message.\n");
30}
31
robertphillips@google.com801cee12012-10-19 19:06:11 +000032// SkFilterRecord allows the filter to manipulate the read in SkPicture
33class SkFilterRecord : public SkPictureRecord {
34public:
robertphillips@google.comd3d377f2012-12-07 20:56:13 +000035 SkFilterRecord(uint32_t recordFlags, SkDevice* device, SkFILEWStream* pathStream)
robertphillips@google.com63f11272012-10-24 19:30:41 +000036 : INHERITED(recordFlags, device)
37 , fTransSkipped(0)
38 , fTransTot(0)
39 , fScalesSkipped(0)
robertphillips@google.comd3d377f2012-12-07 20:56:13 +000040 , fScalesTot(0)
41 , fPathStream(pathStream) {
42 }
43
44 virtual ~SkFilterRecord() {
45 }
46
47 virtual bool clipPath(const SkPath& path, SkRegion::Op op, bool doAntiAlias) SK_OVERRIDE {
48 if (!path.isRect(NULL) && 4 < path.countPoints()) {
49 sk_tools::dump_path(fPathStream, path);
50 }
51 return INHERITED::clipPath(path, op, doAntiAlias);
52 }
53
54 virtual void drawPath(const SkPath& path, const SkPaint& p) SK_OVERRIDE {
55 if (!path.isRect(NULL) && 4 < path.countPoints()) {
56 sk_tools::dump_path(fPathStream, path);
57 }
58 INHERITED::drawPath(path, p);
robertphillips@google.com63f11272012-10-24 19:30:41 +000059 }
60
61 virtual bool translate(SkScalar dx, SkScalar dy) SK_OVERRIDE {
62 ++fTransTot;
63
robertphillips@google.com4e4d75b2012-11-12 18:03:19 +000064#if 0
robertphillips@google.com63f11272012-10-24 19:30:41 +000065 if (0 == dx && 0 == dy) {
66 ++fTransSkipped;
67 return true;
68 }
robertphillips@google.com4e4d75b2012-11-12 18:03:19 +000069#endif
robertphillips@google.com63f11272012-10-24 19:30:41 +000070
71 return INHERITED::translate(dx, dy);
72 }
73
74 virtual bool scale(SkScalar sx, SkScalar sy) SK_OVERRIDE {
75 ++fScalesTot;
76
robertphillips@google.com4e4d75b2012-11-12 18:03:19 +000077#if 0
robertphillips@google.com63f11272012-10-24 19:30:41 +000078 if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
79 ++fScalesSkipped;
80 return true;
81 }
robertphillips@google.com4e4d75b2012-11-12 18:03:19 +000082#endif
robertphillips@google.com63f11272012-10-24 19:30:41 +000083
84 return INHERITED::scale(sx, sy);
robertphillips@google.com801cee12012-10-19 19:06:11 +000085 }
86
87 void saveImages(const SkString& path) {
88 SkTRefArray<SkBitmap>* bitmaps = fBitmapHeap->extractBitmaps();
89
90 if (NULL != bitmaps) {
91 for (int i = 0; i < bitmaps->count(); ++i) {
92 SkString filename(path);
93 if (!path.endsWith("\\")) {
94 filename.append("\\");
95 }
96 filename.append("image");
97 filename.appendS32(i);
98 filename.append(".png");
99
100 SkImageEncoder::EncodeFile(filename.c_str(), (*bitmaps)[i],
101 SkImageEncoder::kPNG_Type, 0);
102 }
103 }
104
105 bitmaps->unref();
106 }
107
robertphillips@google.com63f11272012-10-24 19:30:41 +0000108 void report() {
109 SkDebugf("%d Trans skipped (out of %d)\n", fTransSkipped, fTransTot);
110 SkDebugf("%d Scales skipped (out of %d)\n", fScalesSkipped, fScalesTot);
111 }
112
113protected:
114 int fTransSkipped;
115 int fTransTot;
116
117 int fScalesSkipped;
118 int fScalesTot;
119
robertphillips@google.comd3d377f2012-12-07 20:56:13 +0000120 SkFILEWStream* fPathStream;
robertphillips@google.com801cee12012-10-19 19:06:11 +0000121private:
122 typedef SkPictureRecord INHERITED;
123};
124
robertphillips@google.com63f11272012-10-24 19:30:41 +0000125// Wrap SkPicture to allow installation of a SkFilterRecord object
126class SkFilterPicture : public SkPicture {
127public:
robertphillips@google.com831c7262012-10-25 14:45:08 +0000128 SkFilterPicture(int width, int height, SkPictureRecord* record) {
129 fWidth = width;
130 fHeight = height;
robertphillips@google.com63f11272012-10-24 19:30:41 +0000131 fRecord = record;
132 SkSafeRef(fRecord);
133 }
134
135private:
136 typedef SkPicture INHERITED;
137};
138
humper@google.com05af1af2013-01-07 16:47:43 +0000139static int filter_picture(const SkString& inFile, const SkString& outFile,
robertphillips@google.comd3d377f2012-12-07 20:56:13 +0000140 const SkString& textureDir, SkFILEWStream *pathStream) {
djsollen@google.coma09e8832012-11-13 18:50:33 +0000141 SkPicture* inPicture = NULL;
142
143 SkFILEStream inStream(inFile.c_str());
144 if (inStream.isValid()) {
145 inPicture = SkNEW_ARGS(SkPicture, (&inStream, NULL, &SkImageDecoder::DecodeStream));
146 }
147
148 if (NULL == inPicture) {
149 SkDebugf("Could not read file %s\n", inFile.c_str());
150 return -1;
151 }
152
153 SkBitmap bm;
154 bm.setConfig(SkBitmap::kNo_Config, inPicture->width(), inPicture->height());
155 SkAutoTUnref<SkDevice> dev(SkNEW_ARGS(SkDevice, (bm)));
156
robertphillips@google.comd3d377f2012-12-07 20:56:13 +0000157 SkAutoTUnref<SkFilterRecord> filterRecord(SkNEW_ARGS(SkFilterRecord, (0, dev, pathStream)));
djsollen@google.coma09e8832012-11-13 18:50:33 +0000158
159 // Playback the read in picture to the SkFilterRecorder to allow filtering
160 filterRecord->beginRecording();
161 inPicture->draw(filterRecord);
162 filterRecord->endRecording();
163
164 filterRecord->report();
165
166 if (!outFile.isEmpty()) {
167 SkFilterPicture outPicture(inPicture->width(), inPicture->height(), filterRecord);
168 SkFILEWStream outStream(outFile.c_str());
169
170 outPicture.serialize(&outStream);
171 }
172
173 if (!textureDir.isEmpty()) {
174 filterRecord->saveImages(textureDir);
175 }
176
177 return 0;
178}
179
tfarina@chromium.orga5b7cc02012-10-08 14:41:10 +0000180// This function is not marked as 'static' so it can be referenced externally
181// in the iOS build.
humper@google.com05af1af2013-01-07 16:47:43 +0000182int tool_main(int argc, char** argv); // suppress a warning on mac
183
caryclark@google.com9598f422012-10-09 12:32:37 +0000184int tool_main(int argc, char** argv) {
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000185 SkGraphics::Init();
186
robertphillips@google.com801cee12012-10-19 19:06:11 +0000187 if (argc < 3) {
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000188 usage();
189 return -1;
190 }
191
robertphillips@google.comd3d377f2012-12-07 20:56:13 +0000192 SkString inFile, outFile, inDir, outDir, textureDir, pathFile;
robertphillips@google.com801cee12012-10-19 19:06:11 +0000193
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000194 char* const* stop = argv + argc;
195 for (++argv; argv < stop; ++argv) {
196 if (strcmp(*argv, "-i") == 0) {
197 argv++;
198 if (argv < stop && **argv) {
199 inFile.set(*argv);
200 } else {
robertphillips@google.com801cee12012-10-19 19:06:11 +0000201 SkDebugf("missing arg for -i\n");
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000202 usage();
203 return -1;
204 }
djsollen@google.coma09e8832012-11-13 18:50:33 +0000205 } else if (strcmp(*argv, "--input-dir") == 0) {
206 argv++;
207 if (argv < stop && **argv) {
208 inDir.set(*argv);
209 } else {
210 SkDebugf("missing arg for --input-dir\n");
211 usage();
212 return -1;
213 }
214 } else if (strcmp(*argv, "--output-dir") == 0) {
215 argv++;
216 if (argv < stop && **argv) {
217 outDir.set(*argv);
218 } else {
219 SkDebugf("missing arg for --output-dir\n");
220 usage();
221 return -1;
222 }
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000223 } else if (strcmp(*argv, "-o") == 0) {
224 argv++;
225 if (argv < stop && **argv) {
226 outFile.set(*argv);
227 } else {
robertphillips@google.com801cee12012-10-19 19:06:11 +0000228 SkDebugf("missing arg for -o\n");
229 usage();
230 return -1;
231 }
robertphillips@google.comd3d377f2012-12-07 20:56:13 +0000232 } else if (strcmp(*argv, "-p") == 0) {
233 argv++;
234 if (argv < stop && **argv) {
235 pathFile.set(*argv);
236 } else {
237 SkDebugf("missing arg for -p\n");
238 usage();
239 return -1;
240 }
robertphillips@google.com801cee12012-10-19 19:06:11 +0000241 } else if (strcmp(*argv, "-t") == 0) {
242 argv++;
243 if (argv < stop && **argv) {
244 textureDir.set(*argv);
245 } else {
246 SkDebugf("missing arg for -t\n");
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000247 usage();
248 return -1;
249 }
250 } else if (strcmp(*argv, "--help") == 0 || strcmp(*argv, "-h") == 0) {
251 usage();
252 return 0;
253 } else {
254 SkDebugf("unknown arg %s\n", *argv);
255 usage();
256 return -1;
257 }
258 }
259
djsollen@google.coma09e8832012-11-13 18:50:33 +0000260 if(!inDir.isEmpty() && !textureDir.isEmpty()) {
261 SkDebugf("ERROR: The textureDir option is not permitted when passing an input directory.\n");
robertphillips@google.com801cee12012-10-19 19:06:11 +0000262 usage();
263 return -1;
264 }
265
robertphillips@google.comd3d377f2012-12-07 20:56:13 +0000266 SkFILEWStream *pathStream = NULL;
267
268 if (!pathFile.isEmpty()) {
269 pathStream = new SkFILEWStream(pathFile.c_str());
270 if (!pathStream->isValid()) {
271 SkDebugf("Could open path file %s\n", pathFile.c_str());
272 delete pathStream;
273 return -1;
274 }
275
276 sk_tools::dump_path_prefix(pathStream);
277 }
278
djsollen@google.coma09e8832012-11-13 18:50:33 +0000279 SkOSFile::Iter iter(inDir.c_str(), "skp");
humper@google.com05af1af2013-01-07 16:47:43 +0000280
djsollen@google.coma09e8832012-11-13 18:50:33 +0000281 SkString inputFilename, outputFilename;
282 if (iter.next(&inputFilename)) {
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000283
djsollen@google.coma09e8832012-11-13 18:50:33 +0000284 do {
285 sk_tools::make_filepath(&inFile, inDir, inputFilename);
286 if (!outDir.isEmpty()) {
287 sk_tools::make_filepath(&outFile, outDir, inputFilename);
288 }
289 SkDebugf("Executing %s\n", inputFilename.c_str());
robertphillips@google.comd3d377f2012-12-07 20:56:13 +0000290 filter_picture(inFile, outFile, textureDir, pathStream);
djsollen@google.coma09e8832012-11-13 18:50:33 +0000291 } while(iter.next(&inputFilename));
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000292
djsollen@google.coma09e8832012-11-13 18:50:33 +0000293 } else if (!inFile.isEmpty()) {
robertphillips@google.comd3d377f2012-12-07 20:56:13 +0000294 filter_picture(inFile, outFile, textureDir, pathStream);
djsollen@google.coma09e8832012-11-13 18:50:33 +0000295 } else {
296 usage();
robertphillips@google.comd3d377f2012-12-07 20:56:13 +0000297 if (NULL != pathStream) {
298 delete pathStream;
299 pathStream = NULL;
300 }
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000301 return -1;
302 }
303
robertphillips@google.comd3d377f2012-12-07 20:56:13 +0000304 if (NULL != pathStream) {
305 sk_tools::dump_path_suffix(pathStream);
306 delete pathStream;
307 pathStream = NULL;
308 }
309
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000310 SkGraphics::Term();
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000311 return 0;
312}
313
314#if !defined SK_BUILD_FOR_IOS
315int main(int argc, char * const argv[]) {
caryclark@google.com9598f422012-10-09 12:32:37 +0000316 return tool_main(argc, (char**) argv);
robertphillips@google.comc7e4a5a2012-10-04 13:00:33 +0000317}
318#endif