blob: 5a3668f6ce3ca1840c02cb4a17bbb4273e14b2ec [file] [log] [blame]
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <limits.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9
Lei Zhang9a25ede2017-06-22 00:05:12 -070010#include <iterator>
tonikitoo3e981582016-08-26 08:37:10 -070011#include <map>
Tom Sepezdaa2e842015-01-29 15:44:37 -080012#include <sstream>
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070013#include <string>
14#include <utility>
Tom Sepez5ee12d72014-12-17 16:24:01 -080015#include <vector>
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070016
Cary Clark399be5b2016-03-14 16:51:29 -040017#if defined PDF_ENABLE_SKIA && !defined _SKIA_SUPPORT_
18#define _SKIA_SUPPORT_
19#endif
20
Tom Sepez1d17a042017-03-16 13:22:47 -070021#include "public/cpp/fpdf_deleters.h"
Jane Liu4fd9a472017-06-01 18:56:09 -040022#include "public/fpdf_annot.h"
Lei Zhangb4e7f302015-11-06 15:52:32 -080023#include "public/fpdf_dataavail.h"
Lei Zhang453d96b2015-12-31 13:13:10 -080024#include "public/fpdf_edit.h"
Lei Zhangb4e7f302015-11-06 15:52:32 -080025#include "public/fpdf_ext.h"
26#include "public/fpdf_formfill.h"
Dan Sinclairddcb6e72017-04-05 10:30:33 -040027#include "public/fpdf_structtree.h"
Lei Zhangb4e7f302015-11-06 15:52:32 -080028#include "public/fpdf_text.h"
29#include "public/fpdfview.h"
Lei Zhang143959d2017-06-22 12:20:58 -070030#include "testing/image_diff/image_diff_png.h"
Lei Zhangbde53d22015-11-12 22:21:30 -080031#include "testing/test_support.h"
Jane Liu4fd9a472017-06-01 18:56:09 -040032#include "third_party/base/logging.h"
Tom Sepezd831dc72015-10-19 16:04:22 -070033
thestigf2b940c2016-10-13 06:48:47 -070034#ifdef _WIN32
35#include <io.h>
36#else
37#include <unistd.h>
38#endif
39
Tom Sepez452b4f32015-10-13 09:27:27 -070040#ifdef PDF_ENABLE_V8
John Abd-El-Malekb045ed22015-02-10 09:15:12 -080041#include "v8/include/libplatform/libplatform.h"
Tom Sepez1ed8a212015-05-11 15:25:39 -070042#include "v8/include/v8.h"
Lei Zhang8241df72015-11-06 14:38:48 -080043#endif // PDF_ENABLE_V8
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070044
Cary Clark399be5b2016-03-14 16:51:29 -040045#ifdef PDF_ENABLE_SKIA
46#include "third_party/skia/include/core/SkPictureRecorder.h"
47#include "third_party/skia/include/core/SkStream.h"
48#endif
49
thestigf2b940c2016-10-13 06:48:47 -070050#ifdef _WIN32
51#define access _access
52#define snprintf _snprintf
53#define R_OK 4
54#endif
55
Vitaly Buka9e0177a2014-07-22 18:15:42 -070056enum OutputFormat {
57 OUTPUT_NONE,
Dan Sinclair3c67fbd2017-04-05 16:07:50 -040058 OUTPUT_STRUCTURE,
dsinclairb63068f2016-06-16 07:58:09 -070059 OUTPUT_TEXT,
Vitaly Buka9e0177a2014-07-22 18:15:42 -070060 OUTPUT_PPM,
Tom Sepezaf18cb32015-02-05 15:06:01 -080061 OUTPUT_PNG,
Jane Liu4fd9a472017-06-01 18:56:09 -040062 OUTPUT_ANNOT,
Vitaly Buka9e0177a2014-07-22 18:15:42 -070063#ifdef _WIN32
64 OUTPUT_BMP,
65 OUTPUT_EMF,
Lei Zhangd1c9b452017-05-05 17:21:36 -070066 OUTPUT_PS2,
67 OUTPUT_PS3,
Vitaly Buka9e0177a2014-07-22 18:15:42 -070068#endif
Cary Clark399be5b2016-03-14 16:51:29 -040069#ifdef PDF_ENABLE_SKIA
70 OUTPUT_SKP,
71#endif
Vitaly Buka9e0177a2014-07-22 18:15:42 -070072};
73
Tom Sepez5ee12d72014-12-17 16:24:01 -080074struct Options {
tsepezf09bdfa2016-04-18 16:08:26 -070075 Options()
Dan Sinclair3c67fbd2017-04-05 16:07:50 -040076 : show_config(false),
Henrique Nakashimab73ce7b2017-06-19 16:04:34 -040077 show_metadata(false),
npme3c73152016-11-14 09:14:52 -080078 send_events(false),
79 pages(false),
stephanafa05e972017-01-02 06:19:41 -080080 md5(false),
npme3c73152016-11-14 09:14:52 -080081 output_format(OUTPUT_NONE) {}
Tom Sepez5ee12d72014-12-17 16:24:01 -080082
Tom Sepez2991d8d2016-01-15 16:02:48 -080083 bool show_config;
Henrique Nakashimab73ce7b2017-06-19 16:04:34 -040084 bool show_metadata;
tsepezf09bdfa2016-04-18 16:08:26 -070085 bool send_events;
npme3c73152016-11-14 09:14:52 -080086 bool pages;
stephanafa05e972017-01-02 06:19:41 -080087 bool md5;
Tom Sepez5ee12d72014-12-17 16:24:01 -080088 OutputFormat output_format;
Tom Sepezdaa2e842015-01-29 15:44:37 -080089 std::string scale_factor_as_string;
Tom Sepez5ee12d72014-12-17 16:24:01 -080090 std::string exe_path;
91 std::string bin_directory;
Lei Zhang6f62d532015-09-23 15:31:44 -070092 std::string font_directory;
npmfa20cd52016-11-14 13:33:40 -080093 // 0-based page numbers to be rendered.
94 int first_page;
95 int last_page;
Tom Sepez5ee12d72014-12-17 16:24:01 -080096};
97
tonikitoo81d92f82016-09-21 12:44:56 -070098struct FPDF_FORMFILLINFO_PDFiumTest : public FPDF_FORMFILLINFO {
99 // Hold a map of the currently loaded pages in order to avoid them
100 // to get loaded twice.
npmfa20cd52016-11-14 13:33:40 -0800101 std::map<int, FPDF_PAGE> loaded_pages;
tonikitoo81d92f82016-09-21 12:44:56 -0700102
103 // Hold a pointer of FPDF_FORMHANDLE so that PDFium app hooks can
104 // make use of it.
npmfa20cd52016-11-14 13:33:40 -0800105 FPDF_FORMHANDLE form_handle;
tonikitoo81d92f82016-09-21 12:44:56 -0700106};
107
108static FPDF_FORMFILLINFO_PDFiumTest* ToPDFiumTestFormFillInfo(
npmfa20cd52016-11-14 13:33:40 -0800109 FPDF_FORMFILLINFO* form_fill_info) {
110 return static_cast<FPDF_FORMFILLINFO_PDFiumTest*>(form_fill_info);
tonikitoo81d92f82016-09-21 12:44:56 -0700111}
112
Tom Sepezaf18cb32015-02-05 15:06:01 -0800113static bool CheckDimensions(int stride, int width, int height) {
114 if (stride < 0 || width < 0 || height < 0)
115 return false;
116 if (height > 0 && width > INT_MAX / height)
117 return false;
118 return true;
119}
120
stephanafa05e972017-01-02 06:19:41 -0800121static void OutputMD5Hash(const char* file_name, const char* buffer, int len) {
122 // Get the MD5 hash and write it to stdout.
Lei Zhang143959d2017-06-22 12:20:58 -0700123 std::string hash =
124 GenerateMD5Base16(reinterpret_cast<const uint8_t*>(buffer), len);
125 printf("MD5:%s:%s\n", file_name, hash.c_str());
stephanafa05e972017-01-02 06:19:41 -0800126}
127
128static std::string WritePpm(const char* pdf_name,
129 int num,
130 const void* buffer_void,
131 int stride,
132 int width,
133 int height) {
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700134 const char* buffer = reinterpret_cast<const char*>(buffer_void);
135
Tom Sepezaf18cb32015-02-05 15:06:01 -0800136 if (!CheckDimensions(stride, width, height))
stephanafa05e972017-01-02 06:19:41 -0800137 return "";
Tom Sepezaf18cb32015-02-05 15:06:01 -0800138
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700139 int out_len = width * height;
140 if (out_len > INT_MAX / 3)
stephanafa05e972017-01-02 06:19:41 -0800141 return "";
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700142 out_len *= 3;
143
144 char filename[256];
145 snprintf(filename, sizeof(filename), "%s.%d.ppm", pdf_name, num);
John Abd-El-Maleka548d302014-06-26 10:18:11 -0700146 FILE* fp = fopen(filename, "wb");
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700147 if (!fp)
stephanafa05e972017-01-02 06:19:41 -0800148 return "";
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700149 fprintf(fp, "P6\n# PDF test render\n%d %d\n255\n", width, height);
150 // Source data is B, G, R, unused.
151 // Dest data is R, G, B.
thestig514e8c92016-07-15 17:57:54 -0700152 std::vector<char> result(out_len);
Lei Zhange00660b2015-08-13 15:40:18 -0700153 for (int h = 0; h < height; ++h) {
154 const char* src_line = buffer + (stride * h);
thestig514e8c92016-07-15 17:57:54 -0700155 char* dest_line = result.data() + (width * h * 3);
Lei Zhange00660b2015-08-13 15:40:18 -0700156 for (int w = 0; w < width; ++w) {
157 // R
158 dest_line[w * 3] = src_line[(w * 4) + 2];
159 // G
160 dest_line[(w * 3) + 1] = src_line[(w * 4) + 1];
161 // B
162 dest_line[(w * 3) + 2] = src_line[w * 4];
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700163 }
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700164 }
thestig514e8c92016-07-15 17:57:54 -0700165 fwrite(result.data(), out_len, 1, fp);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700166 fclose(fp);
stephanafa05e972017-01-02 06:19:41 -0800167 return std::string(filename);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700168}
169
dsinclairb63068f2016-06-16 07:58:09 -0700170void WriteText(FPDF_PAGE page, const char* pdf_name, int num) {
171 char filename[256];
172 int chars_formatted =
173 snprintf(filename, sizeof(filename), "%s.%d.txt", pdf_name, num);
174 if (chars_formatted < 0 ||
175 static_cast<size_t>(chars_formatted) >= sizeof(filename)) {
176 fprintf(stderr, "Filename %s is too long\n", filename);
177 return;
178 }
179
180 FILE* fp = fopen(filename, "w");
181 if (!fp) {
182 fprintf(stderr, "Failed to open %s for output\n", filename);
183 return;
184 }
185
186 // Output in UTF32-LE.
187 uint32_t bom = 0x0000FEFF;
188 fwrite(&bom, sizeof(bom), 1, fp);
189
Tom Sepez1d17a042017-03-16 13:22:47 -0700190 std::unique_ptr<void, FPDFTextPageDeleter> textpage(FPDFText_LoadPage(page));
191 for (int i = 0; i < FPDFText_CountChars(textpage.get()); i++) {
192 uint32_t c = FPDFText_GetUnicode(textpage.get(), i);
dsinclairb63068f2016-06-16 07:58:09 -0700193 fwrite(&c, sizeof(c), 1, fp);
194 }
dsinclairb63068f2016-06-16 07:58:09 -0700195 (void)fclose(fp);
196}
197
Jane Liu4fd9a472017-06-01 18:56:09 -0400198std::string AnnotSubtypeToString(FPDF_ANNOTATION_SUBTYPE subtype) {
199 if (subtype == FPDF_ANNOT_TEXT)
200 return "Text";
201 if (subtype == FPDF_ANNOT_LINK)
202 return "Link";
203 if (subtype == FPDF_ANNOT_FREETEXT)
204 return "FreeText";
205 if (subtype == FPDF_ANNOT_LINE)
206 return "Line";
207 if (subtype == FPDF_ANNOT_SQUARE)
208 return "Square";
209 if (subtype == FPDF_ANNOT_CIRCLE)
210 return "Circle";
211 if (subtype == FPDF_ANNOT_POLYGON)
212 return "Polygon";
213 if (subtype == FPDF_ANNOT_POLYLINE)
214 return "PolyLine";
215 if (subtype == FPDF_ANNOT_HIGHLIGHT)
216 return "Highlight";
217 if (subtype == FPDF_ANNOT_UNDERLINE)
218 return "Underline";
219 if (subtype == FPDF_ANNOT_SQUIGGLY)
220 return "Squiggly";
221 if (subtype == FPDF_ANNOT_STRIKEOUT)
222 return "StrikeOut";
223 if (subtype == FPDF_ANNOT_STAMP)
224 return "Stamp";
225 if (subtype == FPDF_ANNOT_CARET)
226 return "Caret";
227 if (subtype == FPDF_ANNOT_INK)
228 return "Ink";
229 if (subtype == FPDF_ANNOT_POPUP)
230 return "Popup";
231 if (subtype == FPDF_ANNOT_FILEATTACHMENT)
232 return "FileAttachment";
233 if (subtype == FPDF_ANNOT_SOUND)
234 return "Sound";
235 if (subtype == FPDF_ANNOT_MOVIE)
236 return "Movie";
237 if (subtype == FPDF_ANNOT_WIDGET)
238 return "Widget";
239 if (subtype == FPDF_ANNOT_SCREEN)
240 return "Screen";
241 if (subtype == FPDF_ANNOT_PRINTERMARK)
242 return "PrinterMark";
243 if (subtype == FPDF_ANNOT_TRAPNET)
244 return "TrapNet";
245 if (subtype == FPDF_ANNOT_WATERMARK)
246 return "Watermark";
247 if (subtype == FPDF_ANNOT_THREED)
248 return "3D";
249 if (subtype == FPDF_ANNOT_RICHMEDIA)
250 return "RichMedia";
251 if (subtype == FPDF_ANNOT_XFAWIDGET)
252 return "XFAWidget";
253 NOTREACHED();
254 return "";
255}
256
257void WriteAnnot(FPDF_PAGE page, const char* pdf_name, int num) {
258 // Open the output text file.
259 char filename[256];
260 int chars_formatted =
261 snprintf(filename, sizeof(filename), "%s.%d.annot.txt", pdf_name, num);
262 if (chars_formatted < 0 ||
263 static_cast<size_t>(chars_formatted) >= sizeof(filename)) {
264 fprintf(stderr, "Filename %s is too long\n", filename);
265 return;
266 }
267 FILE* fp = fopen(filename, "w");
268 if (!fp) {
269 fprintf(stderr, "Failed to open %s for output\n", filename);
270 return;
271 }
272
273 int annot_count = FPDFPage_GetAnnotCount(page);
274 fprintf(fp, "Number of annotations: %d\n\n", annot_count);
275
276 // Iterate through all annotations on this page.
277 for (int i = 0; i < annot_count; i++) {
278 // Retrieve the annotation object and its subtype.
279 fprintf(fp, "Annotation #%d:\n", i + 1);
Jane Liud60e9ad2017-06-26 11:28:36 -0400280 FPDF_ANNOTATION annot = FPDFPage_GetAnnot(page, i);
281 if (!annot) {
Jane Liu4fd9a472017-06-01 18:56:09 -0400282 fprintf(fp, "Failed to retrieve annotation!\n\n");
283 continue;
284 }
285 FPDF_ANNOTATION_SUBTYPE subtype = FPDFAnnot_GetSubtype(annot);
286 fprintf(fp, "Subtype: %s\n", AnnotSubtypeToString(subtype).c_str());
287
288 // Retrieve the annotation's color and interior color.
289 unsigned int R;
290 unsigned int G;
291 unsigned int B;
292 unsigned int A;
293 if (!FPDFAnnot_GetColor(annot, FPDFANNOT_COLORTYPE_Color, &R, &G, &B, &A)) {
294 fprintf(fp, "Failed to retrieve color.\n");
295 } else {
296 fprintf(fp, "Color in RGBA: %d %d %d %d\n", R, G, B, A);
297 }
298 if (!FPDFAnnot_GetColor(annot, FPDFANNOT_COLORTYPE_InteriorColor, &R, &G,
299 &B, &A)) {
300 fprintf(fp, "Failed to retrieve interior color.\n");
301 } else {
302 fprintf(fp, "Interior color in RGBA: %d %d %d %d\n", R, G, B, A);
303 }
304
305 // Retrieve the annotation's contents and author.
306 unsigned long len =
307 FPDFAnnot_GetText(annot, FPDFANNOT_TEXTTYPE_Contents, nullptr, 0);
308 std::vector<char> buf(len);
309 FPDFAnnot_GetText(annot, FPDFANNOT_TEXTTYPE_Contents, buf.data(), len);
310 fprintf(fp, "Content: %ls\n",
311 GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
312 .c_str());
313 len = FPDFAnnot_GetText(annot, FPDFANNOT_TEXTTYPE_Author, nullptr, 0);
314 buf.clear();
315 buf.resize(len);
316 FPDFAnnot_GetText(annot, FPDFANNOT_TEXTTYPE_Author, buf.data(), len);
317 fprintf(fp, "Author: %ls\n",
318 GetPlatformWString(reinterpret_cast<unsigned short*>(buf.data()))
319 .c_str());
320
321 // Retrieve the annotation's quadpoints if it is a markup annotation.
Jane Liu4fd9a472017-06-01 18:56:09 -0400322 if (FPDFAnnot_HasAttachmentPoints(annot)) {
Jane Liud60e9ad2017-06-26 11:28:36 -0400323 FS_QUADPOINTSF quadpoints = FPDFAnnot_GetAttachmentPoints(annot);
324 fprintf(fp, "Quadpoints: (%f, %f), (%f, %f), (%f, %f), (%f, %f)\n",
325 quadpoints.x1, quadpoints.y1, quadpoints.x2, quadpoints.y2,
326 quadpoints.x3, quadpoints.y3, quadpoints.x4, quadpoints.y4);
Jane Liu4fd9a472017-06-01 18:56:09 -0400327 }
328
329 // Retrieve the annotation's rectangle coordinates.
Jane Liud60e9ad2017-06-26 11:28:36 -0400330 FS_RECTF rect = FPDFAnnot_GetRect(annot);
331 fprintf(fp, "Rectangle: l - %f, b - %f, r - %f, t - %f\n\n", rect.left,
332 rect.bottom, rect.right, rect.top);
Jane Liu4fd9a472017-06-01 18:56:09 -0400333 }
334
335 (void)fclose(fp);
336}
337
stephanafa05e972017-01-02 06:19:41 -0800338static std::string WritePng(const char* pdf_name,
339 int num,
340 const void* buffer_void,
341 int stride,
342 int width,
343 int height) {
Tom Sepezaf18cb32015-02-05 15:06:01 -0800344 if (!CheckDimensions(stride, width, height))
stephanafa05e972017-01-02 06:19:41 -0800345 return "";
Tom Sepezaf18cb32015-02-05 15:06:01 -0800346
347 std::vector<unsigned char> png_encoding;
348 const unsigned char* buffer = static_cast<const unsigned char*>(buffer_void);
349 if (!image_diff_png::EncodeBGRAPNG(
350 buffer, width, height, stride, false, &png_encoding)) {
351 fprintf(stderr, "Failed to convert bitmap to PNG\n");
stephanafa05e972017-01-02 06:19:41 -0800352 return "";
Tom Sepezaf18cb32015-02-05 15:06:01 -0800353 }
354
355 char filename[256];
356 int chars_formatted = snprintf(
357 filename, sizeof(filename), "%s.%d.png", pdf_name, num);
358 if (chars_formatted < 0 ||
359 static_cast<size_t>(chars_formatted) >= sizeof(filename)) {
Cary Clark399be5b2016-03-14 16:51:29 -0400360 fprintf(stderr, "Filename %s is too long\n", filename);
stephanafa05e972017-01-02 06:19:41 -0800361 return "";
Tom Sepezaf18cb32015-02-05 15:06:01 -0800362 }
363
364 FILE* fp = fopen(filename, "wb");
365 if (!fp) {
366 fprintf(stderr, "Failed to open %s for output\n", filename);
stephanafa05e972017-01-02 06:19:41 -0800367 return "";
Tom Sepezaf18cb32015-02-05 15:06:01 -0800368 }
369
370 size_t bytes_written = fwrite(
371 &png_encoding.front(), 1, png_encoding.size(), fp);
372 if (bytes_written != png_encoding.size())
373 fprintf(stderr, "Failed to write to %s\n", filename);
374
Lei Zhang5377ebf2015-09-23 14:52:53 -0700375 (void)fclose(fp);
stephanafa05e972017-01-02 06:19:41 -0800376 return std::string(filename);
Tom Sepezaf18cb32015-02-05 15:06:01 -0800377}
378
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700379#ifdef _WIN32
stephanafa05e972017-01-02 06:19:41 -0800380static std::string WriteBmp(const char* pdf_name,
381 int num,
382 const void* buffer,
383 int stride,
384 int width,
385 int height) {
Tom Sepezaf18cb32015-02-05 15:06:01 -0800386 if (!CheckDimensions(stride, width, height))
stephanafa05e972017-01-02 06:19:41 -0800387 return "";
Tom Sepezaf18cb32015-02-05 15:06:01 -0800388
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700389 int out_len = stride * height;
390 if (out_len > INT_MAX / 3)
stephanafa05e972017-01-02 06:19:41 -0800391 return "";
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700392
393 char filename[256];
394 snprintf(filename, sizeof(filename), "%s.%d.bmp", pdf_name, num);
395 FILE* fp = fopen(filename, "wb");
396 if (!fp)
stephanafa05e972017-01-02 06:19:41 -0800397 return "";
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700398
Nico Weber2827bdd2015-07-01 14:08:08 -0700399 BITMAPINFO bmi = {};
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700400 bmi.bmiHeader.biSize = sizeof(bmi) - sizeof(RGBQUAD);
401 bmi.bmiHeader.biWidth = width;
402 bmi.bmiHeader.biHeight = -height; // top-down image
403 bmi.bmiHeader.biPlanes = 1;
404 bmi.bmiHeader.biBitCount = 32;
405 bmi.bmiHeader.biCompression = BI_RGB;
406 bmi.bmiHeader.biSizeImage = 0;
407
Nico Weber2827bdd2015-07-01 14:08:08 -0700408 BITMAPFILEHEADER file_header = {};
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700409 file_header.bfType = 0x4d42;
410 file_header.bfSize = sizeof(file_header) + bmi.bmiHeader.biSize + out_len;
411 file_header.bfOffBits = file_header.bfSize - out_len;
412
413 fwrite(&file_header, sizeof(file_header), 1, fp);
414 fwrite(&bmi, bmi.bmiHeader.biSize, 1, fp);
415 fwrite(buffer, out_len, 1, fp);
416 fclose(fp);
stephanafa05e972017-01-02 06:19:41 -0800417 return std::string(filename);
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700418}
419
420void WriteEmf(FPDF_PAGE page, const char* pdf_name, int num) {
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700421 char filename[256];
422 snprintf(filename, sizeof(filename), "%s.%d.emf", pdf_name, num);
423
Lei Zhang5377ebf2015-09-23 14:52:53 -0700424 HDC dc = CreateEnhMetaFileA(nullptr, filename, nullptr, nullptr);
Tom Sepezaf18cb32015-02-05 15:06:01 -0800425
Lei Zhangd1c9b452017-05-05 17:21:36 -0700426 int width = static_cast<int>(FPDF_GetPageWidth(page));
427 int height = static_cast<int>(FPDF_GetPageHeight(page));
Tom Sepezaf18cb32015-02-05 15:06:01 -0800428 HRGN rgn = CreateRectRgn(0, 0, width, height);
429 SelectClipRgn(dc, rgn);
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700430 DeleteObject(rgn);
431
432 SelectObject(dc, GetStockObject(NULL_PEN));
433 SelectObject(dc, GetStockObject(WHITE_BRUSH));
434 // If a PS_NULL pen is used, the dimensions of the rectangle are 1 pixel less.
435 Rectangle(dc, 0, 0, width + 1, height + 1);
436
437 FPDF_RenderPage(dc, page, 0, 0, width, height, 0,
438 FPDF_ANNOT | FPDF_PRINTING | FPDF_NO_CATCH);
439
440 DeleteEnhMetaFile(CloseEnhMetaFile(dc));
441}
Lei Zhangd1c9b452017-05-05 17:21:36 -0700442
443int CALLBACK EnhMetaFileProc(HDC hdc,
444 HANDLETABLE* handle_table,
445 const ENHMETARECORD* record,
446 int objects_count,
447 LPARAM param) {
448 std::vector<const ENHMETARECORD*>& items =
449 *reinterpret_cast<std::vector<const ENHMETARECORD*>*>(param);
450 items.push_back(record);
451 return 1;
452}
453
454void WritePS(FPDF_PAGE page, const char* pdf_name, int num) {
455 char filename[256];
456 snprintf(filename, sizeof(filename), "%s.%d.ps", pdf_name, num);
457 FILE* fp = fopen(filename, "wb");
458 if (!fp)
459 return;
460
461 HDC dc = CreateEnhMetaFileA(nullptr, nullptr, nullptr, nullptr);
462
463 int width = static_cast<int>(FPDF_GetPageWidth(page));
464 int height = static_cast<int>(FPDF_GetPageHeight(page));
465 FPDF_RenderPage(dc, page, 0, 0, width, height, 0,
466 FPDF_ANNOT | FPDF_PRINTING | FPDF_NO_CATCH);
467
468 HENHMETAFILE emf = CloseEnhMetaFile(dc);
469 std::vector<const ENHMETARECORD*> items;
470 EnumEnhMetaFile(nullptr, emf, &EnhMetaFileProc, &items, nullptr);
471 for (const ENHMETARECORD* record : items) {
472 if (record->iType != EMR_GDICOMMENT)
473 continue;
474
475 const auto* comment = reinterpret_cast<const EMRGDICOMMENT*>(record);
476 const char* data = reinterpret_cast<const char*>(comment->Data);
477 uint16_t size = *reinterpret_cast<const uint16_t*>(data);
478 fwrite(data + sizeof(uint16_t), size, 1, fp);
479 }
480 fclose(fp);
481 DeleteEnhMetaFile(emf);
482}
483#endif // _WIN32
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700484
Cary Clark399be5b2016-03-14 16:51:29 -0400485#ifdef PDF_ENABLE_SKIA
stephanafa05e972017-01-02 06:19:41 -0800486static std::string WriteSkp(const char* pdf_name,
487 int num,
488 SkPictureRecorder* recorder) {
Cary Clark399be5b2016-03-14 16:51:29 -0400489 char filename[256];
490 int chars_formatted =
491 snprintf(filename, sizeof(filename), "%s.%d.skp", pdf_name, num);
492
493 if (chars_formatted < 0 ||
494 static_cast<size_t>(chars_formatted) >= sizeof(filename)) {
495 fprintf(stderr, "Filename %s is too long\n", filename);
stephanafa05e972017-01-02 06:19:41 -0800496 return "";
Cary Clark399be5b2016-03-14 16:51:29 -0400497 }
498
thestigb97e07e2016-09-28 22:16:40 -0700499 sk_sp<SkPicture> picture(recorder->finishRecordingAsPicture());
Cary Clark399be5b2016-03-14 16:51:29 -0400500 SkFILEWStream wStream(filename);
501 picture->serialize(&wStream);
stephanafa05e972017-01-02 06:19:41 -0800502 return std::string(filename);
Cary Clark399be5b2016-03-14 16:51:29 -0400503}
504#endif
505
Tom Sepez58fb36a2016-02-01 10:32:14 -0800506// These example JS platform callback handlers are entirely optional,
507// and exist here to show the flow of information from a document back
508// to the embedder.
Tom Sepezbd932572016-01-29 09:10:41 -0800509int ExampleAppAlert(IPDF_JSPLATFORM*,
510 FPDF_WIDESTRING msg,
511 FPDF_WIDESTRING title,
npmfa20cd52016-11-14 13:33:40 -0800512 int type,
513 int icon) {
Tom Sepezbd932572016-01-29 09:10:41 -0800514 printf("%ls", GetPlatformWString(title).c_str());
npmfa20cd52016-11-14 13:33:40 -0800515 if (icon || type)
516 printf("[icon=%d,type=%d]", icon, type);
Tom Sepezbd932572016-01-29 09:10:41 -0800517 printf(": %ls\n", GetPlatformWString(msg).c_str());
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700518 return 0;
519}
520
Tom Sepez58fb36a2016-02-01 10:32:14 -0800521int ExampleAppResponse(IPDF_JSPLATFORM*,
522 FPDF_WIDESTRING question,
523 FPDF_WIDESTRING title,
npmfa20cd52016-11-14 13:33:40 -0800524 FPDF_WIDESTRING default_value,
Tom Sepez58fb36a2016-02-01 10:32:14 -0800525 FPDF_WIDESTRING label,
npmfa20cd52016-11-14 13:33:40 -0800526 FPDF_BOOL is_password,
Tom Sepez58fb36a2016-02-01 10:32:14 -0800527 void* response,
528 int length) {
529 printf("%ls: %ls, defaultValue=%ls, label=%ls, isPassword=%d, length=%d\n",
530 GetPlatformWString(title).c_str(),
531 GetPlatformWString(question).c_str(),
npmfa20cd52016-11-14 13:33:40 -0800532 GetPlatformWString(default_value).c_str(),
533 GetPlatformWString(label).c_str(), is_password, length);
Tom Sepez58fb36a2016-02-01 10:32:14 -0800534
535 // UTF-16, always LE regardless of platform.
536 uint8_t* ptr = static_cast<uint8_t*>(response);
537 ptr[0] = 'N';
538 ptr[1] = 0;
539 ptr[2] = 'o';
540 ptr[3] = 0;
541 return 4;
542}
543
npmfa20cd52016-11-14 13:33:40 -0800544void ExampleDocGotoPage(IPDF_JSPLATFORM*, int page_number) {
545 printf("Goto Page: %d\n", page_number);
Tom Sepezb7cb36a2015-02-13 16:54:48 -0800546}
547
Tom Sepeze5fbd7a2016-01-29 17:05:08 -0800548void ExampleDocMail(IPDF_JSPLATFORM*,
549 void* mailData,
550 int length,
npmfa20cd52016-11-14 13:33:40 -0800551 FPDF_BOOL UI,
Tom Sepeze5fbd7a2016-01-29 17:05:08 -0800552 FPDF_WIDESTRING To,
553 FPDF_WIDESTRING Subject,
554 FPDF_WIDESTRING CC,
555 FPDF_WIDESTRING BCC,
556 FPDF_WIDESTRING Msg) {
npmfa20cd52016-11-14 13:33:40 -0800557 printf("Mail Msg: %d, to=%ls, cc=%ls, bcc=%ls, subject=%ls, body=%ls\n", UI,
Tom Sepeze5fbd7a2016-01-29 17:05:08 -0800558 GetPlatformWString(To).c_str(), GetPlatformWString(CC).c_str(),
559 GetPlatformWString(BCC).c_str(), GetPlatformWString(Subject).c_str(),
560 GetPlatformWString(Msg).c_str());
561}
562
Tom Sepezb7cb36a2015-02-13 16:54:48 -0800563void ExampleUnsupportedHandler(UNSUPPORT_INFO*, int type) {
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700564 std::string feature = "Unknown";
565 switch (type) {
566 case FPDF_UNSP_DOC_XFAFORM:
567 feature = "XFA";
568 break;
569 case FPDF_UNSP_DOC_PORTABLECOLLECTION:
570 feature = "Portfolios_Packages";
571 break;
572 case FPDF_UNSP_DOC_ATTACHMENT:
573 case FPDF_UNSP_ANNOT_ATTACHMENT:
574 feature = "Attachment";
575 break;
576 case FPDF_UNSP_DOC_SECURITY:
577 feature = "Rights_Management";
578 break;
579 case FPDF_UNSP_DOC_SHAREDREVIEW:
580 feature = "Shared_Review";
581 break;
582 case FPDF_UNSP_DOC_SHAREDFORM_ACROBAT:
583 case FPDF_UNSP_DOC_SHAREDFORM_FILESYSTEM:
584 case FPDF_UNSP_DOC_SHAREDFORM_EMAIL:
585 feature = "Shared_Form";
586 break;
587 case FPDF_UNSP_ANNOT_3DANNOT:
588 feature = "3D";
589 break;
590 case FPDF_UNSP_ANNOT_MOVIE:
591 feature = "Movie";
592 break;
593 case FPDF_UNSP_ANNOT_SOUND:
594 feature = "Sound";
595 break;
596 case FPDF_UNSP_ANNOT_SCREEN_MEDIA:
597 case FPDF_UNSP_ANNOT_SCREEN_RICHMEDIA:
598 feature = "Screen";
599 break;
600 case FPDF_UNSP_ANNOT_SIG:
601 feature = "Digital_Signature";
602 break;
603 }
604 printf("Unsupported feature: %s.\n", feature.c_str());
605}
606
Tom Sepez5ee12d72014-12-17 16:24:01 -0800607bool ParseCommandLine(const std::vector<std::string>& args,
thestig514e8c92016-07-15 17:57:54 -0700608 Options* options,
609 std::vector<std::string>* files) {
610 if (args.empty())
Tom Sepez5ee12d72014-12-17 16:24:01 -0800611 return false;
thestig514e8c92016-07-15 17:57:54 -0700612
Tom Sepez5ee12d72014-12-17 16:24:01 -0800613 options->exe_path = args[0];
Bo Xud44e3922014-12-19 02:27:25 -0800614 size_t cur_idx = 1;
Tom Sepez5ee12d72014-12-17 16:24:01 -0800615 for (; cur_idx < args.size(); ++cur_idx) {
616 const std::string& cur_arg = args[cur_idx];
Tom Sepez2991d8d2016-01-15 16:02:48 -0800617 if (cur_arg == "--show-config") {
618 options->show_config = true;
Henrique Nakashimab73ce7b2017-06-19 16:04:34 -0400619 } else if (cur_arg == "--show-metadata") {
620 options->show_metadata = true;
tsepezf09bdfa2016-04-18 16:08:26 -0700621 } else if (cur_arg == "--send-events") {
622 options->send_events = true;
Tom Sepez2991d8d2016-01-15 16:02:48 -0800623 } else if (cur_arg == "--ppm") {
Tom Sepez5ee12d72014-12-17 16:24:01 -0800624 if (options->output_format != OUTPUT_NONE) {
625 fprintf(stderr, "Duplicate or conflicting --ppm argument\n");
626 return false;
627 }
628 options->output_format = OUTPUT_PPM;
Tom Sepezaf18cb32015-02-05 15:06:01 -0800629 } else if (cur_arg == "--png") {
630 if (options->output_format != OUTPUT_NONE) {
631 fprintf(stderr, "Duplicate or conflicting --png argument\n");
632 return false;
633 }
634 options->output_format = OUTPUT_PNG;
dsinclairb63068f2016-06-16 07:58:09 -0700635 } else if (cur_arg == "--txt") {
636 if (options->output_format != OUTPUT_NONE) {
637 fprintf(stderr, "Duplicate or conflicting --txt argument\n");
638 return false;
639 }
640 options->output_format = OUTPUT_TEXT;
Jane Liu4fd9a472017-06-01 18:56:09 -0400641 } else if (cur_arg == "--annot") {
642 if (options->output_format != OUTPUT_NONE) {
643 fprintf(stderr, "Duplicate or conflicting --annot argument\n");
644 return false;
645 }
646 options->output_format = OUTPUT_ANNOT;
Cary Clark399be5b2016-03-14 16:51:29 -0400647#ifdef PDF_ENABLE_SKIA
648 } else if (cur_arg == "--skp") {
649 if (options->output_format != OUTPUT_NONE) {
650 fprintf(stderr, "Duplicate or conflicting --skp argument\n");
651 return false;
652 }
653 options->output_format = OUTPUT_SKP;
654#endif
Lei Zhang6f62d532015-09-23 15:31:44 -0700655 } else if (cur_arg.size() > 11 &&
656 cur_arg.compare(0, 11, "--font-dir=") == 0) {
657 if (!options->font_directory.empty()) {
658 fprintf(stderr, "Duplicate --font-dir argument\n");
659 return false;
660 }
661 options->font_directory = cur_arg.substr(11);
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700662#ifdef _WIN32
Dan Sinclair738b08c2016-03-01 14:45:20 -0500663 } else if (cur_arg == "--emf") {
Tom Sepez5ee12d72014-12-17 16:24:01 -0800664 if (options->output_format != OUTPUT_NONE) {
665 fprintf(stderr, "Duplicate or conflicting --emf argument\n");
666 return false;
667 }
668 options->output_format = OUTPUT_EMF;
Lei Zhangd1c9b452017-05-05 17:21:36 -0700669 } else if (cur_arg == "--ps2") {
670 if (options->output_format != OUTPUT_NONE) {
671 fprintf(stderr, "Duplicate or conflicting --ps2 argument\n");
672 return false;
673 }
674 options->output_format = OUTPUT_PS2;
675 } else if (cur_arg == "--ps3") {
676 if (options->output_format != OUTPUT_NONE) {
677 fprintf(stderr, "Duplicate or conflicting --ps3 argument\n");
678 return false;
679 }
680 options->output_format = OUTPUT_PS3;
Dan Sinclair50cce602016-02-24 09:51:16 -0500681 } else if (cur_arg == "--bmp") {
Tom Sepez5ee12d72014-12-17 16:24:01 -0800682 if (options->output_format != OUTPUT_NONE) {
683 fprintf(stderr, "Duplicate or conflicting --bmp argument\n");
684 return false;
685 }
686 options->output_format = OUTPUT_BMP;
Tom Sepez5ee12d72014-12-17 16:24:01 -0800687#endif // _WIN32
Dan Sinclair738b08c2016-03-01 14:45:20 -0500688
Tom Sepez452b4f32015-10-13 09:27:27 -0700689#ifdef PDF_ENABLE_V8
Tom Sepez5ee12d72014-12-17 16:24:01 -0800690#ifdef V8_USE_EXTERNAL_STARTUP_DATA
Dan Sinclair738b08c2016-03-01 14:45:20 -0500691 } else if (cur_arg.size() > 10 &&
692 cur_arg.compare(0, 10, "--bin-dir=") == 0) {
Tom Sepez5ee12d72014-12-17 16:24:01 -0800693 if (!options->bin_directory.empty()) {
694 fprintf(stderr, "Duplicate --bin-dir argument\n");
695 return false;
696 }
697 options->bin_directory = cur_arg.substr(10);
Tom Sepez5ee12d72014-12-17 16:24:01 -0800698#endif // V8_USE_EXTERNAL_STARTUP_DATA
Tom Sepez452b4f32015-10-13 09:27:27 -0700699#endif // PDF_ENABLE_V8
Dan Sinclair738b08c2016-03-01 14:45:20 -0500700
701 } else if (cur_arg.size() > 8 && cur_arg.compare(0, 8, "--scale=") == 0) {
Tom Sepezdaa2e842015-01-29 15:44:37 -0800702 if (!options->scale_factor_as_string.empty()) {
703 fprintf(stderr, "Duplicate --scale argument\n");
704 return false;
705 }
706 options->scale_factor_as_string = cur_arg.substr(8);
Dan Sinclairddcb6e72017-04-05 10:30:33 -0400707 } else if (cur_arg == "--show-structure") {
Dan Sinclair3c67fbd2017-04-05 16:07:50 -0400708 if (options->output_format != OUTPUT_NONE) {
709 fprintf(stderr, "Duplicate or conflicting --show-structure argument\n");
710 return false;
711 }
712 options->output_format = OUTPUT_STRUCTURE;
npme3c73152016-11-14 09:14:52 -0800713 } else if (cur_arg.size() > 8 && cur_arg.compare(0, 8, "--pages=") == 0) {
714 if (options->pages) {
715 fprintf(stderr, "Duplicate --pages argument\n");
716 return false;
717 }
718 options->pages = true;
npmfa20cd52016-11-14 13:33:40 -0800719 const std::string pages_string = cur_arg.substr(8);
720 size_t first_dash = pages_string.find("-");
721 if (first_dash == std::string::npos) {
722 std::stringstream(pages_string) >> options->first_page;
723 options->last_page = options->first_page;
npme3c73152016-11-14 09:14:52 -0800724 } else {
npmfa20cd52016-11-14 13:33:40 -0800725 std::stringstream(pages_string.substr(0, first_dash)) >>
726 options->first_page;
727 std::stringstream(pages_string.substr(first_dash + 1)) >>
728 options->last_page;
npme3c73152016-11-14 09:14:52 -0800729 }
stephanafa05e972017-01-02 06:19:41 -0800730 } else if (cur_arg == "--md5") {
731 options->md5 = true;
Tom Sepez2991d8d2016-01-15 16:02:48 -0800732 } else if (cur_arg.size() >= 2 && cur_arg[0] == '-' && cur_arg[1] == '-') {
733 fprintf(stderr, "Unrecognized argument %s\n", cur_arg.c_str());
734 return false;
Dan Sinclair738b08c2016-03-01 14:45:20 -0500735 } else {
Vitaly Buka8f2c3dc2014-08-20 10:32:36 -0700736 break;
Dan Sinclair738b08c2016-03-01 14:45:20 -0500737 }
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700738 }
thestig514e8c92016-07-15 17:57:54 -0700739 for (size_t i = cur_idx; i < args.size(); i++)
Tom Sepez5ee12d72014-12-17 16:24:01 -0800740 files->push_back(args[i]);
thestig514e8c92016-07-15 17:57:54 -0700741
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700742 return true;
743}
744
npmfa20cd52016-11-14 13:33:40 -0800745FPDF_BOOL Is_Data_Avail(FX_FILEAVAIL* avail, size_t offset, size_t size) {
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700746 return true;
747}
748
npmfa20cd52016-11-14 13:33:40 -0800749void Add_Segment(FX_DOWNLOADHINTS* hints, size_t offset, size_t size) {}
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700750
Lei Zhang54d91ec2017-06-16 19:08:02 -0700751void SendPageEvents(FPDF_FORMHANDLE form,
752 FPDF_PAGE page,
tsepezf09bdfa2016-04-18 16:08:26 -0700753 const std::string& events) {
754 auto lines = StringSplit(events, '\n');
755 for (auto line : lines) {
756 auto command = StringSplit(line, '#');
757 if (command[0].empty())
758 continue;
759 auto tokens = StringSplit(command[0], ',');
Nicolas Penae30f07a2017-05-18 18:37:46 -0400760 if (tokens[0] == "charcode") {
761 if (tokens.size() == 2) {
762 int keycode = atoi(tokens[1].c_str());
763 FORM_OnChar(form, page, keycode, 0);
764 } else {
765 fprintf(stderr, "charcode: bad args\n");
766 }
767 } else if (tokens[0] == "keycode") {
tsepezf09bdfa2016-04-18 16:08:26 -0700768 if (tokens.size() == 2) {
769 int keycode = atoi(tokens[1].c_str());
770 FORM_OnKeyDown(form, page, keycode, 0);
771 FORM_OnKeyUp(form, page, keycode, 0);
772 } else {
773 fprintf(stderr, "keycode: bad args\n");
774 }
775 } else if (tokens[0] == "mousedown") {
776 if (tokens.size() == 4) {
777 int x = atoi(tokens[2].c_str());
778 int y = atoi(tokens[3].c_str());
779 if (tokens[1] == "left")
780 FORM_OnLButtonDown(form, page, 0, x, y);
781#ifdef PDF_ENABLE_XFA
782 else if (tokens[1] == "right")
783 FORM_OnRButtonDown(form, page, 0, x, y);
784#endif
785 else
786 fprintf(stderr, "mousedown: bad button name\n");
787 } else {
788 fprintf(stderr, "mousedown: bad args\n");
789 }
790 } else if (tokens[0] == "mouseup") {
791 if (tokens.size() == 4) {
792 int x = atoi(tokens[2].c_str());
793 int y = atoi(tokens[3].c_str());
794 if (tokens[1] == "left")
795 FORM_OnLButtonUp(form, page, 0, x, y);
796#ifdef PDF_ENABLE_XFA
797 else if (tokens[1] == "right")
798 FORM_OnRButtonUp(form, page, 0, x, y);
799#endif
800 else
801 fprintf(stderr, "mouseup: bad button name\n");
802 } else {
803 fprintf(stderr, "mouseup: bad args\n");
804 }
805 } else if (tokens[0] == "mousemove") {
806 if (tokens.size() == 3) {
807 int x = atoi(tokens[1].c_str());
808 int y = atoi(tokens[2].c_str());
809 FORM_OnMouseMove(form, page, 0, x, y);
810 } else {
811 fprintf(stderr, "mousemove: bad args\n");
812 }
813 } else {
814 fprintf(stderr, "Unrecognized event: %s\n", tokens[0].c_str());
815 }
816 }
817}
818
tonikitoo3e981582016-08-26 08:37:10 -0700819FPDF_PAGE GetPageForIndex(FPDF_FORMFILLINFO* param,
820 FPDF_DOCUMENT doc,
821 int index) {
npmfa20cd52016-11-14 13:33:40 -0800822 FPDF_FORMFILLINFO_PDFiumTest* form_fill_info =
823 ToPDFiumTestFormFillInfo(param);
824 auto& loaded_pages = form_fill_info->loaded_pages;
npmfa20cd52016-11-14 13:33:40 -0800825 auto iter = loaded_pages.find(index);
826 if (iter != loaded_pages.end())
tonikitoo3e981582016-08-26 08:37:10 -0700827 return iter->second;
828
829 FPDF_PAGE page = FPDF_LoadPage(doc, index);
830 if (!page)
831 return nullptr;
832
npmfa20cd52016-11-14 13:33:40 -0800833 FPDF_FORMHANDLE& form_handle = form_fill_info->form_handle;
npmfa20cd52016-11-14 13:33:40 -0800834 FORM_OnAfterLoadPage(page, form_handle);
835 FORM_DoPageAAction(page, form_handle, FPDFPAGE_AACTION_OPEN);
npmfa20cd52016-11-14 13:33:40 -0800836 loaded_pages[index] = page;
tonikitoo3e981582016-08-26 08:37:10 -0700837 return page;
838}
839
Dan Sinclairddcb6e72017-04-05 10:30:33 -0400840std::wstring ConvertToWString(const unsigned short* buf,
841 unsigned long buf_size) {
Dan Sinclair3c67fbd2017-04-05 16:07:50 -0400842 std::wstring result;
843 result.reserve(buf_size);
844 std::copy(buf, buf + buf_size, std::back_inserter(result));
845 return result;
Dan Sinclairddcb6e72017-04-05 10:30:33 -0400846}
847
Dan Sinclair3c67fbd2017-04-05 16:07:50 -0400848void DumpChildStructure(FPDF_STRUCTELEMENT child, int indent) {
849 static const size_t kBufSize = 1024;
Dan Sinclairddcb6e72017-04-05 10:30:33 -0400850 unsigned short buf[kBufSize];
851 unsigned long len = FPDF_StructElement_GetType(child, buf, kBufSize);
Dan Sinclair3c67fbd2017-04-05 16:07:50 -0400852 printf("%*s%ls", indent * 2, "", ConvertToWString(buf, len).c_str());
Dan Sinclairddcb6e72017-04-05 10:30:33 -0400853
854 memset(buf, 0, sizeof(buf));
dan sinclaird9dad3a2017-04-06 14:44:02 -0400855 len = FPDF_StructElement_GetTitle(child, buf, kBufSize);
856 if (len > 0)
857 printf(": '%ls'", ConvertToWString(buf, len).c_str());
858
859 memset(buf, 0, sizeof(buf));
Dan Sinclairddcb6e72017-04-05 10:30:33 -0400860 len = FPDF_StructElement_GetAltText(child, buf, kBufSize);
861 if (len > 0)
862 printf(" (%ls)", ConvertToWString(buf, len).c_str());
863 printf("\n");
864
865 for (int i = 0; i < FPDF_StructElement_CountChildren(child); ++i) {
866 FPDF_STRUCTELEMENT sub_child = FPDF_StructElement_GetChildAtIndex(child, i);
867 // If the child is not an Element then this will return null. This can
868 // happen if the element is things like an object reference or a stream.
869 if (!sub_child)
870 continue;
871
Dan Sinclair3c67fbd2017-04-05 16:07:50 -0400872 DumpChildStructure(sub_child, indent + 1);
Dan Sinclairddcb6e72017-04-05 10:30:33 -0400873 }
874}
875
876void DumpPageStructure(FPDF_PAGE page, const int page_idx) {
877 std::unique_ptr<void, FPDFStructTreeDeleter> tree(
878 FPDF_StructTree_GetForPage(page));
879 if (!tree) {
Dan Sinclair3c67fbd2017-04-05 16:07:50 -0400880 fprintf(stderr, "Failed to load struct tree for page %d\n", page_idx);
Dan Sinclairddcb6e72017-04-05 10:30:33 -0400881 return;
882 }
883
884 printf("Structure Tree for Page %d\n", page_idx);
885 for (int i = 0; i < FPDF_StructTree_CountChildren(tree.get()); ++i) {
886 FPDF_STRUCTELEMENT child = FPDF_StructTree_GetChildAtIndex(tree.get(), i);
887 if (!child) {
Dan Sinclair3c67fbd2017-04-05 16:07:50 -0400888 fprintf(stderr, "Failed to load child %d for page %d\n", i, page_idx);
Dan Sinclairddcb6e72017-04-05 10:30:33 -0400889 continue;
890 }
Dan Sinclair3c67fbd2017-04-05 16:07:50 -0400891 DumpChildStructure(child, 0);
Dan Sinclairddcb6e72017-04-05 10:30:33 -0400892 }
893 printf("\n\n");
894}
895
Jun Fangb553bcb2015-11-10 18:49:04 +0800896bool RenderPage(const std::string& name,
tonikitoo3e981582016-08-26 08:37:10 -0700897 FPDF_DOCUMENT doc,
Tom Sepez1d17a042017-03-16 13:22:47 -0700898 FPDF_FORMHANDLE form,
npmfa20cd52016-11-14 13:33:40 -0800899 FPDF_FORMFILLINFO_PDFiumTest& form_fill_info,
Jun Fangb553bcb2015-11-10 18:49:04 +0800900 const int page_index,
tsepezf09bdfa2016-04-18 16:08:26 -0700901 const Options& options,
902 const std::string& events) {
Tom Sepez1d17a042017-03-16 13:22:47 -0700903 std::unique_ptr<void, FPDFPageDeleter> page(
904 GetPageForIndex(&form_fill_info, doc, page_index));
905 if (!page.get())
Jun Fangb553bcb2015-11-10 18:49:04 +0800906 return false;
Dan Sinclair3c67fbd2017-04-05 16:07:50 -0400907 if (options.send_events)
908 SendPageEvents(form, page.get(), events);
909 if (options.output_format == OUTPUT_STRUCTURE) {
Dan Sinclairddcb6e72017-04-05 10:30:33 -0400910 DumpPageStructure(page.get(), page_index);
911 return true;
912 }
913
Tom Sepez1d17a042017-03-16 13:22:47 -0700914 std::unique_ptr<void, FPDFTextPageDeleter> text_page(
915 FPDFText_LoadPage(page.get()));
tsepezf09bdfa2016-04-18 16:08:26 -0700916
Jun Fangdf7f3662015-11-10 18:29:18 +0800917 double scale = 1.0;
thestig514e8c92016-07-15 17:57:54 -0700918 if (!options.scale_factor_as_string.empty())
Jun Fangdf7f3662015-11-10 18:29:18 +0800919 std::stringstream(options.scale_factor_as_string) >> scale;
thestig514e8c92016-07-15 17:57:54 -0700920
Tom Sepez1d17a042017-03-16 13:22:47 -0700921 int width = static_cast<int>(FPDF_GetPageWidth(page.get()) * scale);
922 int height = static_cast<int>(FPDF_GetPageHeight(page.get()) * scale);
923 int alpha = FPDFPage_HasTransparency(page.get()) ? 1 : 0;
924 std::unique_ptr<void, FPDFBitmapDeleter> bitmap(
925 FPDFBitmap_Create(width, height, alpha));
926
thestige97ea032016-05-19 10:59:15 -0700927 if (bitmap) {
928 FPDF_DWORD fill_color = alpha ? 0x00000000 : 0xFFFFFFFF;
Tom Sepez1d17a042017-03-16 13:22:47 -0700929 FPDFBitmap_FillRect(bitmap.get(), 0, 0, width, height, fill_color);
930 FPDF_RenderPageBitmap(bitmap.get(), page.get(), 0, 0, width, height, 0,
931 FPDF_ANNOT);
Jun Fangdf7f3662015-11-10 18:29:18 +0800932
Tom Sepez1d17a042017-03-16 13:22:47 -0700933 FPDF_FFLDraw(form, bitmap.get(), page.get(), 0, 0, width, height, 0,
934 FPDF_ANNOT);
935 int stride = FPDFBitmap_GetStride(bitmap.get());
thestige97ea032016-05-19 10:59:15 -0700936 const char* buffer =
Tom Sepez1d17a042017-03-16 13:22:47 -0700937 reinterpret_cast<const char*>(FPDFBitmap_GetBuffer(bitmap.get()));
Jun Fangdf7f3662015-11-10 18:29:18 +0800938
stephanafa05e972017-01-02 06:19:41 -0800939 std::string&& image_file_name = "";
thestige97ea032016-05-19 10:59:15 -0700940 switch (options.output_format) {
Jun Fangdf7f3662015-11-10 18:29:18 +0800941#ifdef _WIN32
thestige97ea032016-05-19 10:59:15 -0700942 case OUTPUT_BMP:
stephanafa05e972017-01-02 06:19:41 -0800943 image_file_name =
944 WriteBmp(name.c_str(), page_index, buffer, stride, width, height);
thestige97ea032016-05-19 10:59:15 -0700945 break;
Jun Fangdf7f3662015-11-10 18:29:18 +0800946
thestige97ea032016-05-19 10:59:15 -0700947 case OUTPUT_EMF:
Tom Sepez1d17a042017-03-16 13:22:47 -0700948 WriteEmf(page.get(), name.c_str(), page_index);
thestige97ea032016-05-19 10:59:15 -0700949 break;
Lei Zhangd1c9b452017-05-05 17:21:36 -0700950
951 case OUTPUT_PS2:
952 case OUTPUT_PS3:
953 WritePS(page.get(), name.c_str(), page_index);
954 break;
Jun Fangdf7f3662015-11-10 18:29:18 +0800955#endif
dsinclairb63068f2016-06-16 07:58:09 -0700956 case OUTPUT_TEXT:
Tom Sepez1d17a042017-03-16 13:22:47 -0700957 WriteText(page.get(), name.c_str(), page_index);
dsinclairb63068f2016-06-16 07:58:09 -0700958 break;
959
Jane Liu4fd9a472017-06-01 18:56:09 -0400960 case OUTPUT_ANNOT:
961 WriteAnnot(page.get(), name.c_str(), page_index);
962 break;
963
thestige97ea032016-05-19 10:59:15 -0700964 case OUTPUT_PNG:
stephanafa05e972017-01-02 06:19:41 -0800965 image_file_name =
966 WritePng(name.c_str(), page_index, buffer, stride, width, height);
thestige97ea032016-05-19 10:59:15 -0700967 break;
Jun Fangdf7f3662015-11-10 18:29:18 +0800968
thestige97ea032016-05-19 10:59:15 -0700969 case OUTPUT_PPM:
stephanafa05e972017-01-02 06:19:41 -0800970 image_file_name =
971 WritePpm(name.c_str(), page_index, buffer, stride, width, height);
thestige97ea032016-05-19 10:59:15 -0700972 break;
Jun Fangdf7f3662015-11-10 18:29:18 +0800973
Cary Clark399be5b2016-03-14 16:51:29 -0400974#ifdef PDF_ENABLE_SKIA
thestige97ea032016-05-19 10:59:15 -0700975 case OUTPUT_SKP: {
976 std::unique_ptr<SkPictureRecorder> recorder(
thestigb97e07e2016-09-28 22:16:40 -0700977 reinterpret_cast<SkPictureRecorder*>(
Tom Sepez1d17a042017-03-16 13:22:47 -0700978 FPDF_RenderPageSkp(page.get(), width, height)));
979 FPDF_FFLRecord(form, recorder.get(), page.get(), 0, 0, width, height, 0,
980 0);
stephanafa05e972017-01-02 06:19:41 -0800981 image_file_name = WriteSkp(name.c_str(), page_index, recorder.get());
thestige97ea032016-05-19 10:59:15 -0700982 } break;
Cary Clark399be5b2016-03-14 16:51:29 -0400983#endif
thestige97ea032016-05-19 10:59:15 -0700984 default:
985 break;
986 }
Jun Fangdf7f3662015-11-10 18:29:18 +0800987
stephanafa05e972017-01-02 06:19:41 -0800988 // Write the filename and the MD5 of the buffer to stdout if we wrote a
989 // file.
990 if (options.md5 && image_file_name != "")
991 OutputMD5Hash(image_file_name.c_str(), buffer, stride * height);
thestige97ea032016-05-19 10:59:15 -0700992 } else {
993 fprintf(stderr, "Page was too large to be rendered.\n");
994 }
tonikitoo3e981582016-08-26 08:37:10 -0700995
npmfa20cd52016-11-14 13:33:40 -0800996 form_fill_info.loaded_pages.erase(page_index);
Tom Sepez1d17a042017-03-16 13:22:47 -0700997 FORM_DoPageAAction(page.get(), form, FPDFPAGE_AACTION_CLOSE);
998 FORM_OnBeforeClosePage(page.get(), form);
thestige97ea032016-05-19 10:59:15 -0700999 return !!bitmap;
Jun Fangdf7f3662015-11-10 18:29:18 +08001000}
1001
tsepezf09bdfa2016-04-18 16:08:26 -07001002void RenderPdf(const std::string& name,
1003 const char* pBuf,
1004 size_t len,
1005 const Options& options,
1006 const std::string& events) {
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001007 IPDF_JSPLATFORM platform_callbacks;
1008 memset(&platform_callbacks, '\0', sizeof(platform_callbacks));
Tom Sepeza72e8e22015-10-07 10:17:53 -07001009 platform_callbacks.version = 3;
Tom Sepezb7cb36a2015-02-13 16:54:48 -08001010 platform_callbacks.app_alert = ExampleAppAlert;
Tom Sepez58fb36a2016-02-01 10:32:14 -08001011 platform_callbacks.app_response = ExampleAppResponse;
Tom Sepezb7cb36a2015-02-13 16:54:48 -08001012 platform_callbacks.Doc_gotoPage = ExampleDocGotoPage;
Tom Sepeze5fbd7a2016-01-29 17:05:08 -08001013 platform_callbacks.Doc_mail = ExampleDocMail;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001014
tonikitoo81d92f82016-09-21 12:44:56 -07001015 FPDF_FORMFILLINFO_PDFiumTest form_callbacks = {};
Tom Sepezc46d0002015-11-30 15:46:36 -08001016#ifdef PDF_ENABLE_XFA
Tom Sepezed631382014-11-18 14:10:25 -08001017 form_callbacks.version = 2;
Tom Sepezc46d0002015-11-30 15:46:36 -08001018#else // PDF_ENABLE_XFA
1019 form_callbacks.version = 1;
1020#endif // PDF_ENABLE_XFA
tonikitoo3e981582016-08-26 08:37:10 -07001021 form_callbacks.FFI_GetPage = GetPageForIndex;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001022 form_callbacks.m_pJsPlatform = &platform_callbacks;
1023
1024 TestLoader loader(pBuf, len);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001025 FPDF_FILEACCESS file_access;
1026 memset(&file_access, '\0', sizeof(file_access));
John Abd-El-Malek7dc51722014-05-26 12:54:31 -07001027 file_access.m_FileLen = static_cast<unsigned long>(len);
Tom Sepezd831dc72015-10-19 16:04:22 -07001028 file_access.m_GetBlock = TestLoader::GetBlock;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001029 file_access.m_Param = &loader;
1030
1031 FX_FILEAVAIL file_avail;
1032 memset(&file_avail, '\0', sizeof(file_avail));
1033 file_avail.version = 1;
1034 file_avail.IsDataAvail = Is_Data_Avail;
1035
1036 FX_DOWNLOADHINTS hints;
1037 memset(&hints, '\0', sizeof(hints));
1038 hints.version = 1;
1039 hints.AddSegment = Add_Segment;
1040
Jun Fangdf7f3662015-11-10 18:29:18 +08001041 int nRet = PDF_DATA_NOTAVAIL;
Jun Fangb553bcb2015-11-10 18:49:04 +08001042 bool bIsLinearized = false;
Tom Sepez1d17a042017-03-16 13:22:47 -07001043 std::unique_ptr<void, FPDFDocumentDeleter> doc;
1044 std::unique_ptr<void, FPDFAvailDeleter> pdf_avail(
1045 FPDFAvail_Create(&file_avail, &file_access));
Tom Sepezc98895c2015-11-24 15:30:36 -08001046
Tom Sepez1d17a042017-03-16 13:22:47 -07001047 if (FPDFAvail_IsLinearized(pdf_avail.get()) == PDF_LINEARIZED) {
1048 doc.reset(FPDFAvail_GetDocument(pdf_avail.get(), nullptr));
Jun Fangdf7f3662015-11-10 18:29:18 +08001049 if (doc) {
thestig514e8c92016-07-15 17:57:54 -07001050 while (nRet == PDF_DATA_NOTAVAIL)
Tom Sepez1d17a042017-03-16 13:22:47 -07001051 nRet = FPDFAvail_IsDocAvail(pdf_avail.get(), &hints);
thestig514e8c92016-07-15 17:57:54 -07001052
Jun Fangdf7f3662015-11-10 18:29:18 +08001053 if (nRet == PDF_DATA_ERROR) {
1054 fprintf(stderr, "Unknown error in checking if doc was available.\n");
1055 return;
1056 }
Tom Sepez1d17a042017-03-16 13:22:47 -07001057 nRet = FPDFAvail_IsFormAvail(pdf_avail.get(), &hints);
Jun Fangdf7f3662015-11-10 18:29:18 +08001058 if (nRet == PDF_FORM_ERROR || nRet == PDF_FORM_NOTAVAIL) {
1059 fprintf(stderr,
1060 "Error %d was returned in checking if form was available.\n",
1061 nRet);
1062 return;
1063 }
Jun Fangb553bcb2015-11-10 18:49:04 +08001064 bIsLinearized = true;
Jun Fangdf7f3662015-11-10 18:29:18 +08001065 }
1066 } else {
Tom Sepez1d17a042017-03-16 13:22:47 -07001067 doc.reset(FPDF_LoadCustomDocument(&file_access, nullptr));
Jun Fangdf7f3662015-11-10 18:29:18 +08001068 }
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001069
Lei Zhang5377ebf2015-09-23 14:52:53 -07001070 if (!doc) {
Dan Sinclaireb815bf2015-10-27 13:08:41 -04001071 unsigned long err = FPDF_GetLastError();
1072 fprintf(stderr, "Load pdf docs unsuccessful: ");
1073 switch (err) {
1074 case FPDF_ERR_SUCCESS:
1075 fprintf(stderr, "Success");
1076 break;
1077 case FPDF_ERR_UNKNOWN:
1078 fprintf(stderr, "Unknown error");
1079 break;
1080 case FPDF_ERR_FILE:
1081 fprintf(stderr, "File not found or could not be opened");
1082 break;
1083 case FPDF_ERR_FORMAT:
1084 fprintf(stderr, "File not in PDF format or corrupted");
1085 break;
1086 case FPDF_ERR_PASSWORD:
1087 fprintf(stderr, "Password required or incorrect password");
1088 break;
1089 case FPDF_ERR_SECURITY:
1090 fprintf(stderr, "Unsupported security scheme");
1091 break;
1092 case FPDF_ERR_PAGE:
1093 fprintf(stderr, "Page not found or content error");
1094 break;
1095 default:
1096 fprintf(stderr, "Unknown error %ld", err);
1097 }
1098 fprintf(stderr, ".\n");
JUN FANG827a1722015-03-05 13:39:21 -08001099 return;
1100 }
1101
Tom Sepez1d17a042017-03-16 13:22:47 -07001102 (void)FPDF_GetDocPermissions(doc.get());
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001103
Henrique Nakashimab73ce7b2017-06-19 16:04:34 -04001104 if (options.show_metadata) {
1105 const char* metaTags[] = {"Title", "Author", "Subject", "Keywords",
1106 "Creator", "Producer", "CreationDate", "ModDate"};
1107 for (const char* metaTag : metaTags) {
1108 char metaBuffer[4096];
1109 int len = FPDF_GetMetaText(doc.get(), metaTag, metaBuffer, 4096);
1110 printf("%-12s = %ls (%d bytes)\n", metaTag,
1111 GetPlatformWString(reinterpret_cast<unsigned short*>(metaBuffer))
1112 .c_str(),
1113 len);
1114 }
1115 }
1116
Tom Sepez1d17a042017-03-16 13:22:47 -07001117 std::unique_ptr<void, FPDFFormHandleDeleter> form(
1118 FPDFDOC_InitFormFillEnvironment(doc.get(), &form_callbacks));
1119 form_callbacks.form_handle = form.get();
tonikitoo81d92f82016-09-21 12:44:56 -07001120
Tom Sepezc46d0002015-11-30 15:46:36 -08001121#ifdef PDF_ENABLE_XFA
thestigb97e07e2016-09-28 22:16:40 -07001122 int doc_type = DOCTYPE_PDF;
Tom Sepez1d17a042017-03-16 13:22:47 -07001123 if (FPDF_HasXFAField(doc.get(), &doc_type) && doc_type != DOCTYPE_PDF &&
1124 !FPDF_LoadXFA(doc.get())) {
Lei Zhang5377ebf2015-09-23 14:52:53 -07001125 fprintf(stderr, "LoadXFA unsuccessful, continuing anyway.\n");
Tom Sepez56451382014-12-05 13:30:51 -08001126 }
Tom Sepezc46d0002015-11-30 15:46:36 -08001127#endif // PDF_ENABLE_XFA
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001128
Tom Sepez1d17a042017-03-16 13:22:47 -07001129 FPDF_SetFormFieldHighlightColor(form.get(), 0, 0xFFE4DD);
1130 FPDF_SetFormFieldHighlightAlpha(form.get(), 100);
1131 FORM_DoDocumentJSAction(form.get());
1132 FORM_DoDocumentOpenAction(form.get());
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001133
Lei Zhangd1c9b452017-05-05 17:21:36 -07001134#if _WIN32
1135 if (options.output_format == OUTPUT_PS2)
1136 FPDF_SetPrintPostscriptLevel(2);
1137 else if (options.output_format == OUTPUT_PS3)
1138 FPDF_SetPrintPostscriptLevel(3);
1139#endif
1140
Tom Sepez1d17a042017-03-16 13:22:47 -07001141 int page_count = FPDF_GetPageCount(doc.get());
Tom Sepez1ed8a212015-05-11 15:25:39 -07001142 int rendered_pages = 0;
1143 int bad_pages = 0;
npmfa20cd52016-11-14 13:33:40 -08001144 int first_page = options.pages ? options.first_page : 0;
1145 int last_page = options.pages ? options.last_page + 1 : page_count;
1146 for (int i = first_page; i < last_page; ++i) {
Jun Fangdf7f3662015-11-10 18:29:18 +08001147 if (bIsLinearized) {
1148 nRet = PDF_DATA_NOTAVAIL;
thestig514e8c92016-07-15 17:57:54 -07001149 while (nRet == PDF_DATA_NOTAVAIL)
Tom Sepez1d17a042017-03-16 13:22:47 -07001150 nRet = FPDFAvail_IsPageAvail(pdf_avail.get(), i, &hints);
thestig514e8c92016-07-15 17:57:54 -07001151
Jun Fangdf7f3662015-11-10 18:29:18 +08001152 if (nRet == PDF_DATA_ERROR) {
1153 fprintf(stderr, "Unknown error in checking if page %d is available.\n",
1154 i);
1155 return;
1156 }
1157 }
Tom Sepez1d17a042017-03-16 13:22:47 -07001158 if (RenderPage(name, doc.get(), form.get(), form_callbacks, i, options,
1159 events))
Jun Fangdf7f3662015-11-10 18:29:18 +08001160 ++rendered_pages;
thestig514e8c92016-07-15 17:57:54 -07001161 else
Lei Zhang5377ebf2015-09-23 14:52:53 -07001162 ++bad_pages;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001163 }
1164
Tom Sepez1d17a042017-03-16 13:22:47 -07001165 FORM_DoDocumentAAction(form.get(), FPDFDOC_AACTION_WC);
Tom Sepez1ed8a212015-05-11 15:25:39 -07001166 fprintf(stderr, "Rendered %d pages.\n", rendered_pages);
tsepez10b01bf2016-05-04 12:52:42 -07001167 if (bad_pages)
1168 fprintf(stderr, "Skipped %d bad pages.\n", bad_pages);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001169}
1170
Tom Sepez2991d8d2016-01-15 16:02:48 -08001171static void ShowConfig() {
1172 std::string config;
1173 std::string maybe_comma;
1174#if PDF_ENABLE_V8
1175 config.append(maybe_comma);
1176 config.append("V8");
1177 maybe_comma = ",";
1178#endif // PDF_ENABLE_V8
1179#ifdef V8_USE_EXTERNAL_STARTUP_DATA
1180 config.append(maybe_comma);
1181 config.append("V8_EXTERNAL");
1182 maybe_comma = ",";
1183#endif // V8_USE_EXTERNAL_STARTUP_DATA
1184#ifdef PDF_ENABLE_XFA
1185 config.append(maybe_comma);
1186 config.append("XFA");
1187 maybe_comma = ",";
1188#endif // PDF_ENABLE_XFA
dan sinclair00d40642017-01-30 19:48:54 -08001189#ifdef PDF_ENABLE_ASAN
1190 config.append(maybe_comma);
1191 config.append("ASAN");
1192 maybe_comma = ",";
1193#endif // PDF_ENABLE_ASAN
Tom Sepez2991d8d2016-01-15 16:02:48 -08001194 printf("%s\n", config.c_str());
1195}
1196
thestig514e8c92016-07-15 17:57:54 -07001197static const char kUsageString[] =
Tom Sepez23b4e3f2015-02-06 16:05:23 -08001198 "Usage: pdfium_test [OPTION] [FILE]...\n"
Tom Sepez2991d8d2016-01-15 16:02:48 -08001199 " --show-config - print build options and exit\n"
Dan Sinclairddcb6e72017-04-05 10:30:33 -04001200 " --show-structure - print the structure elements from the document\n"
tsepez10b01bf2016-05-04 12:52:42 -07001201 " --send-events - send input described by .evt file\n"
Lei Zhang6f62d532015-09-23 15:31:44 -07001202 " --bin-dir=<path> - override path to v8 external data\n"
1203 " --font-dir=<path> - override path to external fonts\n"
1204 " --scale=<number> - scale output size by number (e.g. 0.5)\n"
npmfa20cd52016-11-14 13:33:40 -08001205 " --pages=<number>(-<number>) - only render the given 0-based page(s)\n"
Tom Sepez23b4e3f2015-02-06 16:05:23 -08001206#ifdef _WIN32
1207 " --bmp - write page images <pdf-name>.<page-number>.bmp\n"
1208 " --emf - write page meta files <pdf-name>.<page-number>.emf\n"
Lei Zhangd1c9b452017-05-05 17:21:36 -07001209 " --ps2 - write page raw PostScript (Lvl 2) <pdf-name>.<page-number>.ps\n"
1210 " --ps3 - write page raw PostScript (Lvl 3) <pdf-name>.<page-number>.ps\n"
Tom Sepezc46d0002015-11-30 15:46:36 -08001211#endif // _WIN32
thestig514e8c92016-07-15 17:57:54 -07001212 " --txt - write page text in UTF32-LE <pdf-name>.<page-number>.txt\n"
Tom Sepez23b4e3f2015-02-06 16:05:23 -08001213 " --png - write page images <pdf-name>.<page-number>.png\n"
thestig514e8c92016-07-15 17:57:54 -07001214 " --ppm - write page images <pdf-name>.<page-number>.ppm\n"
Cary Clark399be5b2016-03-14 16:51:29 -04001215#ifdef PDF_ENABLE_SKIA
1216 " --skp - write page images <pdf-name>.<page-number>.skp\n"
1217#endif
stephanafa05e972017-01-02 06:19:41 -08001218 " --md5 - write output image paths and their md5 hashes to stdout.\n"
Cary Clark399be5b2016-03-14 16:51:29 -04001219 "";
Tom Sepez23b4e3f2015-02-06 16:05:23 -08001220
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001221int main(int argc, const char* argv[]) {
Tom Sepez5ee12d72014-12-17 16:24:01 -08001222 std::vector<std::string> args(argv, argv + argc);
1223 Options options;
thestig514e8c92016-07-15 17:57:54 -07001224 std::vector<std::string> files;
Tom Sepez5ee12d72014-12-17 16:24:01 -08001225 if (!ParseCommandLine(args, &options, &files)) {
thestig514e8c92016-07-15 17:57:54 -07001226 fprintf(stderr, "%s", kUsageString);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001227 return 1;
1228 }
1229
Tom Sepez2991d8d2016-01-15 16:02:48 -08001230 if (options.show_config) {
1231 ShowConfig();
1232 return 0;
1233 }
1234
1235 if (files.empty()) {
1236 fprintf(stderr, "No input files.\n");
1237 return 1;
1238 }
1239
Tom Sepez452b4f32015-10-13 09:27:27 -07001240#ifdef PDF_ENABLE_V8
Tom Sepezd831dc72015-10-19 16:04:22 -07001241 v8::Platform* platform;
Tom Sepez5ee12d72014-12-17 16:24:01 -08001242#ifdef V8_USE_EXTERNAL_STARTUP_DATA
1243 v8::StartupData natives;
1244 v8::StartupData snapshot;
Tom Sepezd831dc72015-10-19 16:04:22 -07001245 InitializeV8ForPDFium(options.exe_path, options.bin_directory, &natives,
1246 &snapshot, &platform);
1247#else // V8_USE_EXTERNAL_STARTUP_DATA
jochen9e077d22016-06-09 02:51:13 -07001248 InitializeV8ForPDFium(options.exe_path, &platform);
Tom Sepez5ee12d72014-12-17 16:24:01 -08001249#endif // V8_USE_EXTERNAL_STARTUP_DATA
Tom Sepez452b4f32015-10-13 09:27:27 -07001250#endif // PDF_ENABLE_V8
Tom Sepez5ee12d72014-12-17 16:24:01 -08001251
Tom Sepeza72e8e22015-10-07 10:17:53 -07001252 FPDF_LIBRARY_CONFIG config;
1253 config.version = 2;
1254 config.m_pUserFontPaths = nullptr;
1255 config.m_pIsolate = nullptr;
1256 config.m_v8EmbedderSlot = 0;
1257
1258 const char* path_array[2];
1259 if (!options.font_directory.empty()) {
Lei Zhang6f62d532015-09-23 15:31:44 -07001260 path_array[0] = options.font_directory.c_str();
1261 path_array[1] = nullptr;
Lei Zhang6f62d532015-09-23 15:31:44 -07001262 config.m_pUserFontPaths = path_array;
Lei Zhang6f62d532015-09-23 15:31:44 -07001263 }
Tom Sepeza72e8e22015-10-07 10:17:53 -07001264 FPDF_InitLibraryWithConfig(&config);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001265
npmfa20cd52016-11-14 13:33:40 -08001266 UNSUPPORT_INFO unsupported_info;
1267 memset(&unsupported_info, '\0', sizeof(unsupported_info));
1268 unsupported_info.version = 1;
1269 unsupported_info.FSDK_UnSupport_Handler = ExampleUnsupportedHandler;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001270
npmfa20cd52016-11-14 13:33:40 -08001271 FSDK_SetUnSpObjProcessHandler(&unsupported_info);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001272
thestig514e8c92016-07-15 17:57:54 -07001273 for (const std::string& filename : files) {
Tom Sepez5ee12d72014-12-17 16:24:01 -08001274 size_t file_length = 0;
Tom Sepez0aa35312016-01-06 10:16:32 -08001275 std::unique_ptr<char, pdfium::FreeDeleter> file_contents =
1276 GetFileContents(filename.c_str(), &file_length);
tsepezf09bdfa2016-04-18 16:08:26 -07001277 if (!file_contents)
1278 continue;
tsepez10b01bf2016-05-04 12:52:42 -07001279 fprintf(stderr, "Rendering PDF file %s.\n", filename.c_str());
tsepezf09bdfa2016-04-18 16:08:26 -07001280 std::string events;
1281 if (options.send_events) {
1282 std::string event_filename = filename;
1283 size_t event_length = 0;
1284 size_t extension_pos = event_filename.find(".pdf");
1285 if (extension_pos != std::string::npos) {
1286 event_filename.replace(extension_pos, 4, ".evt");
thestigf2b940c2016-10-13 06:48:47 -07001287 if (access(event_filename.c_str(), R_OK) == 0) {
1288 fprintf(stderr, "Using event file %s.\n", event_filename.c_str());
1289 std::unique_ptr<char, pdfium::FreeDeleter> event_contents =
1290 GetFileContents(event_filename.c_str(), &event_length);
1291 if (event_contents) {
1292 fprintf(stderr, "Sending events from: %s\n",
1293 event_filename.c_str());
1294 events = std::string(event_contents.get(), event_length);
1295 }
tsepezf09bdfa2016-04-18 16:08:26 -07001296 }
1297 }
1298 }
1299 RenderPdf(filename, file_contents.get(), file_length, options, events);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001300 }
1301
1302 FPDF_DestroyLibrary();
Tom Sepez452b4f32015-10-13 09:27:27 -07001303#ifdef PDF_ENABLE_V8
John Abd-El-Malekb045ed22015-02-10 09:15:12 -08001304 v8::V8::ShutdownPlatform();
1305 delete platform;
thestigc08cd7a2016-06-27 09:47:59 -07001306
1307#ifdef V8_USE_EXTERNAL_STARTUP_DATA
1308 free(const_cast<char*>(natives.data));
1309 free(const_cast<char*>(snapshot.data));
1310#endif // V8_USE_EXTERNAL_STARTUP_DATA
Tom Sepez452b4f32015-10-13 09:27:27 -07001311#endif // PDF_ENABLE_V8
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -07001312
1313 return 0;
1314}