blob: 3c0cef4dbfb38641b7a54845b2d523ef66ea7530 [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
10#include <list>
11#include <string>
12#include <utility>
13
John Abd-El-Malek197fd8d2014-05-23 19:27:48 -070014#include "../fpdfsdk/include/fpdf_dataavail.h"
15#include "../fpdfsdk/include/fpdf_ext.h"
16#include "../fpdfsdk/include/fpdfformfill.h"
17#include "../fpdfsdk/include/fpdftext.h"
18#include "../fpdfsdk/include/fpdfview.h"
Bruce Dawsonddc20622014-11-18 13:42:28 -080019#include "../core/include/fxcrt/fx_system.h"
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070020#include "v8/include/v8.h"
21
22#ifdef _WIN32
23 #define snprintf _snprintf
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070024#endif
25
Vitaly Buka9e0177a2014-07-22 18:15:42 -070026enum OutputFormat {
27 OUTPUT_NONE,
28 OUTPUT_PPM,
29#ifdef _WIN32
30 OUTPUT_BMP,
31 OUTPUT_EMF,
32#endif
33};
34
35static void WritePpm(const char* pdf_name, int num, const void* buffer_void,
36 int stride, int width, int height) {
37 const char* buffer = reinterpret_cast<const char*>(buffer_void);
38
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070039 if (stride < 0 || width < 0 || height < 0)
40 return;
41 if (height > 0 && width > INT_MAX / height)
42 return;
43 int out_len = width * height;
44 if (out_len > INT_MAX / 3)
45 return;
46 out_len *= 3;
47
48 char filename[256];
49 snprintf(filename, sizeof(filename), "%s.%d.ppm", pdf_name, num);
John Abd-El-Maleka548d302014-06-26 10:18:11 -070050 FILE* fp = fopen(filename, "wb");
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -070051 if (!fp)
52 return;
53 fprintf(fp, "P6\n# PDF test render\n%d %d\n255\n", width, height);
54 // Source data is B, G, R, unused.
55 // Dest data is R, G, B.
56 char* result = new char[out_len];
57 if (result) {
58 for (int h = 0; h < height; ++h) {
59 const char* src_line = buffer + (stride * h);
60 char* dest_line = result + (width * h * 3);
61 for (int w = 0; w < width; ++w) {
62 // R
63 dest_line[w * 3] = src_line[(w * 4) + 2];
64 // G
65 dest_line[(w * 3) + 1] = src_line[(w * 4) + 1];
66 // B
67 dest_line[(w * 3) + 2] = src_line[w * 4];
68 }
69 }
70 fwrite(result, out_len, 1, fp);
71 delete [] result;
72 }
73 fclose(fp);
74}
75
Vitaly Buka9e0177a2014-07-22 18:15:42 -070076#ifdef _WIN32
77static void WriteBmp(const char* pdf_name, int num, const void* buffer,
78 int stride, int width, int height) {
79 if (stride < 0 || width < 0 || height < 0)
80 return;
81 if (height > 0 && width > INT_MAX / height)
82 return;
83 int out_len = stride * height;
84 if (out_len > INT_MAX / 3)
85 return;
86
87 char filename[256];
88 snprintf(filename, sizeof(filename), "%s.%d.bmp", pdf_name, num);
89 FILE* fp = fopen(filename, "wb");
90 if (!fp)
91 return;
92
93 BITMAPINFO bmi = {0};
94 bmi.bmiHeader.biSize = sizeof(bmi) - sizeof(RGBQUAD);
95 bmi.bmiHeader.biWidth = width;
96 bmi.bmiHeader.biHeight = -height; // top-down image
97 bmi.bmiHeader.biPlanes = 1;
98 bmi.bmiHeader.biBitCount = 32;
99 bmi.bmiHeader.biCompression = BI_RGB;
100 bmi.bmiHeader.biSizeImage = 0;
101
102 BITMAPFILEHEADER file_header = {0};
103 file_header.bfType = 0x4d42;
104 file_header.bfSize = sizeof(file_header) + bmi.bmiHeader.biSize + out_len;
105 file_header.bfOffBits = file_header.bfSize - out_len;
106
107 fwrite(&file_header, sizeof(file_header), 1, fp);
108 fwrite(&bmi, bmi.bmiHeader.biSize, 1, fp);
109 fwrite(buffer, out_len, 1, fp);
110 fclose(fp);
111}
112
113void WriteEmf(FPDF_PAGE page, const char* pdf_name, int num) {
114 int width = static_cast<int>(FPDF_GetPageWidth(page));
115 int height = static_cast<int>(FPDF_GetPageHeight(page));
116
117 char filename[256];
118 snprintf(filename, sizeof(filename), "%s.%d.emf", pdf_name, num);
119
120 HDC dc = CreateEnhMetaFileA(NULL, filename, NULL, NULL);
121
122 HRGN rgn = CreateRectRgn(0, 0, width, height);
123 SelectClipRgn(dc, rgn);
124 DeleteObject(rgn);
125
126 SelectObject(dc, GetStockObject(NULL_PEN));
127 SelectObject(dc, GetStockObject(WHITE_BRUSH));
128 // If a PS_NULL pen is used, the dimensions of the rectangle are 1 pixel less.
129 Rectangle(dc, 0, 0, width + 1, height + 1);
130
131 FPDF_RenderPage(dc, page, 0, 0, width, height, 0,
132 FPDF_ANNOT | FPDF_PRINTING | FPDF_NO_CATCH);
133
134 DeleteEnhMetaFile(CloseEnhMetaFile(dc));
135}
136#endif
137
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700138int Form_Alert(IPDF_JSPLATFORM*, FPDF_WIDESTRING, FPDF_WIDESTRING, int, int) {
139 printf("Form_Alert called.\n");
140 return 0;
141}
142
143void Unsupported_Handler(UNSUPPORT_INFO*, int type) {
144 std::string feature = "Unknown";
145 switch (type) {
146 case FPDF_UNSP_DOC_XFAFORM:
147 feature = "XFA";
148 break;
149 case FPDF_UNSP_DOC_PORTABLECOLLECTION:
150 feature = "Portfolios_Packages";
151 break;
152 case FPDF_UNSP_DOC_ATTACHMENT:
153 case FPDF_UNSP_ANNOT_ATTACHMENT:
154 feature = "Attachment";
155 break;
156 case FPDF_UNSP_DOC_SECURITY:
157 feature = "Rights_Management";
158 break;
159 case FPDF_UNSP_DOC_SHAREDREVIEW:
160 feature = "Shared_Review";
161 break;
162 case FPDF_UNSP_DOC_SHAREDFORM_ACROBAT:
163 case FPDF_UNSP_DOC_SHAREDFORM_FILESYSTEM:
164 case FPDF_UNSP_DOC_SHAREDFORM_EMAIL:
165 feature = "Shared_Form";
166 break;
167 case FPDF_UNSP_ANNOT_3DANNOT:
168 feature = "3D";
169 break;
170 case FPDF_UNSP_ANNOT_MOVIE:
171 feature = "Movie";
172 break;
173 case FPDF_UNSP_ANNOT_SOUND:
174 feature = "Sound";
175 break;
176 case FPDF_UNSP_ANNOT_SCREEN_MEDIA:
177 case FPDF_UNSP_ANNOT_SCREEN_RICHMEDIA:
178 feature = "Screen";
179 break;
180 case FPDF_UNSP_ANNOT_SIG:
181 feature = "Digital_Signature";
182 break;
183 }
184 printf("Unsupported feature: %s.\n", feature.c_str());
185}
186
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700187bool ParseCommandLine(int argc, const char* argv[], OutputFormat* output_format,
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700188 std::list<const char*>* files) {
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700189 *output_format = OUTPUT_NONE;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700190 files->clear();
191
192 int cur_arg = 1;
Vitaly Buka8f2c3dc2014-08-20 10:32:36 -0700193 for (; cur_arg < argc; ++cur_arg) {
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700194 if (strcmp(argv[cur_arg], "--ppm") == 0)
195 *output_format = OUTPUT_PPM;
196#ifdef _WIN32
Vitaly Buka8f2c3dc2014-08-20 10:32:36 -0700197 else if (strcmp(argv[cur_arg], "--emf") == 0)
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700198 *output_format = OUTPUT_EMF;
Vitaly Buka8f2c3dc2014-08-20 10:32:36 -0700199 else if (strcmp(argv[cur_arg], "--bmp") == 0)
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700200 *output_format = OUTPUT_BMP;
201#endif
Vitaly Buka8f2c3dc2014-08-20 10:32:36 -0700202 else
203 break;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700204 }
205
Vitaly Buka8f2c3dc2014-08-20 10:32:36 -0700206 if (cur_arg > 2) // Multiple options.
207 return false;
208
209 if (cur_arg >= argc) // No input files.
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700210 return false;
211
212 for (int i = cur_arg; i < argc; i++)
213 files->push_back(argv[i]);
214
215 return true;
216}
217
218class TestLoader {
219 public:
220 TestLoader(const char* pBuf, size_t len);
221
222 const char* m_pBuf;
223 size_t m_Len;
224};
225
226TestLoader::TestLoader(const char* pBuf, size_t len)
227 : m_pBuf(pBuf), m_Len(len) {
228}
229
230int Get_Block(void* param, unsigned long pos, unsigned char* pBuf,
231 unsigned long size) {
232 TestLoader* pLoader = (TestLoader*) param;
233 if (pos + size < pos || pos + size > pLoader->m_Len) return 0;
234 memcpy(pBuf, pLoader->m_pBuf + pos, size);
235 return 1;
236}
237
238bool Is_Data_Avail(FX_FILEAVAIL* pThis, size_t offset, size_t size) {
239 return true;
240}
241
242void Add_Segment(FX_DOWNLOADHINTS* pThis, size_t offset, size_t size) {
243}
244
245void RenderPdf(const char* name, const char* pBuf, size_t len,
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700246 OutputFormat format) {
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700247 printf("Rendering PDF file %s.\n", name);
248
249 IPDF_JSPLATFORM platform_callbacks;
250 memset(&platform_callbacks, '\0', sizeof(platform_callbacks));
251 platform_callbacks.version = 1;
252 platform_callbacks.app_alert = Form_Alert;
253
254 FPDF_FORMFILLINFO form_callbacks;
255 memset(&form_callbacks, '\0', sizeof(form_callbacks));
256 form_callbacks.version = 1;
257 form_callbacks.m_pJsPlatform = &platform_callbacks;
258
259 TestLoader loader(pBuf, len);
260
261 FPDF_FILEACCESS file_access;
262 memset(&file_access, '\0', sizeof(file_access));
John Abd-El-Malek7dc51722014-05-26 12:54:31 -0700263 file_access.m_FileLen = static_cast<unsigned long>(len);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700264 file_access.m_GetBlock = Get_Block;
265 file_access.m_Param = &loader;
266
267 FX_FILEAVAIL file_avail;
268 memset(&file_avail, '\0', sizeof(file_avail));
269 file_avail.version = 1;
270 file_avail.IsDataAvail = Is_Data_Avail;
271
272 FX_DOWNLOADHINTS hints;
273 memset(&hints, '\0', sizeof(hints));
274 hints.version = 1;
275 hints.AddSegment = Add_Segment;
276
277 FPDF_DOCUMENT doc;
278 FPDF_AVAIL pdf_avail = FPDFAvail_Create(&file_avail, &file_access);
279
280 (void) FPDFAvail_IsDocAvail(pdf_avail, &hints);
281
282 if (!FPDFAvail_IsLinearized(pdf_avail)) {
283 printf("Non-linearized path...\n");
284 doc = FPDF_LoadCustomDocument(&file_access, NULL);
285 } else {
286 printf("Linearized path...\n");
287 doc = FPDFAvail_GetDocument(pdf_avail, NULL);
288 }
289
290 (void) FPDF_GetDocPermissions(doc);
291 (void) FPDFAvail_IsFormAvail(pdf_avail, &hints);
292
Bo Xu2b7a49d2014-11-14 17:40:50 -0800293 FPDF_FORMHANDLE form = FPDFDOC_InitFormFillEnvironment(doc, &form_callbacks);
Bo Xufdc00a72014-10-28 23:03:33 -0700294 FPDF_LoadXFA(doc);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700295 FPDF_SetFormFieldHighlightColor(form, 0, 0xFFE4DD);
296 FPDF_SetFormFieldHighlightAlpha(form, 100);
297
298 int first_page = FPDFAvail_GetFirstPageNum(doc);
299 (void) FPDFAvail_IsPageAvail(pdf_avail, first_page, &hints);
300
301 int page_count = FPDF_GetPageCount(doc);
302 for (int i = 0; i < page_count; ++i) {
303 (void) FPDFAvail_IsPageAvail(pdf_avail, i, &hints);
304 }
305
306 FORM_DoDocumentJSAction(form);
307 FORM_DoDocumentOpenAction(form);
308
Jun Fangaeacba42014-08-22 17:04:29 -0700309 size_t rendered_pages = 0;
310 size_t bad_pages = 0;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700311 for (int i = 0; i < page_count; ++i) {
312 FPDF_PAGE page = FPDF_LoadPage(doc, i);
Jun Fangaeacba42014-08-22 17:04:29 -0700313 if (!page) {
314 bad_pages ++;
315 continue;
316 }
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700317 FPDF_TEXTPAGE text_page = FPDFText_LoadPage(page);
318 FORM_OnAfterLoadPage(page, form);
319 FORM_DoPageAAction(page, form, FPDFPAGE_AACTION_OPEN);
320
321 int width = static_cast<int>(FPDF_GetPageWidth(page));
322 int height = static_cast<int>(FPDF_GetPageHeight(page));
323 FPDF_BITMAP bitmap = FPDFBitmap_Create(width, height, 0);
Lei Zhang532a6a72014-07-09 11:47:15 -0700324 FPDFBitmap_FillRect(bitmap, 0, 0, width, height, 0xFFFFFFFF);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700325
326 FPDF_RenderPageBitmap(bitmap, page, 0, 0, width, height, 0, 0);
Jun Fangaeacba42014-08-22 17:04:29 -0700327 rendered_pages ++;
328
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700329 FPDF_FFLDraw(form, bitmap, page, 0, 0, width, height, 0, 0);
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700330 int stride = FPDFBitmap_GetStride(bitmap);
331 const char* buffer =
332 reinterpret_cast<const char*>(FPDFBitmap_GetBuffer(bitmap));
333
334 switch (format) {
335#ifdef _WIN32
336 case OUTPUT_BMP:
337 WriteBmp(name, i, buffer, stride, width, height);
338 break;
339
340 case OUTPUT_EMF:
341 WriteEmf(page, name, i);
342 break;
343#endif
344 case OUTPUT_PPM:
345 WritePpm(name, i, buffer, stride, width, height);
346 break;
347 default:
348 break;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700349 }
350
351 FPDFBitmap_Destroy(bitmap);
352
353 FORM_DoPageAAction(page, form, FPDFPAGE_AACTION_CLOSE);
354 FORM_OnBeforeClosePage(page, form);
355 FPDFText_ClosePage(text_page);
356 FPDF_ClosePage(page);
357 }
358
359 FORM_DoDocumentAAction(form, FPDFDOC_AACTION_WC);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700360 FPDF_CloseDocument(doc);
Bo Xu2b7a49d2014-11-14 17:40:50 -0800361 FPDFDOC_ExitFormFillEnvironment(form);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700362 FPDFAvail_Destroy(pdf_avail);
363
Bruce Dawsonddc20622014-11-18 13:42:28 -0800364 printf("Loaded, parsed and rendered %" PRIuS " pages.\n", rendered_pages);
365 printf("Skipped %" PRIuS " bad pages.\n", bad_pages);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700366}
367
368int main(int argc, const char* argv[]) {
369 v8::V8::InitializeICU();
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700370 OutputFormat format = OUTPUT_NONE;
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700371 std::list<const char*> files;
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700372 if (!ParseCommandLine(argc, argv, &format, &files)) {
Vitaly Buka8f2c3dc2014-08-20 10:32:36 -0700373 printf("Usage: pdfium_test [OPTION] [FILE]...\n");
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700374 printf("--ppm write page images <pdf-name>.<page-number>.ppm\n");
375#ifdef _WIN32
376 printf("--bmp write page images <pdf-name>.<page-number>.bmp\n");
377 printf("--emf write page meta files <pdf-name>.<page-number>.emf\n");
378#endif
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700379 return 1;
380 }
381
382 FPDF_InitLibrary(NULL);
383
384 UNSUPPORT_INFO unsuppored_info;
385 memset(&unsuppored_info, '\0', sizeof(unsuppored_info));
386 unsuppored_info.version = 1;
387 unsuppored_info.FSDK_UnSupport_Handler = Unsupported_Handler;
388
389 FSDK_SetUnSpObjProcessHandler(&unsuppored_info);
390
391 while (!files.empty()) {
392 const char* filename = files.front();
393 files.pop_front();
John Abd-El-Maleka548d302014-06-26 10:18:11 -0700394 FILE* file = fopen(filename, "rb");
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700395 if (!file) {
396 fprintf(stderr, "Failed to open: %s\n", filename);
397 continue;
398 }
399 (void) fseek(file, 0, SEEK_END);
400 size_t len = ftell(file);
401 (void) fseek(file, 0, SEEK_SET);
402 char* pBuf = (char*) malloc(len);
403 size_t ret = fread(pBuf, 1, len, file);
404 (void) fclose(file);
405 if (ret != len) {
406 fprintf(stderr, "Failed to read: %s\n", filename);
407 } else {
Vitaly Buka9e0177a2014-07-22 18:15:42 -0700408 RenderPdf(filename, pBuf, len, format);
John Abd-El-Malek3f3b45c2014-05-23 17:28:10 -0700409 }
410 free(pBuf);
411 }
412
413 FPDF_DestroyLibrary();
414
415 return 0;
416}