filtermain.cpp revision 363e546ed626b6dbbc42f5db87b3594bc0b5944b
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 "SkDevice.h" 9#include "SkGraphics.h" 10#include "SkImageDecoder.h" 11#include "SkImageEncoder.h" 12#include "SkOSFile.h" 13#include "SkPicture.h" 14#include "SkPicturePlayback.h" 15#include "SkPictureRecord.h" 16#include "SkStream.h" 17#include "picture_utils.h" 18#include "path_utils.h" 19 20static void usage() { 21 SkDebugf("Usage: filter -i inFile [-o outFile] [--input-dir path] [--output-dir path]\n"); 22 SkDebugf(" [-p pathFile] [-t textureDir] [-h|--help]\n\n"); 23 SkDebugf(" -i inFile : file to file.\n"); 24 SkDebugf(" -o outFile : result of filtering.\n"); 25 SkDebugf(" --input-dir : process all files in dir with .skp extension.\n"); 26 SkDebugf(" --output-dir : results of filtering the input dir.\n"); 27 SkDebugf(" -p pathFile : file in which to place compileable path data.\n"); 28 SkDebugf(" -t textureDir : directory in which to place textures. (only available w/ single file)\n"); 29 SkDebugf(" -h|--help : Show this help message.\n"); 30} 31 32// SkFilterRecord allows the filter to manipulate the read in SkPicture 33class SkFilterRecord : public SkPictureRecord { 34public: 35 SkFilterRecord(uint32_t recordFlags, SkDevice* device, SkFILEWStream* pathStream) 36 : INHERITED(recordFlags, device) 37 , fTransSkipped(0) 38 , fTransTot(0) 39 , fScalesSkipped(0) 40 , 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); 59 } 60 61 virtual bool translate(SkScalar dx, SkScalar dy) SK_OVERRIDE { 62 ++fTransTot; 63 64#if 0 65 if (0 == dx && 0 == dy) { 66 ++fTransSkipped; 67 return true; 68 } 69#endif 70 71 return INHERITED::translate(dx, dy); 72 } 73 74 virtual bool scale(SkScalar sx, SkScalar sy) SK_OVERRIDE { 75 ++fScalesTot; 76 77#if 0 78 if (SK_Scalar1 == sx && SK_Scalar1 == sy) { 79 ++fScalesSkipped; 80 return true; 81 } 82#endif 83 84 return INHERITED::scale(sx, sy); 85 } 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 108 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 120 SkFILEWStream* fPathStream; 121private: 122 typedef SkPictureRecord INHERITED; 123}; 124 125// Wrap SkPicture to allow installation of a SkFilterRecord object 126class SkFilterPicture : public SkPicture { 127public: 128 SkFilterPicture(int width, int height, SkPictureRecord* record) { 129 fWidth = width; 130 fHeight = height; 131 fRecord = record; 132 SkSafeRef(fRecord); 133 } 134 135private: 136 typedef SkPicture INHERITED; 137}; 138 139static bool PNGEncodeBitmapToStream(SkWStream* stream, const SkBitmap& bitmap) { 140 return SkImageEncoder::EncodeStream(stream, bitmap, SkImageEncoder::kPNG_Type, 100); 141} 142 143int filter_picture(const SkString& inFile, const SkString& outFile, 144 const SkString& textureDir, SkFILEWStream *pathStream) { 145 SkPicture* inPicture = NULL; 146 147 SkFILEStream inStream(inFile.c_str()); 148 if (inStream.isValid()) { 149 inPicture = SkNEW_ARGS(SkPicture, (&inStream, NULL, &SkImageDecoder::DecodeStream)); 150 } 151 152 if (NULL == inPicture) { 153 SkDebugf("Could not read file %s\n", inFile.c_str()); 154 return -1; 155 } 156 157 SkBitmap bm; 158 bm.setConfig(SkBitmap::kNo_Config, inPicture->width(), inPicture->height()); 159 SkAutoTUnref<SkDevice> dev(SkNEW_ARGS(SkDevice, (bm))); 160 161 SkAutoTUnref<SkFilterRecord> filterRecord(SkNEW_ARGS(SkFilterRecord, (0, dev, pathStream))); 162 163 // Playback the read in picture to the SkFilterRecorder to allow filtering 164 filterRecord->beginRecording(); 165 inPicture->draw(filterRecord); 166 filterRecord->endRecording(); 167 168 filterRecord->report(); 169 170 if (!outFile.isEmpty()) { 171 SkFilterPicture outPicture(inPicture->width(), inPicture->height(), filterRecord); 172 SkFILEWStream outStream(outFile.c_str()); 173 174 outPicture.serialize(&outStream); 175 } 176 177 if (!textureDir.isEmpty()) { 178 filterRecord->saveImages(textureDir); 179 } 180 181 return 0; 182} 183 184// This function is not marked as 'static' so it can be referenced externally 185// in the iOS build. 186int tool_main(int argc, char** argv) { 187 SkGraphics::Init(); 188 189 if (argc < 3) { 190 usage(); 191 return -1; 192 } 193 194 SkString inFile, outFile, inDir, outDir, textureDir, pathFile; 195 196 char* const* stop = argv + argc; 197 for (++argv; argv < stop; ++argv) { 198 if (strcmp(*argv, "-i") == 0) { 199 argv++; 200 if (argv < stop && **argv) { 201 inFile.set(*argv); 202 } else { 203 SkDebugf("missing arg for -i\n"); 204 usage(); 205 return -1; 206 } 207 } else if (strcmp(*argv, "--input-dir") == 0) { 208 argv++; 209 if (argv < stop && **argv) { 210 inDir.set(*argv); 211 } else { 212 SkDebugf("missing arg for --input-dir\n"); 213 usage(); 214 return -1; 215 } 216 } else if (strcmp(*argv, "--output-dir") == 0) { 217 argv++; 218 if (argv < stop && **argv) { 219 outDir.set(*argv); 220 } else { 221 SkDebugf("missing arg for --output-dir\n"); 222 usage(); 223 return -1; 224 } 225 } else if (strcmp(*argv, "-o") == 0) { 226 argv++; 227 if (argv < stop && **argv) { 228 outFile.set(*argv); 229 } else { 230 SkDebugf("missing arg for -o\n"); 231 usage(); 232 return -1; 233 } 234 } else if (strcmp(*argv, "-p") == 0) { 235 argv++; 236 if (argv < stop && **argv) { 237 pathFile.set(*argv); 238 } else { 239 SkDebugf("missing arg for -p\n"); 240 usage(); 241 return -1; 242 } 243 } else if (strcmp(*argv, "-t") == 0) { 244 argv++; 245 if (argv < stop && **argv) { 246 textureDir.set(*argv); 247 } else { 248 SkDebugf("missing arg for -t\n"); 249 usage(); 250 return -1; 251 } 252 } else if (strcmp(*argv, "--help") == 0 || strcmp(*argv, "-h") == 0) { 253 usage(); 254 return 0; 255 } else { 256 SkDebugf("unknown arg %s\n", *argv); 257 usage(); 258 return -1; 259 } 260 } 261 262 if(!inDir.isEmpty() && !textureDir.isEmpty()) { 263 SkDebugf("ERROR: The textureDir option is not permitted when passing an input directory.\n"); 264 usage(); 265 return -1; 266 } 267 268 SkFILEWStream *pathStream = NULL; 269 270 if (!pathFile.isEmpty()) { 271 pathStream = new SkFILEWStream(pathFile.c_str()); 272 if (!pathStream->isValid()) { 273 SkDebugf("Could open path file %s\n", pathFile.c_str()); 274 delete pathStream; 275 return -1; 276 } 277 278 sk_tools::dump_path_prefix(pathStream); 279 } 280 281 SkOSFile::Iter iter(inDir.c_str(), "skp"); 282 int failures = 0; 283 SkString inputFilename, outputFilename; 284 if (iter.next(&inputFilename)) { 285 286 do { 287 sk_tools::make_filepath(&inFile, inDir, inputFilename); 288 if (!outDir.isEmpty()) { 289 sk_tools::make_filepath(&outFile, outDir, inputFilename); 290 } 291 SkDebugf("Executing %s\n", inputFilename.c_str()); 292 filter_picture(inFile, outFile, textureDir, pathStream); 293 } while(iter.next(&inputFilename)); 294 295 } else if (!inFile.isEmpty()) { 296 filter_picture(inFile, outFile, textureDir, pathStream); 297 } else { 298 usage(); 299 if (NULL != pathStream) { 300 delete pathStream; 301 pathStream = NULL; 302 } 303 return -1; 304 } 305 306 if (NULL != pathStream) { 307 sk_tools::dump_path_suffix(pathStream); 308 delete pathStream; 309 pathStream = NULL; 310 } 311 312 SkGraphics::Term(); 313 return 0; 314} 315 316#if !defined SK_BUILD_FOR_IOS 317int main(int argc, char * const argv[]) { 318 return tool_main(argc, (char**) argv); 319} 320#endif 321