Commit c091aa14 authored by Adrian Johnson's avatar Adrian Johnson

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
parent cc3b39d4
...@@ -7,13 +7,8 @@ ...@@ -7,13 +7,8 @@
#include "pdftocairo-win32.h" #include "pdftocairo-win32.h"
static HDC hdc; static HDC hdc;
static DEVMODEA *devmode;
void win32GetFitToPageTransform(cairo_matrix_t *m) static char *printerName;
{
int logx = GetDeviceCaps(hdc, LOGPIXELSX);
int logy = GetDeviceCaps(hdc, LOGPIXELSY);
cairo_matrix_scale (m, logx / 72.0, logy / 72.0);
}
struct Win32Option struct Win32Option
{ {
...@@ -39,69 +34,69 @@ static const Win32Option win32PaperSource[] = ...@@ -39,69 +34,69 @@ static const Win32Option win32PaperSource[] =
{NULL, 0} {NULL, 0}
}; };
static void parseSource(DEVMODEA *devmode, GooString *source) static void parseSource(GooString *source)
{ {
int src;
const Win32Option *option = win32PaperSource; const Win32Option *option = win32PaperSource;
while (option->name) { while (option->name) {
if (source->cmp(option->name) == 0) { if (source->cmp(option->name) == 0) {
src = option->value; devmode->dmDefaultSource = option->value;
break; devmode->dmFields |= DM_DEFAULTSOURCE;
}
}
if (!option->name) {
if (isInt(source->getCString())) {
src = atoi(source->getCString());
} else {
fprintf(stderr, "Warning: Unknown paper source \"%s\"\n", source->getCString());
return; return;
} }
option++;
} }
fprintf(stderr, "Warning: Unknown paper source \"%s\"\n", source->getCString());
devmode->dmDefaultSource = src;
devmode->dmFields |= DM_DEFAULTSOURCE;
} }
static const Win32Option win32DuplexMode[] = static const Win32Option win32DuplexMode[] =
{ {
{"simplex", DMDUP_SIMPLEX}, {"off", DMDUP_SIMPLEX},
{"horizontal", DMDUP_HORIZONTAL}, {"short", DMDUP_HORIZONTAL},
{"vertical", DMDUP_VERTICAL}, {"long", DMDUP_VERTICAL},
{NULL, 0} {NULL, 0}
}; };
static void parseDuplex(DEVMODEA *devmode, GooString *mode) static void parseDuplex(GooString *mode)
{ {
int win32Duplex;
const Win32Option *option = win32DuplexMode; const Win32Option *option = win32DuplexMode;
while (option->name) { while (option->name) {
if (mode->cmp(option->name) == 0) { if (mode->cmp(option->name) == 0) {
win32Duplex = option->value; devmode->dmDuplex = option->value;
break; devmode->dmFields |= DM_DUPLEX;
return;
} }
option++;
} }
if (!option->name) { fprintf(stderr, "Warning: Unknown duplex mode \"%s\"\n", mode->getCString());
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, 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) { if (duplex) {
devmode->dmDuplex = DMDUP_HORIZONTAL; devmode->dmDuplex = DMDUP_HORIZONTAL;
devmode->dmFields |= DM_DUPLEX; 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>,... //printOpt format is: <opt1>=<val1>,<opt2>=<val2>,...
const char *nextOpt = printOpt->getCString(); const char *nextOpt = printOpt->getCString();
...@@ -128,13 +123,12 @@ static void fillPrinterOptions(DEVMODEA *devmode, GBool duplex, GooString *print ...@@ -128,13 +123,12 @@ static void fillPrinterOptions(DEVMODEA *devmode, GBool duplex, GooString *print
//here opt is "<optN>" and value is "<valN>" //here opt is "<optN>" and value is "<valN>"
if (opt.cmp("source") == 0) { if (opt.cmp("source") == 0) {
parseSource(devmode, &value); parseSource(&value);
} else if (opt.cmp("duplex") == 0) { } else if (opt.cmp("duplex") == 0) {
if (duplex) { if (duplex)
fprintf(stderr, "Warning: duplex mode is specified both as standalone and printer options\n"); fprintf(stderr, "Warning: duplex mode is specified both as standalone and printer options\n");
} else { else
parseDuplex(devmode, &value); parseDuplex( &value);
}
} else { } else {
fprintf(stderr, "Warning: unknown printer option \"%s\"\n", opt.getCString()); fprintf(stderr, "Warning: unknown printer option \"%s\"\n", opt.getCString());
} }
...@@ -147,65 +141,96 @@ cairo_surface_t *win32BeginDocument(GooString *inputFileName, GooString *outputF ...@@ -147,65 +141,96 @@ cairo_surface_t *win32BeginDocument(GooString *inputFileName, GooString *outputF
GooString *printOpt, GooString *printOpt,
GBool duplex) GBool duplex)
{ {
if (printer->getCString()[0] == 0) if (printer->getCString()[0] == 0) {
{ DWORD size = 0;
DWORD szName = 0; GetDefaultPrinterA(NULL, &size);
GetDefaultPrinterA(NULL, &szName); printerName = (char*)gmalloc(size);
char *devname = (char*)gmalloc(szName); GetDefaultPrinterA(printerName, &size);
GetDefaultPrinterA(devname, &szName); } else {
printer->Set(devname); printerName = gstrndup(printer->getCString(), printer->getLength());
gfree(devname);
} }
char *cPrinter = printer->getCString();
//Query the size of the DEVMODE struct //Query the size of the DEVMODE struct
LONG szProp = DocumentPropertiesA(NULL, NULL, cPrinter, NULL, NULL, 0); LONG szProp = DocumentPropertiesA(NULL, NULL, printerName, NULL, NULL, 0);
if (szProp < 0) if (szProp < 0) {
{ fprintf(stderr, "Error: Printer \"%s\" not found\n", printerName);
fprintf(stderr, "Error: Printer \"%s\" not found", cPrinter);
exit(99); exit(99);
} }
DEVMODEA *devmode = (DEVMODEA*)gmalloc(szProp); devmode = (DEVMODEA*)gmalloc(szProp);
memset(devmode, 0, szProp); memset(devmode, 0, szProp);
devmode->dmSize = sizeof(DEVMODEA); devmode->dmSize = sizeof(DEVMODEA);
devmode->dmSpecVersion = DM_SPECVERSION; devmode->dmSpecVersion = DM_SPECVERSION;
//Load the current default configuration for the printer into devmode //Load the current default configuration for the printer into devmode
if (DocumentPropertiesA(NULL, NULL, cPrinter, devmode, NULL, DM_OUT_BUFFER) < 0) if (DocumentPropertiesA(NULL, NULL, printerName, devmode, devmode, DM_OUT_BUFFER) < 0) {
{ fprintf(stderr, "Error: Printer \"%s\" not found\n", printerName);
fprintf(stderr, "Error: Printer \"%s\" not found", cPrinter);
exit(99); exit(99);
} }
fillCommonPrinterOptions(devmode, w, h, duplex); fillCommonPrinterOptions(w, h, duplex);
fillPrinterOptions(devmode, duplex, printOpt); fillPrinterOptions(duplex, printOpt);
hdc = CreateDCA(NULL, cPrinter, NULL, devmode); if (DocumentPropertiesA(NULL, NULL, printerName, devmode, devmode, DM_IN_BUFFER | DM_OUT_BUFFER) < 0) {
gfree(devmode); fprintf(stderr, "Error: Printer \"%s\" not found\n", printerName);
if (!hdc) exit(99);
{ }
fprintf(stderr, "Error: Printer \"%s\" not found", cPrinter); hdc = CreateDCA(NULL, printerName, NULL, devmode);
if (!hdc) {
fprintf(stderr, "Error: Printer \"%s\" not found\n", printerName);
exit(99); exit(99);
} }
DOCINFOA docinfo; DOCINFOA docinfo;
memset(&docinfo, 0, sizeof(docinfo)); memset(&docinfo, 0, sizeof(docinfo));
docinfo.cbSize = sizeof(docinfo); docinfo.cbSize = sizeof(docinfo);
if (inputFileName->cmp("fd://0") == 0) { if (inputFileName->cmp("fd://0") == 0)
docinfo.lpszDocName = "pdftocairo <stdin>"; docinfo.lpszDocName = "pdftocairo <stdin>";
} else { else
docinfo.lpszDocName = inputFileName->getCString(); docinfo.lpszDocName = inputFileName->getCString();
} if (outputFileName)
if (outputFileName) {
docinfo.lpszOutput = outputFileName->getCString(); docinfo.lpszOutput = outputFileName->getCString();
}
if (StartDocA(hdc, &docinfo) <=0) { if (StartDocA(hdc, &docinfo) <=0) {
fprintf(stderr, "Error: StartDoc failed"); fprintf(stderr, "Error: StartDoc failed\n");
exit(99); exit(99);
} }
return cairo_win32_printing_surface_create(hdc); 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); StartPage(hdc);
} }
...@@ -218,6 +243,8 @@ void win32EndDocument() ...@@ -218,6 +243,8 @@ void win32EndDocument()
{ {
EndDoc(hdc); EndDoc(hdc);
DeleteDC(hdc); DeleteDC(hdc);
gfree(devmode);
gfree(printerName);
} }
#endif // CAIRO_HAS_WIN32_SURFACE #endif // CAIRO_HAS_WIN32_SURFACE
...@@ -15,7 +15,7 @@ cairo_surface_t *win32BeginDocument(GooString *inputFileName, GooString *outputF ...@@ -15,7 +15,7 @@ cairo_surface_t *win32BeginDocument(GooString *inputFileName, GooString *outputF
GooString *printer, GooString *printer,
GooString *printOpt, GooString *printOpt,
GBool duplex); GBool duplex);
void win32BeginPage(double w, double h); void win32BeginPage(double *w, double *h, GBool useFullPage);
void win32EndPage(GooString *imageFileName); void win32EndPage(GooString *imageFileName);
void win32EndDocument(); void win32EndDocument();
......
...@@ -268,7 +268,10 @@ Selects the source paper tray to be used (bin). The possible values are "upper", ...@@ -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. "envmanual", "auto", "tractor", "smallfmt", "largefmt", "largecapacity", "formsource", or a numeric value to choose a driver specific source.
.TP .TP
.BI duplex .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 .SH AUTHOR
The pdftocairo software and documentation are copyright 1996-2004 Glyph The pdftocairo software and documentation are copyright 1996-2004 Glyph
& Cog, LLC and copyright 2005-2011 The Poppler Developers. & Cog, LLC and copyright 2005-2011 The Poppler Developers.
......
...@@ -79,7 +79,7 @@ static GBool jpeg = gFalse; ...@@ -79,7 +79,7 @@ static GBool jpeg = gFalse;
static GBool ps = gFalse; static GBool ps = gFalse;
static GBool eps = gFalse; static GBool eps = gFalse;
static GBool pdf = gFalse; static GBool pdf = gFalse;
static GBool print = gFalse; static GBool printToWin32 = gFalse;
static GBool svg = gFalse; static GBool svg = gFalse;
static GBool tiff = gFalse; static GBool tiff = gFalse;
...@@ -159,7 +159,7 @@ static const ArgDesc argDesc[] = { ...@@ -159,7 +159,7 @@ static const ArgDesc argDesc[] = {
"generate a Scalable Vector Graphics (SVG) file"}, "generate a Scalable Vector Graphics (SVG) file"},
#endif #endif
#ifdef CAIRO_HAS_WIN32_SURFACE #ifdef CAIRO_HAS_WIN32_SURFACE
{"-print", argFlag, &print, 0, {"-print", argFlag, &printToWin32, 0,
"print to a Windows printer"}, "print to a Windows printer"},
{"-printer", argGooString, &printer, 0, {"-printer", argGooString, &printer, 0,
"printer name or use default if this option is not specified"}, "printer name or use default if this option is not specified"},
...@@ -483,10 +483,6 @@ static void getFitToPageTransform(double page_w, double page_h, ...@@ -483,10 +483,6 @@ static void getFitToPageTransform(double page_w, double page_h,
// shrink to fit // shrink to fit
cairo_matrix_scale (m, scale, scale); 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) 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 ...@@ -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) static void beginDocument(GooString *inputFileName, GooString *outputFileName, double w, double h)
{ {
if (printing) { if (printing) {
if (!print) { if (printToWin32) {
output_file = NULL;
} else {
if (outputFileName->cmp("fd://0") == 0) if (outputFileName->cmp("fd://0") == 0)
output_file = stdout; output_file = stdout;
else else
...@@ -540,41 +538,41 @@ static void beginDocument(GooString *inputFileName, GooString *outputFileName, d ...@@ -540,41 +538,41 @@ static void beginDocument(GooString *inputFileName, GooString *outputFileName, d
#endif #endif
} }
#ifdef CAIRO_HAS_WIN32_SURFACE #ifdef CAIRO_HAS_WIN32_SURFACE
if (print) if (printToWin32)
surface = win32BeginDocument(inputFileName, outputFileName, w, h, &printer, &printOpt, duplex); surface = win32BeginDocument(inputFileName, outputFileName, w, h, &printer, &printOpt, duplex);
#endif #endif
} }
} }
static void beginPage(double w, double h) static void beginPage(double *w, double *h)
{ {
if (printing) { if (printing) {
if (ps || eps) { if (ps || eps) {
#if CAIRO_HAS_PS_SURFACE #if CAIRO_HAS_PS_SURFACE
if (w > h) { if (*w > *h) {
cairo_ps_surface_dsc_comment (surface, "%%PageOrientation: Landscape"); 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 { } else {
cairo_ps_surface_dsc_comment (surface, "%%PageOrientation: Portrait"); 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 #endif
} }
#if CAIRO_HAS_PDF_SURFACE #if CAIRO_HAS_PDF_SURFACE
if (pdf) if (pdf)
cairo_pdf_surface_set_size (surface, w, h); cairo_pdf_surface_set_size (surface, *w, *h);
#endif #endif
#ifdef CAIRO_HAS_WIN32_SURFACE #ifdef CAIRO_HAS_WIN32_SURFACE
if (print) if (printToWin32)
win32BeginPage(w, h); win32BeginPage(w, h, noShrink); // w,h will be changed to actual size used
#endif #endif
cairo_surface_set_fallback_resolution (surface, x_resolution, y_resolution); cairo_surface_set_fallback_resolution (surface, x_resolution, y_resolution);
} else { } 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) ...@@ -642,7 +640,7 @@ static void endPage(GooString *imageFileName)
cairo_surface_show_page(surface); cairo_surface_show_page(surface);
#ifdef CAIRO_HAS_WIN32_SURFACE #ifdef CAIRO_HAS_WIN32_SURFACE
if (print) if (printToWin32)
win32EndPage(imageFileName); win32EndPage(imageFileName);
#endif #endif
...@@ -662,15 +660,15 @@ static void endDocument() ...@@ -662,15 +660,15 @@ static void endDocument()
cairo_status_t status; cairo_status_t status;
if (printing) { if (printing) {
#ifdef CAIRO_HAS_WIN32_SURFACE
if (print)
win32EndDocument();
#endif
cairo_surface_finish(surface); cairo_surface_finish(surface);
status = cairo_surface_status(surface); status = cairo_surface_status(surface);
if (status) if (status)
error(errInternal, -1, "cairo error: {0:s}\n", cairo_status_to_string(status)); error(errInternal, -1, "cairo error: {0:s}\n", cairo_status_to_string(status));
cairo_surface_destroy(surface); cairo_surface_destroy(surface);
#ifdef CAIRO_HAS_WIN32_SURFACE
if (printToWin32)
win32EndDocument();
#endif
if (output_file) if (output_file)
fclose(output_file); fclose(output_file);
} }
...@@ -737,7 +735,7 @@ static GooString *getOutputFileName(GooString *fileName, GooString *outputName) ...@@ -737,7 +735,7 @@ static GooString *getOutputFileName(GooString *fileName, GooString *outputName)
if (outputName) { if (outputName) {
if (outputName->cmp("-") == 0) { 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"); fprintf(stderr, "Error: stdout may only be used with the ps, eps, pdf, svg output options or if -singlefile is used.\n");
exit(99); exit(99);
} }
...@@ -746,9 +744,8 @@ static GooString *getOutputFileName(GooString *fileName, GooString *outputName) ...@@ -746,9 +744,8 @@ static GooString *getOutputFileName(GooString *fileName, GooString *outputName)
return new GooString(outputName); return new GooString(outputName);
} }
if (print) { if (printToWin32)
return NULL; // No output file means print to printer return NULL; // No output file means print to printer
}
if (fileName->cmp("fd://0") == 0) { if (fileName->cmp("fd://0") == 0) {
fprintf(stderr, "Error: an output filename or '-' must be supplied when the PDF file is stdin.\n"); 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[]) { ...@@ -853,7 +850,7 @@ int main(int argc, char *argv[]) {
(ps ? 1 : 0) + (ps ? 1 : 0) +
(eps ? 1 : 0) + (eps ? 1 : 0) +
(pdf ? 1 : 0) + (pdf ? 1 : 0) +
(print ? 1 : 0) + (printToWin32 ? 1 : 0) +
(svg ? 1 : 0); (svg ? 1 : 0);
if (num_outputs == 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, -svg) must be used.\n");
...@@ -1098,7 +1095,7 @@ int main(int argc, char *argv[]) { ...@@ -1098,7 +1095,7 @@ int main(int argc, char *argv[]) {
if (pg == firstPage) if (pg == firstPage)
beginDocument(fileName, outputFileName, output_w, output_h); 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); renderPage(doc, cairoOut, pg, pg_w, pg_h, output_w, output_h);
endPage(imageFileName); endPage(imageFileName);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment