22#if defined(PDF_ENABLE_SKIA) && !defined(PDF_USE_SKIA)
26#include "core/fxcrt/check_op.h"
27#include "core/fxcrt/compiler_specific.h"
28#include "core/fxcrt/span.h"
29#include "public/cpp/fpdf_scopers.h"
30#include "public/fpdf_annot.h"
31#include "public/fpdf_attachment.h"
32#include "public/fpdf_dataavail.h"
33#include "public/fpdf_edit.h"
34#include "public/fpdf_ext.h"
35#include "public/fpdf_formfill.h"
36#include "public/fpdf_progressive.h"
37#include "public/fpdf_structtree.h"
38#include "public/fpdf_text.h"
39#include "public/fpdfview.h"
40#include "testing/command_line_helpers.h"
41#include "testing/font_renamer.h"
42#include "testing/fx_string_testhelpers.h"
43#include "testing/helpers/dump.h"
44#include "testing/helpers/event.h"
45#include "testing/helpers/page_renderer.h"
46#include "testing/helpers/write.h"
47#include "testing/test_loader.h"
48#include "testing/utils/file_util.h"
49#include "testing/utils/hash.h"
50#include "testing/utils/path_service.h"
54#include <errhandlingapi.h>
58#include "testing/helpers/win32/com_factory.h"
63#ifdef ENABLE_CALLGRIND
64#include <valgrind/callgrind.h>
67#if defined(PDF_USE_PARTITION_ALLOC)
68#include "testing/allocator_shim_config.h"
72#include "third_party/skia/include/core/SkCanvas.h"
73#include "third_party/skia/include/core/SkColor.h"
74#include "third_party/skia/include/core/SkDocument.h"
75#include "third_party/skia/include/core/SkPicture.h"
76#include "third_party/skia/include/core/SkPictureRecorder.h"
77#include "third_party/skia/include/core/SkPixmap.h"
78#include "third_party/skia/include/core/SkRefCnt.h"
79#include "third_party/skia/include/core/SkStream.h"
80#include "third_party/skia/include/core/SkSurface.h"
83#include "third_party/skia/include/docs/SkXPSDocument.h"
86#ifdef BUILD_WITH_CHROMIUM
87#include "testing/chromium_support/discardable_memory_allocator.h"
92#include "testing/v8_initializer.h"
93#include "v8/include/libplatform/libplatform.h"
94#include "v8/include/v8-array-buffer.h"
95#include "v8/include/v8-isolate.h"
96#include "v8/include/v8-platform.h"
97#include "v8/include/v8-snapshot.h"
101#define access _access
102#define snprintf _snprintf
108#if defined(__APPLE__) || (defined(__linux__
) && !defined(__ANDROID__))
109#define WORDEXP_AVAILABLE
112#ifdef WORDEXP_AVAILABLE
118enum class RendererType {
124#if defined(PDF_ENABLE_SKIA)
129enum class OutputFormat {
144#ifdef PDF_ENABLE_SKIA
155 bool show_config =
false;
156 bool show_metadata =
false;
157 bool send_events =
false;
158 bool use_load_mem_document =
false;
159 bool render_oneshot =
false;
160 bool lcd_text =
false;
161 bool no_nativetext =
false;
162 bool grayscale =
false;
163 bool forced_color =
false;
164 bool fill_to_stroke =
false;
165 bool limit_cache =
false;
166 bool force_halftone =
false;
167 bool printing =
false;
168 bool no_smoothtext =
false;
169 bool no_smoothimage =
false;
170 bool no_smoothpath =
false;
171 bool reverse_byte_order =
false;
172 bool save_attachments =
false;
173 bool save_images =
false;
174 bool save_rendered_images =
false;
175 bool save_thumbnails =
false;
176 bool save_thumbnails_decoded =
false;
177 bool save_thumbnails_raw =
false;
178 RendererType use_renderer_type = RendererType::kDefault;
180 bool disable_javascript =
false;
181 std::string js_flags;
183 bool disable_xfa =
false;
188#ifdef ENABLE_CALLGRIND
189 bool callgrind_delimiters =
false;
191#if defined(__APPLE__) || (defined(__linux__
) && !defined(__ANDROID__))
192 bool linux_no_system_fonts =
false;
194 bool croscore_font_names =
false;
195 OutputFormat output_format = OutputFormat::kNone;
196 std::string password;
197 std::string scale_factor_as_string;
198 std::string exe_path;
199 std::string bin_directory;
200 std::string font_directory;
206int PageRenderFlagsFromOptions(
const Options& options) {
208 if (options.lcd_text)
210 if (options.no_nativetext)
212 if (options.grayscale)
214 if (options.fill_to_stroke)
216 if (options.limit_cache)
218 if (options.force_halftone)
220 if (options.printing)
222 if (options.no_smoothtext)
224 if (options.no_smoothimage)
226 if (options.no_smoothpath)
228 if (options.reverse_byte_order)
233std::optional<
std::string> ExpandDirectoryPath(
const std::string& path) {
234#if defined(WORDEXP_AVAILABLE
)
236 if (wordexp(path.c_str(), &expansion, 0) != 0 || expansion.we_wordc < 1) {
237 wordfree(&expansion);
242 std::optional<
std::string> ret_val = {expansion.we_wordv[0]};
243 wordfree(&expansion);
250std::optional<
const char*> GetCustomFontPath(
const Options& options) {
251#if defined(__APPLE__) || (defined(__linux__
) && !defined(__ANDROID__))
254 if (options.linux_no_system_fonts)
259 if (options.font_directory.empty())
263 return options.font_directory.c_str();
266struct FPDF_FORMFILLINFO_PDFiumTest
final :
public FPDF_FORMFILLINFO {
269 std::map<
int, ScopedFPDFPage> loaded_pages;
273 FPDF_FORMHANDLE form_handle;
276FPDF_FORMFILLINFO_PDFiumTest* ToPDFiumTestFormFillInfo(
277 FPDF_FORMFILLINFO* form_fill_info) {
278 return static_cast<FPDF_FORMFILLINFO_PDFiumTest*>(form_fill_info);
281void OutputMD5Hash(
const char* file_name, pdfium::span<
const uint8_t> output) {
283 std::string hash = GenerateMD5Base16(output);
284 printf(
"MD5:%s:%s\n", file_name, hash.c_str());
289struct V8IsolateDeleter {
290 inline void operator()(v8::Isolate* ptr) { ptr->Dispose(); }
296int ExampleAppAlert(IPDF_JSPLATFORM*,
298 FPDF_WIDESTRING title,
301 printf(
"%ls", GetPlatformWString(title).c_str());
303 printf(
"[icon=%d,type=%d]", icon, type);
304 printf(
": %ls\n", GetPlatformWString(msg).c_str());
308void ExampleAppBeep(IPDF_JSPLATFORM*,
int type) {
309 printf(
"BEEP!!! %d\n", type);
312int ExampleAppResponse(IPDF_JSPLATFORM*,
313 FPDF_WIDESTRING question,
314 FPDF_WIDESTRING title,
315 FPDF_WIDESTRING default_value,
316 FPDF_WIDESTRING label,
317 FPDF_BOOL is_password,
320 printf(
"%ls: %ls, defaultValue=%ls, label=%ls, isPassword=%d, length=%d\n",
321 GetPlatformWString(title).c_str(),
322 GetPlatformWString(question).c_str(),
323 GetPlatformWString(default_value).c_str(),
324 GetPlatformWString(label).c_str(), is_password, length);
327 auto* ptr =
static_cast<uint8_t*>(response);
335int ExampleDocGetFilePath(IPDF_JSPLATFORM*,
void* file_path,
int length) {
336 static const char kPath[] =
"myfile.pdf";
337 constexpr int kRequired =
static_cast<
int>(
sizeof(kPath));
338 if (file_path && length >= kRequired)
339 memcpy(file_path, kPath, kRequired);
343void ExampleDocMail(IPDF_JSPLATFORM*,
348 FPDF_WIDESTRING Subject,
351 FPDF_WIDESTRING Msg) {
352 printf(
"Mail Msg: %d, to=%ls, cc=%ls, bcc=%ls, subject=%ls, body=%ls\n", UI,
353 GetPlatformWString(To).c_str(), GetPlatformWString(CC).c_str(),
354 GetPlatformWString(BCC).c_str(), GetPlatformWString(Subject).c_str(),
355 GetPlatformWString(Msg).c_str());
358void ExampleDocPrint(IPDF_JSPLATFORM*,
363 FPDF_BOOL bShrinkToFit,
364 FPDF_BOOL bPrintAsImage,
366 FPDF_BOOL bAnnotations) {
367 printf(
"Doc Print: %d, %d, %d, %d, %d, %d, %d, %d\n", bUI, nStart, nEnd,
368 bSilent, bShrinkToFit, bPrintAsImage, bReverse, bAnnotations);
371void ExampleDocSubmitForm(IPDF_JSPLATFORM*,
374 FPDF_WIDESTRING url) {
375 printf(
"Doc Submit Form: url=%ls + %d data bytes:\n",
376 GetPlatformWString(url).c_str(), length);
377 uint8_t* ptr =
reinterpret_cast<uint8_t*>(formData);
378 for (
int i = 0; i < length; ++i)
379 printf(
" %02x", ptr[i]);
383void ExampleDocGotoPage(IPDF_JSPLATFORM*,
int page_number) {
384 printf(
"Goto Page: %d\n", page_number);
387int ExampleFieldBrowse(IPDF_JSPLATFORM*,
void* file_path,
int length) {
388 static const char kPath[] =
"selected.txt";
389 constexpr int kRequired =
static_cast<
int>(
sizeof(kPath));
390 if (file_path && length >= kRequired)
391 memcpy(file_path, kPath, kRequired);
397FPDF_BOOL ExamplePopupMenu(FPDF_FORMFILLINFO* pInfo,
399 FPDF_WIDGET always_null,
403 printf(
"Popup: x=%2.1f, y=%2.1f, flags=0x%x\n", x, y, flags);
408void ExampleNamedAction(FPDF_FORMFILLINFO* pInfo, FPDF_BYTESTRING name) {
409 printf(
"Execute named action: %s\n", name);
412void ExampleUnsupportedHandler(UNSUPPORT_INFO*,
int type) {
413 std::string feature =
"Unknown";
419 feature =
"Portfolios_Packages";
423 feature =
"Attachment";
426 feature =
"Rights_Management";
429 feature =
"Shared_Review";
434 feature =
"Shared_Form";
450 feature =
"Digital_Signature";
453 printf(
"Unsupported feature: %s.\n", feature.c_str());
456bool ParseCommandLine(
const std::vector<std::string>& args,
458 std::vector<std::string>* files) {
462 options->exe_path = args[0];
465 for (; cur_idx < args.size(); ++cur_idx) {
466 const std::string& cur_arg = args[cur_idx];
467 if (cur_arg ==
"--show-config") {
468 options->show_config =
true;
469 }
else if (cur_arg ==
"--show-metadata") {
470 options->show_metadata =
true;
471 }
else if (cur_arg ==
"--send-events") {
472 options->send_events =
true;
473 }
else if (cur_arg ==
"--mem-document") {
474 options->use_load_mem_document =
true;
475 }
else if (cur_arg ==
"--render-oneshot") {
476 options->render_oneshot =
true;
477 }
else if (cur_arg ==
"--lcd-text") {
478 options->lcd_text =
true;
479 }
else if (cur_arg ==
"--no-nativetext") {
480 options->no_nativetext =
true;
481 }
else if (cur_arg ==
"--grayscale") {
482 options->grayscale =
true;
483 }
else if (cur_arg ==
"--forced-color") {
484 options->forced_color =
true;
485 }
else if (cur_arg ==
"--fill-to-stroke") {
486 options->fill_to_stroke =
true;
487 }
else if (cur_arg ==
"--limit-cache") {
488 options->limit_cache =
true;
489 }
else if (cur_arg ==
"--force-halftone") {
490 options->force_halftone =
true;
491 }
else if (cur_arg ==
"--printing") {
492 options->printing =
true;
493 }
else if (cur_arg ==
"--no-smoothtext") {
494 options->no_smoothtext =
true;
495 }
else if (cur_arg ==
"--no-smoothimage") {
496 options->no_smoothimage =
true;
497 }
else if (cur_arg ==
"--no-smoothpath") {
498 options->no_smoothpath =
true;
499 }
else if (cur_arg ==
"--reverse-byte-order") {
500 options->reverse_byte_order =
true;
501 }
else if (cur_arg ==
"--save-attachments") {
502 options->save_attachments =
true;
503 }
else if (cur_arg ==
"--save-images") {
504 if (options->save_rendered_images) {
506 "--save-rendered-images conflicts with --save-images\n");
509 options->save_images =
true;
510 }
else if (cur_arg ==
"--save-rendered-images") {
511 if (options->save_images) {
513 "--save-images conflicts with --save-rendered-images\n");
516 options->save_rendered_images =
true;
517 }
else if (cur_arg ==
"--save-thumbs") {
518 options->save_thumbnails =
true;
519 }
else if (cur_arg ==
"--save-thumbs-dec") {
520 options->save_thumbnails_decoded =
true;
521 }
else if (cur_arg ==
"--save-thumbs-raw") {
522 options->save_thumbnails_raw =
true;
523 }
else if (ParseSwitchKeyValue(cur_arg,
"--use-renderer=", &value)) {
524 if (options->use_renderer_type != RendererType::kDefault) {
525 fprintf(stderr,
"Duplicate --use-renderer argument\n");
528 if (value ==
"agg") {
529 options->use_renderer_type = RendererType::kAgg;
531 }
else if (value ==
"gdi") {
532 options->use_renderer_type = RendererType::kGdi;
534#if defined(PDF_ENABLE_SKIA)
535 }
else if (value ==
"skia") {
536 options->use_renderer_type = RendererType::kSkia;
539 fprintf(stderr,
"Invalid --use-renderer argument\n");
543 }
else if (cur_arg ==
"--disable-javascript") {
544 options->disable_javascript =
true;
545 }
else if (ParseSwitchKeyValue(cur_arg,
"--js-flags=", &value)) {
546 if (!options->js_flags.empty()) {
547 fprintf(stderr,
"Duplicate --js-flags argument\n");
550 options->js_flags = value;
552 }
else if (cur_arg ==
"--disable-xfa") {
553 options->disable_xfa =
true;
556#ifdef ENABLE_CALLGRIND
557 }
else if (cur_arg ==
"--callgrind-delim") {
558 options->callgrind_delimiters =
true;
560#if defined(__APPLE__) || (defined(__linux__
) && !defined(__ANDROID__))
561 }
else if (cur_arg ==
"--no-system-fonts") {
562 options->linux_no_system_fonts =
true;
564 }
else if (cur_arg ==
"--croscore-font-names") {
565 options->croscore_font_names =
true;
566 }
else if (cur_arg ==
"--ppm") {
567 if (options->output_format != OutputFormat::kNone) {
568 fprintf(stderr,
"Duplicate or conflicting --ppm argument\n");
571 options->output_format = OutputFormat::kPpm;
572 }
else if (cur_arg ==
"--png") {
573 if (options->output_format != OutputFormat::kNone) {
574 fprintf(stderr,
"Duplicate or conflicting --png argument\n");
577 options->output_format = OutputFormat::kPng;
578 }
else if (cur_arg ==
"--txt") {
579 if (options->output_format != OutputFormat::kNone) {
580 fprintf(stderr,
"Duplicate or conflicting --txt argument\n");
583 options->output_format = OutputFormat::kText;
584 }
else if (cur_arg ==
"--annot") {
585 if (options->output_format != OutputFormat::kNone) {
586 fprintf(stderr,
"Duplicate or conflicting --annot argument\n");
589 options->output_format = OutputFormat::kAnnot;
590#ifdef PDF_ENABLE_SKIA
591 }
else if (cur_arg ==
"--skp") {
592 if (options->output_format != OutputFormat::kNone) {
593 fprintf(stderr,
"Duplicate or conflicting --skp argument\n");
596 options->output_format = OutputFormat::kSkp;
598 }
else if (cur_arg ==
"--xps") {
599 if (options->output_format != OutputFormat::kNone) {
600 fprintf(stderr,
"Duplicate or conflicting --xps argument\n");
603 options->output_format = OutputFormat::kXps;
606 }
else if (ParseSwitchKeyValue(cur_arg,
"--font-dir=", &value)) {
607 if (!options->font_directory.empty()) {
608 fprintf(stderr,
"Duplicate --font-dir argument\n");
611 std::string path = value;
612 std::optional<
std::string> expanded_path = ExpandDirectoryPath(path);
613 if (!expanded_path.has_value()) {
614 fprintf(stderr,
"Failed to expand --font-dir, %s\n", path.c_str());
619 fprintf(stderr,
"--font-dir, %s, appears to not be a directory\n",
624 options->font_directory = expanded_path.value();
627 }
else if (cur_arg ==
"--emf") {
628 if (options->output_format != OutputFormat::kNone) {
629 fprintf(stderr,
"Duplicate or conflicting --emf argument\n");
632 options->output_format = OutputFormat::kEmf;
633 }
else if (cur_arg ==
"--ps2") {
634 if (options->output_format != OutputFormat::kNone) {
635 fprintf(stderr,
"Duplicate or conflicting --ps2 argument\n");
638 options->output_format = OutputFormat::kPs2;
639 }
else if (cur_arg ==
"--ps3") {
640 if (options->output_format != OutputFormat::kNone) {
641 fprintf(stderr,
"Duplicate or conflicting --ps3 argument\n");
644 options->output_format = OutputFormat::kPs3;
645 }
else if (cur_arg ==
"--ps3-type42") {
646 if (options->output_format != OutputFormat::kNone) {
647 fprintf(stderr,
"Duplicate or conflicting --ps3-type42 argument\n");
650 options->output_format = OutputFormat::kPs3Type42;
651 }
else if (cur_arg ==
"--bmp") {
652 if (options->output_format != OutputFormat::kNone) {
653 fprintf(stderr,
"Duplicate or conflicting --bmp argument\n");
656 options->output_format = OutputFormat::kBmp;
660#ifdef V8_USE_EXTERNAL_STARTUP_DATA
661 }
else if (ParseSwitchKeyValue(cur_arg,
"--bin-dir=", &value)) {
662 if (!options->bin_directory.empty()) {
663 fprintf(stderr,
"Duplicate --bin-dir argument\n");
666 std::string path = value;
667 std::optional<std::string> expanded_path = ExpandDirectoryPath(path);
668 if (!expanded_path.has_value()) {
669 fprintf(stderr,
"Failed to expand --bin-dir, %s\n", path.c_str());
672 options->bin_directory = expanded_path.value();
676 }
else if (ParseSwitchKeyValue(cur_arg,
"--password=", &value)) {
677 if (!options->password.empty()) {
678 fprintf(stderr,
"Duplicate --password argument\n");
681 options->password = value;
682 }
else if (ParseSwitchKeyValue(cur_arg,
"--scale=", &value)) {
683 if (!options->scale_factor_as_string.empty()) {
684 fprintf(stderr,
"Duplicate --scale argument\n");
687 options->scale_factor_as_string = value;
688 }
else if (cur_arg ==
"--show-pageinfo") {
689 if (options->output_format != OutputFormat::kNone) {
690 fprintf(stderr,
"Duplicate or conflicting --show-pageinfo argument\n");
693 options->output_format = OutputFormat::kPageInfo;
694 }
else if (cur_arg ==
"--show-structure") {
695 if (options->output_format != OutputFormat::kNone) {
696 fprintf(stderr,
"Duplicate or conflicting --show-structure argument\n");
699 options->output_format = OutputFormat::kStructure;
700 }
else if (ParseSwitchKeyValue(cur_arg,
"--pages=", &value)) {
701 if (options->pages) {
702 fprintf(stderr,
"Duplicate --pages argument\n");
705 options->pages =
true;
706 const std::string pages_string = value;
707 size_t first_dash = pages_string.find(
'-');
708 if (first_dash == std::string::npos) {
709 std::stringstream(pages_string) >> options->first_page;
710 options->last_page = options->first_page;
712 std::stringstream(pages_string.substr(0, first_dash)) >>
714 std::stringstream(pages_string.substr(first_dash + 1)) >>
717 }
else if (cur_arg ==
"--md5") {
719 }
else if (ParseSwitchKeyValue(cur_arg,
"--time=", &value)) {
720 if (options->time > -1) {
721 fprintf(stderr,
"Duplicate --time argument\n");
724 const std::string time_string = value;
725 std::stringstream(time_string) >> options->time;
726 if (options->time < 0) {
727 fprintf(stderr,
"Invalid --time argument, must be non-negative\n");
730 }
else if (cur_arg.size() >= 2 && cur_arg[0] ==
'-' && cur_arg[1] ==
'-') {
731 fprintf(stderr,
"Unrecognized argument %s\n", cur_arg.c_str());
737 for (size_t i = cur_idx; i < args.size(); i++)
738 files->push_back(args[i]);
743void PrintLastError() {
745 fprintf(stderr,
"Load pdf docs unsuccessful: ");
748 fprintf(stderr,
"Success");
751 fprintf(stderr,
"Unknown error");
754 fprintf(stderr,
"File not found or could not be opened");
757 fprintf(stderr,
"File not in PDF format or corrupted");
760 fprintf(stderr,
"Password required or incorrect password");
763 fprintf(stderr,
"Unsupported security scheme");
766 fprintf(stderr,
"Page not found or content error");
769 fprintf(stderr,
"Unknown error %ld", err);
771 fprintf(stderr,
".\n");
774FPDF_BOOL Is_Data_Avail(FX_FILEAVAIL* avail, size_t offset, size_t size) {
778void Add_Segment(FX_DOWNLOADHINTS* hints, size_t offset, size_t size) {}
780FPDF_PAGE GetPageForIndex(FPDF_FORMFILLINFO* param,
783 FPDF_FORMFILLINFO_PDFiumTest* form_fill_info =
784 ToPDFiumTestFormFillInfo(param);
785 auto& loaded_pages = form_fill_info->loaded_pages;
786 auto iter = loaded_pages.find(index);
787 if (iter != loaded_pages.end())
788 return iter->second.get();
795 FPDF_PAGE page_ptr = page.get();
796 loaded_pages[index] =
std::move(page);
798 FPDF_FORMHANDLE& form_handle = form_fill_info->form_handle;
807FPDF_BOOL NeedToPauseNow(IFSDK_PAUSE* p) {
811class Processor
final {
813 Processor(
const Options* options,
const std::function<
void()>* idler)
814 : options_(options), idler_(idler) {
819 const Options& options()
const {
return *options_; }
820 const std::function<
void()>& idler()
const {
return *idler_; }
823 ComFactory& com_factory() {
return com_factory_; }
827 void Idle()
const { idler()(); }
829 void ProcessPdf(
const std::string& name,
830 pdfium::span<
const uint8_t> data,
831 const std::string& events);
834 const Options* options_;
835 const std::function<
void()>* idler_;
838 ComFactory com_factory_;
842class PdfProcessor
final {
844 PdfProcessor(Processor* processor,
845 const std::string* name,
846 const std::string* events,
848 FPDF_FORMHANDLE form,
849 FPDF_FORMFILLINFO_PDFiumTest* form_fill_info)
850 : processor_(processor),
855 form_fill_info_(form_fill_info) {
864 bool ProcessPage(
int page_index);
868 const Options& options()
const {
return processor_->options(); }
869 const std::function<
void()>& idler()
const {
return processor_->idler(); }
872 ComFactory& com_factory() {
return processor_->com_factory(); }
876 const std::string& name()
const {
return *name_; }
877 const std::string& events()
const {
return *events_; }
878 FPDF_DOCUMENT doc()
const {
return doc_; }
879 FPDF_FORMHANDLE form()
const {
return form_; }
882 void Idle()
const { idler()(); }
884 FPDF_PAGE GetPage(
int page_index)
const {
885 return GetPageForIndex(form_fill_info_, doc_, page_index);
888 Processor* processor_;
889 const std::string* name_;
890 const std::string* events_;
892 FPDF_FORMHANDLE form_;
893 FPDF_FORMFILLINFO_PDFiumTest* form_fill_info_;
903 using PageWriter =
std::function<
bool(BitmapPageRenderer& renderer,
904 const std::string& name,
909 static PageWriter WrapPageWriter(
910 void (*text_page_writer)(FPDF_TEXTPAGE text_page,
911 const char* pdf_name,
913 return [text_page_writer](BitmapPageRenderer& renderer,
914 const std::string& name,
int page_index,
916 ScopedFPDFTextPage text_page(FPDFText_LoadPage(renderer
.page()));
921 text_page_writer(text_page.get(), name.c_str(), page_index);
927 static PageWriter WrapPageWriter(
void (*page_writer)(FPDF_PAGE page,
928 const char* pdf_name,
930 return [page_writer](BitmapPageRenderer& renderer,
const std::string& name,
931 int page_index,
bool ) {
932 page_writer(renderer
.page(), name.c_str(), page_index);
939 static PageWriter WrapPageWriter(
940 std::string (*bitmap_writer)(
const char* pdf_name,
946 return [bitmap_writer](BitmapPageRenderer& renderer,
947 const std::string& name,
int page_index,
bool md5) {
950 std::string image_file_name = bitmap_writer(
951 name.c_str(), page_index, buffer, stride,
953 if (image_file_name.empty()) {
959 OutputMD5Hash(image_file_name.c_str(),
961 static_cast<
const uint8_t*>(buffer),
962 static_cast<size_t>(stride) * renderer
.height())));
968 bool HasOutput()
const override {
return !!bitmap_; }
970 void Finish(FPDF_FORMHANDLE form)
override {
971 FPDF_FFLDraw(form, bitmap(),
page(), 0, 0,
977 bool Write(
const std::string& name,
int page_index,
bool md5)
override {
978 return writer_ && writer_(*
this, name, page_index, md5);
982 BitmapPageRenderer(FPDF_PAGE page,
986 const std::function<
void()>& idler,
990 writer_(std::move(writer)) {}
992 bool InitializeBitmap(
void* first_scan) {
993 bool alpha = FPDFPage_HasTransparency(
page());
994 bitmap_.reset(FPDFBitmap_CreateEx(
997 width() *
sizeof(uint32_t)));
1002 FPDF_DWORD fill_color = alpha ? 0x00000000 : 0xFFFFFFFF;
1003 return FPDFBitmap_FillRect(bitmap(), 0, 0,
1008 void ResetBitmap() { bitmap_.reset(); }
1010 void Idle()
const { idler_(); }
1011 FPDF_BITMAP bitmap() {
return bitmap_.get(); }
1014 const std::function<
void()>& idler_;
1016 ScopedFPDFBitmap bitmap_;
1020class OneShotBitmapPageRenderer :
public BitmapPageRenderer {
1022 OneShotBitmapPageRenderer(FPDF_PAGE page,
1026 const std::function<
void()>& idler,
1028 : BitmapPageRenderer(page,
1033 std::move(writer)) {}
1035 bool Start()
override {
1036 if (!InitializeBitmap(
nullptr)) {
1043 FPDF_RenderPageBitmap(bitmap(),
page(), 0, 0,
1051class ProgressiveBitmapPageRenderer :
public BitmapPageRenderer {
1053 ProgressiveBitmapPageRenderer(FPDF_PAGE page,
1057 const std::function<
void()>& idler,
1059 const FPDF_COLORSCHEME* color_scheme)
1060 : BitmapPageRenderer(page,
1066 color_scheme_(color_scheme) {
1068 pause_.NeedToPauseNow = &NeedToPauseNow;
1071 bool Start()
override {
1072 if (!InitializeBitmap(
nullptr)) {
1076 if (FPDF_RenderPageBitmapWithColorScheme_Start(
1080 to_be_continued_ =
true;
1085 bool Continue()
override {
1086 if (to_be_continued_) {
1087 to_be_continued_ = (FPDF_RenderPage_Continue(
page(), &pause_) ==
1090 return to_be_continued_;
1093 void Finish(FPDF_FORMHANDLE form)
override {
1094 BitmapPageRenderer::Finish(form);
1095 FPDF_RenderPage_Close(
page());
1100 const FPDF_COLORSCHEME* color_scheme_;
1102 bool to_be_continued_ =
false;
1106class ScopedGdiDc final {
1108 ~ScopedGdiDc() { Reset(
nullptr); }
1110 void Reset(HDC dc) {
1112 [[maybe_unused]] BOOL success = DeleteDC(dc_);
1118 HDC Get()
const {
return dc_; }
1124class ScopedGdiObject final {
1126 ~ScopedGdiObject() { Reset(
nullptr); }
1128 void Reset(HGDIOBJ object) {
1130 [[maybe_unused]] BOOL success = DeleteObject(object_);
1136 HGDIOBJ Get()
const {
return object_; }
1139 HGDIOBJ object_ =
nullptr;
1142class GdiDisplayPageRenderer :
public BitmapPageRenderer {
1144 GdiDisplayPageRenderer(FPDF_PAGE page,
1148 const std::function<
void()>& idler,
1150 : BitmapPageRenderer(page,
1155 std::move(writer)) {}
1157 ~GdiDisplayPageRenderer() override {
1162 bool Start() override {
1164 dc_.Reset(CreateCompatibleDC(
nullptr));
1170 BITMAPINFO dib_info;
1171 memset(&dib_info, 0,
sizeof(BITMAPINFO));
1172 dib_info.bmiHeader.biSize =
sizeof(BITMAPINFOHEADER);
1173 dib_info.bmiHeader.biWidth = width();
1174 dib_info.bmiHeader.biHeight = -height();
1175 dib_info.bmiHeader.biPlanes = 1;
1176 dib_info.bmiHeader.biBitCount = 32;
1177 dib_info.bmiHeader.biCompression = BI_RGB;
1180 dib_.Reset(CreateDIBSection(dc_.Get(), &dib_info, DIB_RGB_COLORS,
1181 &dib_pixels,
nullptr,
1183 if (!dib_.Get() || !InitializeBitmap(dib_pixels)) {
1187 HGDIOBJ old_obj = SelectObject(dc_.Get(), dib_.Get());
1189 CHECK_NE(old_obj, HGDI_ERROR);
1192 FPDF_RenderPage(dc_.Get(), page(), 0, 0,
1193 width(), height(), 0,
1196 bool result = !!GdiFlush();
1197 HGDIOBJ dib_obj = SelectObject(dc_.Get(), old_obj);
1198 CHECK((GetObjectType(old_obj) != OBJ_REGION && dib_obj) ||
1199 (GetObjectType(old_obj) == OBJ_REGION && dib_obj != HGDI_ERROR));
1203 void Finish(FPDF_FORMHANDLE ) override {
1208 const int stride = FPDFBitmap_GetStride(bitmap());
1209 DCHECK_EQ(width() *
sizeof(uint32_t),
static_cast<size_t>(stride));
1210 const int pixel_stride = stride /
sizeof(uint32_t);
1212 uint32_t* scanline =
1213 reinterpret_cast<uint32_t*>(FPDFBitmap_GetBuffer(bitmap()));
1214 for (
int row = 0; row < height(); ++row) {
1215 for (
int column = 0; column < width(); ++column) {
1216 scanline[column] |= 0xFF000000;
1218 scanline += pixel_stride;
1224 ScopedGdiObject dib_;
1228#ifdef PDF_ENABLE_SKIA
1229class SkCanvasPageRenderer :
public PageRenderer {
1231 bool Start() override {
1232 FPDF_RenderPageSkia(
reinterpret_cast<FPDF_SKIA_CANVAS>(canvas()), page(),
1237 void Finish(FPDF_FORMHANDLE form) override {
1238 FPDF_FFLDrawSkia(form,
reinterpret_cast<FPDF_SKIA_CANVAS>(canvas()), page(),
1239 0, 0, width(), height(),
1244 SkCanvasPageRenderer(FPDF_PAGE page,
int width,
int height,
int flags)
1245 : PageRenderer(page, width, height, flags) {}
1247 virtual SkCanvas* canvas() = 0;
1250class SkPicturePageRenderer final :
public SkCanvasPageRenderer {
1252 SkPicturePageRenderer(FPDF_PAGE page,
int width,
int height,
int flags)
1253 : SkCanvasPageRenderer(page, width, height, flags) {}
1255 bool HasOutput()
const override {
return !!picture_; }
1257 bool Start() override {
1258 recorder_ = std::make_unique<SkPictureRecorder>();
1259 recorder_->beginRecording(width(), height());
1260 return SkCanvasPageRenderer::Start();
1263 void Finish(FPDF_FORMHANDLE form) override {
1264 SkCanvasPageRenderer::Finish(form);
1265 picture_ = recorder_->finishRecordingAsPicture();
1269 bool Write(
const std::string& name,
int page_index,
bool md5) override {
1270 std::string image_file_name = WriteSkp(name.c_str(), page_index, *picture_);
1271 if (image_file_name.empty())
1276 sk_sp<SkSurface> surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(
1277 width(), height()));
1282 surface->getCanvas()->clear(SK_ColorWHITE);
1283 surface->getCanvas()->drawPicture(picture_);
1287 if (!surface->peekPixels(&pixmap))
1290 OutputMD5Hash(image_file_name.c_str(),
1291 UNSAFE_TODO(pdfium::make_span(
1292 static_cast<
const uint8_t*>(pixmap.addr()),
1293 pixmap.computeByteSize())));
1299 SkCanvas* canvas() override {
return recorder_->getRecordingCanvas(); }
1302 std::unique_ptr<SkPictureRecorder> recorder_;
1303 sk_sp<SkPicture> picture_;
1306class SkDocumentPageRenderer final :
public SkCanvasPageRenderer {
1308 SkDocumentPageRenderer(std::unique_ptr<SkWStream> stream,
1309 sk_sp<SkDocument> document,
1314 : SkCanvasPageRenderer(page, width, height, flags),
1315 stream_(std::move(stream)),
1316 document_(std::move(document)) {
1321 bool HasOutput()
const override {
return has_output_; }
1323 bool Start() override {
1329 canvas_ = document_->beginPage(width(), height());
1334 return SkCanvasPageRenderer::Start();
1337 void Finish(FPDF_FORMHANDLE form) override {
1338 SkCanvasPageRenderer::Finish(form);
1342 document_->endPage();
1347 bool Write(
const std::string& ,
1350 bool success = HasOutput();
1363 SkCanvas* canvas() override {
return canvas_; }
1366 std::unique_ptr<SkWStream> stream_;
1367 sk_sp<SkDocument> document_;
1369 SkCanvas* canvas_ =
nullptr;
1370 bool has_output_ =
false;
1374bool PdfProcessor::ProcessPage(
const int page_index) {
1375 FPDF_PAGE page = GetPage(page_index);
1380 if (options().send_events) {
1383 if (options().save_images) {
1384 WriteImages(page, name().c_str(), page_index);
1386 if (options().save_rendered_images) {
1387 WriteRenderedImages(doc(), page, name().c_str(), page_index);
1389 if (options().save_thumbnails) {
1390 WriteThumbnail(page, name().c_str(), page_index);
1392 if (options().save_thumbnails_decoded) {
1393 WriteDecodedThumbnailStream(page, name().c_str(), page_index);
1395 if (options().save_thumbnails_raw) {
1396 WriteRawThumbnailStream(page, name().c_str(), page_index);
1398 if (options().output_format == OutputFormat::kPageInfo) {
1402 if (options().output_format == OutputFormat::kStructure) {
1409 if (!options().scale_factor_as_string.empty()) {
1410 std::stringstream(options().scale_factor_as_string) >> scale;
1415 int flags = PageRenderFlagsFromOptions(options());
1417 std::unique_ptr<PageRenderer> renderer;
1418 BitmapPageRenderer::PageWriter writer;
1419 switch (options().output_format) {
1420 case OutputFormat::kText:
1421 writer = BitmapPageRenderer::WrapPageWriter(
WriteText);
1424 case OutputFormat::kAnnot:
1425 writer = BitmapPageRenderer::WrapPageWriter(
WriteAnnot);
1428 case OutputFormat::kPpm:
1429 writer = BitmapPageRenderer::WrapPageWriter(
WritePpm);
1432 case OutputFormat::kPng:
1433 writer = BitmapPageRenderer::WrapPageWriter(
WritePng);
1437 case OutputFormat::kBmp:
1438 writer = BitmapPageRenderer::WrapPageWriter(WriteBmp);
1441 case OutputFormat::kEmf:
1443 writer = BitmapPageRenderer::WrapPageWriter(WriteEmf);
1446 case OutputFormat::kPs2:
1447 case OutputFormat::kPs3:
1449 writer = BitmapPageRenderer::WrapPageWriter(WritePS);
1453#ifdef PDF_ENABLE_SKIA
1454 case OutputFormat::kSkp:
1455 renderer = std::make_unique<SkPicturePageRenderer>(
1456 page, width, height, flags);
1460 case OutputFormat::kXps: {
1461 IXpsOMObjectFactory* xps_factory = com_factory().GetXpsOMObjectFactory();
1466 std::unique_ptr<SkWStream> stream =
1467 WriteToSkWStream(name(), page_index,
"xps");
1472 sk_sp<SkDocument> document =
1473 SkXPS::MakeDocument(stream.get(), xps_factory);
1478 renderer = std::make_unique<SkDocumentPageRenderer>(
1479 std::move(stream), std::move(document), page, width, height, flags);
1491 if (!renderer && options().use_renderer_type == RendererType::kGdi) {
1492 renderer = std::make_unique<GdiDisplayPageRenderer>(
1493 page, width, height, flags, idler(),
1500 if (options().render_oneshot) {
1501 renderer =
std::make_unique<OneShotBitmapPageRenderer>(
1502 page, width, height, flags, idler(),
1508 FPDF_COLORSCHEME color_scheme;
1509 color_scheme.path_fill_color = 0xFFFF0000;
1510 color_scheme.path_stroke_color = 0xFF00FF00;
1511 color_scheme.text_fill_color = 0xFF0000FF;
1512 color_scheme.text_stroke_color = 0xFF00FFFF;
1514 renderer =
std::make_unique<ProgressiveBitmapPageRenderer>(
1515 page, width, height, flags, idler(),
1516 std::move(writer), options().forced_color ? &color_scheme :
nullptr);
1520 if (renderer->Start()) {
1521 while (renderer->Continue())
1523 renderer->Finish(form());
1524 renderer->Write(name(), page_index, options().md5);
1526 fprintf(stderr,
"Page was too large to be rendered.\n");
1535 return renderer->HasOutput();
1538void Processor::ProcessPdf(
const std::string& name,
1539 pdfium::span<
const uint8_t> data,
1540 const std::string& events) {
1543 FPDF_FILEACCESS file_access = {};
1544 file_access.m_FileLen =
static_cast<
unsigned long>(data.size());
1546 file_access.m_Param = &loader;
1548 FX_FILEAVAIL file_avail = {};
1550 file_avail.IsDataAvail = Is_Data_Avail;
1552 FX_DOWNLOADHINTS hints = {};
1560 ScopedFPDFDocument doc;
1562 const char* password =
1563 options().password.empty() ?
nullptr : options().password.c_str();
1564 bool is_linearized =
false;
1565 if (options().use_load_mem_document) {
1566 doc.reset(FPDF_LoadMemDocument(data.data(), data.size(), password));
1570 doc.reset(FPDFAvail_GetDocument(pdf_avail.get(), password));
1573 avail_status = FPDFAvail_IsDocAvail(pdf_avail.get(), &hints);
1576 fprintf(stderr,
"Unknown error in checking if doc was available.\n");
1579 avail_status = FPDFAvail_IsFormAvail(pdf_avail.get(), &hints);
1583 "Error %d was returned in checking if form was available.\n",
1587 is_linearized =
true;
1599 if (!FPDF_DocumentHasValidCrossReferenceTable(doc.get()))
1600 fprintf(stderr,
"Document has invalid cross reference table\n");
1602 if (options().show_metadata) {
1603 DumpMetaData(doc.get());
1606 if (options().save_attachments) {
1607 WriteAttachments(doc.get(), name);
1611 IPDF_JSPLATFORM platform_callbacks = {};
1612 platform_callbacks.version = 3;
1613 platform_callbacks.app_alert = ExampleAppAlert;
1614 platform_callbacks.app_beep = ExampleAppBeep;
1615 platform_callbacks.app_response = ExampleAppResponse;
1616 platform_callbacks.Doc_getFilePath = ExampleDocGetFilePath;
1617 platform_callbacks.Doc_mail = ExampleDocMail;
1618 platform_callbacks.Doc_print = ExampleDocPrint;
1619 platform_callbacks.Doc_submitForm = ExampleDocSubmitForm;
1620 platform_callbacks.Doc_gotoPage = ExampleDocGotoPage;
1621 platform_callbacks.Field_browse = ExampleFieldBrowse;
1624 FPDF_FORMFILLINFO_PDFiumTest form_callbacks = {};
1625#ifdef PDF_ENABLE_XFA
1626 form_callbacks.version = 2;
1627 form_callbacks.xfa_disabled =
1628 options().disable_xfa || options().disable_javascript;
1629 form_callbacks.FFI_PopupMenu = ExamplePopupMenu;
1634 form_callbacks.FFI_GetPage = GetPageForIndex;
1637 if (!options().disable_javascript) {
1638 form_callbacks.m_pJsPlatform = &platform_callbacks;
1642 ScopedFPDFFormHandle form(
1643 FPDFDOC_InitFormFillEnvironment(doc.get(), &form_callbacks));
1644 form_callbacks.form_handle = form.get();
1646#ifdef PDF_ENABLE_XFA
1647 if (!options().disable_xfa && !options().disable_javascript) {
1648 int doc_type = FPDF_GetFormType(doc.get());
1649 if (doc_type == FORMTYPE_XFA_FULL || doc_type == FORMTYPE_XFA_FOREGROUND) {
1650 if (!FPDF_LoadXFA(doc.get()))
1651 fprintf(stderr,
"LoadXFA unsuccessful, continuing anyway.\n");
1657 FPDF_SetFormFieldHighlightAlpha(form.get(), 100);
1658 FORM_DoDocumentJSAction(form.get());
1659 FORM_DoDocumentOpenAction(form.get());
1662 if (options().output_format == OutputFormat::kPs2) {
1663 FPDF_SetPrintMode(FPDF_PRINTMODE_POSTSCRIPT2);
1664 }
else if (options().output_format == OutputFormat::kPs3) {
1665 FPDF_SetPrintMode(FPDF_PRINTMODE_POSTSCRIPT3);
1666 }
else if (options().output_format == OutputFormat::kPs3Type42) {
1667 FPDF_SetPrintMode(FPDF_PRINTMODE_POSTSCRIPT3_TYPE42);
1671 int page_count = FPDF_GetPageCount(doc.get());
1672 int processed_pages = 0;
1674 int first_page = options().pages ? options().first_page : 0;
1675 int last_page = options().pages ? options().last_page + 1 : page_count;
1676 PdfProcessor pdf_processor(
this, &name, &events, doc.get(), form.get(),
1678 for (
int i = first_page; i < last_page; ++i) {
1679 if (is_linearized) {
1682 avail_status = FPDFAvail_IsPageAvail(pdf_avail.get(), i, &hints);
1685 fprintf(stderr,
"Unknown error in checking if page %d is available.\n",
1690 if (pdf_processor.ProcessPage(i)) {
1701 fprintf(stderr,
"Processed %d pages.\n", processed_pages);
1703 fprintf(stderr,
"Skipped %d bad pages.\n", bad_pages);
1708 [[maybe_unused]]
auto append_config = [&config](
const char* name) {
1709 if (!config.empty())
1715 append_config(
"V8");
1717#ifdef V8_USE_EXTERNAL_STARTUP_DATA
1718 append_config(
"V8_EXTERNAL");
1720#ifdef PDF_ENABLE_XFA
1721 append_config(
"XFA");
1723#ifdef PDF_ENABLE_ASAN
1724 append_config(
"ASAN");
1726#ifdef PDF_ENABLE_SKIA
1727 append_config(
"SKIA");
1730 append_config(
"GDI");
1732 printf(
"%s\n", config.c_str());
1735constexpr char kUsageString[] =
1736 "Usage: pdfium_test [OPTION] [FILE]...\n"
1737 " --show-config - print build options and exit\n"
1738 " --show-metadata - print the file metadata\n"
1739 " --show-pageinfo - print information about pages\n"
1740 " --show-structure - print the structure elements from the "
1742 " --send-events - send input described by .evt file\n"
1743 " --mem-document - load document with FPDF_LoadMemDocument()\n"
1744 " --render-oneshot - render image without using progressive "
1746 " --lcd-text - render text optimized for LCD displays\n"
1747 " --no-nativetext - render without using the native text output\n"
1748 " --grayscale - render grayscale output\n"
1749 " --forced-color - render in forced color mode\n"
1750 " --fill-to-stroke - render fill as stroke in forced color mode\n"
1751 " --limit-cache - render limiting image cache size\n"
1752 " --force-halftone - render forcing halftone\n"
1753 " --printing - render as if for printing\n"
1754 " --no-smoothtext - render disabling text anti-aliasing\n"
1755 " --no-smoothimage - render disabling image anti-alisasing\n"
1756 " --no-smoothpath - render disabling path anti-aliasing\n"
1757 " --reverse-byte-order - render to BGRA, if supported by the output "
1759 " --save-attachments - write embedded attachments "
1760 "<pdf-name>.attachment.<attachment-name>\n"
1761 " --save-images - write raw embedded images "
1762 "<pdf-name>.<page-number>.<object-number>.png\n"
1763 " --save-rendered-images - write embedded images as rendered on the page "
1764 "<pdf-name>.<page-number>.<object-number>.png\n"
1765 " --save-thumbs - write page thumbnails "
1766 "<pdf-name>.thumbnail.<page-number>.png\n"
1767 " --save-thumbs-dec - write page thumbnails' decoded stream data"
1768 "<pdf-name>.thumbnail.decoded.<page-number>.png\n"
1769 " --save-thumbs-raw - write page thumbnails' raw stream data"
1770 "<pdf-name>.thumbnail.raw.<page-number>.png\n"
1772#if defined(PDF_ENABLE_SKIA)
1774 " --use-renderer - renderer to use, one of [agg | gdi | skia]\n"
1776 " --use-renderer - renderer to use, one of [agg | skia]\n"
1780 " --use-renderer - renderer to use, one of [agg | gdi]\n"
1782 " --use-renderer - renderer to use, one of [agg]\n"
1787 " --disable-javascript - do not execute JS in PDF files\n"
1788 " --js-flags=<flags> - additional flags to pass to V8\n"
1789#ifdef PDF_ENABLE_XFA
1790 " --disable-xfa - do not process XFA forms\n"
1793#ifdef ENABLE_CALLGRIND
1794 " --callgrind-delim - delimit interesting section when using "
1797#if defined(__APPLE__) || (defined(__linux__
) && !defined(__ANDROID__))
1798 " --no-system-fonts - do not use system fonts, overrides --font-dir\n"
1800 " --croscore-font-names - use Croscore font names\n"
1801 " --bin-dir=<path> - override path to v8 external data\n"
1802 " --font-dir=<path> - override path to external fonts\n"
1803 " --scale=<number> - scale output size by number (e.g. 0.5)\n"
1804 " --password=<secret> - password to decrypt the PDF with\n"
1805 " --pages=<number>(-<number>) - only render the given 0-based page(s)\n"
1807 " --bmp - write page images <pdf-name>.<page-number>.bmp\n"
1808 " --emf - write page meta files <pdf-name>.<page-number>.emf\n"
1809 " --ps2 - write page raw PostScript (Lvl 2) "
1810 "<pdf-name>.<page-number>.ps\n"
1811 " --ps3 - write page raw PostScript (Lvl 3) "
1812 "<pdf-name>.<page-number>.ps\n"
1813 " --ps3-type42 - write page raw PostScript (Lvl 3 with Type 42 fonts) "
1814 "<pdf-name>.<page-number>.ps\n"
1816 " --txt - write page text in UTF32-LE <pdf-name>.<page-number>.txt\n"
1817 " --png - write page images <pdf-name>.<page-number>.png\n"
1818 " --ppm - write page images <pdf-name>.<page-number>.ppm\n"
1819 " --annot - write annotation info <pdf-name>.<page-number>.annot.txt\n"
1820#ifdef PDF_ENABLE_SKIA
1821 " --skp - write page images <pdf-name>.<page-number>.skp\n"
1823 " --xps - write page images <pdf-name>.<page-number>.xps\n"
1826 " --md5 - write output image paths and their md5 hashes to stdout.\n"
1827 " --time=<number> - Seconds since the epoch to set system time.\n"
1830void SetUpErrorHandling() {
1834 SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT |
1835 SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
1836 _set_error_mode(_OUT_TO_STDERR);
1837 _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
1838 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
1839 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
1845int main(
int argc,
const char* argv[]) {
1846#if defined(PDF_USE_PARTITION_ALLOC)
1847 pdfium::ConfigurePartitionAllocShimPartitionForTest();
1850 SetUpErrorHandling();
1851 setlocale(LC_CTYPE,
"en_US.UTF-8");
1853 std::vector<std::string> args(argv, argv + argc);
1855 std::vector<std::string> files;
1856 if (!ParseCommandLine(args, &options, &files)) {
1857 fprintf(stderr,
"%s", kUsageString);
1861 if (options.show_config) {
1866 if (files.empty()) {
1867 fprintf(stderr,
"No input files.\n");
1871 FPDF_LIBRARY_CONFIG config;
1873 config.m_pUserFontPaths =
nullptr;
1874 config.m_pIsolate =
nullptr;
1875 config.m_v8EmbedderSlot = 0;
1876 config.m_pPlatform =
nullptr;
1878 switch (options.use_renderer_type) {
1879 case RendererType::kDefault:
1883 case RendererType::kAgg:
1884 config.m_RendererType = FPDF_RENDERERTYPE_AGG;
1888 case RendererType::kGdi:
1890 config.m_RendererType = GetDefaultRendererType();
1894#if defined(PDF_ENABLE_SKIA)
1895 case RendererType::kSkia:
1896#if defined(BUILD_WITH_CHROMIUM)
1899 chromium_support::InitializeDiscardableMemoryAllocator();
1901 config.m_RendererType = FPDF_RENDERERTYPE_SKIA;
1906 std::function<
void()> idler = []() {};
1908#ifdef V8_USE_EXTERNAL_STARTUP_DATA
1909 v8::StartupData snapshot;
1911 std::unique_ptr<v8::Platform> platform;
1912 std::unique_ptr<v8::Isolate, V8IsolateDeleter> isolate;
1913 if (!options.disable_javascript) {
1914#ifdef V8_USE_EXTERNAL_STARTUP_DATA
1915 platform = InitializeV8ForPDFiumWithStartupData(
1916 options.exe_path, options.js_flags, options.bin_directory, &snapshot);
1918 platform = InitializeV8ForPDFium(options.exe_path, options.js_flags);
1921 fprintf(stderr,
"V8 initialization failed.\n");
1924 config.m_pPlatform = platform.get();
1926 v8::Isolate::CreateParams params;
1927 params.array_buffer_allocator =
static_cast<v8::ArrayBuffer::Allocator*>(
1928 FPDF_GetArrayBufferAllocatorSharedInstance());
1929 isolate.reset(v8::Isolate::New(params));
1930 config.m_pIsolate = isolate.get();
1932 idler = [&platform, &isolate]() {
1934 while (v8::platform::PumpMessageLoop(platform.get(), isolate.get()))
1937 fprintf(stderr,
"Pumped %d tasks\n", task_count);
1942 const char* path_array[2] = {
nullptr,
nullptr};
1943 std::optional<
const char*> custom_font_path = GetCustomFontPath(options);
1944 if (custom_font_path.has_value()) {
1945 path_array[0] = custom_font_path.value();
1946 config.m_pUserFontPaths = path_array;
1952 std::unique_ptr<FontRenamer> font_renamer;
1953 if (options.croscore_font_names) {
1955 font_renamer =
std::make_unique<FontRenamer>();
1958 UNSUPPORT_INFO unsupported_info = {};
1964 if (options.time > -1) {
1967 static time_t time_ret = options.time;
1972 Processor processor(&options, &idler);
1973 for (
const std::string& filename : files) {
1974 std::vector<uint8_t> file_contents = GetFileContents(filename.c_str());
1975 if (file_contents.empty()) {
1978 fprintf(stderr,
"Processing PDF file %s.\n", filename.c_str());
1980#ifdef ENABLE_CALLGRIND
1981 if (options.callgrind_delimiters) {
1982 CALLGRIND_START_INSTRUMENTATION;
1987 if (options.send_events) {
1988 std::string event_filename = filename;
1989 size_t extension_pos = event_filename.find(
".pdf");
1990 if (extension_pos != std::string::npos) {
1991 event_filename.replace(extension_pos, 4,
".evt");
1992 if (access(event_filename.c_str(), R_OK) == 0) {
1993 fprintf(stderr,
"Using event file %s.\n", event_filename.c_str());
1994 std::vector<uint8_t> event_contents =
1995 GetFileContents(event_filename.c_str());
1996 if (!event_contents.empty()) {
1997 fprintf(stderr,
"Sending events from: %s\n",
1998 event_filename.c_str());
1999 std::copy(event_contents.begin(), event_contents.end(),
2000 std::back_inserter(events));
2006 processor.ProcessPdf(filename, file_contents, events);
2008#ifdef ENABLE_CALLGRIND
2009 if (options.callgrind_delimiters) {
2010 CALLGRIND_STOP_INSTRUMENTATION;
2019 if (!options.disable_javascript) {
2021 ShutdownV8ForPDFium();
2022#ifdef V8_USE_EXTERNAL_STARTUP_DATA
2023 free(
const_cast<
char*>(snapshot.data));
static bool DirectoryExists(const std::string &path)
static int GetBlock(void *param, unsigned long pos, unsigned char *pBuf, unsigned long size)
FPDF_RENDERER_TYPE GetDefaultRendererType()
void DumpPageStructure(FPDF_PAGE page, int page_idx)
void DumpPageInfo(FPDF_PAGE page, int page_idx)
void SendPageEvents(FPDF_FORMHANDLE form, FPDF_PAGE page, const std::string &events, const std::function< void()> &idler)
#define PDF_FORM_NOTAVAIL
#define PDF_DATA_NOTAVAIL
FPDF_EXPORT FPDF_AVAIL FPDF_CALLCONV FPDFAvail_Create(FX_FILEAVAIL *file_avail, FPDF_FILEACCESS *file)
#define FPDF_UNSP_DOC_PORTABLECOLLECTION
#define FPDF_UNSP_ANNOT_SCREEN_RICHMEDIA
#define FPDF_UNSP_ANNOT_ATTACHMENT
#define FPDF_UNSP_DOC_SECURITY
#define FPDF_UNSP_DOC_SHAREDFORM_FILESYSTEM
FPDF_EXPORT void FPDF_CALLCONV FSDK_SetLocaltimeFunction(struct tm *(*func)(const time_t *))
FPDF_EXPORT FPDF_BOOL FPDF_CALLCONV FSDK_SetUnSpObjProcessHandler(UNSUPPORT_INFO *unsp_info)
#define FPDF_UNSP_DOC_ATTACHMENT
#define FPDF_UNSP_ANNOT_SIG
#define FPDF_UNSP_ANNOT_SOUND
#define FPDF_UNSP_DOC_SHAREDFORM_EMAIL
#define FPDF_UNSP_DOC_XFAFORM
#define FPDF_UNSP_DOC_SHAREDFORM_ACROBAT
#define FPDF_UNSP_ANNOT_3DANNOT
#define FPDF_UNSP_ANNOT_MOVIE
FPDF_EXPORT void FPDF_CALLCONV FSDK_SetTimeFunction(time_t(*func)())
#define FPDF_UNSP_ANNOT_SCREEN_MEDIA
#define FPDF_UNSP_DOC_SHAREDREVIEW
#define FPDF_RENDER_TOBECONTINUED
FPDF_EXPORT FPDF_TEXTPAGE FPDF_CALLCONV FPDFText_LoadPage(FPDF_PAGE page)
FPDF_EXPORT FPDF_PAGE FPDF_CALLCONV FPDF_LoadPage(FPDF_DOCUMENT document, int page_index)
FPDF_EXPORT unsigned long FPDF_CALLCONV FPDF_GetLastError()
FPDF_EXPORT FPDF_DOCUMENT FPDF_CALLCONV FPDF_LoadCustomDocument(FPDF_FILEACCESS *pFileAccess, FPDF_BYTESTRING password)
FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageHeightF(FPDF_PAGE page)
FPDF_EXPORT void FPDF_CALLCONV FPDF_DestroyLibrary()
FPDF_EXPORT int FPDF_CALLCONV FPDFBitmap_GetStride(FPDF_BITMAP bitmap)
FPDF_EXPORT void FPDF_CALLCONV FPDF_InitLibraryWithConfig(const FPDF_LIBRARY_CONFIG *config)
FPDF_EXPORT void *FPDF_CALLCONV FPDFBitmap_GetBuffer(FPDF_BITMAP bitmap)
FPDF_EXPORT float FPDF_CALLCONV FPDF_GetPageWidthF(FPDF_PAGE page)
#define FPDF_RENDER_LIMITEDIMAGECACHE
#define FPDF_RENDER_NO_SMOOTHTEXT
#define FPDF_ERR_SECURITY
#define FPDF_RENDER_NO_SMOOTHIMAGE
#define FPDF_CONVERT_FILL_TO_STROKE
#define FPDF_REVERSE_BYTE_ORDER
#define FPDF_ERR_PASSWORD
#define FPDF_RENDER_FORCEHALFTONE
#define FPDF_NO_NATIVETEXT
#define FPDF_RENDER_NO_SMOOTHPATH
int main(int argc, const char *argv[])
void(* AddSegment)(struct _FX_DOWNLOADHINTS *pThis, size_t offset, size_t size)
void(* FSDK_UnSupport_Handler)(struct _UNSUPPORT_INFO *pThis, int nType)
void WriteAnnot(FPDF_PAGE page, const char *pdf_name, int num)
std::string WritePng(const char *pdf_name, int num, void *buffer, int stride, int width, int height)
void WriteText(FPDF_TEXTPAGE textpage, const char *pdf_name, int num)
std::string WritePpm(const char *pdf_name, int num, void *buffer_void, int stride, int width, int height)