1
/* Copyright (C) 2001-2006 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
7
This software is distributed under license and may not be copied, modified
8
or distributed except as expressly authorized under the terms of that
9
license. Refer to licensing information at http://www.artifex.com/
10
or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11
San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
14
/* $Id: gdevwpr2.c 8250 2007-09-25 13:31:24Z giles $ */
16
* Microsoft Windows 3.n printer driver for Ghostscript.
17
* Original version by Russell Lang and
18
* L. Peter Deutsch, Aladdin Enterprises.
19
* Modified by rjl 1995-03-29 to use BMP printer code
20
* Modified by Pierre Arnaud 1999-02-18 (see description below)
21
* Modified by lpd 1999-04-03 for compatibility with Borland C++ 4.5.
22
* Modified by Pierre Arnaud 1999-10-03 (accept b&w printing on color printers).
23
* Modified by Pierre Arnaud 1999-11-20 (accept lower resolution)
24
* Bug fixed by Pierre Arnaud 2000-03-09 (win_pr2_put_params error when is_open)
25
* Bug fixed by Pierre Arnaud 2000-03-20 (win_pr2_set_bpp did not set anti_alias)
26
* Bug fixed by Pierre Arnaud 2000-03-22 (win_pr2_set_bpp depth was wrong)
27
* Modified by Pierre Arnaud 2000-12-12 (mainly added support for Tumble)
28
* Bug fixed by Pierre Arnaud 2000-12-18 (-dQueryUser now works from cmd line)
31
/* This driver uses the printer default size and resolution and
32
* ignores page size and resolution set using -gWIDTHxHEIGHT and
33
* -rXxY. You must still set the correct PageSize to get the
34
* correct clipping path.
35
* The code in win_pr2_getdc() does try to set the printer page
36
* size from the PostScript PageSize, but it isn't working
37
* reliably at the moment.
39
* This driver doesn't work with some Windows printer drivers.
40
* The reason is unknown. All printers to which I have access
46
/* Additions by Pierre Arnaud (Pierre.Arnaud@opac.ch)
48
* The driver has been extended in order to provide some run-time
49
* feed-back about the default Windows printer and to give the user
50
* the opportunity to select the printer's properties before the
51
* device gets opened (and any spooling starts).
53
* The driver returns an additional property named "UserSettings".
54
* This is a dictionary which contens are valid only after setting
55
* the QueryUser property (see below). The UserSettings dict contains
58
* DocumentRange [begin end] (int array, can be set)
59
* Defines the range of pages in the document; [1 10] would
60
* describe a document starting at page 1 and ending at page 10.
62
* SelectedRange [begin end] (int array, can be set)
63
* Defines the pages the user wants to print.
65
* MediaSize [width height] (float array, read only)
66
* Current printer's media size.
68
* Copies n (integer, can be set)
69
* User selected number of copies.
71
* PrintCopies n (integer, read only)
72
* Number of copies which must be printed by Ghostscript itself.
73
* This is still experimental.
75
* DocumentName name (string, can be set)
76
* Name to be associated with the print job.
78
* UserChangedSettings (bool, read only)
79
* Set to 'true' if the last QueryUser operation succeeded.
81
* Paper n (integer, can be set)
82
* Windows paper selection (0 = automatic).
84
* Orient n (integer, can be set)
85
* Windows paper orientation (0 = automatic).
87
* Color n (integer, can be set)
88
* Windows color (0 = automatic, 1 = monochrome, 2 = color).
90
* MaxResolution n (integer, can be set)
91
* Maximum resolution in pixels pet inch (0 = no maximum). If
92
* the printer has a higher resolution than the maximum, trim
93
* the used resolution to the best one (dpi_chosen <= dpi_max,
94
* with dpi_chosen = dpi_printer / ratio).
97
/* Supported printer parameters are :
100
* Override what the Window printer driver returns.
103
* Don't display cancel dialog box. Useful for unattended or
104
* console EXE operation.
107
* Query user interactively for the destination printer, before
108
* the device gets opened. This fills in the UserSettings dict
109
* and the OutputFile name properties. The following values are
111
* 1 => show standard Print dialog
112
* 2 => show Print Setup dialog instead
113
* 3 => select default printer
114
* other, does nothing
116
* The /Duplex & /Tumble keys of the setpagedevice dict are supported
117
* if the Windows printer supports duplex printing.
121
#include "gdevpccm.h"
123
#include "windows_.h"
124
#include <shellapi.h>
125
#include "gp_mswin.h"
132
/* Make sure we cast to the correct structure type. */
133
typedef struct gx_device_win_pr2_s gx_device_win_pr2;
136
#define wdev ((gx_device_win_pr2 *)dev)
138
/* Device procedures */
140
/* See gxdevice.h for the definitions of the procedures. */
141
static dev_proc_open_device(win_pr2_open);
142
static dev_proc_close_device(win_pr2_close);
143
static dev_proc_print_page(win_pr2_print_page);
144
static dev_proc_map_rgb_color(win_pr2_map_rgb_color);
145
static dev_proc_map_color_rgb(win_pr2_map_color_rgb);
146
static dev_proc_get_params(win_pr2_get_params);
147
static dev_proc_put_params(win_pr2_put_params);
149
static void win_pr2_set_bpp(gx_device * dev, int depth);
151
static const gx_device_procs win_pr2_procs =
152
prn_color_params_procs(win_pr2_open, gdev_prn_output_page, win_pr2_close,
153
win_pr2_map_rgb_color, win_pr2_map_color_rgb,
154
win_pr2_get_params, win_pr2_put_params);
156
#define PARENT_WINDOW HWND_DESKTOP
157
BOOL CALLBACK CancelDlgProc(HWND, UINT, WPARAM, LPARAM);
158
BOOL CALLBACK AbortProc2(HDC, int);
161
/* The device descriptor */
162
typedef struct gx_device_win_pr2_s gx_device_win_pr2;
163
struct gx_device_win_pr2_s {
165
gx_prn_device_common;
169
int doc_page_begin; /* first page number in document */
170
int doc_page_end; /* last page number in document */
171
int user_page_begin; /* user's choice: first page to print */
172
int user_page_end; /* user's choice: last page to print */
173
int user_copies; /* user's choice: number of copies */
174
int print_copies; /* number of times GS should print each page */
175
float user_media_size[2]; /* width/height of media selected by user */
176
char doc_name[200]; /* name of document for the spooler */
177
char paper_name[64]; /* name of selected paper format */
178
bool user_changed_settings; /* true if user validated dialog */
179
int user_paper; /* user's choice: paper format */
180
int user_orient; /* user's choice: paper orientation */
181
int user_color; /* user's choice: color format */
182
int max_dpi; /* maximum resolution in DPI */
183
int ratio; /* stretch ratio when printing */
184
int selected_bpp; /* selected bpp, memorised by win_pr2_set_bpp */
185
bool tumble; /* tumble setting (with duplex) */
186
int query_user; /* query user (-dQueryUser) */
188
HANDLE win32_hdevmode; /* handle to device mode information */
189
HANDLE win32_hdevnames; /* handle to device names information */
191
DLGPROC lpfnAbortProc;
192
DLGPROC lpfnCancelProc;
195
bool use_old_spool_name; /* user prefers old \\spool\ name */
196
gx_device_win_pr2* original_device; /* used to detect copies */
199
gx_device_win_pr2 far_data gs_mswinpr2_device =
201
prn_device_std_body(gx_device_win_pr2, win_pr2_procs, "mswinpr2",
202
DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, 72.0, 72.0,
204
0, win_pr2_print_page), /* depth = 0 */
207
0, /* doc_page_begin */
208
0, /* doc_page_end */
209
0, /* user_page_begin */
210
0, /* user_page_end */
212
1, /* print_copies */
213
{ 0.0, 0.0 }, /* user_media_size */
214
{ 0 }, /* doc_name */
215
{ 0 }, /* paper_name */
216
0, /* user_changed_settings */
222
0, /* selected_bpp */
225
NULL, /* win32_hdevmode */
226
NULL, /* win32_hdevnames */
227
NULL, /* lpfnAbortProc */
228
NULL, /* lpfnCancelProc */
229
NULL, /* hDlgModeless */
230
false, /* use_old_spool_name */
231
NULL /* original_device */
234
/********************************************************************************/
236
static int win_pr2_getdc(gx_device_win_pr2 * dev);
237
static int win_pr2_update_dev(gx_device_win_pr2 * dev, LPDEVMODE pdevmode);
238
static int win_pr2_update_win(gx_device_win_pr2 * dev, LPDEVMODE pdevmode);
239
static int win_pr2_print_setup_interaction(gx_device_win_pr2 * dev, int mode);
240
static int win_pr2_write_user_settings(gx_device_win_pr2 * dev, gs_param_list * plist);
241
static int win_pr2_read_user_settings(gx_device_win_pr2 * dev, gs_param_list * plist);
242
static void win_pr2_copy_check(gx_device_win_pr2 * dev);
244
/********************************************************************************/
246
/* Open the win_pr2 driver */
248
win_pr2_open(gx_device * dev)
260
win_pr2_copy_check(wdev);
262
/* get a HDC for the printer */
263
if ((wdev->win32_hdevmode) &&
264
(wdev->win32_hdevnames)) {
265
/* The user has already had the opportunity to choose the output */
266
/* file interactively. Just use the specified parameters. */
268
LPDEVMODE devmode = (LPDEVMODE) GlobalLock(wdev->win32_hdevmode);
269
LPDEVNAMES devnames = (LPDEVNAMES) GlobalLock(wdev->win32_hdevnames);
271
const char* driver = (char*)(devnames)+(devnames->wDriverOffset);
272
const char* device = (char*)(devnames)+(devnames->wDeviceOffset);
273
const char* output = (char*)(devnames)+(devnames->wOutputOffset);
275
wdev->hdcprn = CreateDC(driver, device, output, devmode);
277
GlobalUnlock(wdev->win32_hdevmode);
278
GlobalUnlock(wdev->win32_hdevnames);
280
if (wdev->hdcprn == NULL) {
281
return gs_error_Fatal;
284
} else if (!win_pr2_getdc(wdev)) {
285
/* couldn't get a printer from -sOutputFile= */
286
/* Prompt with dialog box */
288
LPDEVMODE devmode = NULL;
289
memset(&pd, 0, sizeof(pd));
291
pd.lStructSize = sizeof(pd);
292
pd.hwndOwner = PARENT_WINDOW;
293
pd.Flags = PD_RETURNDC;
294
pd.nMinPage = wdev->doc_page_begin;
295
pd.nMaxPage = wdev->doc_page_end;
296
pd.nFromPage = wdev->user_page_begin;
297
pd.nToPage = wdev->user_page_end;
298
pd.nCopies = wdev->user_copies;
300
if (!PrintDlg(&pd)) {
301
/* device not opened - exit ghostscript */
302
return gs_error_Fatal; /* exit Ghostscript cleanly */
305
devmode = GlobalLock(pd.hDevMode);
306
win_pr2_update_dev(wdev,devmode);
307
GlobalUnlock(pd.hDevMode);
309
if (wdev->win32_hdevmode)
310
GlobalFree(wdev->win32_hdevmode);
311
if (wdev->win32_hdevnames)
312
GlobalFree(wdev->win32_hdevnames);
314
wdev->hdcprn = pd.hDC;
315
wdev->win32_hdevmode = pd.hDevMode;
316
wdev->win32_hdevnames = pd.hDevNames;
321
if (!(GetDeviceCaps(wdev->hdcprn, RASTERCAPS) != RC_DIBTODEV)) {
322
errprintf( "Windows printer does not have RC_DIBTODEV\n");
323
DeleteDC(wdev->hdcprn);
324
return gs_error_limitcheck;
326
/* initialise printer, install abort proc */
327
wdev->lpfnAbortProc = (DLGPROC) AbortProc2;
328
SetAbortProc(wdev->hdcprn, (ABORTPROC) wdev->lpfnAbortProc);
331
* Some versions of the Windows headers include lpszDatatype and fwType,
332
* and some don't. Since we want to set these fields to zero anyway,
333
* we just start by zeroing the whole structure.
335
memset(&docinfo, 0, sizeof(docinfo));
336
docinfo.cbSize = sizeof(docinfo);
337
docinfo.lpszDocName = wdev->doc_name;
338
/*docinfo.lpszOutput = NULL;*/
339
/*docinfo.lpszDatatype = NULL;*/
340
/*docinfo.fwType = 0;*/
342
if (docinfo.lpszDocName[0] == 0) {
343
docinfo.lpszDocName = "Ghostscript output";
346
if (StartDoc(wdev->hdcprn, &docinfo) <= 0) {
347
errprintf("Printer StartDoc failed (error %08x)\n", GetLastError());
348
DeleteDC(wdev->hdcprn);
349
return gs_error_limitcheck;
352
dev->x_pixels_per_inch = (float)GetDeviceCaps(wdev->hdcprn, LOGPIXELSX);
353
dev->y_pixels_per_inch = (float)GetDeviceCaps(wdev->hdcprn, LOGPIXELSY);
357
if (wdev->max_dpi > 50) {
359
float dpi_x = dev->x_pixels_per_inch;
360
float dpi_y = dev->y_pixels_per_inch;
362
while ((dev->x_pixels_per_inch > wdev->max_dpi)
363
|| (dev->y_pixels_per_inch > wdev->max_dpi)) {
366
dev->x_pixels_per_inch = dpi_x / ratio;
367
dev->y_pixels_per_inch = dpi_y / ratio;
371
size.x = GetDeviceCaps(wdev->hdcprn, PHYSICALWIDTH);
372
size.y = GetDeviceCaps(wdev->hdcprn, PHYSICALHEIGHT);
373
gx_device_set_width_height(dev, (int)(size.x / ratio), (int)(size.y / ratio));
374
offset.x = GetDeviceCaps(wdev->hdcprn, PHYSICALOFFSETX);
375
offset.y = GetDeviceCaps(wdev->hdcprn, PHYSICALOFFSETY);
377
/* m[] gives margins in inches */
378
m[0] /*left */ = offset.x / dev->x_pixels_per_inch / ratio;
379
m[3] /*top */ = offset.y / dev->y_pixels_per_inch / ratio;
380
m[2] /*right */ = (size.x - offset.x - GetDeviceCaps(wdev->hdcprn, HORZRES)) / dev->x_pixels_per_inch / ratio;
381
m[1] /*bottom */ = (size.y - offset.y - GetDeviceCaps(wdev->hdcprn, VERTRES)) / dev->y_pixels_per_inch / ratio;
382
gx_device_set_margins(dev, m, true);
384
depth = dev->color_info.depth;
386
/* Set parameters that were unknown before opening device */
387
/* Find out if the device supports color */
388
/* We recognize 1, 4 (but use only 3), 8 and 24 bit color devices */
389
depth = GetDeviceCaps(wdev->hdcprn, PLANES) * GetDeviceCaps(wdev->hdcprn, BITSPIXEL);
391
win_pr2_set_bpp(dev, depth);
393
/* gdev_prn_open opens a temporary file which we don't want */
394
/* so we specify the name now so we can delete it later */
395
wdev->fname[0] = '\0';
396
pfile = gp_open_scratch_file(gp_scratch_file_name_prefix,
399
code = gdev_prn_open(dev);
400
if ((code < 0) && wdev->fname[0])
403
if (!wdev->nocancel) {
404
/* inform user of progress with dialog box and allow cancel */
405
wdev->lpfnCancelProc = (DLGPROC) CancelDlgProc;
406
wdev->hDlgModeless = CreateDialog(phInstance, "CancelDlgBox",
407
PARENT_WINDOW, wdev->lpfnCancelProc);
408
ShowWindow(wdev->hDlgModeless, SW_HIDE);
413
/* Close the win_pr2 driver */
415
win_pr2_close(gx_device * dev)
420
win_pr2_copy_check(wdev);
424
if (!wdev->nocancel) {
425
if (!wdev->hDlgModeless)
428
DestroyWindow(wdev->hDlgModeless);
429
wdev->hDlgModeless = 0;
432
AbortDoc(wdev->hdcprn);
434
EndDoc(wdev->hdcprn);
436
DeleteDC(wdev->hdcprn);
438
if (wdev->win32_hdevmode != NULL) {
439
GlobalFree(wdev->win32_hdevmode);
440
wdev->win32_hdevmode = NULL;
442
if (wdev->win32_hdevnames != NULL) {
443
GlobalFree(wdev->win32_hdevnames);
444
wdev->win32_hdevnames = NULL;
447
code = gdev_prn_close(dev);
449
/* delete unwanted temporary file */
457
/* ------ Internal routines ------ */
460
#define wdev ((gx_device_win_pr2 *)pdev)
462
/********************************************************************************/
464
/* ------ Private definitions ------ */
467
/* new win_pr2_print_page routine */
469
/* Write BMP header to memory, then send bitmap to printer */
470
/* one scan line at a time */
472
win_pr2_print_page(gx_device_printer * pdev, FILE * file)
474
int raster = gdev_prn_raster(pdev);
476
/* BMP scan lines are padded to 32 bits. */
477
ulong bmp_raster = raster + (-raster & 3);
478
ulong bmp_raster_multi;
479
int scan_lines, yslice, lines, i;
481
int depth = pdev->color_info.depth;
484
int code = 0; /* return code */
488
int ratio = ((gx_device_win_pr2 *)pdev)->ratio;
495
scan_lines = dev_print_scan_lines(pdev);
496
width = (int)(pdev->width - ((dev_l_margin(pdev) + dev_r_margin(pdev) -
497
dev_x_offset(pdev)) * pdev->x_pixels_per_inch));
499
yslice = 65535 / bmp_raster; /* max lines in 64k */
500
bmp_raster_multi = bmp_raster * yslice;
501
hrow = GlobalAlloc(0, bmp_raster_multi);
502
row = GlobalLock(hrow);
503
if (row == 0) /* can't allocate row buffer */
504
return_error(gs_error_VMerror);
506
/* Write the info header. */
508
bmi.h.biSize = sizeof(bmi.h);
509
bmi.h.biWidth = pdev->width; /* wdev->mdev.width; */
510
bmi.h.biHeight = yslice;
512
bmi.h.biBitCount = pdev->color_info.depth;
513
bmi.h.biCompression = 0;
514
bmi.h.biSizeImage = 0; /* default */
515
bmi.h.biXPelsPerMeter = 0; /* default */
516
bmi.h.biYPelsPerMeter = 0; /* default */
518
StartPage(wdev->hdcprn);
520
/* Write the palette. */
524
gx_color_value rgb[3];
527
bmi.h.biClrUsed = 1 << depth;
528
bmi.h.biClrImportant = 1 << depth;
529
for (i = 0; i != 1 << depth; i++) {
530
(*dev_proc(pdev, map_color_rgb)) ((gx_device *) pdev,
531
(gx_color_index) i, rgb);
533
pq->rgbRed = gx_color_value_to_byte(rgb[0]);
534
pq->rgbGreen = gx_color_value_to_byte(rgb[1]);
535
pq->rgbBlue = gx_color_value_to_byte(rgb[2]);
540
bmi.h.biClrImportant = 0;
543
if (!wdev->nocancel) {
544
sprintf(dlgtext, "Printing page %d", (int)(pdev->PageCount) + 1);
545
SetWindowText(GetDlgItem(wdev->hDlgModeless, CANCEL_PRINTING), dlgtext);
546
ShowWindow(wdev->hDlgModeless, SW_SHOW);
548
for (y = 0; y < scan_lines;) {
549
/* copy slice to row buffer */
550
if (y > scan_lines - yslice)
551
lines = scan_lines - y;
554
for (i = 0; i < lines; i++)
555
gdev_prn_copy_scan_lines(pdev, y + i,
556
row + (bmp_raster * (lines - 1 - i)), raster);
559
StretchDIBits(wdev->hdcprn, 0, y*ratio, pdev->width*ratio, lines*ratio,
560
0, 0, pdev->width, lines,
562
(BITMAPINFO FAR *) & bmi, DIB_RGB_COLORS, SRCCOPY);
564
SetDIBitsToDevice(wdev->hdcprn, 0, y, pdev->width, lines,
567
(BITMAPINFO FAR *) & bmi, DIB_RGB_COLORS);
571
if (!wdev->nocancel) {
572
/* inform user of progress */
573
sprintf(dlgtext, "%d%% done", (int)(y * 100L / scan_lines));
574
SetWindowText(GetDlgItem(wdev->hDlgModeless, CANCEL_PCDONE), dlgtext);
576
/* process message loop */
577
while (PeekMessage(&msg, wdev->hDlgModeless, 0, 0, PM_REMOVE)) {
578
if ((wdev->hDlgModeless == 0) || !IsDialogMessage(wdev->hDlgModeless, &msg)) {
579
TranslateMessage(&msg);
580
DispatchMessage(&msg);
583
if ((!wdev->nocancel) && (wdev->hDlgModeless == 0)) {
584
/* user pressed cancel button */
589
if ((!wdev->nocancel) && (wdev->hDlgModeless == 0))
590
code = gs_error_Fatal; /* exit Ghostscript cleanly */
592
/* push out the page */
594
SetWindowText(GetDlgItem(wdev->hDlgModeless, CANCEL_PCDONE),
596
EndPage(wdev->hdcprn);
598
ShowWindow(wdev->hDlgModeless, SW_HIDE);
607
/* combined color mappers */
609
/* 24-bit color mappers (taken from gdevmem2.c). */
610
/* Note that Windows expects RGB values in the order B,G,R. */
612
/* Map a r-g-b color to a color index. */
613
static gx_color_index
614
win_pr2_map_rgb_color(gx_device * dev, const gx_color_value cv[])
616
gx_color_value r = cv[0];
617
gx_color_value g = cv[1];
618
gx_color_value b = cv[2];
619
switch (dev->color_info.depth) {
621
return gdev_prn_map_rgb_color(dev, cv);
623
/* use only 8 colors */
624
return (r > (gx_max_color_value / 2 + 1) ? 4 : 0) +
625
(g > (gx_max_color_value / 2 + 1) ? 2 : 0) +
626
(b > (gx_max_color_value / 2 + 1) ? 1 : 0);
628
return pc_8bit_map_rgb_color(dev, cv);
630
return gx_color_value_to_byte(r) +
631
((uint) gx_color_value_to_byte(g) << 8) +
632
((ulong) gx_color_value_to_byte(b) << 16);
634
return 0; /* error */
637
/* Map a color index to a r-g-b color. */
639
win_pr2_map_color_rgb(gx_device * dev, gx_color_index color,
640
gx_color_value prgb[3])
642
switch (dev->color_info.depth) {
644
gdev_prn_map_color_rgb(dev, color, prgb);
647
/* use only 8 colors */
648
prgb[0] = (color & 4) ? gx_max_color_value : 0;
649
prgb[1] = (color & 2) ? gx_max_color_value : 0;
650
prgb[2] = (color & 1) ? gx_max_color_value : 0;
653
pc_8bit_map_color_rgb(dev, color, prgb);
656
prgb[2] = gx_color_value_from_byte(color >> 16);
657
prgb[1] = gx_color_value_from_byte((color >> 8) & 0xff);
658
prgb[0] = gx_color_value_from_byte(color & 0xff);
665
win_pr2_set_bpp(gx_device * dev, int depth)
668
static const gx_device_color_info win_pr2_24color = dci_std_color(24);
670
dev->color_info = win_pr2_24color;
672
} else if (depth >= 8) {
673
/* 8-bit (SuperVGA-style) color. */
674
/* (Uses a fixed palette of 3,3,2 bits.) */
675
static const gx_device_color_info win_pr2_8color = dci_pc_8bit;
677
dev->color_info = win_pr2_8color;
679
} else if (depth >= 3) {
680
/* 3 plane printer */
681
/* suitable for impact dot matrix CMYK printers */
682
/* create 4-bit bitmap, but only use 8 colors */
683
static const gx_device_color_info win_pr2_4color = dci_values(3, 4, 1, 1, 2, 2);
685
dev->color_info = win_pr2_4color;
687
} else { /* default is black_and_white */
688
static const gx_device_color_info win_pr2_1color = dci_std_color(1);
690
dev->color_info = win_pr2_1color;
694
((gx_device_win_pr2 *)dev)->selected_bpp = depth;
696
/* copy encode/decode procedures */
697
dev->procs.encode_color = dev->procs.map_rgb_color;
698
dev->procs.decode_color = dev->procs.map_color_rgb;
700
dev->procs.get_color_mapping_procs =
701
gx_default_DevGray_get_color_mapping_procs;
702
dev->procs.get_color_comp_index =
703
gx_default_DevGray_get_color_comp_index;
706
dev->procs.get_color_mapping_procs =
707
gx_default_DevRGB_get_color_mapping_procs;
708
dev->procs.get_color_comp_index =
709
gx_default_DevRGB_get_color_comp_index;
713
/********************************************************************************/
715
/* Get device parameters */
717
win_pr2_get_params(gx_device * pdev, gs_param_list * plist)
719
int code = gdev_prn_get_params(pdev, plist);
721
win_pr2_copy_check(wdev);
724
code = param_write_bool(plist, "NoCancel",
727
code = param_write_int(plist, "QueryUser",
728
&(wdev->query_user));
730
code = win_pr2_write_user_settings(wdev, plist);
732
if ((code >= 0) && (wdev->Duplex_set > 0))
733
code = param_write_bool(plist, "Tumble",
740
/* We implement this ourselves so that we can change BitsPerPixel */
741
/* before the device is opened */
743
win_pr2_put_params(gx_device * pdev, gs_param_list * plist)
746
int old_bpp = pdev->color_info.depth;
748
bool tumble = wdev->tumble;
749
bool nocancel = wdev->nocancel;
751
bool old_duplex = wdev->Duplex;
752
bool old_tumble = wdev->tumble;
753
int old_orient = wdev->user_orient;
754
int old_color = wdev->user_color;
755
int old_paper = wdev->user_paper;
756
int old_mx_dpi = wdev->max_dpi;
758
if (wdev->Duplex_set < 0) {
759
wdev->Duplex_set = 0;
760
wdev->Duplex = false;
761
wdev->tumble = false;
764
win_pr2_copy_check(wdev);
766
code = win_pr2_read_user_settings(wdev, plist);
768
switch (code = param_read_int(plist, "BitsPerPixel", &bpp)) {
771
if (wdev->selected_bpp == bpp) {
774
ecode = gs_error_rangecheck;
775
} else { /* change dev->color_info is valid before device is opened */
776
win_pr2_set_bpp(pdev, bpp);
782
bppe:param_signal_error(plist, "BitsPerPixel", ecode);
787
switch (code = param_read_bool(plist, "NoCancel", &nocancel)) {
790
if (wdev->nocancel == nocancel) {
793
ecode = gs_error_rangecheck;
795
wdev->nocancel = nocancel;
801
nocancele:param_signal_error(plist, "NoCancel", ecode);
806
switch (code = param_read_bool(plist, "Tumble", &tumble)) {
808
wdev->tumble = tumble;
812
param_signal_error(plist, "Tumble", ecode);
817
switch (code = param_read_int(plist, "QueryUser", &queryuser)) {
819
if ((queryuser > 0) &&
821
win_pr2_print_setup_interaction(wdev, queryuser);
826
param_signal_error(plist, "QueryUser", ecode);
832
ecode = gdev_prn_put_params(pdev, plist);
834
if (wdev->win32_hdevmode && wdev->hdcprn) {
835
if ( (old_duplex != wdev->Duplex)
836
|| (old_tumble != wdev->tumble)
837
|| (old_orient != wdev->user_orient)
838
|| (old_color != wdev->user_color)
839
|| (old_paper != wdev->user_paper)
840
|| (old_mx_dpi != wdev->max_dpi) ) {
842
LPDEVMODE pdevmode = GlobalLock(wdev->win32_hdevmode);
845
win_pr2_update_win(wdev, pdevmode);
846
ResetDC(wdev->hdcprn, pdevmode);
847
GlobalUnlock(pdevmode);
857
/********************************************************************************/
860
/* Get Device Context for printer */
862
win_pr2_getdc(gx_device_win_pr2 * wdev)
877
int paperwidth, paperheight;
881
LPDEVMODE podevmode, pidevmode;
884
/* first try to derive the printer name from -sOutputFile= */
885
/* is printer if name prefixed by \\spool\ or by %printer% */
886
if (is_spool(wdev->fname)) {
887
device = wdev->fname + 8; /* skip over \\spool\ */
888
wdev->use_old_spool_name = true;
889
} else if (strncmp("%printer%",wdev->fname,9) == 0) {
890
device = wdev->fname + 9; /* skip over %printer% */
891
wdev->use_old_spool_name = false;
896
/* now try to match the printer name against the [Devices] section */
897
if ((devices = gs_malloc(wdev->memory, 4096, 1, "win_pr2_getdc")) == (char *)NULL)
899
GetProfileString("Devices", NULL, "", devices, 4096);
902
if (stricmp(p, device) == 0)
908
gs_free(wdev->memory, devices, 4096, 1, "win_pr2_getdc");
910
return FALSE; /* doesn't match an available printer */
912
/* the printer exists, get the remaining information from win.ini */
913
GetProfileString("Devices", device, "", driverbuf, sizeof(driverbuf));
914
driver = strtok(driverbuf, ",");
915
output = strtok(NULL, ",");
917
if (!OpenPrinter(device, &hprinter, NULL))
919
devmode_size = DocumentProperties(NULL, hprinter, device, NULL, NULL, 0);
920
if ((podevmode = gs_malloc(wdev->memory, devmode_size, 1, "win_pr2_getdc"))
921
== (LPDEVMODE) NULL) {
922
ClosePrinter(hprinter);
925
if ((pidevmode = gs_malloc(wdev->memory, devmode_size, 1, "win_pr2_getdc")) == (LPDEVMODE) NULL) {
926
gs_free(wdev->memory, podevmode, devmode_size, 1, "win_pr2_getdc");
927
ClosePrinter(hprinter);
930
DocumentProperties(NULL, hprinter, device, podevmode, NULL, DM_OUT_BUFFER);
932
/* now find out what paper sizes are available */
933
devcapsize = DeviceCapabilities(device, output, DC_PAPERSIZE, NULL, NULL);
934
devcapsize *= sizeof(POINT);
935
if ((devcap = gs_malloc(wdev->memory, devcapsize, 1, "win_pr2_getdc")) == (LPBYTE) NULL)
937
n = DeviceCapabilities(device, output, DC_PAPERSIZE, devcap, NULL);
938
paperwidth = (int)(wdev->MediaSize[0] * 254 / 72);
939
paperheight = (int)(wdev->MediaSize[1] * 254 / 72);
944
pp = (POINT *) devcap;
945
for (i = 0; i < n; i++, pp++) {
946
if ((pp->x < paperwidth + 20) && (pp->x > paperwidth - 20) &&
947
(pp->y < paperheight + 20) && (pp->y > paperheight - 20)) {
951
orientation = DMORIENT_PORTRAIT;
955
if (paperindex < 0) {
956
/* try again in landscape */
957
pp = (POINT *) devcap;
958
for (i = 0; i < n; i++, pp++) {
959
if ((pp->x < paperheight + 20) && (pp->x > paperheight - 20) &&
960
(pp->y < paperwidth + 20) && (pp->y > paperwidth - 20)) {
964
orientation = DMORIENT_LANDSCAPE;
969
gs_free(wdev->memory, devcap, devcapsize, 1, "win_pr2_getdc");
971
/* get the dmPaperSize */
972
devcapsize = DeviceCapabilities(device, output, DC_PAPERS, NULL, NULL);
973
devcapsize *= sizeof(WORD);
974
if ((devcap = gs_malloc(wdev->memory, devcapsize, 1, "win_pr2_getdc")) == (LPBYTE) NULL)
976
n = DeviceCapabilities(device, output, DC_PAPERS, devcap, NULL);
977
if ((paperindex >= 0) && (paperindex < n))
978
papersize = ((WORD *) devcap)[paperindex];
979
gs_free(wdev->memory, devcap, devcapsize, 1, "win_pr2_getdc");
981
/* get the paper name */
982
devcapsize = DeviceCapabilities(device, output, DC_PAPERNAMES, NULL, NULL);
984
if ((devcap = gs_malloc(wdev->memory, devcapsize, 1, "win_pr2_getdc")) == (LPBYTE) NULL)
986
n = DeviceCapabilities(device, output, DC_PAPERNAMES, devcap, NULL);
987
if ((paperindex >= 0) && (paperindex < n))
988
strcpy(papername, devcap + paperindex * 64);
989
gs_free(wdev->memory, devcap, devcapsize, 1, "win_pr2_getdc");
991
memcpy(pidevmode, podevmode, devmode_size);
993
pidevmode->dmFields = 0;
995
wdev->paper_name[0] = 0;
997
if ( (wdev->user_paper)
998
&& (wdev->user_paper != papersize) ) {
999
papersize = wdev->user_paper;
1004
if (wdev->user_orient) {
1005
orientation = wdev->user_orient;
1008
pidevmode->dmFields &= ~(DM_PAPERSIZE | DM_ORIENTATION | DM_COLOR | DM_PAPERLENGTH | DM_PAPERWIDTH | DM_DUPLEX);
1009
pidevmode->dmFields |= DM_DEFAULTSOURCE;
1010
pidevmode->dmDefaultSource = 0;
1013
wdev->user_orient = orientation;
1016
wdev->user_paper = papersize;
1017
strcpy (wdev->paper_name, papername);
1020
if (paperheight && paperwidth) {
1021
pidevmode->dmFields |= (DM_PAPERLENGTH | DM_PAPERWIDTH);
1022
pidevmode->dmPaperWidth = paperwidth;
1023
pidevmode->dmPaperLength = paperheight;
1024
wdev->user_media_size[0] = paperwidth / 254.0 * 72.0;
1025
wdev->user_media_size[1] = paperheight / 254.0 * 72.0;
1028
if (DeviceCapabilities(device, output, DC_DUPLEX, NULL, NULL)) {
1029
wdev->Duplex_set = 1;
1032
win_pr2_update_win(wdev, pidevmode);
1034
/* merge the entries */
1035
DocumentProperties(NULL, hprinter, device, podevmode, pidevmode, DM_IN_BUFFER | DM_OUT_BUFFER);
1036
ClosePrinter(hprinter);
1039
wdev->hdcprn = CreateDC(driver, device, NULL, podevmode);
1041
if (wdev->win32_hdevmode == NULL)
1042
wdev->win32_hdevmode = GlobalAlloc(0, devmode_size);
1044
if (wdev->win32_hdevmode) {
1045
LPDEVMODE pdevmode = (LPDEVMODE) GlobalLock(wdev->win32_hdevmode);
1047
memcpy(pdevmode, podevmode, devmode_size);
1048
GlobalUnlock(wdev->win32_hdevmode);
1052
gs_free(wdev->memory, pidevmode, devmode_size, 1, "win_pr2_getdc");
1053
gs_free(wdev->memory, podevmode, devmode_size, 1, "win_pr2_getdc");
1055
if (wdev->hdcprn != (HDC) NULL)
1056
return TRUE; /* success */
1058
/* fall back to prompting user */
1064
* Minimalist update of the wdev parameters (mainly for the
1065
* UserSettings parameters).
1069
win_pr2_update_dev(gx_device_win_pr2 * dev, LPDEVMODE pdevmode)
1074
if (pdevmode->dmFields & DM_COLOR) {
1075
dev->user_color = pdevmode->dmColor;
1077
if (pdevmode->dmFields & DM_ORIENTATION) {
1078
dev->user_orient = pdevmode->dmOrientation;
1080
if (pdevmode->dmFields & DM_PAPERSIZE) {
1081
dev->user_paper = pdevmode->dmPaperSize;
1082
dev->user_media_size[0] = pdevmode->dmPaperWidth / 254.0 * 72.0;
1083
dev->user_media_size[1] = pdevmode->dmPaperLength / 254.0 * 72.0;
1084
dev->paper_name[0] = 0; /* unknown paper size */
1086
if (pdevmode->dmFields & DM_DUPLEX) {
1087
dev->Duplex_set = 1;
1088
dev->Duplex = pdevmode->dmDuplex == DMDUP_SIMPLEX ? false : true;
1089
dev->tumble = pdevmode->dmDuplex == DMDUP_HORIZONTAL ? true : false;
1096
win_pr2_update_win(gx_device_win_pr2 * dev, LPDEVMODE pdevmode)
1098
if (dev->Duplex_set > 0) {
1099
pdevmode->dmFields |= DM_DUPLEX;
1100
pdevmode->dmDuplex = DMDUP_SIMPLEX;
1102
if (dev->tumble == false) {
1103
pdevmode->dmDuplex = DMDUP_VERTICAL;
1105
pdevmode->dmDuplex = DMDUP_HORIZONTAL;
1110
if (dev->user_color) {
1111
pdevmode->dmColor = dev->user_color;
1112
pdevmode->dmFields |= DM_COLOR;
1115
if (dev->user_orient) {
1116
pdevmode->dmFields |= DM_ORIENTATION;
1117
pdevmode->dmOrientation = dev->user_orient;
1120
if (dev->user_paper) {
1121
pdevmode->dmFields |= DM_PAPERSIZE;
1122
pdevmode->dmPaperSize = dev->user_paper;
1127
/********************************************************************************/
1129
#define BEGIN_ARRAY_PARAM(pread, pname, pa, psize, e)\
1130
switch ( code = pread(dict.list, (param_name = pname), &(pa)) )\
1133
if ( (pa).size != psize )\
1134
ecode = gs_note_error(gs_error_rangecheck);\
1136
/* The body of the processing code goes here. */
1137
/* If it succeeds, it should do a 'break'; */
1138
/* if it fails, it should set ecode and fall through. */
1139
#define END_ARRAY_PARAM(pa, e)\
1144
e: param_signal_error(dict.list, param_name, ecode);\
1146
(pa).data = 0; /* mark as not filled */\
1150
/* Put the user params from UserSettings into our */
1151
/* internal variables. */
1153
win_pr2_read_user_settings(gx_device_win_pr2 * wdev, gs_param_list * plist)
1156
gs_param_string docn = { 0 };
1157
const char* dict_name = "UserSettings";
1158
const char* param_name = "";
1162
switch (code = param_begin_read_dict(plist, dict_name, &dict, false)) {
1164
param_signal_error(plist, dict_name, code);
1170
gs_param_int_array ia;
1172
BEGIN_ARRAY_PARAM(param_read_int_array, "DocumentRange", ia, 2, ia)
1173
if ((ia.data[0] < 0) ||
1175
(ia.data[0] > ia.data[1]))
1176
ecode = gs_note_error(gs_error_rangecheck);
1177
wdev->doc_page_begin = ia.data[0];
1178
wdev->doc_page_end = ia.data[1];
1179
END_ARRAY_PARAM(ia, doc_range_error)
1181
BEGIN_ARRAY_PARAM(param_read_int_array, "SelectedRange", ia, 2, ia)
1182
if ((ia.data[0] < 0) ||
1184
(ia.data[0] > ia.data[1]))
1185
ecode = gs_note_error(gs_error_rangecheck);
1186
wdev->user_page_begin = ia.data[0];
1187
wdev->user_page_end = ia.data[1];
1188
END_ARRAY_PARAM(ia, sel_range_error)
1190
param_read_int(dict.list, "Copies", &wdev->user_copies);
1191
param_read_int(dict.list, "Paper", &wdev->user_paper);
1192
param_read_int(dict.list, "Orientation", &wdev->user_orient);
1193
param_read_int(dict.list, "Color", &wdev->user_color);
1194
param_read_int(dict.list, "MaxResolution", &wdev->max_dpi);
1196
switch (code = param_read_string(dict.list, (param_name = "DocumentName"), &docn)) {
1198
if (docn.size < sizeof(wdev->doc_name))
1200
code = gs_error_rangecheck;
1204
param_signal_error(plist, param_name, ecode);
1211
param_end_read_dict(plist, dict_name, &dict);
1214
memcpy(wdev->doc_name, docn.data, docn.size);
1215
wdev->doc_name[docn.size] = 0;
1218
wdev->print_copies = 1;
1220
if (wdev->win32_hdevmode) {
1221
LPDEVMODE devmode = (LPDEVMODE) GlobalLock(wdev->win32_hdevmode);
1223
devmode->dmCopies = wdev->user_copies;
1224
devmode->dmPaperSize = wdev->user_paper;
1225
devmode->dmOrientation = wdev->user_orient;
1226
devmode->dmColor = wdev->user_color;
1227
GlobalUnlock(wdev->win32_hdevmode);
1239
win_pr2_write_user_settings(gx_device_win_pr2 * wdev, gs_param_list * plist)
1242
gs_param_int_array range;
1243
gs_param_float_array box;
1244
gs_param_string docn;
1245
gs_param_string papn;
1247
const char* pname = "UserSettings";
1251
code = param_begin_write_dict(plist, pname, &dict, false);
1252
if (code < 0) return code;
1254
array[0] = wdev->doc_page_begin;
1255
array[1] = wdev->doc_page_end;
1258
range.persistent = false;
1259
code = param_write_int_array(dict.list, "DocumentRange", &range);
1260
if (code < 0) goto error;
1262
array[0] = wdev->user_page_begin;
1263
array[1] = wdev->user_page_end;
1266
range.persistent = false;
1267
code = param_write_int_array(dict.list, "SelectedRange", &range);
1268
if (code < 0) goto error;
1270
box.data = wdev->user_media_size;
1272
box.persistent = false;
1273
code = param_write_float_array(dict.list, "MediaSize", &box);
1274
if (code < 0) goto error;
1276
code = param_write_int(dict.list, "Copies", &wdev->user_copies);
1277
if (code < 0) goto error;
1279
code = param_write_int(dict.list, "Paper", &wdev->user_paper);
1280
if (code < 0) goto error;
1282
code = param_write_int(dict.list, "Orientation", &wdev->user_orient);
1283
if (code < 0) goto error;
1285
code = param_write_int(dict.list, "Color", &wdev->user_color);
1286
if (code < 0) goto error;
1288
code = param_write_int(dict.list, "MaxResolution", &wdev->max_dpi);
1289
if (code < 0) goto error;
1291
code = param_write_int(dict.list, "PrintCopies", &wdev->print_copies);
1292
if (code < 0) goto error;
1294
docn.data = (const byte*)wdev->doc_name;
1295
docn.size = strlen(wdev->doc_name);
1296
docn.persistent = false;
1298
code = param_write_string(dict.list, "DocumentName", &docn);
1299
if (code < 0) goto error;
1301
papn.data = (const byte*)wdev->paper_name;
1302
papn.size = strlen(wdev->paper_name);
1303
papn.persistent = false;
1305
code = param_write_string(dict.list, "PaperName", &papn);
1306
if (code < 0) goto error;
1308
code = param_write_bool(dict.list, "UserChangedSettings", &wdev->user_changed_settings);
1311
param_end_write_dict(plist, pname, &dict);
1315
/********************************************************************************/
1317
/* Show up a dialog for the user to choose a printer and a paper size.
1318
* If mode == 3, then automatically select the default Windows printer
1319
* instead of asking the user.
1323
win_pr2_print_setup_interaction(gx_device_win_pr2 * wdev, int mode)
1327
LPDEVNAMES devnames;
1329
wdev->user_changed_settings = FALSE;
1330
wdev->query_user = mode;
1332
memset(&pd, 0, sizeof(pd));
1333
pd.lStructSize = sizeof(pd);
1334
pd.hwndOwner = PARENT_WINDOW;
1337
case 2: pd.Flags = PD_PRINTSETUP; break;
1338
case 3: pd.Flags = PD_RETURNDEFAULT; break;
1339
default: pd.Flags = 0; break;
1342
pd.Flags |= PD_USEDEVMODECOPIES;
1344
pd.nMinPage = wdev->doc_page_begin;
1345
pd.nMaxPage = wdev->doc_page_end;
1346
pd.nFromPage = wdev->user_page_begin;
1347
pd.nToPage = wdev->user_page_end;
1348
pd.nCopies = wdev->user_copies;
1350
/* Show the Print Setup dialog and let the user choose a printer
1351
* and a paper size/orientation.
1354
if (!PrintDlg(&pd)) return FALSE;
1356
devmode = (LPDEVMODE) GlobalLock(pd.hDevMode);
1357
devnames = (LPDEVNAMES) GlobalLock(pd.hDevNames);
1359
wdev->user_changed_settings = TRUE;
1360
if (wdev->use_old_spool_name) {
1361
sprintf(wdev->fname, "\\\\spool\\%s", (char*)(devnames)+(devnames->wDeviceOffset));
1363
sprintf(wdev->fname, "%%printer%%%s", (char*)(devnames)+(devnames->wDeviceOffset));
1367
devmode->dmCopies = wdev->user_copies * wdev->print_copies;
1371
wdev->user_page_begin = pd.nFromPage;
1372
wdev->user_page_end = pd.nToPage;
1373
wdev->user_copies = devmode->dmCopies;
1374
wdev->print_copies = pd.nCopies;
1375
wdev->user_media_size[0] = devmode->dmPaperWidth / 254.0 * 72.0;
1376
wdev->user_media_size[1] = devmode->dmPaperLength / 254.0 * 72.0;
1377
wdev->user_paper = devmode->dmPaperSize;
1378
wdev->user_orient = devmode->dmOrientation;
1379
wdev->user_color = devmode->dmColor;
1381
if (devmode->dmFields & DM_DUPLEX) {
1382
wdev->Duplex_set = 1;
1383
wdev->Duplex = devmode->dmDuplex == DMDUP_SIMPLEX ? false : true;
1384
wdev->tumble = devmode->dmDuplex == DMDUP_HORIZONTAL ? true : false;
1390
const char* driver = (char*)(devnames)+(devnames->wDriverOffset);
1391
const char* device = (char*)(devnames)+(devnames->wDeviceOffset);
1392
const char* output = (char*)(devnames)+(devnames->wOutputOffset);
1394
HDC hic = CreateIC(driver, device, output, devmode);
1397
xppinch = (float)GetDeviceCaps(hic, LOGPIXELSX);
1398
yppinch = (float)GetDeviceCaps(hic, LOGPIXELSY);
1399
wdev->user_media_size[0] = GetDeviceCaps(hic, PHYSICALWIDTH) * 72.0 / xppinch;
1400
wdev->user_media_size[1] = GetDeviceCaps(hic, PHYSICALHEIGHT) * 72.0 / yppinch;
1408
GlobalUnlock(pd.hDevMode);
1409
GlobalUnlock(pd.hDevNames);
1411
if (wdev->win32_hdevmode != NULL) {
1412
GlobalFree(wdev->win32_hdevmode);
1414
if (wdev->win32_hdevnames != NULL) {
1415
GlobalFree(wdev->win32_hdevnames);
1418
wdev->win32_hdevmode = pd.hDevMode;
1419
wdev->win32_hdevnames = pd.hDevNames;
1424
/* Check that we are dealing with an original device. If this
1425
* happens to be a copy made by "copydevice", we will have to
1426
* copy the original's handles to the associated Win32 params.
1430
win_pr2_copy_check(gx_device_win_pr2 * wdev)
1432
HGLOBAL hdevmode = wdev->win32_hdevmode;
1433
HGLOBAL hdevnames = wdev->win32_hdevnames;
1434
DWORD devmode_len = (hdevmode) ? GlobalSize(hdevmode) : 0;
1435
DWORD devnames_len = (hdevnames) ? GlobalSize(hdevnames) : 0;
1437
if (wdev->original_device == wdev)
1440
wdev->hdcprn = NULL;
1441
wdev->win32_hdevmode = NULL;
1442
wdev->win32_hdevnames = NULL;
1444
wdev->original_device = wdev;
1447
wdev->win32_hdevmode = GlobalAlloc(0, devmode_len);
1448
if (wdev->win32_hdevmode) {
1449
memcpy(GlobalLock(wdev->win32_hdevmode), GlobalLock(hdevmode), devmode_len);
1450
GlobalUnlock(wdev->win32_hdevmode);
1451
GlobalUnlock(hdevmode);
1456
wdev->win32_hdevnames = GlobalAlloc(0, devnames_len);
1457
if (wdev->win32_hdevnames) {
1458
memcpy(GlobalLock(wdev->win32_hdevnames), GlobalLock(hdevnames), devnames_len);
1459
GlobalUnlock(wdev->win32_hdevnames);
1460
GlobalUnlock(hdevnames);
1466
/* Modeless dialog box - Cancel printing */
1468
CancelDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
1472
SetWindowText(hDlg, szAppName);
1475
switch (LOWORD(wParam)) {
1477
DestroyWindow(hDlg);
1487
AbortProc2(HDC hdcPrn, int code)
1489
process_interrupts(NULL);
1490
if (code == SP_OUTOFDISK)
1491
return (FALSE); /* cancel job */