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 |