blob: 737846b36e472a9da5a45e24ba93081693a66f84 [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>
Tom Sepezfb947282014-12-08 09:55:11 -08009#include <wchar.h>
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070010
11#include <list>
12#include <string>
13#include <utility>
14
John Abd-El-Malek197fd8d2014-05-23 19:27:48 -070015#include "../fpdfsdk/include/fpdf_dataavail.h"
16#include "../fpdfsdk/include/fpdf_ext.h"
17#include "../fpdfsdk/include/fpdfformfill.h"
18#include "../fpdfsdk/include/fpdftext.h"
19#include "../fpdfsdk/include/fpdfview.h"
Bruce Dawsonddc20622014-11-18 13:42:28 -080020#include "../core/include/fxcrt/fx_system.h"
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070021#include "v8/include/v8.h"
22
23#ifdef _WIN32
24 #define snprintf _snprintf
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070025#endif
26
Vitaly Buka9e0177a2014-07-22 18:15:42 -070027enum OutputFormat {
28 OUTPUT_NONE,
29 OUTPUT_PPM,
30#ifdef _WIN32
31 OUTPUT_BMP,
32 OUTPUT_EMF,
33#endif
34};
35
36static void WritePpm(const char* pdf_name, int num, const void* buffer_void,
37 int stride, int width, int height) {
38 const char* buffer = reinterpret_cast<const char*>(buffer_void);
39
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070040 if (stride < 0 || width < 0 || height < 0)
41 return;
42 if (height > 0 && width > INT_MAX / height)
43 return;
44 int out_len = width * height;
45 if (out_len > INT_MAX / 3)
46 return;
47 out_len *= 3;
48
49 char filename[256];
50 snprintf(filename, sizeof(filename), "%s.%d.ppm", pdf_name, num);
John Abd-El-Maleka548d302014-06-26 10:18:11 -070051 FILE* fp = fopen(filename, "wb");
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070052 if (!fp)
53 return;
54 fprintf(fp, "P6\n# PDF test render\n%d %d\n255\n", width, height);
55 // Source data is B, G, R, unused.
56 // Dest data is R, G, B.
57 char* result = new char[out_len];
58 if (result) {
59 for (int h = 0; h < height; ++h) {
60 const char* src_line = buffer + (stride * h);
61 char* dest_line = result + (width * h * 3);
62 for (int w = 0; w < width; ++w) {
63 // R
64 dest_line[w * 3] = src_line[(w * 4) + 2];
65 // G
66 dest_line[(w * 3) + 1] = src_line[(w * 4) + 1];
67 // B
68 dest_line[(w * 3) + 2] = src_line[w * 4];
69 }
70 }
71 fwrite(result, out_len, 1, fp);
72 delete [] result;
73 }
74 fclose(fp);
75}
76
Vitaly Buka9e0177a2014-07-22 18:15:42 -070077#ifdef _WIN32
78static void WriteBmp(const char* pdf_name, int num, const void* buffer,
79 int stride, int width, int height) {
80 if (stride < 0 || width < 0 || height < 0)
81 return;
82 if (height > 0 && width > INT_MAX / height)
83 return;
84 int out_len = stride * height;
85 if (out_len > INT_MAX / 3)
86 return;
87
88 char filename[256];
89 snprintf(filename, sizeof(filename), "%s.%d.bmp", pdf_name, num);
90 FILE* fp = fopen(filename, "wb");
91 if (!fp)
92 return;
93
94 BITMAPINFO bmi = {0};
95 bmi.bmiHeader.biSize = sizeof(bmi) - sizeof(RGBQUAD);
96 bmi.bmiHeader.biWidth = width;
97 bmi.bmiHeader.biHeight = -height; // top-down image
98 bmi.bmiHeader.biPlanes = 1;
99 bmi.bmiHeader.biBitCount = 32;
100 bmi.bmiHeader.biCompression = BI_RGB;
101 bmi.bmiHeader.biSizeImage = 0;
102
103 BITMAPFILEHEADER file_header = {0};
104 file_header.bfType = 0x4d42;
105 file_header.bfSize = sizeof(file_header) + bmi.bmiHeader.biSize + out_len;
106 file_header.bfOffBits = file_header.bfSize - out_len;
107
108 fwrite(&file_header, sizeof(file_header), 1, fp);
109 fwrite(&bmi, bmi.bmiHeader.biSize, 1, fp);
110 fwrite(buffer, out_len, 1, fp);
111 fclose(fp);
112}
113
114void WriteEmf(FPDF_PAGE page, const char* pdf_name, int num) {
115 int width = static_cast<int>(FPDF_GetPageWidth(page));
116 int height = static_cast<int>(FPDF_GetPageHeight(page));
117
118 char filename[256];
119 snprintf(filename, sizeof(filename), "%s.%d.emf", pdf_name, num);
120
121 HDC dc = CreateEnhMetaFileA(NULL, filename, NULL, NULL);
122
123 HRGN rgn = CreateRectRgn(0, 0, width, height);
124 SelectClipRgn(dc, rgn);
125 DeleteObject(rgn);
126
127 SelectObject(dc, GetStockObject(NULL_PEN));
128 SelectObject(dc, GetStockObject(WHITE_BRUSH));
129 // If a PS_NULL pen is used, the dimensions of the rectangle are 1 pixel less.
130 Rectangle(dc, 0, 0, width + 1, height + 1);
131
132 FPDF_RenderPage(dc, page, 0, 0, width, height, 0,
133 FPDF_ANNOT | FPDF_PRINTING | FPDF_NO_CATCH);
134
135 DeleteEnhMetaFile(CloseEnhMetaFile(dc));
136}
137#endif
138
Tom Sepezfb947282014-12-08 09:55:11 -0800139int Form_Alert(IPDF_JSPLATFORM*, FPDF_WIDESTRING msg, FPDF_WIDESTRING,
140 int, int) {
141 // Deal with differences between UTF16LE and wchar_t on this platform.
142 size_t characters = 0;
143 while (msg[characters]) {
144 ++characters;
145 }
146 wchar_t* platform_string =
147 (wchar_t*)malloc((characters + 1) * sizeof(wchar_t));
148 for (size_t i = 0; i < characters + 1; ++i) {
149 unsigned char* ptr = (unsigned char*)&msg[i];
150 platform_string[i] = ptr[0] + 256 * ptr[1];
151 }
152 printf("Alert: %ls\n", platform_string);
153 free(platform_string);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700154 return 0;
155}
156
157void Unsupported_Handler(UNSUPPORT_INFO*, int type) {
158 std::string feature = "Unknown";
159 switch (type) {
160 case FPDF_UNSP_DOC_XFAFORM:
161 feature = "XFA";
162 break;
163 case FPDF_UNSP_DOC_PORTABLECOLLECTION:
164 feature = "Portfolios_Packages";
165 break;
166 case FPDF_UNSP_DOC_ATTACHMENT:
167 case FPDF_UNSP_ANNOT_ATTACHMENT:
168 feature = "Attachment";
169 break;
170 case FPDF_UNSP_DOC_SECURITY:
171 feature = "Rights_Management";
172 break;
173 case FPDF_UNSP_DOC_SHAREDREVIEW:
174 feature = "Shared_Review";
175 break;
176 case FPDF_UNSP_DOC_SHAREDFORM_ACROBAT:
177 case FPDF_UNSP_DOC_SHAREDFORM_FILESYSTEM:
178 case FPDF_UNSP_DOC_SHAREDFORM_EMAIL:
179 feature = "Shared_Form";
180 break;
181 case FPDF_UNSP_ANNOT_3DANNOT:
182 feature = "3D";
183 break;
184 case FPDF_UNSP_ANNOT_MOVIE:
185 feature = "Movie";
186 break;
187 case FPDF_UNSP_ANNOT_SOUND:
188 feature = "Sound";
189 break;
190 case FPDF_UNSP_ANNOT_SCREEN_MEDIA:
191 case FPDF_UNSP_ANNOT_SCREEN_RICHMEDIA:
192 feature = "Screen";
193 break;
194 case FPDF_UNSP_ANNOT_SIG:
195 feature = "Digital_Signature";
196 break;
197 }
198 printf("Unsupported feature: %s.\n", feature.c_str());
199}
200
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700201bool ParseCommandLine(int argc, const char* argv[], OutputFormat* output_format,
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700202 std::list<const char*>* files) {
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700203 *output_format = OUTPUT_NONE;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700204 files->clear();
205
206 int cur_arg = 1;
Vitaly Buka8f2c3dc2014-08-20 10:32:36 -0700207 for (; cur_arg < argc; ++cur_arg) {
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700208 if (strcmp(argv[cur_arg], "--ppm") == 0)
209 *output_format = OUTPUT_PPM;
210#ifdef _WIN32
Vitaly Buka8f2c3dc2014-08-20 10:32:36 -0700211 else if (strcmp(argv[cur_arg], "--emf") == 0)
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700212 *output_format = OUTPUT_EMF;
Vitaly Buka8f2c3dc2014-08-20 10:32:36 -0700213 else if (strcmp(argv[cur_arg], "--bmp") == 0)
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700214 *output_format = OUTPUT_BMP;
215#endif
Vitaly Buka8f2c3dc2014-08-20 10:32:36 -0700216 else
217 break;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700218 }
219
Vitaly Buka8f2c3dc2014-08-20 10:32:36 -0700220 if (cur_arg > 2) // Multiple options.
221 return false;
222
223 if (cur_arg >= argc) // No input files.
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700224 return false;
225
226 for (int i = cur_arg; i < argc; i++)
227 files->push_back(argv[i]);
228
229 return true;
230}
231
232class TestLoader {
233 public:
234 TestLoader(const char* pBuf, size_t len);
235
236 const char* m_pBuf;
237 size_t m_Len;
238};
239
240TestLoader::TestLoader(const char* pBuf, size_t len)
241 : m_pBuf(pBuf), m_Len(len) {
242}
243
244int Get_Block(void* param, unsigned long pos, unsigned char* pBuf,
245 unsigned long size) {
246 TestLoader* pLoader = (TestLoader*) param;
247 if (pos + size < pos || pos + size > pLoader->m_Len) return 0;
248 memcpy(pBuf, pLoader->m_pBuf + pos, size);
249 return 1;
250}
251
252bool Is_Data_Avail(FX_FILEAVAIL* pThis, size_t offset, size_t size) {
253 return true;
254}
255
256void Add_Segment(FX_DOWNLOADHINTS* pThis, size_t offset, size_t size) {
257}
258
259void RenderPdf(const char* name, const char* pBuf, size_t len,
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700260 OutputFormat format) {
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700261 printf("Rendering PDF file %s.\n", name);
262
263 IPDF_JSPLATFORM platform_callbacks;
264 memset(&platform_callbacks, '\0', sizeof(platform_callbacks));
265 platform_callbacks.version = 1;
266 platform_callbacks.app_alert = Form_Alert;
267
268 FPDF_FORMFILLINFO form_callbacks;
269 memset(&form_callbacks, '\0', sizeof(form_callbacks));
Tom Sepezed631382014-11-18 14:10:25 -0800270 form_callbacks.version = 2;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700271 form_callbacks.m_pJsPlatform = &platform_callbacks;
272
273 TestLoader loader(pBuf, len);
274
275 FPDF_FILEACCESS file_access;
276 memset(&file_access, '\0', sizeof(file_access));
John Abd-El-Malek7dc51722014-05-26 12:54:31 -0700277 file_access.m_FileLen = static_cast<unsigned long>(len);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700278 file_access.m_GetBlock = Get_Block;
279 file_access.m_Param = &loader;
280
281 FX_FILEAVAIL file_avail;
282 memset(&file_avail, '\0', sizeof(file_avail));
283 file_avail.version = 1;
284 file_avail.IsDataAvail = Is_Data_Avail;
285
286 FX_DOWNLOADHINTS hints;
287 memset(&hints, '\0', sizeof(hints));
288 hints.version = 1;
289 hints.AddSegment = Add_Segment;
290
291 FPDF_DOCUMENT doc;
292 FPDF_AVAIL pdf_avail = FPDFAvail_Create(&file_avail, &file_access);
293
294 (void) FPDFAvail_IsDocAvail(pdf_avail, &hints);
295
296 if (!FPDFAvail_IsLinearized(pdf_avail)) {
297 printf("Non-linearized path...\n");
298 doc = FPDF_LoadCustomDocument(&file_access, NULL);
299 } else {
300 printf("Linearized path...\n");
301 doc = FPDFAvail_GetDocument(pdf_avail, NULL);
302 }
303
304 (void) FPDF_GetDocPermissions(doc);
305 (void) FPDFAvail_IsFormAvail(pdf_avail, &hints);
306
Bo Xu2b7a49d2014-11-14 17:40:50 -0800307 FPDF_FORMHANDLE form = FPDFDOC_InitFormFillEnvironment(doc, &form_callbacks);
Tom Sepez56451382014-12-05 13:30:51 -0800308 if (!FPDF_LoadXFA(doc)) {
309 printf("LoadXFA unsuccessful, continuing anyway.\n");
310 }
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700311 FPDF_SetFormFieldHighlightColor(form, 0, 0xFFE4DD);
312 FPDF_SetFormFieldHighlightAlpha(form, 100);
313
314 int first_page = FPDFAvail_GetFirstPageNum(doc);
315 (void) FPDFAvail_IsPageAvail(pdf_avail, first_page, &hints);
316
317 int page_count = FPDF_GetPageCount(doc);
318 for (int i = 0; i < page_count; ++i) {
319 (void) FPDFAvail_IsPageAvail(pdf_avail, i, &hints);
320 }
321
322 FORM_DoDocumentJSAction(form);
323 FORM_DoDocumentOpenAction(form);
324
Jun Fangaeacba42014-08-22 17:04:29 -0700325 size_t rendered_pages = 0;
326 size_t bad_pages = 0;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700327 for (int i = 0; i < page_count; ++i) {
328 FPDF_PAGE page = FPDF_LoadPage(doc, i);
Jun Fangaeacba42014-08-22 17:04:29 -0700329 if (!page) {
330 bad_pages ++;
331 continue;
332 }
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700333 FPDF_TEXTPAGE text_page = FPDFText_LoadPage(page);
334 FORM_OnAfterLoadPage(page, form);
335 FORM_DoPageAAction(page, form, FPDFPAGE_AACTION_OPEN);
336
337 int width = static_cast<int>(FPDF_GetPageWidth(page));
338 int height = static_cast<int>(FPDF_GetPageHeight(page));
339 FPDF_BITMAP bitmap = FPDFBitmap_Create(width, height, 0);
Lei Zhang532a6a72014-07-09 11:47:15 -0700340 FPDFBitmap_FillRect(bitmap, 0, 0, width, height, 0xFFFFFFFF);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700341
342 FPDF_RenderPageBitmap(bitmap, page, 0, 0, width, height, 0, 0);
Jun Fangaeacba42014-08-22 17:04:29 -0700343 rendered_pages ++;
344
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700345 FPDF_FFLDraw(form, bitmap, page, 0, 0, width, height, 0, 0);
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700346 int stride = FPDFBitmap_GetStride(bitmap);
347 const char* buffer =
348 reinterpret_cast<const char*>(FPDFBitmap_GetBuffer(bitmap));
349
350 switch (format) {
351#ifdef _WIN32
352 case OUTPUT_BMP:
353 WriteBmp(name, i, buffer, stride, width, height);
354 break;
355
356 case OUTPUT_EMF:
357 WriteEmf(page, name, i);
358 break;
359#endif
360 case OUTPUT_PPM:
361 WritePpm(name, i, buffer, stride, width, height);
362 break;
363 default:
364 break;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700365 }
366
367 FPDFBitmap_Destroy(bitmap);
368
369 FORM_DoPageAAction(page, form, FPDFPAGE_AACTION_CLOSE);
370 FORM_OnBeforeClosePage(page, form);
371 FPDFText_ClosePage(text_page);
372 FPDF_ClosePage(page);
373 }
374
375 FORM_DoDocumentAAction(form, FPDFDOC_AACTION_WC);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700376 FPDF_CloseDocument(doc);
Bo Xu2b7a49d2014-11-14 17:40:50 -0800377 FPDFDOC_ExitFormFillEnvironment(form);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700378 FPDFAvail_Destroy(pdf_avail);
379
Bruce Dawsonddc20622014-11-18 13:42:28 -0800380 printf("Loaded, parsed and rendered %" PRIuS " pages.\n", rendered_pages);
381 printf("Skipped %" PRIuS " bad pages.\n", bad_pages);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700382}
383
384int main(int argc, const char* argv[]) {
385 v8::V8::InitializeICU();
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700386 OutputFormat format = OUTPUT_NONE;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700387 std::list<const char*> files;
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700388 if (!ParseCommandLine(argc, argv, &format, &files)) {
Vitaly Buka8f2c3dc2014-08-20 10:32:36 -0700389 printf("Usage: pdfium_test [OPTION] [FILE]...\n");
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700390 printf("--ppm write page images <pdf-name>.<page-number>.ppm\n");
391#ifdef _WIN32
392 printf("--bmp write page images <pdf-name>.<page-number>.bmp\n");
393 printf("--emf write page meta files <pdf-name>.<page-number>.emf\n");
394#endif
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700395 return 1;
396 }
397
398 FPDF_InitLibrary(NULL);
399
400 UNSUPPORT_INFO unsuppored_info;
401 memset(&unsuppored_info, '\0', sizeof(unsuppored_info));
402 unsuppored_info.version = 1;
403 unsuppored_info.FSDK_UnSupport_Handler = Unsupported_Handler;
404
405 FSDK_SetUnSpObjProcessHandler(&unsuppored_info);
406
407 while (!files.empty()) {
408 const char* filename = files.front();
409 files.pop_front();
John Abd-El-Maleka548d302014-06-26 10:18:11 -0700410 FILE* file = fopen(filename, "rb");
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700411 if (!file) {
412 fprintf(stderr, "Failed to open: %s\n", filename);
413 continue;
414 }
415 (void) fseek(file, 0, SEEK_END);
416 size_t len = ftell(file);
417 (void) fseek(file, 0, SEEK_SET);
418 char* pBuf = (char*) malloc(len);
419 size_t ret = fread(pBuf, 1, len, file);
420 (void) fclose(file);
421 if (ret != len) {
422 fprintf(stderr, "Failed to read: %s\n", filename);
423 } else {
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700424 RenderPdf(filename, pBuf, len, format);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700425 }
426 free(pBuf);
427 }
428
429 FPDF_DestroyLibrary();
430
431 return 0;
432}