1
/* Copyright (C) 2001-2012 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,
8
modified or distributed except as expressly authorized under the terms
9
of the license contained in the file LICENSE in this distribution.
11
Refer to licensing information at http://www.artifex.com or contact
12
Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
13
CA 94903, U.S.A., +1(415)492-9861, for further information.
19
* By Russell Lang, derived from mswinpr2 device by Russell Lang and
20
* L. Peter Deutsch, Aladdin Enterprises.
22
* Bug fixed by Pierre Arnaud 2000-03-20 (os2prn_set_bpp did not set anti_alias)
25
/* This device works when GS is a DLL loaded by a PM program */
26
/* It does not work when GS is a text mode EXE */
28
/* This driver uses the printer default size and resolution and
29
* ignores page size and resolution set using -gWIDTHxHEIGHT and
30
* -rXxY. You must still set the correct PageSize to get the
31
* correct clipping path. If you don't specify a value for
32
* -dBitsPerPixel, the depth will be obtained from the printer
37
#define INCL_DOSERRORS
39
#define INCL_GPIBITMAPS
41
#define INCL_SPLDOSPRINT
42
#define INCL_SPLERRORS
49
#include "gscdefs.h" /* for gs_product */
51
extern HWND hwndtext; /* in gp_os2.h */
53
typedef struct tagOS2QL {
54
PRQINFO3 *prq; /* queue list */
55
ULONG len; /* bytes in queue list (for gs_free) */
56
int defqueue; /* default queue */
57
int nqueues; /* number of queues */
60
#ifndef NERR_BufTooSmall
61
#define NERR_BufTooSmall 2123 /* For SplEnumQueue */
64
/* Make sure we cast to the correct structure type. */
65
typedef struct gx_device_os2prn_s gx_device_os2prn;
68
#define opdev ((gx_device_os2prn *)dev)
70
/* Device procedures */
72
/* See gxdevice.h for the definitions of the procedures. */
73
static dev_proc_open_device(os2prn_open);
74
static dev_proc_close_device(os2prn_close);
75
static dev_proc_print_page(os2prn_print_page);
76
static dev_proc_map_rgb_color(os2prn_map_rgb_color);
77
static dev_proc_map_color_rgb(os2prn_map_color_rgb);
78
static dev_proc_put_params(os2prn_put_params);
79
static dev_proc_get_params(os2prn_get_params);
81
static void os2prn_set_bpp(gx_device * dev, int depth);
82
static int os2prn_get_queue_list(gs_memory_t *mem, OS2QL * ql);
83
static void os2prn_free_queue_list(gs_memory_t *mem, OS2QL * ql);
84
int os2prn_get_printer(OS2QL * ql);
86
static gx_device_procs os2prn_procs =
87
prn_color_params_procs(os2prn_open, gdev_prn_output_page, os2prn_close,
88
os2prn_map_rgb_color, os2prn_map_color_rgb,
89
os2prn_get_params, os2prn_put_params);
91
/* The device descriptor */
92
struct gx_device_os2prn_s {
98
char queue_name[256]; /* OS/2 printer queue name */
99
int newframe; /* false before first page */
101
int clipbox[4]; /* llx, lly, urx, ury in pixels */
106
gx_device_os2prn far_data gs_os2prn_device =
108
prn_device_std_body(gx_device_os2prn, os2prn_procs, "os2prn",
109
DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, 72, 72,
111
0, os2prn_print_page), /* depth = 0 */
118
/* Open the os2prn driver */
120
os2prn_open(gx_device * dev)
139
char *prefix = "\\\\spool\\"; /* 8 characters long */
142
gx_device_os2prn *oprn;
146
if (DosGetInfoBlocks(&pptib, &pppib)) {
147
errprintf(dev->memory, "\nos2prn_open: Couldn't get pid\n");
148
return gs_error_limitcheck;
150
if (pppib->pib_ultype != 3) {
151
/* if caller is not PM app */
152
errprintf(dev->memory, "os2prn device can only be used from a PM application\n");
153
return gs_error_limitcheck;
155
opdev->hab = WinQueryAnchorBlock(hwndtext);
158
if (os2prn_get_queue_list(dev->memory, &opdev->ql))
159
return gs_error_limitcheck;
161
if (opdev->queue_name[0] == '\0') {
162
/* obtain printer name from filename */
164
for (i = 0; i < 8; i++) {
165
if (prefix[i] == '\\') {
166
if ((*p != '\\') && (*p != '/'))
168
} else if (tolower(*p) != prefix[i])
172
if (i == 8 && (strlen(p) != 0))
173
strcpy(opdev->queue_name, p);
176
if (opdev->queue_name[0] != '\0') {
177
for (i = 0; i < opdev->ql.nqueues; i++) {
178
if (strcmp(opdev->ql.prq[i].pszName, opdev->queue_name) == 0) {
179
pprq = &(opdev->ql.prq[i]);
184
/* use default queue */
185
pprq = &(opdev->ql.prq[opdev->ql.defqueue]);
187
if (pprq == (PRQINFO3 *) NULL) {
188
errprintf(opdev->memory, "Invalid os2prn queue name -sOS2QUEUE=\042%s\042\n", opdev->queue_name);
189
errprintf(opdev->memory, "Valid device names are:\n");
190
for (i = 0; i < opdev->ql.nqueues; i++) {
191
errprintf(opdev->memory, " -sOS2QUEUE=\042%s\042\n", opdev->ql.prq[i].pszName);
193
return gs_error_rangecheck;
195
/* open printer device */
196
memset(&dop, 0, sizeof(dop));
197
dop.pszLogAddress = pprq->pszName; /* queue name */
198
p = strchr(pprq->pszDriverName, '.');
199
if (p != (char *)NULL)
201
dop.pszDriverName = pprq->pszDriverName;
202
dop.pszDataType = "PM_Q_STD";
203
dop.pdriv = pprq->pDriverData;
204
opdev->hdc = DevOpenDC(opdev->hab, OD_QUEUED, "*", 9L, (PDEVOPENDATA) & dop, (HDC) NULL);
205
if (opdev->hdc == DEV_ERROR) {
206
ERRORID eid = WinGetLastError(opdev->hab);
208
errprintf(opdev->memory, "DevOpenDC for printer error 0x%x\n", eid);
209
return gs_error_limitcheck;
211
os2prn_free_queue_list(dev->memory, &opdev->ql);
213
/* find out resolution of printer */
214
/* this is returned in pixels/metre */
215
DevQueryCaps(opdev->hdc, CAPS_HORIZONTAL_RESOLUTION, 2, caps);
216
dev->x_pixels_per_inch = (int)(caps[0] * 0.0254 + 0.5);
217
dev->y_pixels_per_inch = (int)(caps[1] * 0.0254 + 0.5);
219
/* find out page size and margins */
220
/* these are returned in millimetres */
221
nforms = DevQueryHardcopyCaps(opdev->hdc, 0, 0, &hcinfo);
222
for (i = 0; i < nforms; i++) {
223
DevQueryHardcopyCaps(opdev->hdc, i, 1, &hcinfo);
224
if (hcinfo.flAttributes & HCAPS_CURRENT)
225
break; /* this is the default page size */
227
/* GS size is in pixels */
228
dev->width = hcinfo.cx * caps[0] / 1000;
229
dev->height = hcinfo.cy * caps[1] / 1000;
230
/* GS margins are in inches */
231
m[0] /*left */ = hcinfo.xLeftClip / 25.4;
232
m[1] /*bottom */ = hcinfo.yBottomClip / 25.4;
233
m[2] /*right */ = (hcinfo.cx - hcinfo.xRightClip) / 25.4;
234
m[3] /*top */ = (hcinfo.cy - hcinfo.yTopClip) / 25.4;
235
gx_device_set_margins(dev, m, true);
236
/* set bounding box in pixels for later drawing */
237
opdev->clipbox[0] = (int)(hcinfo.xLeftClip / 25.4 * dev->x_pixels_per_inch + 1); /* round inwards */
238
opdev->clipbox[1] = (int)(hcinfo.yBottomClip / 25.4 * dev->y_pixels_per_inch + 1);
239
opdev->clipbox[2] = (int)(hcinfo.xRightClip / 25.4 * dev->x_pixels_per_inch);
240
opdev->clipbox[3] = (int)(hcinfo.yTopClip / 25.4 * dev->y_pixels_per_inch);
242
/* get presentation space */
243
sizlPage.cx = dev->width;
244
sizlPage.cy = dev->height;
245
opdev->hps = GpiCreatePS(opdev->hab, opdev->hdc, &sizlPage,
246
PU_PELS | GPIF_DEFAULT | GPIT_NORMAL | GPIA_ASSOC);
248
depth = dev->color_info.depth;
250
/* Set parameters that were unknown before opening device */
251
/* Find out if the device supports color */
252
/* We recognize 1 bit monochrome and 24 bit color devices */
253
DevQueryCaps(opdev->hdc, CAPS_COLOR_PLANES, 2, caps);
254
/* caps[0] is #color planes, caps[1] is #bits per plane */
255
depth = caps[0] * caps[1];
259
os2prn_set_bpp(dev, depth);
261
/* create a memory DC compatible with printer */
262
opdev->hdcMem = DevOpenDC(opdev->hab, OD_MEMORY, "*", 0L, NULL, opdev->hdc);
263
if (opdev->hdcMem == DEV_ERROR) {
264
ERRORID eid = WinGetLastError(opdev->hab);
266
errprintf(opdev->memory, "DevOpenDC for memory error 0x%x\n", eid);
267
return gs_error_limitcheck;
269
sizlPage.cx = dev->width;
270
sizlPage.cy = dev->height;
271
opdev->hpsMem = GpiCreatePS(opdev->hab, opdev->hdcMem, &sizlPage,
272
PU_PELS | GPIF_DEFAULT | GPIT_NORMAL | GPIA_ASSOC);
273
if (opdev->hpsMem == GPI_ERROR) {
274
ERRORID eid = WinGetLastError(opdev->hab);
276
errprintf(opdev->memory, "GpiCreatePS for memory error 0x%x\n", eid);
277
return gs_error_limitcheck;
279
if (DevEscape(opdev->hdc, DEVESC_STARTDOC, (LONG) strlen(gs_product),
280
(char *)gs_product, NULL, NULL) == DEVESC_ERROR) {
281
ERRORID eid = WinGetLastError(opdev->hab);
283
errprintf(opdev->memory, "DEVESC_STARTDOC error 0x%x\n", eid);
284
return gs_error_limitcheck;
286
/* gdev_prn_open opens a temporary file which we don't want */
287
/* so we specify the name now so we can delete it later */
288
pfile = gp_open_scratch_file(opdev->memory, gp_scratch_file_name_prefix,
291
code = gdev_prn_open(dev);
296
/* Close the os2prn driver */
298
os2prn_close(gx_device * dev)
304
/* tell printer that all is finished */
305
DevEscape(opdev->hdc, DEVESC_ENDDOC, 0L, NULL, &lOut, (PBYTE) & usJobID);
307
GpiAssociate(opdev->hps, (HDC) NULL);
308
GpiDestroyPS(opdev->hps);
309
DevCloseDC(opdev->hdc);
311
if (opdev->hpsMem != GPI_ERROR)
312
GpiDestroyPS(opdev->hpsMem);
313
if (opdev->hdcMem != DEV_ERROR)
314
DevCloseDC(opdev->hdcMem);
316
code = gdev_prn_close(dev);
317
/* delete unwanted temporary file */
318
unlink(opdev->fname);
322
/* Get os2pm parameters */
324
os2prn_get_params(gx_device * dev, gs_param_list * plist)
326
int code = gdev_prn_get_params(dev, plist);
329
qs.data = opdev->queue_name, qs.size = strlen(qs.data),
330
qs.persistent = false;
332
(code = param_write_string(plist, "OS2QUEUE", &qs)) < 0;
336
/* We implement this ourselves so that we can change BitsPerPixel */
337
/* before the device is opened */
339
os2prn_put_params(gx_device * dev, gs_param_list * plist)
342
int old_bpp = dev->color_info.depth;
346
/* Handle extra parameters */
347
switch (code = param_read_string(plist, "OS2QUEUE", &qs)) {
349
if (qs.size == strlen(opdev->queue_name) &&
350
!memcmp(opdev->queue_name, qs.data, qs.size)
356
ecode = gs_error_rangecheck;
357
else if (qs.size >= sizeof(opdev->queue_name))
358
ecode = gs_error_limitcheck;
364
qe:param_signal_error(plist, "OS2QUEUE", ecode);
370
switch (code = param_read_int(plist, "BitsPerPixel", &bpp)) {
373
ecode = gs_error_rangecheck;
374
else { /* change dev->color_info is valid before device is opened */
375
os2prn_set_bpp(dev, bpp);
381
bppe:param_signal_error(plist, "BitsPerPixel", ecode);
387
ecode = gdev_prn_put_params(dev, plist);
389
if ((ecode >= 0) && (qs.data != 0)) {
390
memcpy(opdev->queue_name, qs.data, qs.size);
391
opdev->queue_name[qs.size] = 0;
396
/* ------ Internal routines ------ */
399
#define opdev ((gx_device_os2prn *)pdev)
401
/************************************************/
403
/* ------ Private definitions ------ */
405
/* new os2prn_print_page routine */
407
/* Write BMP header to memory, then send bitmap to printer */
408
/* one scan line at a time */
410
os2prn_print_page(gx_device_printer * pdev, FILE * file)
412
int raster = gdev_prn_raster(pdev);
414
/* BMP scan lines are padded to 32 bits. */
415
ulong bmp_raster = (raster + 3) & (~3);
416
ulong bmp_raster_multi;
417
int height = pdev->height;
418
int depth = pdev->color_info.depth;
421
int code = 0; /* return code */
435
yslice = 65535 / bmp_raster;
436
bmp_raster_multi = bmp_raster * yslice;
437
row = (byte *) gs_malloc(pdev->memory, bmp_raster_multi, 1, "bmp file buffer");
438
if (row == 0) /* can't allocate row buffer */
439
return_error(gs_error_VMerror);
442
DevEscape(opdev->hdc, DEVESC_NEWFRAME, 0L, NULL, NULL, NULL);
445
/* Write the info header. */
447
memset(&bmi.h, 0, sizeof(bmi.h));
448
bmi.h.cbFix = sizeof(bmi.h);
449
bmi.h.cx = pdev->width; /* opdev->mdev.width; */
450
/* bmi.h.cy = height; */
451
bmi.h.cy = yslice; /* size for memory PS */
453
bmi.h.cBitCount = pdev->color_info.depth;
455
/* Write the palette. */
459
gx_color_value rgb[3];
462
bmi.h.cclrUsed = 1 << depth;
463
bmi.h.cclrImportant = 1 << depth;
464
for (i = 0; i != 1 << depth; i++) {
465
(*dev_proc(pdev, map_color_rgb)) ((gx_device *) pdev,
466
(gx_color_index) i, rgb);
468
pq->bRed = gx_color_value_to_byte(rgb[0]);
469
pq->bGreen = gx_color_value_to_byte(rgb[1]);
470
pq->bBlue = gx_color_value_to_byte(rgb[2]);
475
bmi.h.cclrImportant = 0;
478
/* for GpiDrawBits */
479
/* target is inclusive */
481
apts[0].y = 0; /* filled in later */
482
apts[1].x = pdev->width - 1;
483
apts[1].y = 0; /* filled in later */
484
/* source is not inclusive of top & right borders */
487
apts[3].x = pdev->width;
488
apts[3].y = 0; /* filled in later */
491
/* target is not inclusive */
492
aptsb[0].x = opdev->clipbox[0];
493
aptsb[0].y = 0; /* filled in later */
494
aptsb[1].x = opdev->clipbox[2];
495
aptsb[1].y = 0; /* filled in later */
496
/* source is not inclusive */
497
aptsb[2].x = opdev->clipbox[0];
499
aptsb[3].x = opdev->clipbox[2];
500
aptsb[3].y = 0; /* filled in later */
503
ystart = opdev->clipbox[3];
504
yend = opdev->clipbox[1];
507
/* create a bitmap for the memory DC */
508
hbmp = GpiCreateBitmap(opdev->hpsMem, &bmi.h, 0L, NULL, NULL);
509
if (hbmp == GPI_ERROR)
511
hbmr = GpiSetBitmap(opdev->hpsMem, hbmp);
513
/* copy slice to memory bitmap */
514
if (y > yend + yslice)
519
for (i = lines - 1; i >= 0; i--)
520
gdev_prn_copy_scan_lines(pdev, ystart - 1 - (y + i), row + (bmp_raster * i), raster);
521
apts[0].y = 0; /* target */
523
apts[3].y = lines - 1; /* source */
524
/* copy DIB bitmap to memory bitmap */
525
rc = GpiDrawBits(opdev->hpsMem, row, (BITMAPINFO2 *) & bmi, 4, apts,
526
(depth != 1) ? ROP_SRCCOPY : ROP_NOTSRCCOPY, 0);
528
/* copy slice to printer */
530
aptsb[1].y = y + lines;
532
rc = GpiBitBlt(opdev->hps, opdev->hpsMem, 4, aptsb, ROP_SRCCOPY, BBO_IGNORE);
535
if (hbmr != HBM_ERROR)
536
GpiSetBitmap(opdev->hpsMem, (ULONG) 0);
538
if (hbmp != GPI_ERROR)
539
GpiDeleteBitmap(hbmp);
545
gs_free(pdev->memory, (char *)row, bmp_raster_multi, 1, "bmp file buffer");
550
/* combined color mappers */
552
/* 24-bit color mappers (taken from gdevmem2.c). */
553
/* Note that OS/2 expects RGB values in the order B,G,R. */
555
/* Encode a r-g-b color to a color index. */
556
static gx_color_index
557
os2prn_map_rgb_color(gx_device * dev, const gx_color_value cv[])
559
gx_color_value r = cv[0];
560
gx_color_value g = cv[1];
561
gx_color_value b = cv[2];
562
return gx_color_value_to_byte(r) +
563
((uint) gx_color_value_to_byte(g) << 8) +
564
((ulong) gx_color_value_to_byte(b) << 16);
567
/* Decode a color index to a r-g-b color. */
569
os2prn_map_color_rgb(gx_device * dev, gx_color_index color,
570
gx_color_value prgb[3])
572
prgb[2] = gx_color_value_from_byte(color >> 16);
573
prgb[1] = gx_color_value_from_byte((color >> 8) & 0xff);
574
prgb[0] = gx_color_value_from_byte(color & 0xff);
579
os2prn_set_bpp(gx_device * dev, int depth)
581
gx_device_color_info dci = dev->color_info;
582
static const gx_device_color_info os2prn_dci_rgb = dci_std_color(24);
583
static const gx_device_color_info os2prn_dci_mono = dci_black_and_white;
585
dci = os2prn_dci_rgb;
586
dev->procs.get_color_mapping_procs = gx_default_DevRGB_get_color_mapping_procs;
587
dev->procs.get_color_comp_index = gx_default_DevRGB_get_color_comp_index;
588
dev->procs.map_rgb_color = dev->procs.encode_color =
589
os2prn_map_rgb_color;
590
dev->procs.map_color_rgb = dev->procs.decode_color =
591
os2prn_map_color_rgb;
592
} else { /* default is black and white */
593
dci = os2prn_dci_mono;
594
dev->procs.get_color_mapping_procs = gx_default_DevGray_get_color_mapping_procs;
595
dev->procs.get_color_comp_index = gx_default_DevGray_get_color_comp_index;
596
dev->procs.map_rgb_color = dev->procs.encode_color =
597
gx_default_b_w_map_rgb_color;
598
dev->procs.map_color_rgb = dev->procs.decode_color =
599
gx_default_b_w_map_color_rgb;
601
/* restore old anti_alias info */
602
dci.anti_alias = dev->color_info.anti_alias;
603
dev->color_info = dci;
604
/* Set the mask bits, etc. even though we are setting linear: unknown */
605
set_linear_color_bits_mask_shift(dev);
608
/* Get list of queues from SplEnumQueue */
609
/* returns 0 if OK, non-zero for error */
611
os2prn_get_queue_list(gs_memory_t *mem, OS2QL * ql)
626
pszComputerName = (PSZ) NULL;
627
splerr = SplEnumQueue(pszComputerName, ulLevel, pBuf, 0L, /* cbBuf */
630
if (splerr == ERROR_MORE_DATA || splerr == NERR_BufTooSmall) {
631
pBuf = gs_malloc(mem, cbNeeded, 1, "OS/2 printer device info buffer");
632
ql->prq = (PRQINFO3 *) pBuf;
633
if (ql->prq != (PRQINFO3 *) NULL) {
636
splerr = SplEnumQueue(pszComputerName, ulLevel, pBuf, cbBuf,
639
if (splerr == NO_ERROR) {
640
/* Set pointer to point to the beginning of the buffer. */
641
prq = (PPRQINFO3) pBuf;
642
/* cReturned has the count of the number of PRQINFO3 structures. */
643
ql->nqueues = cReturned;
645
for (i = 0; i < cReturned; i++) {
646
if (prq->fsType & PRQ3_TYPE_APPDEFAULT)
649
} /*endfor cReturned */
653
/* If we are here we had a bad error code. Print it and some other info. */
655
"SplEnumQueue Error=%ld, Total=%ld, Returned=%ld, Needed=%ld\n",
656
splerr, cTotal, cReturned, cbNeeded);
664
os2prn_free_queue_list(gs_memory_t *mem, OS2QL * ql)
666
gs_free(mem, (char *)ql->prq, ql->len, 1, "os2prn queue list");