[poppler] 6 commits - configure.ac utils/CMakeLists.txt utils/Makefile.am utils/pdftocairo.1 utils/pdftocairo.cc utils/pdftocairo-win32.cc utils/pdftocairo-win32.h

Adrian Johnson ajohnson at kemper.freedesktop.org
Tue Oct 21 04:39:24 PDT 2014


 configure.ac              |    2 
 utils/CMakeLists.txt      |    1 
 utils/Makefile.am         |    3 
 utils/pdftocairo-win32.cc |  549 ++++++++++++++++++++++++++++++++++++++++++++++
 utils/pdftocairo-win32.h  |   21 +
 utils/pdftocairo.1        |   39 +++
 utils/pdftocairo.cc       |  126 ++++++++--
 7 files changed, 713 insertions(+), 28 deletions(-)

New commits:
commit 4963332ca4db13d8a9186b06d2aa0d59abbc10ee
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Oct 5 21:58:37 2014 +1030

    pdftocairo: add -printdlg output option for win32
    
    when set the win32 print dialog is displayed before printing

diff --git a/configure.ac b/configure.ac
index 10a4b39..7a5d747 100644
--- a/configure.ac
+++ b/configure.ac
@@ -48,7 +48,7 @@ case "$host_os" in
   ;;
   mingw*)
     os_win32=yes
-    win32_libs="-lgdi32 -lwinspool"
+    win32_libs="-lgdi32 -lwinspool -lcomdlg32"
     create_shared_lib="-no-undefined"
     auto_import_flags="-Wl,--enable-auto-import"
 
diff --git a/utils/pdftocairo-win32.cc b/utils/pdftocairo-win32.cc
index de7da57..565d8a1 100644
--- a/utils/pdftocairo-win32.cc
+++ b/utils/pdftocairo-win32.cc
@@ -6,7 +6,13 @@
 #include "parseargs.h"
 #include "pdftocairo-win32.h"
 
+#include <dlgs.h>
+#include <commctrl.h>
+#include <windowsx.h>
+
 static HDC hdc;
+static HGLOBAL hDevmode = 0;
+static HGLOBAL hDevnames = 0;
 static DEVMODEA *devmode;
 static char *printerName;
 
@@ -70,7 +76,7 @@ static void parseDuplex(GooString *mode)
   fprintf(stderr, "Warning: Unknown duplex mode \"%s\"\n", mode->getCString());
 }
 
-static void fillCommonPrinterOptions(double w, double h, GBool duplex)
+static void fillCommonPrinterOptions(GBool duplex)
 {
   if (duplex) {
     devmode->dmDuplex = DMDUP_HORIZONTAL;
@@ -135,12 +141,214 @@ static void fillPrinterOptions(GBool duplex, GooString *printOpt)
   }
 }
 
-cairo_surface_t *win32BeginDocument(GooString *inputFileName, GooString *outputFileName,
-				    double w, double h,
-				    GooString *printer,
-				    GooString *printOpt,
-				    GBool setupdlg,
-				    GBool duplex)
+static void getLocalPos(HWND wind, HWND dlg, RECT *rect)
+{
+  GetClientRect(wind, rect);
+  MapWindowPoints(wind, dlg, (LPPOINT)rect, 2);
+}
+
+static HWND createGroupBox(HWND parent, HINSTANCE hInstance, int id, const char *label, RECT *rect)
+{
+  HWND hwnd = CreateWindowA(WC_BUTTONA,
+			    label,
+			    WS_CHILD | WS_VISIBLE | BS_GROUPBOX,
+			    rect->left, rect->top,
+			    rect->right - rect->left,
+			    rect->bottom - rect->top,
+			    parent, (HMENU)id,
+			    hInstance, NULL);
+  HFONT hFont = (HFONT)SendMessage(parent, WM_GETFONT, (WPARAM)0, (LPARAM)0);
+  if (hFont)
+    SendMessage(hwnd, WM_SETFONT, (WPARAM) hFont, (LPARAM)0);
+  return hwnd;
+}
+
+static HWND createCheckBox(HWND parent, HINSTANCE hInstance, int id, const char *label, RECT *rect)
+{
+  HWND hwnd = CreateWindowA(WC_BUTTONA,
+			    label,
+			    WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX | WS_TABSTOP,
+			    rect->left, rect->top,
+			    rect->right - rect->left,
+			    rect->bottom - rect->top,
+			    parent, (HMENU)id,
+			    hInstance, NULL);
+  HFONT hFont = (HFONT)SendMessage(parent, WM_GETFONT, (WPARAM)0, (LPARAM)0);
+  if (hFont)
+    SendMessage(hwnd, WM_SETFONT, (WPARAM) hFont, (LPARAM)0);
+  return hwnd;
+}
+
+static HWND createStaticText(HWND parent, HINSTANCE hinstance, int id, const char *text, RECT *rect)
+{
+  HWND hwnd = CreateWindowA(WC_STATICA,
+			    text,
+			    WS_CHILD | WS_VISIBLE | SS_LEFT,
+			    rect->left, rect->top,
+			    rect->right - rect->left,
+			    rect->bottom - rect->top,
+			    parent, (HMENU)id,
+			    hinstance, NULL);
+  HFONT hFont = (HFONT)SendMessage(parent, WM_GETFONT, (WPARAM)0, (LPARAM)0);
+  if (hFont)
+    SendMessage(hwnd, WM_SETFONT, (WPARAM) hFont, (LPARAM)0);
+  return hwnd;
+}
+
+HWND createPageScaleComboBox(HWND parent, HINSTANCE hinstance, int id, RECT *rect)
+{
+  HWND hwnd = CreateWindowA(WC_COMBOBOX,
+			    "",
+			    WS_CHILD | WS_VISIBLE | WS_GROUP | WS_TABSTOP |
+			    CBS_DROPDOWNLIST,
+			    rect->left, rect->top,
+			    rect->right - rect->left,
+			    rect->bottom - rect->top,
+			    parent, (HMENU)id,
+			    hinstance, NULL);
+  HFONT hFont = (HFONT)SendMessage(parent, WM_GETFONT, (WPARAM)0, (LPARAM)0);
+  if (hFont)
+    SendMessage(hwnd, WM_SETFONT, (WPARAM) hFont, (LPARAM)0);
+  ComboBox_AddString(hwnd, "None");
+  ComboBox_AddString(hwnd, "Shrink to Printable Area");
+  ComboBox_AddString(hwnd, "Fit to Printable Area");
+  return hwnd;
+}
+
+enum PageScale { NONE = 0, SHRINK = 1, FIT = 2 };
+
+// used to set/get option values in printDialogHookProc
+static PageScale pageScale;
+static GBool centerPage;
+static GBool useOrigPageSize;
+
+// PrintDlg callback to customize the print dialog with additional controls.
+static UINT_PTR CALLBACK printDialogHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
+{
+  if (uiMsg == WM_INITDIALOG) {
+    // Get the extant controls. See dlgs.h and prnsetup.dlg for the PrintDlg control ids.
+    HWND printerGroupWind = GetDlgItem(hdlg, grp4);
+    HWND printerComboWind = GetDlgItem(hdlg, cmb4);
+    HWND nameLabelWind = GetDlgItem(hdlg, stc6);
+    HWND statusLabelWind = GetDlgItem(hdlg, stc8);
+    HWND printRangeGroupWind = GetDlgItem(hdlg, grp1);
+    HWND radio1Wind = GetDlgItem(hdlg, rad1);
+    HWND radio2Wind = GetDlgItem(hdlg, rad3);
+    HWND copiesGroupWind = GetDlgItem(hdlg, grp2);
+    HWND okWind = GetDlgItem(hdlg, IDOK);
+    HWND cancelWind = GetDlgItem(hdlg, IDCANCEL);
+    if (!printerGroupWind || !printerComboWind || !nameLabelWind || !statusLabelWind ||
+	!printRangeGroupWind || !radio1Wind || !radio2Wind || !copiesGroupWind ||
+	!okWind || !cancelWind)
+      return 0;
+
+    // Get the size and position of the above controls relative to the
+    // print dialog window
+    RECT printerGroupRect;
+    RECT printerComboRect;
+    RECT nameLabelRect;
+    RECT statusLabelRect;
+    RECT printRangeGroupRect;
+    RECT radio1Rect, radio2Rect;
+    RECT copiesGroupRect;
+    RECT okRect, cancelRect;
+    getLocalPos(printerGroupWind, hdlg, &printerGroupRect);
+    getLocalPos(printerComboWind, hdlg, &printerComboRect);
+    getLocalPos(nameLabelWind, hdlg, &nameLabelRect);
+    getLocalPos(statusLabelWind, hdlg, &statusLabelRect);
+    getLocalPos(printRangeGroupWind, hdlg, &printRangeGroupRect);
+    getLocalPos(radio1Wind, hdlg, &radio1Rect);
+    getLocalPos(radio2Wind, hdlg, &radio2Rect);
+    getLocalPos(copiesGroupWind, hdlg, &copiesGroupRect);
+    getLocalPos(okWind, hdlg, &okRect);
+    getLocalPos(cancelWind, hdlg, &cancelRect);
+
+    // Calc space required for new group
+    int interGroupSpace = printRangeGroupRect.top - printerGroupRect.bottom;
+    int groupHeight = statusLabelRect.top - printerGroupRect.top +
+      printRangeGroupRect.bottom - radio1Rect.bottom;
+
+    // Increase dialog size
+    RECT dlgRect;
+    GetWindowRect(hdlg, &dlgRect);
+    SetWindowPos(hdlg, NULL,
+		 dlgRect.left, dlgRect.top,
+		 dlgRect.right - dlgRect.left,
+		 dlgRect.bottom - dlgRect.top + interGroupSpace + groupHeight,
+		 SWP_NOMOVE|SWP_NOREDRAW|SWP_NOZORDER);
+
+    // Add new group and controls
+    HINSTANCE hinstance = (HINSTANCE)GetWindowLongPtr(hdlg, GWLP_HINSTANCE);
+    RECT pdfGroupBoxRect;
+    pdfGroupBoxRect.left = printRangeGroupRect.left;
+    pdfGroupBoxRect.right = copiesGroupRect.right;
+    pdfGroupBoxRect.top = printRangeGroupRect.bottom + interGroupSpace;
+    pdfGroupBoxRect.bottom = pdfGroupBoxRect.top + groupHeight;
+    createGroupBox(hdlg, hinstance, grp3, "PDF Print Options", &pdfGroupBoxRect);
+
+    RECT textRect;
+    textRect.left = nameLabelRect.left;
+    textRect.right = nameLabelRect.left + 1.8*(printerComboRect.left - nameLabelRect.left);
+    textRect.top = pdfGroupBoxRect.top + nameLabelRect.top - printerGroupRect.top;
+    textRect.bottom = textRect.top + nameLabelRect.bottom - nameLabelRect.top;
+    createStaticText(hdlg, hinstance, stc1, "Page Scaling:", &textRect);
+
+    RECT comboBoxRect;
+    comboBoxRect.left = textRect.right;
+    comboBoxRect.right = comboBoxRect.left + printerComboRect.right - printerComboRect.left;;
+    comboBoxRect.top = pdfGroupBoxRect.top + printerComboRect.top - printerGroupRect.top;
+    comboBoxRect.bottom = textRect.top + 4*(printerComboRect.bottom - printerComboRect.top);
+    HWND comboBoxWind = createPageScaleComboBox(hdlg, hinstance, cmb1, &comboBoxRect);
+
+    RECT checkBox1Rect;
+    checkBox1Rect.left = radio1Rect.left;
+    checkBox1Rect.right = pdfGroupBoxRect.right - 10;
+    checkBox1Rect.top = pdfGroupBoxRect.top + statusLabelRect.top - printerGroupRect.top;
+    checkBox1Rect.bottom = checkBox1Rect.top + radio1Rect.bottom - radio1Rect.top;
+    HWND checkBox1Wind = createCheckBox(hdlg, hinstance, chx3, "Center", &checkBox1Rect);
+
+    RECT checkBox2Rect;
+    checkBox2Rect.left = radio1Rect.left;
+    checkBox2Rect.right = pdfGroupBoxRect.right - 10;
+    checkBox2Rect.top =  checkBox1Rect.top + radio2Rect.top - radio1Rect.top;
+    checkBox2Rect.bottom = checkBox2Rect.top + radio1Rect.bottom - radio1Rect.top;
+    HWND checkBox2Wind = createCheckBox(hdlg, hinstance, chx4, "Select page size using document page size", &checkBox2Rect);
+
+    // Move OK and Cancel buttons down ensuring they are last in the Z order
+    // so that the tab order is correct.
+    SetWindowPos(okWind,
+		 HWND_BOTTOM,
+		 okRect.left,
+		 okRect.top + interGroupSpace + groupHeight,
+		 0, 0,
+		 SWP_NOSIZE); // keep current size
+    SetWindowPos(cancelWind,
+		 HWND_BOTTOM,
+		 cancelRect.left,
+		 cancelRect.top + interGroupSpace + groupHeight,
+		 0, 0,
+		 SWP_NOSIZE); // keep current size
+
+    // Initialize control values
+    ComboBox_SetCurSel(comboBoxWind, pageScale);
+    Button_SetCheck(checkBox1Wind, centerPage ? BST_CHECKED : BST_UNCHECKED);
+    Button_SetCheck(checkBox2Wind, useOrigPageSize ? BST_CHECKED : BST_UNCHECKED);
+
+  } else if (uiMsg == WM_COMMAND) {
+    // Save settings
+    UINT id = LOWORD(wParam);
+    if (id == cmb1)
+      pageScale = (PageScale)ComboBox_GetCurSel(GetDlgItem(hdlg, cmb1));
+    if (id == chx3)
+      centerPage = IsDlgButtonChecked(hdlg, chx3);
+    if (id == chx4)
+      useOrigPageSize = IsDlgButtonChecked(hdlg, chx4);
+  }
+  return 0;
+}
+
+void win32SetupPrinter(GooString *printer, GooString *printOpt,
+		       GBool duplex, GBool setupdlg)
 {
   if (printer->getCString()[0] == 0) {
     DWORD size = 0;
@@ -168,7 +376,7 @@ cairo_surface_t *win32BeginDocument(GooString *inputFileName, GooString *outputF
   }
 
   // Update devmode with selected print options
-  fillCommonPrinterOptions(w, h, duplex);
+  fillCommonPrinterOptions(duplex);
   fillPrinterOptions(duplex, printOpt);
 
   // Call DocumentProperties again so the driver can update its private data
@@ -191,7 +399,72 @@ cairo_surface_t *win32BeginDocument(GooString *inputFileName, GooString *outputF
     fprintf(stderr, "Error: Printer \"%s\" not found\n", printerName);
     exit(99);
   }
+}
+
+void win32ShowPrintDialog(GBool *expand, GBool *noShrink, GBool *noCenter,
+			  GBool *usePDFPageSize, GBool *allPages,
+			  int *firstPage, int *lastPage, int maxPages)
+{
+  PRINTDLG pd;
+  memset(&pd, 0, sizeof(PRINTDLG));
+  pd.lStructSize = sizeof(PRINTDLG);
+  pd.Flags = PD_NOSELECTION | PD_ENABLEPRINTHOOK | PD_USEDEVMODECOPIESANDCOLLATE | PD_RETURNDC;
+  if (*allPages) {
+    pd.nFromPage = 1;
+    pd.nToPage = maxPages;
+  } else {
+    pd.Flags |= PD_PAGENUMS;
+    pd.nFromPage = *firstPage;
+    pd.nToPage = *lastPage;
+  }
+  pd.nCopies = 1;
+  pd.nMinPage = 1;
+  pd.nMaxPage = maxPages;
+  pd.lpfnPrintHook = printDialogHookProc;
+  if (!*expand && *noShrink)
+    pageScale = NONE;
+  else if (!*expand && !*noShrink)
+    pageScale = SHRINK;
+  else
+    pageScale = FIT;
+  centerPage = !*noCenter;
+  useOrigPageSize = *usePDFPageSize;
+
+  if (PrintDlgA(&pd)) {
+    // Ok
+    hDevnames = pd.hDevNames;
+    DEVNAMES *devnames = (DEVNAMES*)GlobalLock(hDevnames);
+    printerName = (char*)devnames + devnames->wDeviceOffset;
+    hDevmode = pd.hDevMode;
+    devmode = (DEVMODEA*)GlobalLock(hDevmode);
+    hdc = pd.hDC;
+    if (pd.Flags & PD_PAGENUMS) {
+      *allPages = gFalse;
+      *firstPage = pd.nFromPage;
+      *lastPage = pd.nToPage;
+    } else {
+      *allPages = gTrue;
+    }
+    if (pageScale == NONE) {
+      *expand = gFalse;
+      *noShrink = gTrue;
+    } else if (pageScale == SHRINK) {
+      *expand = gFalse;
+      *noShrink = gFalse;
+    } else {
+      *expand = gTrue;
+      *noShrink = gFalse;
+    }
+    *noCenter = !centerPage;
+    *usePDFPageSize = useOrigPageSize;
+  } else {
+    // Cancel
+    exit(0);
+  }
+}
 
+cairo_surface_t *win32BeginDocument(GooString *inputFileName, GooString *outputFileName)
+{
   DOCINFOA docinfo;
   memset(&docinfo, 0, sizeof(docinfo));
   docinfo.cbSize = sizeof(docinfo);
@@ -259,8 +532,18 @@ void win32EndDocument()
 {
   EndDoc(hdc);
   DeleteDC(hdc);
-  gfree(devmode);
-  gfree(printerName);
+  if (hDevmode) {
+    GlobalUnlock(hDevmode);
+    GlobalFree(hDevmode);
+  } else {
+    gfree(devmode);
+  }
+  if (hDevnames) {
+    GlobalUnlock(hDevnames);
+    GlobalFree(hDevnames);
+  } else {
+    gfree(printerName);
+  }
 }
 
 #endif // CAIRO_HAS_WIN32_SURFACE
diff --git a/utils/pdftocairo-win32.h b/utils/pdftocairo-win32.h
index 3f797b4..fe2cf4d 100644
--- a/utils/pdftocairo-win32.h
+++ b/utils/pdftocairo-win32.h
@@ -4,18 +4,16 @@
 #include "goo/gtypes_p.h"
 #include "goo/GooString.h"
 
-
 #ifdef CAIRO_HAS_WIN32_SURFACE
 
 #include <cairo-win32.h>
 
-void win32GetFitToPageTransform(cairo_matrix_t *m);
-cairo_surface_t *win32BeginDocument(GooString *inputFileName, GooString *outputFileName,
-				    double w, double h,
-				    GooString *printer,
-				    GooString *printOpt,
-				    GBool setupdlg,
-				    GBool duplex);
+void win32SetupPrinter(GooString *printer, GooString *printOpt,
+		       GBool duplex, GBool setupdlg);
+void win32ShowPrintDialog(GBool *expand, GBool *noShrink, GBool *noCenter,
+			  GBool *usePDFPageSize, GBool *allPages,
+			  int *firstPage, int *lastPage, int maxPages);
+cairo_surface_t *win32BeginDocument(GooString *inputFileName, GooString *outputFileName);
 void win32BeginPage(double *w, double *h, GBool changePageSize, GBool useFullPage);
 void win32EndPage(GooString *imageFileName);
 void win32EndDocument();
diff --git a/utils/pdftocairo.1 b/utils/pdftocairo.1
index 1045436..7575cab 100644
--- a/utils/pdftocairo.1
+++ b/utils/pdftocairo.1
@@ -82,11 +82,6 @@ Generates a TIFF file(s)
 .BI \-pdf
 Generates a PDF file
 .TP
-.BI \-print
-(Windows only) Prints to a system printer. See also \-printer and \-printeropt.
- If an output file is not specified, the output will be sent to the printer.
- The output file '-' can not be used with this option.
-.TP
 .BI \-ps
 Generate a PS file
 .TP
@@ -99,6 +94,15 @@ to specify a single page.  The page size options (\-origpagesizes,
 .BI \-svg
 Generate a SVG (Scalable Vector Graphics) file
 .TP
+.BI \-print
+(Windows only) Prints to a system printer. See also \-printer and \-printeropt.
+ If an output file is not specified, the output will be sent to the printer.
+ The output file '-' can not be used with this option.
+.TP
+.BI \-printdlg
+(Windows only) Prints to a system printer. Displays the print dialog to allow
+the print options to be modified before printing.
+.TP
 .BI \-f " number"
 Specifies the first page to convert.
 .TP
diff --git a/utils/pdftocairo.cc b/utils/pdftocairo.cc
index 0c25b14..d779123 100644
--- a/utils/pdftocairo.cc
+++ b/utils/pdftocairo.cc
@@ -80,6 +80,7 @@ static GBool ps = gFalse;
 static GBool eps = gFalse;
 static GBool pdf = gFalse;
 static GBool printToWin32 = gFalse;
+static GBool printdlg = gFalse;
 static GBool svg = gFalse;
 static GBool tiff = gFalse;
 
@@ -160,6 +161,8 @@ static const ArgDesc argDesc[] = {
 #ifdef CAIRO_HAS_WIN32_SURFACE
   {"-print",    argFlag,     &printToWin32,       0,
    "print to a Windows printer"},
+  {"-printdlg",    argFlag,     &printdlg, 0,
+   "show Windows print dialog and print"},
   {"-printer",  argGooString, &printer,    0,
    "printer name or use default if this option is not specified"},
   {"-printopt",  argGooString, &printOpt,    0,
@@ -541,7 +544,7 @@ static void beginDocument(GooString *inputFileName, GooString *outputFileName, d
     }
 #ifdef CAIRO_HAS_WIN32_SURFACE
     if (printToWin32)
-      surface = win32BeginDocument(inputFileName, outputFileName, w, h, &printer, &printOpt, setupdlg, duplex);
+      surface = win32BeginDocument(inputFileName, outputFileName);
 #endif
   }
 }
@@ -857,13 +860,14 @@ int main(int argc, char *argv[]) {
                 (eps ? 1 : 0) +
                 (pdf ? 1 : 0) +
                 (printToWin32 ? 1 : 0) +
+                (printdlg ? 1 : 0) +
                 (svg ? 1 : 0);
   if (num_outputs == 0) {
-    fprintf(stderr, "Error: one of the output format options (-png, -jpeg, -ps, -eps, -pdf, -print, -svg) must be used.\n");
+    fprintf(stderr, "Error: one of the output format options (-png, -jpeg, -ps, -eps, -pdf, -print, -printdlg, -svg) must be used.\n");
     exit(99);
   }
   if (num_outputs > 1) {
-    fprintf(stderr, "Error: use only one of the output format options (-png, -jpeg, -ps, -eps, -pdf, -print, -svg).\n");
+    fprintf(stderr, "Error: use only one of the output format options (-png, -jpeg, -ps, -eps, -pdf, -printdlg, -print, -svg).\n");
     exit(99);
   }
   if (png || jpeg || tiff)
@@ -947,6 +951,9 @@ int main(int argc, char *argv[]) {
   else
     usePDFPageSize = gFalse;
 
+  if (printdlg)
+    printToWin32 = gTrue;
+
   globalParams = new GlobalParams();
   if (quiet) {
     globalParams->setErrQuiet(quiet);
@@ -1046,6 +1053,24 @@ int main(int argc, char *argv[]) {
     lastPage = firstPage;
   }
 
+#ifdef CAIRO_HAS_WIN32_SURFACE
+    if (printdlg) {
+      GBool allPages = gFalse;
+      if (firstPage == 1 && lastPage == doc->getNumPages())
+	allPages = gTrue;
+      win32ShowPrintDialog(&expand, &noShrink, &noCenter,
+			   &usePDFPageSize, &allPages,
+			   &firstPage, &lastPage, doc->getNumPages());
+      if (allPages) {
+	firstPage = 1;
+	lastPage = doc->getNumPages();
+      }
+    } else if (printToWin32) {
+      win32SetupPrinter(&printer, &printOpt,
+			duplex, setupdlg);
+    }
+#endif
+
   // Make sure firstPage is always used so that beginDocument() is called
   if ((printOnlyEven && firstPage % 2 == 0) || (printOnlyOdd && firstPage % 2 == 1))
     firstPage++;
commit d8fe025c36f555a5438677e20df803eee216bb13
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Oct 5 18:11:09 2014 +1030

    pdftocairo: add a -setupdlg option that will the show printer properties
    
    dialog when printing to a win32 printer.

diff --git a/utils/pdftocairo-win32.cc b/utils/pdftocairo-win32.cc
index dcabb69..de7da57 100644
--- a/utils/pdftocairo-win32.cc
+++ b/utils/pdftocairo-win32.cc
@@ -139,6 +139,7 @@ cairo_surface_t *win32BeginDocument(GooString *inputFileName, GooString *outputF
 				    double w, double h,
 				    GooString *printer,
 				    GooString *printOpt,
+				    GBool setupdlg,
 				    GBool duplex)
 {
   if (printer->getCString()[0] == 0) {
@@ -165,12 +166,26 @@ cairo_surface_t *win32BeginDocument(GooString *inputFileName, GooString *outputF
     fprintf(stderr, "Error: Printer \"%s\" not found\n", printerName);
     exit(99);
   }
+
+  // Update devmode with selected print options
   fillCommonPrinterOptions(w, h, duplex);
   fillPrinterOptions(duplex, printOpt);
-  if (DocumentPropertiesA(NULL, NULL, printerName, devmode, devmode, DM_IN_BUFFER | DM_OUT_BUFFER) < 0) {
+
+  // Call DocumentProperties again so the driver can update its private data
+  // with the modified print options. This will also display the printer
+  // properties dialog if setupdlg is true.
+  int ret;
+  DWORD mode = DM_IN_BUFFER | DM_OUT_BUFFER;
+  if (setupdlg)
+    mode |= DM_IN_PROMPT;
+  ret = DocumentPropertiesA(NULL, NULL, printerName, devmode, devmode, mode);
+  if (ret < 0) {
     fprintf(stderr, "Error: Printer \"%s\" not found\n", printerName);
     exit(99);
   }
+  if (setupdlg && ret == IDCANCEL)
+    exit(0);
+
   hdc = CreateDCA(NULL, printerName, NULL, devmode);
   if (!hdc) {
     fprintf(stderr, "Error: Printer \"%s\" not found\n", printerName);
@@ -194,9 +209,10 @@ cairo_surface_t *win32BeginDocument(GooString *inputFileName, GooString *outputF
   return cairo_win32_printing_surface_create(hdc);
 }
 
-void win32BeginPage(double *w, double *h, GBool useFullPage)
+void win32BeginPage(double *w, double *h, GBool changePageSize, GBool useFullPage)
 {
-  fillPagePrinterOptions(*w, *h);
+  if (changePageSize)
+    fillPagePrinterOptions(*w, *h);
   if (DocumentPropertiesA(NULL, NULL, printerName, devmode, devmode, DM_IN_BUFFER | DM_OUT_BUFFER) < 0) {
     fprintf(stderr, "Error: Printer \"%s\" not found\n", printerName);
     exit(99);
diff --git a/utils/pdftocairo-win32.h b/utils/pdftocairo-win32.h
index 07e200c..3f797b4 100644
--- a/utils/pdftocairo-win32.h
+++ b/utils/pdftocairo-win32.h
@@ -14,8 +14,9 @@ cairo_surface_t *win32BeginDocument(GooString *inputFileName, GooString *outputF
 				    double w, double h,
 				    GooString *printer,
 				    GooString *printOpt,
+				    GBool setupdlg,
 				    GBool duplex);
-void win32BeginPage(double *w, double *h, GBool useFullPage);
+void win32BeginPage(double *w, double *h, GBool changePageSize, GBool useFullPage);
 void win32EndPage(GooString *imageFileName);
 void win32EndDocument();
 
diff --git a/utils/pdftocairo.1 b/utils/pdftocairo.1
index 00d93c4..1045436 100644
--- a/utils/pdftocairo.1
+++ b/utils/pdftocairo.1
@@ -220,6 +220,11 @@ PostScript file (PS only).  This tells the print manager to enable duplexing.
 .B WINDOWS PRINTER OPTIONS
 for the available options.
 .TP
+.BI \-setupdlg
+(Windows only). When used with \-print, the printer properties dialog is displayed
+allowing the print settings to be modified before printing. The paper size selected
+in the print properties dialog will be used except when -origpagesizes is specified.
+.TP
 .BI \-opw " password"
 Specify the owner password for the PDF file.  Providing this will
 bypass all security restrictions.
diff --git a/utils/pdftocairo.cc b/utils/pdftocairo.cc
index b0a689e..0c25b14 100644
--- a/utils/pdftocairo.cc
+++ b/utils/pdftocairo.cc
@@ -124,10 +124,9 @@ static GBool quiet = gFalse;
 static GBool printVersion = gFalse;
 static GBool printHelp = gFalse;
 
-#ifdef CAIRO_HAS_WIN32_SURFACE
 static GooString printer;
 static GooString printOpt;
-#endif
+static GBool setupdlg = gFalse;
 
 static const ArgDesc argDesc[] = {
 #if ENABLE_LIBPNG
@@ -165,6 +164,8 @@ static const ArgDesc argDesc[] = {
    "printer name or use default if this option is not specified"},
   {"-printopt",  argGooString, &printOpt,    0,
    "printer options, with format <opt1>=<val1>[,<optN>=<valN>]*"},
+  {"-setupdlg",    argFlag,     &setupdlg,       0,
+   "show printer setup dialog before printing"},
 #endif
 
   {"-f",      argInt,      &firstPage,     0,
@@ -262,6 +263,7 @@ static const ArgDesc argDesc[] = {
 static  cairo_surface_t *surface;
 static  GBool printing;
 static  FILE *output_file;
+static GBool usePDFPageSize;
 
 #if USE_CMS
 static unsigned char *icc_data;
@@ -435,7 +437,7 @@ static void getOutputSize(double page_w, double page_h, double *width, double *h
 {
 
   if (printing) {
-    if (origPageSizes) {
+    if (usePDFPageSize) {
       *width = page_w;
       *height = page_h;
     } else {
@@ -539,7 +541,7 @@ static void beginDocument(GooString *inputFileName, GooString *outputFileName, d
     }
 #ifdef CAIRO_HAS_WIN32_SURFACE
     if (printToWin32)
-      surface = win32BeginDocument(inputFileName, outputFileName, w, h, &printer, &printOpt, duplex);
+      surface = win32BeginDocument(inputFileName, outputFileName, w, h, &printer, &printOpt, setupdlg, duplex);
 #endif
   }
 }
@@ -565,8 +567,12 @@ static void beginPage(double *w, double *h)
 #endif
 
 #ifdef CAIRO_HAS_WIN32_SURFACE
-    if (printToWin32)
-      win32BeginPage(w, h, noShrink); // w,h will be changed to actual size used
+    if (printToWin32) {
+      GBool changePageSize = gTrue;
+      if (setupdlg && !origPageSizes)
+	changePageSize = gFalse;
+      win32BeginPage(w, h, changePageSize, noShrink); // w,h will be changed to actual size used
+    }
 #endif
 
     cairo_surface_set_fallback_resolution (surface, x_resolution, y_resolution);
@@ -936,8 +942,10 @@ int main(int argc, char *argv[]) {
       exit(99);
     }
   }
-  if (paperWidth < 0 || paperHeight < 0)
-    origPageSizes = gTrue;
+  if (origPageSizes || paperWidth < 0 || paperHeight < 0)
+    usePDFPageSize = gTrue;
+  else
+    usePDFPageSize = gFalse;
 
   globalParams = new GlobalParams();
   if (quiet) {
commit c091aa14513859ab76223f5e4e6055d92082433c
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Sep 14 20:43:47 2014 +0930

    pdftocairo: fix a number of bugs in win32 printing
    
    - make origPageSizes work
    - make landscape pages work
    - make -noshrink option work
    - return actual page size in use back to main() so fit page transform works
    - hdc should be destroyed after cairo surface
    - improve option parsing and rename duplex values
    - Add third call to DocumentProperties as discussed in bug 79936
    - fix error messages

diff --git a/utils/pdftocairo-win32.cc b/utils/pdftocairo-win32.cc
index 7ad5615..dcabb69 100644
--- a/utils/pdftocairo-win32.cc
+++ b/utils/pdftocairo-win32.cc
@@ -7,13 +7,8 @@
 #include "pdftocairo-win32.h"
 
 static HDC hdc;
-
-void win32GetFitToPageTransform(cairo_matrix_t *m)
-{
-  int logx = GetDeviceCaps(hdc, LOGPIXELSX);
-  int logy = GetDeviceCaps(hdc, LOGPIXELSY);
-  cairo_matrix_scale (m, logx / 72.0, logy / 72.0);
-}
+static DEVMODEA *devmode;
+static char *printerName;
 
 struct Win32Option
 {
@@ -39,69 +34,69 @@ static const Win32Option win32PaperSource[] =
   {NULL, 0}
 };
 
-static void parseSource(DEVMODEA *devmode, GooString *source)
+static void parseSource(GooString *source)
 {
-  int src;
   const Win32Option *option = win32PaperSource;
   while (option->name) {
     if (source->cmp(option->name) == 0) {
-      src = option->value;
-      break;
-    }
-  }
-  if (!option->name) {
-    if (isInt(source->getCString())) {
-      src = atoi(source->getCString());
-    } else {
-      fprintf(stderr, "Warning: Unknown paper source \"%s\"\n", source->getCString());
+      devmode->dmDefaultSource = option->value;
+      devmode->dmFields |= DM_DEFAULTSOURCE;
       return;
     }
+    option++;
   }
-
-  devmode->dmDefaultSource = src;
-  devmode->dmFields |= DM_DEFAULTSOURCE;
+  fprintf(stderr, "Warning: Unknown paper source \"%s\"\n", source->getCString());
 }
 
 static const Win32Option win32DuplexMode[] =
 {
-  {"simplex", DMDUP_SIMPLEX},
-  {"horizontal", DMDUP_HORIZONTAL},
-  {"vertical", DMDUP_VERTICAL},
+  {"off", DMDUP_SIMPLEX},
+  {"short", DMDUP_HORIZONTAL},
+  {"long", DMDUP_VERTICAL},
   {NULL, 0}
 };
 
-static void parseDuplex(DEVMODEA *devmode, GooString *mode)
+static void parseDuplex(GooString *mode)
 {
-  int win32Duplex;
   const Win32Option *option = win32DuplexMode;
   while (option->name) {
     if (mode->cmp(option->name) == 0) {
-      win32Duplex = option->value;
-      break;
+      devmode->dmDuplex = option->value;
+      devmode->dmFields |= DM_DUPLEX;
+      return;
     }
+    option++;
   }
-  if (!option->name) {
-    fprintf(stderr, "Warning: Unknown duplex mode \"%s\"\n", mode->getCString());
-    return;
-  }
-
-  devmode->dmDuplex = win32Duplex;
-  devmode->dmFields |= DM_DUPLEX;
+  fprintf(stderr, "Warning: Unknown duplex mode \"%s\"\n", mode->getCString());
 }
 
-static void fillCommonPrinterOptions(DEVMODEA *devmode, double w, double h, GBool duplex)
+static void fillCommonPrinterOptions(double w, double h, GBool duplex)
 {
-  devmode->dmPaperWidth = w * 254.0 / 72.0;
-  devmode->dmPaperLength = h * 254.0 / 72.0;
-  printf("PAPER %d, %d\n", devmode->dmPaperWidth, devmode->dmPaperLength);
-  devmode->dmFields |= DM_PAPERWIDTH | DM_PAPERLENGTH;
   if (duplex) {
     devmode->dmDuplex = DMDUP_HORIZONTAL;
     devmode->dmFields |= DM_DUPLEX;
   }
 }
 
-static void fillPrinterOptions(DEVMODEA *devmode, GBool duplex, GooString *printOpt)
+static void fillPagePrinterOptions(double w, double h)
+{
+  w *= 254.0 / 72.0; // units are 0.1mm
+  h *= 254.0 / 72.0;
+  if (w > h) {
+    devmode->dmOrientation = DMORIENT_LANDSCAPE;
+    devmode->dmPaperWidth = h;
+    devmode->dmPaperLength = w;
+  } else {
+    devmode->dmOrientation = DMORIENT_PORTRAIT;
+    devmode->dmPaperWidth = w;
+    devmode->dmPaperLength = h;
+  }
+  devmode->dmPaperSize = 0;
+  devmode->dmFields |= DM_ORIENTATION | DM_PAPERWIDTH | DM_PAPERLENGTH;
+}
+
+
+static void fillPrinterOptions(GBool duplex, GooString *printOpt)
 {
   //printOpt format is: <opt1>=<val1>,<opt2>=<val2>,...
   const char *nextOpt = printOpt->getCString();
@@ -128,13 +123,12 @@ static void fillPrinterOptions(DEVMODEA *devmode, GBool duplex, GooString *print
     //here opt is "<optN>" and value is "<valN>"
 
     if (opt.cmp("source") == 0) {
-      parseSource(devmode, &value);
+      parseSource(&value);
     } else if (opt.cmp("duplex") == 0) {
-      if (duplex) {
+      if (duplex)
 	fprintf(stderr, "Warning: duplex mode is specified both as standalone and printer options\n");
-      } else {
-	parseDuplex(devmode, &value);
-      }
+      else
+	parseDuplex( &value);
     } else {
       fprintf(stderr, "Warning: unknown printer option \"%s\"\n", opt.getCString());
     }
@@ -147,65 +141,96 @@ cairo_surface_t *win32BeginDocument(GooString *inputFileName, GooString *outputF
 				    GooString *printOpt,
 				    GBool duplex)
 {
-  if (printer->getCString()[0] == 0)
-  {
-    DWORD szName = 0;
-    GetDefaultPrinterA(NULL, &szName);
-    char *devname = (char*)gmalloc(szName);
-    GetDefaultPrinterA(devname, &szName);
-    printer->Set(devname);
-    gfree(devname);
+  if (printer->getCString()[0] == 0) {
+    DWORD size = 0;
+    GetDefaultPrinterA(NULL, &size);
+    printerName = (char*)gmalloc(size);
+    GetDefaultPrinterA(printerName, &size);
+  } else {
+    printerName = gstrndup(printer->getCString(), printer->getLength());
   }
-  char *cPrinter = printer->getCString();
 
   //Query the size of the DEVMODE struct
-  LONG szProp = DocumentPropertiesA(NULL, NULL, cPrinter, NULL, NULL, 0);
-  if (szProp < 0)
-  {
-    fprintf(stderr, "Error: Printer \"%s\" not found", cPrinter);
+  LONG szProp = DocumentPropertiesA(NULL, NULL, printerName, NULL, NULL, 0);
+  if (szProp < 0) {
+    fprintf(stderr, "Error: Printer \"%s\" not found\n", printerName);
     exit(99);
   }
-  DEVMODEA *devmode = (DEVMODEA*)gmalloc(szProp);
+  devmode = (DEVMODEA*)gmalloc(szProp);
   memset(devmode, 0, szProp);
   devmode->dmSize = sizeof(DEVMODEA);
   devmode->dmSpecVersion = DM_SPECVERSION;
   //Load the current default configuration for the printer into devmode
-  if (DocumentPropertiesA(NULL, NULL, cPrinter, devmode, NULL, DM_OUT_BUFFER) < 0)
-  {
-    fprintf(stderr, "Error: Printer \"%s\" not found", cPrinter);
+  if (DocumentPropertiesA(NULL, NULL, printerName, devmode, devmode, DM_OUT_BUFFER) < 0) {
+    fprintf(stderr, "Error: Printer \"%s\" not found\n", printerName);
     exit(99);
   }
-  fillCommonPrinterOptions(devmode, w, h, duplex);
-  fillPrinterOptions(devmode, duplex, printOpt);
-  hdc = CreateDCA(NULL, cPrinter, NULL, devmode);
-  gfree(devmode);
-  if (!hdc)
-  {
-    fprintf(stderr, "Error: Printer \"%s\" not found", cPrinter);
+  fillCommonPrinterOptions(w, h, duplex);
+  fillPrinterOptions(duplex, printOpt);
+  if (DocumentPropertiesA(NULL, NULL, printerName, devmode, devmode, DM_IN_BUFFER | DM_OUT_BUFFER) < 0) {
+    fprintf(stderr, "Error: Printer \"%s\" not found\n", printerName);
+    exit(99);
+  }
+  hdc = CreateDCA(NULL, printerName, NULL, devmode);
+  if (!hdc) {
+    fprintf(stderr, "Error: Printer \"%s\" not found\n", printerName);
     exit(99);
   }
 
   DOCINFOA docinfo;
   memset(&docinfo, 0, sizeof(docinfo));
   docinfo.cbSize = sizeof(docinfo);
-  if (inputFileName->cmp("fd://0") == 0) {
+  if (inputFileName->cmp("fd://0") == 0)
     docinfo.lpszDocName = "pdftocairo <stdin>";
-  } else {
+  else
     docinfo.lpszDocName = inputFileName->getCString();
-  }
-  if (outputFileName) {
+  if (outputFileName)
     docinfo.lpszOutput = outputFileName->getCString();
-  }
   if (StartDocA(hdc, &docinfo) <=0) {
-    fprintf(stderr, "Error: StartDoc failed");
+    fprintf(stderr, "Error: StartDoc failed\n");
     exit(99);
   }
 
   return cairo_win32_printing_surface_create(hdc);
 }
 
-void win32BeginPage(double w, double h)
+void win32BeginPage(double *w, double *h, GBool useFullPage)
 {
+  fillPagePrinterOptions(*w, *h);
+  if (DocumentPropertiesA(NULL, NULL, printerName, devmode, devmode, DM_IN_BUFFER | DM_OUT_BUFFER) < 0) {
+    fprintf(stderr, "Error: Printer \"%s\" not found\n", printerName);
+    exit(99);
+  }
+  ResetDCA(hdc, devmode);
+
+  // Get actual paper size or if useFullPage is false the printable area.
+  // Transform the hdc scale to points to be consistent with other cairo backends
+  int x_dpi = GetDeviceCaps (hdc, LOGPIXELSX);
+  int y_dpi = GetDeviceCaps (hdc, LOGPIXELSY);
+  int x_off = GetDeviceCaps (hdc, PHYSICALOFFSETX);
+  int y_off = GetDeviceCaps (hdc, PHYSICALOFFSETY);
+  if (useFullPage) {
+    *w = GetDeviceCaps (hdc, PHYSICALWIDTH)*72.0/x_dpi;
+    *h = GetDeviceCaps (hdc, PHYSICALHEIGHT)*72.0/y_dpi;
+  } else {
+    *w = GetDeviceCaps (hdc, HORZRES)*72.0/x_dpi;
+    *h = GetDeviceCaps (hdc, VERTRES)*72.0/y_dpi;
+  }
+  XFORM xform;
+  xform.eM11 = x_dpi/72.0;
+  xform.eM12 = 0;
+  xform.eM21 = 0;
+  xform.eM22 = y_dpi/72.0;
+  if (useFullPage) {
+    xform.eDx = -x_off;
+    xform.eDy = -y_off;
+  } else {
+    xform.eDx = 0;
+    xform.eDy = 0;
+  }
+  SetGraphicsMode (hdc, GM_ADVANCED);
+  SetWorldTransform (hdc, &xform);
+
   StartPage(hdc);
 }
 
@@ -218,6 +243,8 @@ void win32EndDocument()
 {
   EndDoc(hdc);
   DeleteDC(hdc);
+  gfree(devmode);
+  gfree(printerName);
 }
 
 #endif // CAIRO_HAS_WIN32_SURFACE
diff --git a/utils/pdftocairo-win32.h b/utils/pdftocairo-win32.h
index 8ecd84c..07e200c 100644
--- a/utils/pdftocairo-win32.h
+++ b/utils/pdftocairo-win32.h
@@ -15,7 +15,7 @@ cairo_surface_t *win32BeginDocument(GooString *inputFileName, GooString *outputF
 				    GooString *printer,
 				    GooString *printOpt,
 				    GBool duplex);
-void win32BeginPage(double w, double h);
+void win32BeginPage(double *w, double *h, GBool useFullPage);
 void win32EndPage(GooString *imageFileName);
 void win32EndDocument();
 
diff --git a/utils/pdftocairo.1 b/utils/pdftocairo.1
index 8725722..00d93c4 100644
--- a/utils/pdftocairo.1
+++ b/utils/pdftocairo.1
@@ -268,7 +268,10 @@ Selects the source paper tray to be used (bin). The possible values are "upper",
 "envmanual", "auto", "tractor", "smallfmt", "largefmt", "largecapacity", "formsource", or a numeric value to choose a driver specific source.
 .TP
 .BI duplex
-Sets the duplex mode of the printer. It can be "simplex", "horizontal" or "vertical". General option \-duplex is a synonym of "duplex=horizontal". If both are specified, the \-printopt one has priority.
+Sets the duplex mode of the printer. The possible values are "off", "short" or "long",
+indicating no duplexing, short-edge binding, or long-edge binding, respectively.
+General option \-duplex is a synonym of "duplex=long". If both options are specified,
+\-printopt has priority.
 .SH AUTHOR
 The pdftocairo software and documentation are copyright 1996-2004 Glyph
 & Cog, LLC and copyright 2005-2011 The Poppler Developers.
diff --git a/utils/pdftocairo.cc b/utils/pdftocairo.cc
index aa76226..b0a689e 100644
--- a/utils/pdftocairo.cc
+++ b/utils/pdftocairo.cc
@@ -79,7 +79,7 @@ static GBool jpeg = gFalse;
 static GBool ps = gFalse;
 static GBool eps = gFalse;
 static GBool pdf = gFalse;
-static GBool print = gFalse;
+static GBool printToWin32 = gFalse;
 static GBool svg = gFalse;
 static GBool tiff = gFalse;
 
@@ -159,7 +159,7 @@ static const ArgDesc argDesc[] = {
    "generate a Scalable Vector Graphics (SVG) file"},
 #endif
 #ifdef CAIRO_HAS_WIN32_SURFACE
-  {"-print",    argFlag,     &print,       0,
+  {"-print",    argFlag,     &printToWin32,       0,
    "print to a Windows printer"},
   {"-printer",  argGooString, &printer,    0,
    "printer name or use default if this option is not specified"},
@@ -483,10 +483,6 @@ static void getFitToPageTransform(double page_w, double page_h,
       // shrink to fit
       cairo_matrix_scale (m, scale, scale);
     }
-#ifdef CAIRO_HAS_WIN32_SURFACE
-  if (print)
-    win32GetFitToPageTransform(m);
-#endif
 }
 
 static cairo_status_t writeStream(void *closure, const unsigned char *data, unsigned int length)
@@ -502,7 +498,9 @@ static cairo_status_t writeStream(void *closure, const unsigned char *data, unsi
 static void beginDocument(GooString *inputFileName, GooString *outputFileName, double w, double h)
 {
   if (printing) {
-    if (!print) {
+    if (printToWin32) {
+      output_file = NULL;
+    } else {
       if (outputFileName->cmp("fd://0") == 0)
         output_file = stdout;
       else
@@ -540,41 +538,41 @@ static void beginDocument(GooString *inputFileName, GooString *outputFileName, d
 #endif
     }
 #ifdef CAIRO_HAS_WIN32_SURFACE
-    if (print)
+    if (printToWin32)
       surface = win32BeginDocument(inputFileName, outputFileName, w, h, &printer, &printOpt, duplex);
 #endif
   }
 }
 
-static void beginPage(double w, double h)
+static void beginPage(double *w, double *h)
 {
   if (printing) {
     if (ps || eps) {
 #if CAIRO_HAS_PS_SURFACE
-      if (w > h) {
+      if (*w > *h) {
 	cairo_ps_surface_dsc_comment (surface, "%%PageOrientation: Landscape");
-	cairo_ps_surface_set_size (surface, h, w);
+	cairo_ps_surface_set_size (surface, *h, *w);
       } else {
 	cairo_ps_surface_dsc_comment (surface, "%%PageOrientation: Portrait");
-	cairo_ps_surface_set_size (surface, w, h);
+	cairo_ps_surface_set_size (surface, *w, *h);
       }
 #endif
     }
 
 #if CAIRO_HAS_PDF_SURFACE
     if (pdf)
-      cairo_pdf_surface_set_size (surface, w, h);
+      cairo_pdf_surface_set_size (surface, *w, *h);
 #endif
 
 #ifdef CAIRO_HAS_WIN32_SURFACE
-    if (print)
-      win32BeginPage(w, h);
+    if (printToWin32)
+      win32BeginPage(w, h, noShrink); // w,h will be changed to actual size used
 #endif
 
     cairo_surface_set_fallback_resolution (surface, x_resolution, y_resolution);
 
   } else {
-    surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, ceil(w), ceil(h));
+    surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, ceil(*w), ceil(*h));
   }
 }
 
@@ -642,7 +640,7 @@ static void endPage(GooString *imageFileName)
     cairo_surface_show_page(surface);
 
 #ifdef CAIRO_HAS_WIN32_SURFACE
-    if (print)
+    if (printToWin32)
       win32EndPage(imageFileName);
 #endif
 
@@ -662,15 +660,15 @@ static void endDocument()
   cairo_status_t status;
 
   if (printing) {
-#ifdef CAIRO_HAS_WIN32_SURFACE
-    if (print)
-      win32EndDocument();
-#endif
     cairo_surface_finish(surface);
     status = cairo_surface_status(surface);
     if (status)
       error(errInternal, -1, "cairo error: {0:s}\n", cairo_status_to_string(status));
     cairo_surface_destroy(surface);
+#ifdef CAIRO_HAS_WIN32_SURFACE
+    if (printToWin32)
+      win32EndDocument();
+#endif
     if (output_file)
       fclose(output_file);
   }
@@ -737,7 +735,7 @@ static GooString *getOutputFileName(GooString *fileName, GooString *outputName)
 
   if (outputName) {
     if (outputName->cmp("-") == 0) {
-      if (print || (!printing && !singleFile)) {
+      if (printToWin32 || (!printing && !singleFile)) {
 	fprintf(stderr, "Error: stdout may only be used with the ps, eps, pdf, svg output options or if -singlefile is used.\n");
 	exit(99);
       }
@@ -746,9 +744,8 @@ static GooString *getOutputFileName(GooString *fileName, GooString *outputName)
     return new GooString(outputName);
   }
 
-  if (print) {
+  if (printToWin32)
     return NULL; // No output file means print to printer
-  }
 
   if (fileName->cmp("fd://0") == 0) {
     fprintf(stderr, "Error: an output filename or '-' must be supplied when the PDF file is stdin.\n");
@@ -853,7 +850,7 @@ int main(int argc, char *argv[]) {
                 (ps ? 1 : 0) +
                 (eps ? 1 : 0) +
                 (pdf ? 1 : 0) +
-                (print ? 1 : 0) +
+                (printToWin32 ? 1 : 0) +
                 (svg ? 1 : 0);
   if (num_outputs == 0) {
     fprintf(stderr, "Error: one of the output format options (-png, -jpeg, -ps, -eps, -pdf, -print, -svg) must be used.\n");
@@ -1098,7 +1095,7 @@ int main(int argc, char *argv[]) {
 
     if (pg == firstPage)
       beginDocument(fileName, outputFileName, output_w, output_h);
-    beginPage(output_w, output_h);
+    beginPage(&output_w, &output_h);
     renderPage(doc, cairoOut, pg, pg_w, pg_h, output_w, output_h);
     endPage(imageFileName);
   }
commit cc3b39d49c656e912a7461212f3bb4e58c6444e7
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Fri Sep 12 18:17:49 2014 +0930

    make pdftocairo-win32.cc a standalone .cc file
    
    instead of #including it in pdftocairo.cc

diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt
index 2f04b39..9c16018 100644
--- a/utils/CMakeLists.txt
+++ b/utils/CMakeLists.txt
@@ -21,6 +21,7 @@ if (HAVE_CAIRO)
   # pdftocairo
   set(pdftocairo_SOURCES ${common_srcs}
     pdftocairo.cc
+    pdftocairo-win32.cc
     ${CMAKE_SOURCE_DIR}/poppler/CairoFontEngine.cc
     ${CMAKE_SOURCE_DIR}/poppler/CairoOutputDev.cc
     ${CMAKE_SOURCE_DIR}/poppler/CairoRescaleBox.cc
diff --git a/utils/Makefile.am b/utils/Makefile.am
index bc0a549..7a5ab4d 100644
--- a/utils/Makefile.am
+++ b/utils/Makefile.am
@@ -107,7 +107,8 @@ pdftoppm_SOURCES =				\
 	pdftoppm.cc
 
 pdftocairo_SOURCES =				\
-	pdftocairo.cc
+	pdftocairo.cc				\
+	pdftocairo-win32.cc
 
 if BUILD_CAIRO_OUTPUT
 if USE_CMS
diff --git a/utils/pdftocairo-win32.cc b/utils/pdftocairo-win32.cc
index 195e6ad..7ad5615 100644
--- a/utils/pdftocairo-win32.cc
+++ b/utils/pdftocairo-win32.cc
@@ -1,11 +1,15 @@
+#include <cairo.h>
+#ifdef CAIRO_HAS_WIN32_SURFACE
+
 #include <cairo-win32.h>
 
-static void win32GetFitToPageTransform(cairo_matrix_t *m)
-{
-  if (!print)
-    return;
+#include "parseargs.h"
+#include "pdftocairo-win32.h"
+
+static HDC hdc;
 
-  HDC hdc = cairo_win32_surface_get_dc(surface);
+void win32GetFitToPageTransform(cairo_matrix_t *m)
+{
   int logx = GetDeviceCaps(hdc, LOGPIXELSX);
   int logy = GetDeviceCaps(hdc, LOGPIXELSY);
   cairo_matrix_scale (m, logx / 72.0, logy / 72.0);
@@ -68,9 +72,6 @@ static const Win32Option win32DuplexMode[] =
 
 static void parseDuplex(DEVMODEA *devmode, GooString *mode)
 {
-  if (duplex)
-    fprintf(stderr, "Warning: duplex mode is specified both as standalone and printer options\n");
-
   int win32Duplex;
   const Win32Option *option = win32DuplexMode;
   while (option->name) {
@@ -88,7 +89,7 @@ static void parseDuplex(DEVMODEA *devmode, GooString *mode)
   devmode->dmFields |= DM_DUPLEX;
 }
 
-static void fillCommonPrinterOptions(DEVMODEA *devmode, double w, double h)
+static void fillCommonPrinterOptions(DEVMODEA *devmode, double w, double h, GBool duplex)
 {
   devmode->dmPaperWidth = w * 254.0 / 72.0;
   devmode->dmPaperLength = h * 254.0 / 72.0;
@@ -100,10 +101,10 @@ static void fillCommonPrinterOptions(DEVMODEA *devmode, double w, double h)
   }
 }
 
-static void fillPrinterOptions(DEVMODEA *devmode)
+static void fillPrinterOptions(DEVMODEA *devmode, GBool duplex, GooString *printOpt)
 {
   //printOpt format is: <opt1>=<val1>,<opt2>=<val2>,...
-  const char *nextOpt = printOpt.getCString();
+  const char *nextOpt = printOpt->getCString();
   while (nextOpt && *nextOpt)
   {
     const char *comma = strchr(nextOpt, ',');
@@ -129,28 +130,33 @@ static void fillPrinterOptions(DEVMODEA *devmode)
     if (opt.cmp("source") == 0) {
       parseSource(devmode, &value);
     } else if (opt.cmp("duplex") == 0) {
-      parseDuplex(devmode, &value);
+      if (duplex) {
+	fprintf(stderr, "Warning: duplex mode is specified both as standalone and printer options\n");
+      } else {
+	parseDuplex(devmode, &value);
+      }
     } else {
       fprintf(stderr, "Warning: unknown printer option \"%s\"\n", opt.getCString());
     }
   }
 }
 
-static void win32BeginDocument(GooString *inputFileName, GooString *outputFileName, double w, double h)
+cairo_surface_t *win32BeginDocument(GooString *inputFileName, GooString *outputFileName,
+				    double w, double h,
+				    GooString *printer,
+				    GooString *printOpt,
+				    GBool duplex)
 {
-  if (!print)
-    return;
-
-  if (printer.getCString()[0] == 0)
+  if (printer->getCString()[0] == 0)
   {
     DWORD szName = 0;
     GetDefaultPrinterA(NULL, &szName);
     char *devname = (char*)gmalloc(szName);
     GetDefaultPrinterA(devname, &szName);
-    printer.Set(devname);
+    printer->Set(devname);
     gfree(devname);
   }
-  char *cPrinter = printer.getCString();
+  char *cPrinter = printer->getCString();
 
   //Query the size of the DEVMODE struct
   LONG szProp = DocumentPropertiesA(NULL, NULL, cPrinter, NULL, NULL, 0);
@@ -169,9 +175,9 @@ static void win32BeginDocument(GooString *inputFileName, GooString *outputFileNa
     fprintf(stderr, "Error: Printer \"%s\" not found", cPrinter);
     exit(99);
   }
-  fillCommonPrinterOptions(devmode, w, h);
-  fillPrinterOptions(devmode);
-  HDC hdc = CreateDCA(NULL, cPrinter, NULL, devmode);
+  fillCommonPrinterOptions(devmode, w, h, duplex);
+  fillPrinterOptions(devmode, duplex, printOpt);
+  hdc = CreateDCA(NULL, cPrinter, NULL, devmode);
   gfree(devmode);
   if (!hdc)
   {
@@ -194,30 +200,24 @@ static void win32BeginDocument(GooString *inputFileName, GooString *outputFileNa
     fprintf(stderr, "Error: StartDoc failed");
     exit(99);
   }
-    
-  surface = cairo_win32_printing_surface_create(hdc);
+
+  return cairo_win32_printing_surface_create(hdc);
 }
 
-static void win32BeginPage(double w, double h)
+void win32BeginPage(double w, double h)
 {
-  if (!print)
-    return;
-  StartPage(cairo_win32_surface_get_dc(surface));
+  StartPage(hdc);
 }
 
-static void win32EndPage(GooString *imageFileName)
+void win32EndPage(GooString *imageFileName)
 {
-  if (!print)
-    return;
-  EndPage(cairo_win32_surface_get_dc(surface));
+  EndPage(hdc);
 }
 
-static void win32EndDocument()
+void win32EndDocument()
 {
-  if (!print)
-    return;
-
-  HDC hdc = cairo_win32_surface_get_dc(surface);
   EndDoc(hdc);
   DeleteDC(hdc);
 }
+
+#endif // CAIRO_HAS_WIN32_SURFACE
diff --git a/utils/pdftocairo-win32.h b/utils/pdftocairo-win32.h
new file mode 100644
index 0000000..8ecd84c
--- /dev/null
+++ b/utils/pdftocairo-win32.h
@@ -0,0 +1,22 @@
+#include <cairo.h>
+#include "goo/gmem.h"
+#include "goo/gtypes.h"
+#include "goo/gtypes_p.h"
+#include "goo/GooString.h"
+
+
+#ifdef CAIRO_HAS_WIN32_SURFACE
+
+#include <cairo-win32.h>
+
+void win32GetFitToPageTransform(cairo_matrix_t *m);
+cairo_surface_t *win32BeginDocument(GooString *inputFileName, GooString *outputFileName,
+				    double w, double h,
+				    GooString *printer,
+				    GooString *printOpt,
+				    GBool duplex);
+void win32BeginPage(double w, double h);
+void win32EndPage(GooString *imageFileName);
+void win32EndDocument();
+
+#endif // CAIRO_HAS_WIN32_SURFACE
diff --git a/utils/pdftocairo.cc b/utils/pdftocairo.cc
index 65d7c23..aa76226 100644
--- a/utils/pdftocairo.cc
+++ b/utils/pdftocairo.cc
@@ -71,6 +71,8 @@
 #include <cairo-svg.h>
 #endif
 
+#include "pdftocairo-win32.h"
+
 
 static GBool png = gFalse;
 static GBool jpeg = gFalse;
@@ -267,10 +269,6 @@ static int icc_data_size;
 static cmsHPROFILE profile;
 #endif
 
-#ifdef CAIRO_HAS_WIN32_SURFACE
-#include "pdftocairo-win32.cc"
-#endif
-
 void writePageImage(GooString *filename)
 {
   ImgWriter *writer = 0;
@@ -486,7 +484,8 @@ static void getFitToPageTransform(double page_w, double page_h,
       cairo_matrix_scale (m, scale, scale);
     }
 #ifdef CAIRO_HAS_WIN32_SURFACE
-  win32GetFitToPageTransform(m);
+  if (print)
+    win32GetFitToPageTransform(m);
 #endif
 }
 
@@ -541,7 +540,8 @@ static void beginDocument(GooString *inputFileName, GooString *outputFileName, d
 #endif
     }
 #ifdef CAIRO_HAS_WIN32_SURFACE
-    win32BeginDocument(inputFileName, outputFileName, w, h);
+    if (print)
+      surface = win32BeginDocument(inputFileName, outputFileName, w, h, &printer, &printOpt, duplex);
 #endif
   }
 }
@@ -565,8 +565,10 @@ static void beginPage(double w, double h)
     if (pdf)
       cairo_pdf_surface_set_size (surface, w, h);
 #endif
+
 #ifdef CAIRO_HAS_WIN32_SURFACE
-    win32BeginPage(w, h);
+    if (print)
+      win32BeginPage(w, h);
 #endif
 
     cairo_surface_set_fallback_resolution (surface, x_resolution, y_resolution);
@@ -638,9 +640,12 @@ static void endPage(GooString *imageFileName)
 
   if (printing) {
     cairo_surface_show_page(surface);
+
 #ifdef CAIRO_HAS_WIN32_SURFACE
-    win32EndPage(imageFileName);
+    if (print)
+      win32EndPage(imageFileName);
 #endif
+
   } else {
     writePageImage(imageFileName);
     cairo_surface_finish(surface);
@@ -658,7 +663,8 @@ static void endDocument()
 
   if (printing) {
 #ifdef CAIRO_HAS_WIN32_SURFACE
-    win32EndDocument();
+    if (print)
+      win32EndDocument();
 #endif
     cairo_surface_finish(surface);
     status = cairo_surface_status(surface);
commit 700205af19ef1ae5f2c713d118ebd5dd4a0afba3
Author: Adrian Johnson <ajohnson at redneon.com>
Date:   Sun Sep 7 20:18:36 2014 +0930

    pdftocairo: Allow an output file for win32 printing to be specified
    
    Can be used for testing win32 print output without wasting paper.

diff --git a/utils/pdftocairo-win32.cc b/utils/pdftocairo-win32.cc
index 515ffa7..195e6ad 100644
--- a/utils/pdftocairo-win32.cc
+++ b/utils/pdftocairo-win32.cc
@@ -136,7 +136,7 @@ static void fillPrinterOptions(DEVMODEA *devmode)
   }
 }
 
-static void win32BeginDocument(GooString *outputFileName, double w, double h)
+static void win32BeginDocument(GooString *inputFileName, GooString *outputFileName, double w, double h)
 {
   if (!print)
     return;
@@ -182,10 +182,14 @@ static void win32BeginDocument(GooString *outputFileName, double w, double h)
   DOCINFOA docinfo;
   memset(&docinfo, 0, sizeof(docinfo));
   docinfo.cbSize = sizeof(docinfo);
-  if (outputFileName->cmp("fd://0") == 0)
+  if (inputFileName->cmp("fd://0") == 0) {
     docinfo.lpszDocName = "pdftocairo <stdin>";
-  else
-    docinfo.lpszDocName = outputFileName->getCString();
+  } else {
+    docinfo.lpszDocName = inputFileName->getCString();
+  }
+  if (outputFileName) {
+    docinfo.lpszOutput = outputFileName->getCString();
+  }
   if (StartDocA(hdc, &docinfo) <=0) {
     fprintf(stderr, "Error: StartDoc failed");
     exit(99);
diff --git a/utils/pdftocairo.1 b/utils/pdftocairo.1
index 7747409..8725722 100644
--- a/utils/pdftocairo.1
+++ b/utils/pdftocairo.1
@@ -23,6 +23,8 @@ PostScript (PS)
 Encapsulated PostScript (EPS)
 .IP \(bu
 Scalable Vector Graphics (SVG)
+.IP \(bu
+Windows Printer
 .PP
 .B pdftocairo
 reads the PDF file,
@@ -82,6 +84,8 @@ Generates a PDF file
 .TP
 .BI \-print
 (Windows only) Prints to a system printer. See also \-printer and \-printeropt.
+ If an output file is not specified, the output will be sent to the printer.
+ The output file '-' can not be used with this option.
 .TP
 .BI \-ps
 Generate a PS file
diff --git a/utils/pdftocairo.cc b/utils/pdftocairo.cc
index 79d71d9..65d7c23 100644
--- a/utils/pdftocairo.cc
+++ b/utils/pdftocairo.cc
@@ -500,7 +500,7 @@ static cairo_status_t writeStream(void *closure, const unsigned char *data, unsi
     return CAIRO_STATUS_WRITE_ERROR;
 }
 
-static void beginDocument(GooString *outputFileName, double w, double h)
+static void beginDocument(GooString *inputFileName, GooString *outputFileName, double w, double h)
 {
   if (printing) {
     if (!print) {
@@ -541,7 +541,7 @@ static void beginDocument(GooString *outputFileName, double w, double h)
 #endif
     }
 #ifdef CAIRO_HAS_WIN32_SURFACE
-    win32BeginDocument(outputFileName, w, h);
+    win32BeginDocument(inputFileName, outputFileName, w, h);
 #endif
   }
 }
@@ -731,7 +731,7 @@ static GooString *getOutputFileName(GooString *fileName, GooString *outputName)
 
   if (outputName) {
     if (outputName->cmp("-") == 0) {
-      if (!printing && !singleFile) {
+      if (print || (!printing && !singleFile)) {
 	fprintf(stderr, "Error: stdout may only be used with the ps, eps, pdf, svg output options or if -singlefile is used.\n");
 	exit(99);
       }
@@ -740,8 +740,9 @@ static GooString *getOutputFileName(GooString *fileName, GooString *outputName)
     return new GooString(outputName);
   }
 
-  if (print)
-    return fileName; //it will be used as the job name
+  if (print) {
+    return NULL; // No output file means print to printer
+  }
 
   if (fileName->cmp("fd://0") == 0) {
     fprintf(stderr, "Error: an output filename or '-' must be supplied when the PDF file is stdin.\n");
@@ -1090,7 +1091,7 @@ int main(int argc, char *argv[]) {
     getOutputSize(pg_w, pg_h, &output_w, &output_h);
 
     if (pg == firstPage)
-      beginDocument(outputFileName, output_w, output_h);
+      beginDocument(fileName, outputFileName, output_w, output_h);
     beginPage(output_w, output_h);
     renderPage(doc, cairoOut, pg, pg_w, pg_h, output_w, output_h);
     endPage(imageFileName);
commit 40d3ae87befad489fd8c0b38ff2561a0782cae0b
Author: Rodrigo Rivas Costa <rodrigorivascosta at gmail.com>
Date:   Sat Sep 6 21:04:10 2014 +0930

    Add support for printing to a Windows printer from pdftocairo
    
    Bug 79936

diff --git a/configure.ac b/configure.ac
index 7a34f82..10a4b39 100644
--- a/configure.ac
+++ b/configure.ac
@@ -48,7 +48,7 @@ case "$host_os" in
   ;;
   mingw*)
     os_win32=yes
-    win32_libs="-lgdi32"
+    win32_libs="-lgdi32 -lwinspool"
     create_shared_lib="-no-undefined"
     auto_import_flags="-Wl,--enable-auto-import"
 
diff --git a/utils/pdftocairo-win32.cc b/utils/pdftocairo-win32.cc
new file mode 100644
index 0000000..515ffa7
--- /dev/null
+++ b/utils/pdftocairo-win32.cc
@@ -0,0 +1,219 @@
+#include <cairo-win32.h>
+
+static void win32GetFitToPageTransform(cairo_matrix_t *m)
+{
+  if (!print)
+    return;
+
+  HDC hdc = cairo_win32_surface_get_dc(surface);
+  int logx = GetDeviceCaps(hdc, LOGPIXELSX);
+  int logy = GetDeviceCaps(hdc, LOGPIXELSY);
+  cairo_matrix_scale (m, logx / 72.0, logy / 72.0);
+}
+
+struct Win32Option
+{
+  const char *name;
+  int value;
+};
+
+static const Win32Option win32PaperSource[] =
+{
+  {"upper", DMBIN_UPPER},
+  {"onlyone", DMBIN_ONLYONE},
+  {"lower", DMBIN_LOWER},
+  {"middle", DMBIN_MIDDLE},
+  {"manual", DMBIN_MANUAL},
+  {"envelope", DMBIN_ENVELOPE},
+  {"envmanual", DMBIN_ENVMANUAL},
+  {"auto", DMBIN_AUTO},
+  {"tractor", DMBIN_TRACTOR},
+  {"smallfmt", DMBIN_SMALLFMT},
+  {"largefmt", DMBIN_LARGEFMT},
+  {"largecapacity", DMBIN_LARGECAPACITY},
+  {"formsource", DMBIN_FORMSOURCE},
+  {NULL, 0}
+};
+
+static void parseSource(DEVMODEA *devmode, GooString *source)
+{
+  int src;
+  const Win32Option *option = win32PaperSource;
+  while (option->name) {
+    if (source->cmp(option->name) == 0) {
+      src = option->value;
+      break;
+    }
+  }
+  if (!option->name) {
+    if (isInt(source->getCString())) {
+      src = atoi(source->getCString());
+    } else {
+      fprintf(stderr, "Warning: Unknown paper source \"%s\"\n", source->getCString());
+      return;
+    }
+  }
+
+  devmode->dmDefaultSource = src;
+  devmode->dmFields |= DM_DEFAULTSOURCE;
+}
+
+static const Win32Option win32DuplexMode[] =
+{
+  {"simplex", DMDUP_SIMPLEX},
+  {"horizontal", DMDUP_HORIZONTAL},
+  {"vertical", DMDUP_VERTICAL},
+  {NULL, 0}
+};
+
+static void parseDuplex(DEVMODEA *devmode, GooString *mode)
+{
+  if (duplex)
+    fprintf(stderr, "Warning: duplex mode is specified both as standalone and printer options\n");
+
+  int win32Duplex;
+  const Win32Option *option = win32DuplexMode;
+  while (option->name) {
+    if (mode->cmp(option->name) == 0) {
+      win32Duplex = option->value;
+      break;
+    }
+  }
+  if (!option->name) {
+    fprintf(stderr, "Warning: Unknown duplex mode \"%s\"\n", mode->getCString());
+    return;
+  }
+
+  devmode->dmDuplex = win32Duplex;
+  devmode->dmFields |= DM_DUPLEX;
+}
+
+static void fillCommonPrinterOptions(DEVMODEA *devmode, double w, double h)
+{
+  devmode->dmPaperWidth = w * 254.0 / 72.0;
+  devmode->dmPaperLength = h * 254.0 / 72.0;
+  printf("PAPER %d, %d\n", devmode->dmPaperWidth, devmode->dmPaperLength);
+  devmode->dmFields |= DM_PAPERWIDTH | DM_PAPERLENGTH;
+  if (duplex) {
+    devmode->dmDuplex = DMDUP_HORIZONTAL;
+    devmode->dmFields |= DM_DUPLEX;
+  }
+}
+
+static void fillPrinterOptions(DEVMODEA *devmode)
+{
+  //printOpt format is: <opt1>=<val1>,<opt2>=<val2>,...
+  const char *nextOpt = printOpt.getCString();
+  while (nextOpt && *nextOpt)
+  {
+    const char *comma = strchr(nextOpt, ',');
+    GooString opt;
+    if (comma) {
+      opt.Set(nextOpt, comma - nextOpt);
+      nextOpt = comma + 1;
+    } else {
+      opt.Set(nextOpt);
+      nextOpt = NULL;
+    }
+    //here opt is "<optN>=<valN> "
+    const char *equal = strchr(opt.getCString(), '=');
+    if (!equal) {
+      fprintf(stderr, "Warning: unknown printer option \"%s\"\n", opt.getCString());
+      continue;
+    }
+    int iequal = equal - opt.getCString();
+    GooString value(&opt, iequal + 1, opt.getLength() - iequal - 1);
+    opt.del(iequal, opt.getLength() - iequal);
+    //here opt is "<optN>" and value is "<valN>"
+
+    if (opt.cmp("source") == 0) {
+      parseSource(devmode, &value);
+    } else if (opt.cmp("duplex") == 0) {
+      parseDuplex(devmode, &value);
+    } else {
+      fprintf(stderr, "Warning: unknown printer option \"%s\"\n", opt.getCString());
+    }
+  }
+}
+
+static void win32BeginDocument(GooString *outputFileName, double w, double h)
+{
+  if (!print)
+    return;
+
+  if (printer.getCString()[0] == 0)
+  {
+    DWORD szName = 0;
+    GetDefaultPrinterA(NULL, &szName);
+    char *devname = (char*)gmalloc(szName);
+    GetDefaultPrinterA(devname, &szName);
+    printer.Set(devname);
+    gfree(devname);
+  }
+  char *cPrinter = printer.getCString();
+
+  //Query the size of the DEVMODE struct
+  LONG szProp = DocumentPropertiesA(NULL, NULL, cPrinter, NULL, NULL, 0);
+  if (szProp < 0)
+  {
+    fprintf(stderr, "Error: Printer \"%s\" not found", cPrinter);
+    exit(99);
+  }
+  DEVMODEA *devmode = (DEVMODEA*)gmalloc(szProp);
+  memset(devmode, 0, szProp);
+  devmode->dmSize = sizeof(DEVMODEA);
+  devmode->dmSpecVersion = DM_SPECVERSION;
+  //Load the current default configuration for the printer into devmode
+  if (DocumentPropertiesA(NULL, NULL, cPrinter, devmode, NULL, DM_OUT_BUFFER) < 0)
+  {
+    fprintf(stderr, "Error: Printer \"%s\" not found", cPrinter);
+    exit(99);
+  }
+  fillCommonPrinterOptions(devmode, w, h);
+  fillPrinterOptions(devmode);
+  HDC hdc = CreateDCA(NULL, cPrinter, NULL, devmode);
+  gfree(devmode);
+  if (!hdc)
+  {
+    fprintf(stderr, "Error: Printer \"%s\" not found", cPrinter);
+    exit(99);
+  }
+
+  DOCINFOA docinfo;
+  memset(&docinfo, 0, sizeof(docinfo));
+  docinfo.cbSize = sizeof(docinfo);
+  if (outputFileName->cmp("fd://0") == 0)
+    docinfo.lpszDocName = "pdftocairo <stdin>";
+  else
+    docinfo.lpszDocName = outputFileName->getCString();
+  if (StartDocA(hdc, &docinfo) <=0) {
+    fprintf(stderr, "Error: StartDoc failed");
+    exit(99);
+  }
+    
+  surface = cairo_win32_printing_surface_create(hdc);
+}
+
+static void win32BeginPage(double w, double h)
+{
+  if (!print)
+    return;
+  StartPage(cairo_win32_surface_get_dc(surface));
+}
+
+static void win32EndPage(GooString *imageFileName)
+{
+  if (!print)
+    return;
+  EndPage(cairo_win32_surface_get_dc(surface));
+}
+
+static void win32EndDocument()
+{
+  if (!print)
+    return;
+
+  HDC hdc = cairo_win32_surface_get_dc(surface);
+  EndDoc(hdc);
+  DeleteDC(hdc);
+}
diff --git a/utils/pdftocairo.1 b/utils/pdftocairo.1
index c903ffa..7747409 100644
--- a/utils/pdftocairo.1
+++ b/utils/pdftocairo.1
@@ -48,7 +48,7 @@ is not used, the output filename will be derived from the
 .IR PDF-file
 filename.
 .PP
-Not all options are valid with all output formats. One (and only one) of the output format options (\-png, \-jpeg, \-tiff, \-pdf, \-ps, \-eps, or \-svg) must be used.
+Not all options are valid with all output formats. One (and only one) of the output format options (\-png, \-jpeg, \-tiff, \-pdf, \-print, \-ps, \-eps, or \-svg) must be used.
 .PP
 The resolution options (\-r, \-rx, \-ry) set the resolution of the
 image output formats. The image dimensions will depend on the PDF page
@@ -80,6 +80,9 @@ Generates a TIFF file(s)
 .BI \-pdf
 Generates a PDF file
 .TP
+.BI \-print
+(Windows only) Prints to a system printer. See also \-printer and \-printeropt.
+.TP
 .BI \-ps
 Generate a PS file
 .TP
@@ -205,6 +208,14 @@ lower-left corner of the paper instead (PS,PDF,SVG only).
 Adds the %%IncludeFeature: *Duplex DuplexNoTumble DSC comment to the
 PostScript file (PS only).  This tells the print manager to enable duplexing.
 .TP
+.BI \-printer " printer-name"
+(Windows only). When used with \-print, specifies the name of the printer to be used, instead of the system default.
+.TP
+.BI \-printopt " printer-options"
+(Windows only). When used with \-print, takes a list of options to be used to configure the printer. See
+.B WINDOWS PRINTER OPTIONS
+for the available options.
+.TP
 .BI \-opw " password"
 Specify the owner password for the PDF file.  Providing this will
 bypass all security restrictions.
@@ -244,6 +255,16 @@ Error related to ICC profile.
 .TP
 99
 Other error.
+.SH WINDOWS PRINTER OPTIONS
+In Windows, you can use the \-print option to print directly to a system printer. Additionally, you can use the \-printopt 
+option to configure the printer. It takes a string of the form "<opt>=<val>[,<opt>=<val>]". Currently the available options are:
+.TP
+.BI source
+Selects the source paper tray to be used (bin). The possible values are "upper", "onlyone", "lower", "middle", "manual", "envelope",
+"envmanual", "auto", "tractor", "smallfmt", "largefmt", "largecapacity", "formsource", or a numeric value to choose a driver specific source.
+.TP
+.BI duplex
+Sets the duplex mode of the printer. It can be "simplex", "horizontal" or "vertical". General option \-duplex is a synonym of "duplex=horizontal". If both are specified, the \-printopt one has priority.
 .SH AUTHOR
 The pdftocairo software and documentation are copyright 1996-2004 Glyph
 & Cog, LLC and copyright 2005-2011 The Poppler Developers.
diff --git a/utils/pdftocairo.cc b/utils/pdftocairo.cc
index b3f57b6..79d71d9 100644
--- a/utils/pdftocairo.cc
+++ b/utils/pdftocairo.cc
@@ -77,6 +77,7 @@ static GBool jpeg = gFalse;
 static GBool ps = gFalse;
 static GBool eps = gFalse;
 static GBool pdf = gFalse;
+static GBool print = gFalse;
 static GBool svg = gFalse;
 static GBool tiff = gFalse;
 
@@ -121,6 +122,11 @@ static GBool quiet = gFalse;
 static GBool printVersion = gFalse;
 static GBool printHelp = gFalse;
 
+#ifdef CAIRO_HAS_WIN32_SURFACE
+static GooString printer;
+static GooString printOpt;
+#endif
+
 static const ArgDesc argDesc[] = {
 #if ENABLE_LIBPNG
   {"-png",    argFlag,     &png,           0,
@@ -150,6 +156,14 @@ static const ArgDesc argDesc[] = {
   {"-svg",    argFlag,     &svg,           0,
    "generate a Scalable Vector Graphics (SVG) file"},
 #endif
+#ifdef CAIRO_HAS_WIN32_SURFACE
+  {"-print",    argFlag,     &print,       0,
+   "print to a Windows printer"},
+  {"-printer",  argGooString, &printer,    0,
+   "printer name or use default if this option is not specified"},
+  {"-printopt",  argGooString, &printOpt,    0,
+   "printer options, with format <opt1>=<val1>[,<optN>=<valN>]*"},
+#endif
 
   {"-f",      argInt,      &firstPage,     0,
    "first page to print"},
@@ -253,6 +267,9 @@ static int icc_data_size;
 static cmsHPROFILE profile;
 #endif
 
+#ifdef CAIRO_HAS_WIN32_SURFACE
+#include "pdftocairo-win32.cc"
+#endif
 
 void writePageImage(GooString *filename)
 {
@@ -468,6 +485,9 @@ static void getFitToPageTransform(double page_w, double page_h,
       // shrink to fit
       cairo_matrix_scale (m, scale, scale);
     }
+#ifdef CAIRO_HAS_WIN32_SURFACE
+  win32GetFitToPageTransform(m);
+#endif
 }
 
 static cairo_status_t writeStream(void *closure, const unsigned char *data, unsigned int length)
@@ -483,14 +503,16 @@ static cairo_status_t writeStream(void *closure, const unsigned char *data, unsi
 static void beginDocument(GooString *outputFileName, double w, double h)
 {
   if (printing) {
-    if (outputFileName->cmp("fd://0") == 0)
-      output_file = stdout;
-    else
-    {
-      output_file = fopen(outputFileName->getCString(), "wb");
-      if (!output_file) {
-        fprintf(stderr, "Error opening output file %s\n", outputFileName->getCString());
-        exit(2);
+    if (!print) {
+      if (outputFileName->cmp("fd://0") == 0)
+        output_file = stdout;
+      else
+      {
+        output_file = fopen(outputFileName->getCString(), "wb");
+        if (!output_file) {
+          fprintf(stderr, "Error opening output file %s\n", outputFileName->getCString());
+          exit(2);
+        }
       }
     }
 
@@ -518,6 +540,9 @@ static void beginDocument(GooString *outputFileName, double w, double h)
       cairo_svg_surface_restrict_to_version (surface, CAIRO_SVG_VERSION_1_2);
 #endif
     }
+#ifdef CAIRO_HAS_WIN32_SURFACE
+    win32BeginDocument(outputFileName, w, h);
+#endif
   }
 }
 
@@ -540,6 +565,9 @@ static void beginPage(double w, double h)
     if (pdf)
       cairo_pdf_surface_set_size (surface, w, h);
 #endif
+#ifdef CAIRO_HAS_WIN32_SURFACE
+    win32BeginPage(w, h);
+#endif
 
     cairo_surface_set_fallback_resolution (surface, x_resolution, y_resolution);
 
@@ -610,6 +638,9 @@ static void endPage(GooString *imageFileName)
 
   if (printing) {
     cairo_surface_show_page(surface);
+#ifdef CAIRO_HAS_WIN32_SURFACE
+    win32EndPage(imageFileName);
+#endif
   } else {
     writePageImage(imageFileName);
     cairo_surface_finish(surface);
@@ -626,12 +657,16 @@ static void endDocument()
   cairo_status_t status;
 
   if (printing) {
+#ifdef CAIRO_HAS_WIN32_SURFACE
+    win32EndDocument();
+#endif
     cairo_surface_finish(surface);
     status = cairo_surface_status(surface);
     if (status)
       error(errInternal, -1, "cairo error: {0:s}\n", cairo_status_to_string(status));
     cairo_surface_destroy(surface);
-    fclose(output_file);
+    if (output_file)
+      fclose(output_file);
   }
 }
 
@@ -705,6 +740,9 @@ static GooString *getOutputFileName(GooString *fileName, GooString *outputName)
     return new GooString(outputName);
   }
 
+  if (print)
+    return fileName; //it will be used as the job name
+
   if (fileName->cmp("fd://0") == 0) {
     fprintf(stderr, "Error: an output filename or '-' must be supplied when the PDF file is stdin.\n");
     exit(99);
@@ -808,13 +846,14 @@ int main(int argc, char *argv[]) {
                 (ps ? 1 : 0) +
                 (eps ? 1 : 0) +
                 (pdf ? 1 : 0) +
+                (print ? 1 : 0) +
                 (svg ? 1 : 0);
   if (num_outputs == 0) {
-    fprintf(stderr, "Error: one of the output format options (-png, -jpeg, -ps, -eps, -pdf, -svg) must be used.\n");
+    fprintf(stderr, "Error: one of the output format options (-png, -jpeg, -ps, -eps, -pdf, -print, -svg) must be used.\n");
     exit(99);
   }
   if (num_outputs > 1) {
-    fprintf(stderr, "Error: use only one of the output format options (-png, -jpeg, -ps, -eps, -pdf, -svg).\n");
+    fprintf(stderr, "Error: use only one of the output format options (-png, -jpeg, -ps, -eps, -pdf, -print, -svg).\n");
     exit(99);
   }
   if (png || jpeg || tiff)


More information about the poppler mailing list