| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkCanvas.h" | 8 #include "SkCanvas.h" |
| 9 #include "SkCommandLineFlags.h" | 9 #include "SkCommandLineFlags.h" |
| 10 #include "SkDevice.h" | 10 #include "SkDocument.h" |
| 11 #include "SkForceLinking.h" | 11 #include "SkForceLinking.h" |
| 12 #include "SkGraphics.h" | 12 #include "SkGraphics.h" |
| 13 #include "SkImageEncoder.h" | 13 #include "SkImageEncoder.h" |
| 14 #include "SkOSFile.h" | 14 #include "SkOSFile.h" |
| 15 #include "SkPicture.h" | 15 #include "SkPicture.h" |
| 16 #include "SkPixelRef.h" | |
| 17 #include "SkStream.h" | 16 #include "SkStream.h" |
| 18 #include "SkTArray.h" | 17 #include "SkTArray.h" |
| 19 #include "SkTSort.h" | 18 #include "SkTSort.h" |
| 20 #include "PdfRenderer.h" | |
| 21 #include "ProcStats.h" | 19 #include "ProcStats.h" |
| 22 #include "picture_utils.h" | |
| 23 | 20 |
| 24 __SK_FORCE_IMAGE_DECODER_LINKING; | 21 __SK_FORCE_IMAGE_DECODER_LINKING; |
| 25 | 22 |
| 26 #ifdef SK_USE_CDB | 23 #ifdef SK_USE_CDB |
| 27 #include "win_dbghelp.h" | 24 #include "win_dbghelp.h" |
| 28 #endif | 25 #endif |
| 29 | 26 |
| 30 /** | 27 /** |
| 31 * render_pdfs | 28 * render_pdfs |
| 32 * | 29 * |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 113 * if false is returned, contents of path are undefined. | 110 * if false is returned, contents of path are undefined. |
| 114 */ | 111 */ |
| 115 static bool make_output_filepath(SkString* path, const SkString& dir, | 112 static bool make_output_filepath(SkString* path, const SkString& dir, |
| 116 const SkString& name) { | 113 const SkString& name) { |
| 117 *path = SkOSPath::Join(dir.c_str(), name.c_str()); | 114 *path = SkOSPath::Join(dir.c_str(), name.c_str()); |
| 118 return replace_filename_extension(path, | 115 return replace_filename_extension(path, |
| 119 SKP_FILE_EXTENSION, | 116 SKP_FILE_EXTENSION, |
| 120 PDF_FILE_EXTENSION); | 117 PDF_FILE_EXTENSION); |
| 121 } | 118 } |
| 122 | 119 |
| 120 namespace { |
| 121 // This is a write-only stream. |
| 122 class NullWStream : public SkWStream { |
| 123 public: |
| 124 NullWStream() : fBytesWritten(0) { } |
| 125 virtual bool write(const void*, size_t size) SK_OVERRIDE { |
| 126 fBytesWritten += size; |
| 127 return true; |
| 128 } |
| 129 virtual size_t bytesWritten() const SK_OVERRIDE { return fBytesWritten; } |
| 130 size_t fBytesWritten; |
| 131 }; |
| 132 } // namespace |
| 133 |
| 123 /** Write the output of pdf renderer to a file. | 134 /** Write the output of pdf renderer to a file. |
| 124 * @param outputDir Output dir. | 135 * @param outputDir Output dir. |
| 125 * @param inputFilename The skp file that was read. | 136 * @param inputFilename The skp file that was read. |
| 126 * @param renderer The object responsible to write the pdf file. | 137 * @param renderer The object responsible to write the pdf file. |
| 127 */ | 138 */ |
| 128 static SkWStream* open_stream(const SkString& outputDir, | 139 static SkWStream* open_stream(const SkString& outputDir, |
| 129 const SkString& inputFilename) { | 140 const SkString& inputFilename) { |
| 130 if (outputDir.isEmpty()) { | 141 if (outputDir.isEmpty()) { |
| 131 return SkNEW(SkDynamicMemoryWStream); | 142 return SkNEW(NullWStream); |
| 132 } | 143 } |
| 133 | 144 |
| 134 SkString outputPath; | 145 SkString outputPath; |
| 135 if (!make_output_filepath(&outputPath, outputDir, inputFilename)) { | 146 if (!make_output_filepath(&outputPath, outputDir, inputFilename)) { |
| 136 return NULL; | 147 return NULL; |
| 137 } | 148 } |
| 138 | 149 |
| 139 SkFILEWStream* stream = SkNEW_ARGS(SkFILEWStream, (outputPath.c_str())); | 150 SkAutoTDelete<SkFILEWStream> stream( |
| 140 if (!stream->isValid()) { | 151 SkNEW_ARGS(SkFILEWStream, (outputPath.c_str()))); |
| 152 if (!stream.get() || !stream->isValid()) { |
| 141 SkDebugf("Could not write to file %s\n", outputPath.c_str()); | 153 SkDebugf("Could not write to file %s\n", outputPath.c_str()); |
| 142 return NULL; | 154 return NULL; |
| 143 } | 155 } |
| 144 | 156 |
| 145 return stream; | 157 return stream.detach(); |
| 146 } | 158 } |
| 147 | 159 |
| 148 /** Reads an skp file, renders it to pdf and writes the output to a pdf file | 160 /** |
| 149 * @param inputPath The skp file to be read. | 161 * Given a SkPicture, write a one-page PDF document to the given |
| 150 * @param outputDir Output dir. | 162 * output, using the provided encoder. |
| 151 * @param renderer The object responsible to render the skp object into pdf. | |
| 152 */ | 163 */ |
| 153 static bool render_pdf(const SkString& inputPath, const SkString& outputDir, | 164 static bool pdf_to_stream(SkPicture* picture, |
| 154 sk_tools::PdfRenderer& renderer) { | 165 SkWStream* output, |
| 155 SkString inputFilename = SkOSPath::Basename(inputPath.c_str()); | 166 SkPicture::EncodeBitmap encoder) { |
| 156 | 167 SkAutoTUnref<SkDocument> pdfDocument( |
| 157 SkFILEStream inputStream; | 168 SkDocument::CreatePDF(output, NULL, encoder)); |
| 158 inputStream.setPath(inputPath.c_str()); | 169 SkCanvas* canvas = pdfDocument->beginPage( |
| 159 if (!inputStream.isValid()) { | 170 SkIntToScalar(picture->width()), |
| 160 SkDebugf("Could not open file %s\n", inputPath.c_str()); | 171 SkIntToScalar(picture->height())); |
| 161 return false; | 172 canvas->drawPicture(picture); |
| 162 } | 173 canvas->flush(); |
| 163 | 174 return pdfDocument->close(); |
| 164 SkAutoTUnref<SkPicture> picture(SkPicture::CreateFromStream(&inputStream)); | |
| 165 | |
| 166 if (NULL == picture.get()) { | |
| 167 SkDebugf("Could not read an SkPicture from %s\n", inputPath.c_str()); | |
| 168 return false; | |
| 169 } | |
| 170 | |
| 171 SkDebugf("exporting... [%-4i %6i] %s\n", | |
| 172 picture->width(), picture->height(), inputPath.c_str()); | |
| 173 | |
| 174 SkWStream* stream(open_stream(outputDir, inputFilename)); | |
| 175 | |
| 176 if (!stream) { | |
| 177 return false; | |
| 178 } | |
| 179 | |
| 180 renderer.init(picture, stream); | |
| 181 | |
| 182 bool success = renderer.render(); | |
| 183 SkDELETE(stream); | |
| 184 | |
| 185 renderer.end(); | |
| 186 | |
| 187 return success; | |
| 188 } | 175 } |
| 189 | 176 |
| 190 static bool operator<(const SkString& a, const SkString& b) { | 177 static bool operator<(const SkString& a, const SkString& b) { |
| 191 return strcmp(a.c_str(), b.c_str()) < 0; | 178 return strcmp(a.c_str(), b.c_str()) < 0; |
| 192 } | 179 } |
| 193 | 180 |
| 194 /** For each file in the directory or for the file passed in input, call | 181 /** |
| 195 * render_pdf. | 182 * @param A list of directories or a skp files. |
| 196 * @param input A directory or an skp file. | 183 * @returns an alphabetical list of skp files. |
| 197 * @param outputDir Output dir. | |
| 198 * @param renderer The object responsible to render the skp object into pdf. | |
| 199 */ | 184 */ |
| 200 static int process_input( | 185 static void process_input_files( |
| 201 const SkCommandLineFlags::StringArray& inputs, | 186 const SkCommandLineFlags::StringArray& inputs, |
| 202 const SkString& outputDir, | 187 SkTArray<SkString>* files) { |
| 203 sk_tools::PdfRenderer& renderer) { | |
| 204 SkTArray<SkString> files; | |
| 205 for (int i = 0; i < inputs.count(); i ++) { | 188 for (int i = 0; i < inputs.count(); i ++) { |
| 206 const char* input = inputs[i]; | 189 const char* input = inputs[i]; |
| 207 if (sk_isdir(input)) { | 190 if (sk_isdir(input)) { |
| 208 SkOSFile::Iter iter(input, SKP_FILE_EXTENSION); | 191 SkOSFile::Iter iter(input, SKP_FILE_EXTENSION); |
| 209 SkString inputFilename; | 192 SkString inputFilename; |
| 210 while (iter.next(&inputFilename)) { | 193 while (iter.next(&inputFilename)) { |
| 211 if (!SkCommandLineFlags::ShouldSkip( | 194 if (!SkCommandLineFlags::ShouldSkip( |
| 212 FLAGS_match, inputFilename.c_str())) { | 195 FLAGS_match, inputFilename.c_str())) { |
| 213 files.push_back( | 196 files->push_back( |
| 214 SkOSPath::Join(input, inputFilename.c_str())); | 197 SkOSPath::Join(input, inputFilename.c_str())); |
| 215 } | 198 } |
| 216 } | 199 } |
| 217 } else { | 200 } else { |
| 218 if (!SkCommandLineFlags::ShouldSkip(FLAGS_match, input)) { | 201 if (!SkCommandLineFlags::ShouldSkip(FLAGS_match, input)) { |
| 219 files.push_back(SkString(input)); | 202 files->push_back(SkString(input)); |
| 220 } | 203 } |
| 221 } | 204 } |
| 222 } | 205 } |
| 223 if (files.count() > 0) { | 206 if (files->count() > 0) { |
| 224 SkTQSort<SkString>(files.begin(), files.end() - 1); | 207 SkTQSort<SkString>(files->begin(), files->end() - 1); |
| 225 } | 208 } |
| 226 int failures = 0; | |
| 227 for (int i = 0; i < files.count(); i ++) { | |
| 228 if (!render_pdf(files[i], outputDir, renderer)) { | |
| 229 ++failures; | |
| 230 } | |
| 231 } | |
| 232 return failures; | |
| 233 } | 209 } |
| 234 | 210 |
| 211 /** For each input skp file, read it, render it to pdf and write. the |
| 212 * output to a pdf file |
| 213 */ |
| 235 int tool_main_core(int argc, char** argv); | 214 int tool_main_core(int argc, char** argv); |
| 236 int tool_main_core(int argc, char** argv) { | 215 int tool_main_core(int argc, char** argv) { |
| 237 SkCommandLineFlags::Parse(argc, argv); | 216 SkCommandLineFlags::Parse(argc, argv); |
| 238 | 217 |
| 239 SkAutoGraphics ag; | 218 SkAutoGraphics ag; |
| 240 | 219 |
| 241 SkAutoTUnref<sk_tools::PdfRenderer> | |
| 242 renderer(SkNEW_ARGS(sk_tools::SimplePdfRenderer, (encode_to_dct_data))); | |
| 243 SkASSERT(renderer.get()); | |
| 244 | |
| 245 SkString outputDir; | 220 SkString outputDir; |
| 246 if (FLAGS_outputDir.count() > 0) { | 221 if (FLAGS_outputDir.count() > 0) { |
| 247 outputDir = FLAGS_outputDir[0]; | 222 outputDir = FLAGS_outputDir[0]; |
| 223 if (!sk_mkdir(outputDir.c_str())) { |
| 224 SkDebugf("Unable to mkdir '%s'\n", outputDir.c_str()); |
| 225 return 1; |
| 226 } |
| 248 } | 227 } |
| 249 | 228 |
| 250 int failures = process_input(FLAGS_inputPaths, outputDir, *renderer); | 229 SkTArray<SkString> files; |
| 230 process_input_files(FLAGS_inputPaths, &files); |
| 251 | 231 |
| 252 int max_rss_kb = sk_tools::getMaxResidentSetSizeKB(); | 232 size_t maximumPathLength = 0; |
| 253 if (max_rss_kb >= 0) { | 233 for (int i = 0; i < files.count(); i ++) { |
| 254 SkDebugf("%4dM peak ResidentSetSize\n", max_rss_kb / 1024); | 234 SkString basename = SkOSPath::Basename(files[i].c_str()); |
| 235 maximumPathLength = SkTMax(maximumPathLength, basename.size()); |
| 255 } | 236 } |
| 256 | 237 |
| 238 int failures = 0; |
| 239 for (int i = 0; i < files.count(); i ++) { |
| 240 SkString basename = SkOSPath::Basename(files[i].c_str()); |
| 241 |
| 242 SkFILEStream inputStream; |
| 243 inputStream.setPath(files[i].c_str()); |
| 244 if (!inputStream.isValid()) { |
| 245 SkDebugf("Could not open file %s\n", files[i].c_str()); |
| 246 ++failures; |
| 247 continue; |
| 248 } |
| 249 |
| 250 SkAutoTUnref<SkPicture> picture( |
| 251 SkPicture::CreateFromStream(&inputStream)); |
| 252 if (NULL == picture.get()) { |
| 253 SkDebugf("Could not read an SkPicture from %s\n", |
| 254 files[i].c_str()); |
| 255 ++failures; |
| 256 continue; |
| 257 } |
| 258 SkDebugf("[%-4i %6i] %-*s", picture->width(), picture->height(), |
| 259 maximumPathLength, basename.c_str()); |
| 260 |
| 261 SkAutoTDelete<SkWStream> stream(open_stream(outputDir, files[i])); |
| 262 if (!stream.get()) { |
| 263 ++failures; |
| 264 continue; |
| 265 } |
| 266 if (!pdf_to_stream(picture, stream.get(), encode_to_dct_data)) { |
| 267 SkDebugf("Error in PDF Serialization."); |
| 268 ++failures; |
| 269 } |
| 270 |
| 271 int max_rss_kb = sk_tools::getMaxResidentSetSizeKB(); |
| 272 if (max_rss_kb >= 0) { |
| 273 SkDebugf(" %4dM peak rss", max_rss_kb / 1024); |
| 274 } |
| 275 |
| 276 SkDebugf("\n"); |
| 277 } |
| 257 if (failures != 0) { | 278 if (failures != 0) { |
| 258 SkDebugf("Failed to render %i PDFs.\n", failures); | 279 SkDebugf("Failed to render %i of %i PDFs.\n", failures, files.count()); |
| 259 return 1; | 280 return 1; |
| 260 } | 281 } |
| 261 | 282 |
| 262 return 0; | 283 return 0; |
| 263 } | 284 } |
| 264 | 285 |
| 265 int tool_main(int argc, char** argv); | 286 int tool_main(int argc, char** argv); |
| 266 int tool_main(int argc, char** argv) { | 287 int tool_main(int argc, char** argv) { |
| 267 #ifdef SK_USE_CDB | 288 #ifdef SK_USE_CDB |
| 268 setUpDebuggingFromArgs(argv[0]); | 289 setUpDebuggingFromArgs(argv[0]); |
| 269 __try { | 290 __try { |
| 270 #endif | 291 #endif |
| 271 return tool_main_core(argc, argv); | 292 return tool_main_core(argc, argv); |
| 272 #ifdef SK_USE_CDB | 293 #ifdef SK_USE_CDB |
| 273 } | 294 } |
| 274 __except(GenerateDumpAndPrintCallstack(GetExceptionInformation())) | 295 __except(GenerateDumpAndPrintCallstack(GetExceptionInformation())) |
| 275 { | 296 { |
| 276 return -1; | 297 return -1; |
| 277 } | 298 } |
| 278 #endif | 299 #endif |
| 279 return 0; | 300 return 0; |
| 280 } | 301 } |
| 281 | |
| 282 #if !defined SK_BUILD_FOR_IOS | 302 #if !defined SK_BUILD_FOR_IOS |
| 283 int main(int argc, char * const argv[]) { | 303 int main(int argc, char * const argv[]) { |
| 284 return tool_main(argc, (char**) argv); | 304 return tool_main(argc, (char**) argv); |
| 285 } | 305 } |
| 286 #endif | 306 #endif |
| OLD | NEW |