Add raw PostScript output to pdfium_test on Windows.

Activated by --ps2 and --ps3 for PostScript level 2 and 3, respectively.
The raw output is not formatted in a way for most PostScript processing
tools to recognize as actually PostScript.

Also fix the type of the parameter to FPDF_SetPrintPostscriptLevel()
even though it ends up being a no-op.

Change-Id: Iaa34fd3dfaedad2b016fefe1227cbed9c974ae2a
Reviewed-on: https://pdfium-review.googlesource.com/4996
Commit-Queue: dsinclair <dsinclair@chromium.org>
Reviewed-by: dsinclair <dsinclair@chromium.org>
diff --git a/public/fpdfview.h b/public/fpdfview.h
index 0ed9187..13e4f1f 100644
--- a/public/fpdfview.h
+++ b/public/fpdfview.h
@@ -248,8 +248,7 @@
 //                              All other values are invalid.
 // Return value:
 //          True if successful, false if unsucessful (typically invalid input).
-DLLEXPORT FPDF_BOOL STDCALL
-FPDF_SetPrintPostscriptLevel(FPDF_BOOL postscript_level);
+DLLEXPORT FPDF_BOOL STDCALL FPDF_SetPrintPostscriptLevel(int postscript_level);
 #endif  // defined(_WIN32)
 
 // Function: FPDF_LoadDocument
diff --git a/samples/pdfium_test.cc b/samples/pdfium_test.cc
index d2b3c01..fa57d65 100644
--- a/samples/pdfium_test.cc
+++ b/samples/pdfium_test.cc
@@ -60,6 +60,8 @@
 #ifdef _WIN32
   OUTPUT_BMP,
   OUTPUT_EMF,
+  OUTPUT_PS2,
+  OUTPUT_PS3,
 #endif
 #ifdef PDF_ENABLE_SKIA
   OUTPUT_SKP,
@@ -274,14 +276,13 @@
 }
 
 void WriteEmf(FPDF_PAGE page, const char* pdf_name, int num) {
-  int width = static_cast<int>(FPDF_GetPageWidth(page));
-  int height = static_cast<int>(FPDF_GetPageHeight(page));
-
   char filename[256];
   snprintf(filename, sizeof(filename), "%s.%d.emf", pdf_name, num);
 
   HDC dc = CreateEnhMetaFileA(nullptr, filename, nullptr, nullptr);
 
+  int width = static_cast<int>(FPDF_GetPageWidth(page));
+  int height = static_cast<int>(FPDF_GetPageHeight(page));
   HRGN rgn = CreateRectRgn(0, 0, width, height);
   SelectClipRgn(dc, rgn);
   DeleteObject(rgn);
@@ -296,7 +297,48 @@
 
   DeleteEnhMetaFile(CloseEnhMetaFile(dc));
 }
-#endif
+
+int CALLBACK EnhMetaFileProc(HDC hdc,
+                             HANDLETABLE* handle_table,
+                             const ENHMETARECORD* record,
+                             int objects_count,
+                             LPARAM param) {
+  std::vector<const ENHMETARECORD*>& items =
+      *reinterpret_cast<std::vector<const ENHMETARECORD*>*>(param);
+  items.push_back(record);
+  return 1;
+}
+
+void WritePS(FPDF_PAGE page, const char* pdf_name, int num) {
+  char filename[256];
+  snprintf(filename, sizeof(filename), "%s.%d.ps", pdf_name, num);
+  FILE* fp = fopen(filename, "wb");
+  if (!fp)
+    return;
+
+  HDC dc = CreateEnhMetaFileA(nullptr, nullptr, nullptr, nullptr);
+
+  int width = static_cast<int>(FPDF_GetPageWidth(page));
+  int height = static_cast<int>(FPDF_GetPageHeight(page));
+  FPDF_RenderPage(dc, page, 0, 0, width, height, 0,
+                  FPDF_ANNOT | FPDF_PRINTING | FPDF_NO_CATCH);
+
+  HENHMETAFILE emf = CloseEnhMetaFile(dc);
+  std::vector<const ENHMETARECORD*> items;
+  EnumEnhMetaFile(nullptr, emf, &EnhMetaFileProc, &items, nullptr);
+  for (const ENHMETARECORD* record : items) {
+    if (record->iType != EMR_GDICOMMENT)
+      continue;
+
+    const auto* comment = reinterpret_cast<const EMRGDICOMMENT*>(record);
+    const char* data = reinterpret_cast<const char*>(comment->Data);
+    uint16_t size = *reinterpret_cast<const uint16_t*>(data);
+    fwrite(data + sizeof(uint16_t), size, 1, fp);
+  }
+  fclose(fp);
+  DeleteEnhMetaFile(emf);
+}
+#endif  // _WIN32
 
 #ifdef PDF_ENABLE_SKIA
 static std::string WriteSkp(const char* pdf_name,
@@ -474,6 +516,18 @@
         return false;
       }
       options->output_format = OUTPUT_EMF;
+    } else if (cur_arg == "--ps2") {
+      if (options->output_format != OUTPUT_NONE) {
+        fprintf(stderr, "Duplicate or conflicting --ps2 argument\n");
+        return false;
+      }
+      options->output_format = OUTPUT_PS2;
+    } else if (cur_arg == "--ps3") {
+      if (options->output_format != OUTPUT_NONE) {
+        fprintf(stderr, "Duplicate or conflicting --ps3 argument\n");
+        return false;
+      }
+      options->output_format = OUTPUT_PS3;
     } else if (cur_arg == "--bmp") {
       if (options->output_format != OUTPUT_NONE) {
         fprintf(stderr, "Duplicate or conflicting --bmp argument\n");
@@ -736,6 +790,11 @@
       case OUTPUT_EMF:
         WriteEmf(page.get(), name.c_str(), page_index);
         break;
+
+      case OUTPUT_PS2:
+      case OUTPUT_PS3:
+        WritePS(page.get(), name.c_str(), page_index);
+        break;
 #endif
       case OUTPUT_TEXT:
         WriteText(page.get(), name.c_str(), page_index);
@@ -898,6 +957,13 @@
   FORM_DoDocumentJSAction(form.get());
   FORM_DoDocumentOpenAction(form.get());
 
+#if _WIN32
+  if (options.output_format == OUTPUT_PS2)
+    FPDF_SetPrintPostscriptLevel(2);
+  else if (options.output_format == OUTPUT_PS3)
+    FPDF_SetPrintPostscriptLevel(3);
+#endif
+
   int page_count = FPDF_GetPageCount(doc.get());
   int rendered_pages = 0;
   int bad_pages = 0;
@@ -966,6 +1032,8 @@
 #ifdef _WIN32
     "  --bmp - write page images <pdf-name>.<page-number>.bmp\n"
     "  --emf - write page meta files <pdf-name>.<page-number>.emf\n"
+    "  --ps2 - write page raw PostScript (Lvl 2) <pdf-name>.<page-number>.ps\n"
+    "  --ps3 - write page raw PostScript (Lvl 3) <pdf-name>.<page-number>.ps\n"
 #endif  // _WIN32
     "  --txt - write page text in UTF32-LE <pdf-name>.<page-number>.txt\n"
     "  --png - write page images <pdf-name>.<page-number>.png\n"