summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorRodrigo Rivas Costa <rodrigorivascosta@gmail.com>2014-09-06 21:04:10 +0930
committerAdrian Johnson <ajohnson@redneon.com>2014-10-21 22:04:23 +1030
commit40d3ae87befad489fd8c0b38ff2561a0782cae0b (patch)
tree78aa0623042e1291cfad6468f3ca5a10f6218020 /utils
parentee4a389872d86b619c677888da8f13f1f6c54472 (diff)
Add support for printing to a Windows printer from pdftocairo
Bug 79936
Diffstat (limited to 'utils')
-rw-r--r--utils/pdftocairo-win32.cc219
-rw-r--r--utils/pdftocairo.123
-rw-r--r--utils/pdftocairo.cc61
3 files changed, 291 insertions, 12 deletions
diff --git a/utils/pdftocairo-win32.cc b/utils/pdftocairo-win32.cc
new file mode 100644
index 00000000..515ffa72
--- /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 c903ffac..77474094 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 b3f57b65..79d71d9b 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)