1 /* Copyright (C) 2001-2002 artofcode LLC. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify it
4 under the terms of the GNU General Public License as published by the
5 Free Software Foundation; either version 2 of the License, or (at your
6 option) any later version.
7
8 This program is distributed in the hope that it will be useful, but
9 WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along
14 with this program; if not, write to the Free Software Foundation, Inc.,
15 59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16
17 */
18
19 /*$Id: gdevijs.c,v 1.1.2.3.2.1 2003/01/17 00:49:00 giles Exp $ */
20 /*
21 * IJS device for Ghostscript.
22 * Intended to work with any IJS compliant inkjet driver, including
23 * hpijs 1.0 and later, an IJS-enhanced gimp-print driver, and
24 * the IJS Windows GDI server (ijsmswin.exe).
25 *
26 * DRAFT
27 *
28 * WARNING: The ijs server can be selected on the gs command line
29 * which is a security risk, since any program can be run.
30 * You should use -dSAFER which sets .LockSafetyParams to true
31 * before opening this device.
32 *
33 * 11/26/03 David Suffield
34 * (c) 2003-2004 Copyright Hewlett-Packard Development Company, LP
35 *
36 * 1. Removed hpijs 1.0-1.0.2 workarounds, use hpijs 1.0.3 or higher.
37 * 2. Added krgb support.
38 *
39 * 02/21/05 David Suffield
40 * 1. Fixed segfault issue with 1-bit color space.
41 * 2. Fixed z-order issue with colored text on black rectangle.
42 *
43 */
44
45 #include "unistd_.h" /* for dup() */
46 #include <stdlib.h>
47 #include <fcntl.h>
48 #include "gdevprn.h"
49 #include "gp.h"
50 #include "ijs.h"
51 #include "ijs_client.h"
52
53 //#define KRGB_DEBUG
54
55 /* This should go into gdevprn.h, or, better yet, gdevprn should
56 acquire an API for changing resolution. */
57 int gdev_prn_maybe_realloc_memory(gx_device_printer *pdev,
58 gdev_prn_space_params *old_space,
59 int old_width, int old_height);
60
61 /* Device procedures */
62
63 /* See gxdevice.h for the definitions of the procedures. */
64 private dev_proc_open_device(gsijs_open);
65 private dev_proc_close_device(gsijs_close);
66 private dev_proc_output_page(gsijs_output_page);
67 private dev_proc_get_params(gsijs_get_params);
68 private dev_proc_put_params(gsijs_put_params);
69
70 /* Following definitions are for krgb support. */
71 private dev_proc_create_buf_device(gsijs_create_buf_device);
72 private dev_proc_fill_rectangle(gsijs_fill_rectangle);
73 private dev_proc_copy_mono(gsijs_copy_mono);
74 private dev_proc_fill_mask(gsijs_fill_mask);
75 private dev_proc_fill_path(gsijs_fill_path);
76 private dev_proc_stroke_path(gsijs_stroke_path);
77
78 private const gx_device_procs gsijs_procs =
79 prn_color_params_procs(gsijs_open, gsijs_output_page, gsijs_close,
80 gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb,
81 gsijs_get_params, gsijs_put_params);
82
83 typedef struct gx_device_ijs_s gx_device_ijs;
84
85 /* The device descriptor */
86 struct gx_device_ijs_s {
87 gx_device_common;
88 gx_prn_device_common;
89 bool IjsUseOutputFD;
90 char IjsServer[gp_file_name_sizeof]; /* name of executable ijs server */
91 char *ColorSpace;
92 int ColorSpace_size;
93 int BitsPerSample;
94 char *DeviceManufacturer;
95 int DeviceManufacturer_size;
96 char *DeviceModel;
97 int DeviceModel_size;
98 char *IjsParams;
99 int IjsParams_size;
100
101 /* Common setpagedevice parameters supported by ijs but not
102 currently parsed by gx_prn_device. We prefix these with Ijs to
103 avoid namespace collision if they do get added to gx_prn_device.
104 */
105 bool IjsTumble;
106 bool IjsTumble_set;
107
108 IjsClientCtx *ctx;
109 int ijs_version;
110
111 /* Additional parameters for krgb support. */
112 int krgb_mode; /* 0=false, 1=true */
113 int k_path; /* k plane path, 0=false, 1=true */
114 int k_width; /* k plane width in pixels */
115 int k_band_size; /* k plane buffer size in bytes, byte aligned */
116 unsigned char *k_band; /* k plane buffer */
117 gx_device_procs prn_procs; /* banding playback procedures */
118 };
119
120 #define DEFAULT_DPI 74 /* See gsijs_set_resolution() below. */
121
122 gx_device_ijs gs_ijs_device =
123 {
124 prn_device_std_body(gx_device_ijs, gsijs_procs, "ijs",
125 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
126 DEFAULT_DPI, DEFAULT_DPI,
127 0, 0, 0, 0,
128 24 /* depth */, NULL /* print page */),
129 FALSE, /* IjsUseOutputFD */
130 "", /* IjsServer */
131 NULL, /* ColorSpace */
132 0, /* ColorSpace_size */
133 8, /* BitsPerSample */
134 NULL, /* DeviceManufacturer */
135 0, /* DeviceManufacturer_size */
136 NULL, /* DeviceModel */
137 0, /* DeviceModel_size */
138 NULL, /* IjsParams */
139 0, /* IjsParams_size */
140
141 FALSE, /* Tumble */
142 FALSE, /* Tumble_set */
143
144 NULL, /* IjsClient *ctx */
145 0, /* ijs_version */
146 0, /* krgb_mode */
147 0, /* k_path */
148 0, /* k_width */
149 0, /* k_band_size */
150 NULL /* k_band buffer */
151 };
152
153
154 private int gsijs_client_set_param(gx_device_ijs *ijsdev, const char *key,
155 const char *value);
156 private int gsijs_set_color_format(gx_device_ijs *ijsdev);
157 private int gsijs_read_int(gs_param_list *plist, gs_param_name pname,
158 int *pval, int min_value, int max_value, bool only_when_closed);
159 private int gsijs_read_bool(gs_param_list *plist, gs_param_name pname,
160 bool *pval, bool only_when_closed);
161 private int gsijs_read_string(gs_param_list * plist, gs_param_name pname,
162 char * str, uint size, bool safety, bool only_when_closed);
163
164 /**************************************************************************/
165
166 /* ---------------- Low-level graphic procedures ---------------- */
167
168 static unsigned char xmask[] =
169 {
170 0x80, /* x=0 */
171 0x40, /* 1 */
172 0x20, /* 2 */
173 0x10, /* 3 */
174 0x08, /* 4 */
175 0x04, /* 5 */
176 0x02, /* 6 */
177 0x01 /* 7 */
178 };
179
gsijs_fill_rectangle(gx_device * dev,int x,int y,int w,int h,gx_color_index color)180 private int gsijs_fill_rectangle(gx_device * dev, int x, int y, int w, int h,
181 gx_color_index color)
182 {
183 gx_device_ijs *ijsdev = (gx_device_ijs *)((gx_device_forward *)dev)->target;
184
185 if (ijsdev->krgb_mode && ijsdev->k_path && y >= 0 && x >= 0)
186 {
187 int raster = (ijsdev->k_width+7) >> 3;
188 register unsigned char *dest=ijsdev->k_band+(raster*y)+(x >> 3);
189 int dest_start_bit = x & 7;
190 int i,j,w1;
191
192 if (h <= 0 || w <= 0)
193 return 0;
194
195 if ((x+w) > ijsdev->k_width)
196 w1 = ijsdev->k_width - x;
197 else
198 w1 = w;
199
200 /* Note x,y orgin 0,0 is stored first byte 0 left to right. */
201
202 if (color==0x0)
203 {
204 /* Color is black, store in k plane band instead of regular band. */
205 for (j=0; j<h; j++)
206 {
207 for (i=0; i<w1; i++)
208 dest[(dest_start_bit+i)>>3] |= xmask[(dest_start_bit+i)&7];
209 dest+=raster;
210 }
211 return 0;
212 }
213 else
214 {
215 /* Color is not black, remove any k plane bits for z-order dependencies, store in regular band. */
216 for (j=0; j<h; j++)
217 {
218 for (i=0; i<w1; i++)
219 dest[(dest_start_bit+i)>>3] &= ~xmask[(dest_start_bit+i)&7];
220 dest+=raster;
221 }
222 }
223 }
224
225 return (*ijsdev->prn_procs.fill_rectangle)(dev, x, y, w, h, color);
226 }
227
gsijs_copy_mono(gx_device * dev,const byte * data,int dx,int draster,gx_bitmap_id id,int x,int y,int w,int height,gx_color_index zero,gx_color_index one)228 private int gsijs_copy_mono(gx_device * dev, const byte * data,
229 int dx, int draster, gx_bitmap_id id,
230 int x, int y, int w, int height, gx_color_index zero, gx_color_index one)
231 {
232 gx_device_ijs *ijsdev = (gx_device_ijs *)((gx_device_forward *)dev)->target;
233
234 // if (ijsdev->krgb_mode && ijsdev->k_path && one==0x0)
235 if (ijsdev->krgb_mode && ijsdev->k_path)
236 {
237 /* Store in k plane band instead of regular band. */
238 int raster = (ijsdev->k_width+7) >> 3; /* raster width in bytes, byte aligned */
239 register unsigned char *dest=ijsdev->k_band+(raster*y)+(x >> 3);
240 register const unsigned char *scan=data+(dx >> 3);
241 int dest_start_bit = x & 7;
242 int scan_start_bit = dx & 7;
243 int i, h=height;
244
245 if (h <= 0 || w <= 0)
246 return 0;
247
248 if (one==0x0)
249 {
250 /* Color is black, store in k plane band instead of regular band. */
251 while (h-- > 0)
252 {
253 for (i=0; i<w; i++)
254 {
255 if (scan[(scan_start_bit+i)>>3] & xmask[(scan_start_bit+i)&7])
256 dest[(dest_start_bit+i)>>3] |= xmask[(dest_start_bit+i)&7];
257 }
258 scan+=draster;
259 dest+=raster;
260 }
261 return 0;
262 }
263 else
264 {
265 /* Color is not black, remove any k plane bits for z-order dependencies, store in regular band. */
266 while (h-- > 0)
267 {
268 for (i=0; i<w; i++)
269 {
270 if (scan[(scan_start_bit+i)>>3] & xmask[(scan_start_bit+i)&7])
271 dest[(dest_start_bit+i)>>3] &= ~xmask[(dest_start_bit+i)&7];
272 }
273 scan+=draster;
274 dest+=raster;
275 }
276 }
277 }
278
279 return (*ijsdev->prn_procs.copy_mono)(dev, data, dx, draster, id, x, y, w, height, zero, one);
280 }
281
282 /* ---------------- High-level graphic procedures ---------------- */
283
gsijs_fill_mask(gx_device * dev,const byte * data,int dx,int raster,gx_bitmap_id id,int x,int y,int w,int h,const gx_drawing_color * pdcolor,int depth,gs_logical_operation_t lop,const gx_clip_path * pcpath)284 private int gsijs_fill_mask(gx_device * dev,
285 const byte * data, int dx, int raster, gx_bitmap_id id,
286 int x, int y, int w, int h,
287 const gx_drawing_color * pdcolor, int depth,
288 gs_logical_operation_t lop, const gx_clip_path * pcpath)
289 {
290 gx_device_ijs *ijsdev = (gx_device_ijs *)((gx_device_forward *)dev)->target;
291 int code;
292
293 ijsdev->k_path = 1;
294
295 code = (*ijsdev->prn_procs.fill_mask)(dev, data, dx, raster, id, x, y, w, h, pdcolor, depth, lop, pcpath);
296
297 ijsdev->k_path = 0;
298
299 return code;
300 }
301
gsijs_fill_path(gx_device * dev,const gs_imager_state * pis,gx_path * ppath,const gx_fill_params * params,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath)302 private int gsijs_fill_path(gx_device * dev, const gs_imager_state * pis,
303 gx_path * ppath, const gx_fill_params * params,
304 const gx_drawing_color * pdcolor,
305 const gx_clip_path * pcpath)
306 {
307 gx_device_ijs *ijsdev = (gx_device_ijs *)((gx_device_forward *)dev)->target;
308 int code;
309
310 ijsdev->k_path = 1;
311
312 code = (*ijsdev->prn_procs.fill_path)(dev, pis, ppath, params, pdcolor, pcpath);
313
314 ijsdev->k_path = 0;
315
316 return 0;
317 }
318
gsijs_stroke_path(gx_device * dev,const gs_imager_state * pis,gx_path * ppath,const gx_stroke_params * params,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath)319 private int gsijs_stroke_path(gx_device * dev, const gs_imager_state * pis,
320 gx_path * ppath, const gx_stroke_params * params,
321 const gx_drawing_color * pdcolor,
322 const gx_clip_path * pcpath)
323 {
324 gx_device_ijs *ijsdev = (gx_device_ijs *)((gx_device_forward *)dev)->target;
325 int code;
326
327 ijsdev->k_path = 1;
328
329 code = (*ijsdev->prn_procs.stroke_path)(dev, pis, ppath, params, pdcolor, pcpath);
330
331 ijsdev->k_path = 0;
332
333 return code;
334 }
335
336 /* ---------------- krgb banding playback procedures ---------------- */
337
gsijs_get_bits(gx_device_printer * pdev,int y,byte * str,byte ** actual_data)338 private int gsijs_get_bits(gx_device_printer * pdev, int y, byte * str, byte ** actual_data)
339 {
340 gx_device_ijs *ijsdev = (gx_device_ijs *)pdev;
341 gx_device_clist_common *cdev = (gx_device_clist_common *)pdev;
342 int band_height = cdev->page_info.band_params.BandHeight;
343 int band_number = y/band_height;
344 int raster = (ijsdev->k_width+7) >> 3; /* raster width in bytes, byte aligned */
345 int y1=raster*(y-(band_height*band_number));
346
347 if (y1 == 0)
348 {
349 /* First raster for band, clear k_band. Banding playback occurs on first raster. */
350 memset(ijsdev->k_band, 0, ijsdev->k_band_size);
351 }
352
353 return gdev_prn_get_bits(pdev, y, str, actual_data); /* get raster from regular band */
354 }
355
gsijs_k_get_bits(gx_device_printer * pdev,int y,byte ** actual_data)356 private int gsijs_k_get_bits(gx_device_printer * pdev, int y, byte ** actual_data)
357 {
358 gx_device_ijs *ijsdev = (gx_device_ijs *)pdev;
359 gx_device_clist_common *cdev = (gx_device_clist_common *)pdev;
360 int band_height = cdev->page_info.band_params.BandHeight;
361 int band_number = y/band_height;
362 int raster = (ijsdev->k_width+7) >> 3; /* raster width in bytes, byte aligned */
363 int y1=raster*(y-(band_height*band_number));
364
365 *actual_data = ijsdev->k_band+y1;
366
367 return 0;
368 }
369
gsijs_create_buf_device(gx_device ** pbdev,gx_device * target,const gx_render_plane_t * render_plane,gs_memory_t * mem,bool for_band)370 private int gsijs_create_buf_device(gx_device **pbdev, gx_device *target,
371 const gx_render_plane_t *render_plane, gs_memory_t *mem, bool for_band)
372 {
373 gx_device_ijs *ijsdev = (gx_device_ijs *)target;
374 int n_chan = ijsdev->color_info.num_components;
375 int code = gx_default_create_buf_device(pbdev, target, render_plane, mem, for_band);
376 if (code < 0 || n_chan != 3)
377 return code;
378
379 /* Save buffer (vector) procedures so that we can hook them during banding playback. */
380 ijsdev->prn_procs = (*pbdev)->procs;
381
382 /* Replace buffer procedures with krgb procedures. */
383 set_dev_proc(*pbdev, fill_rectangle, gsijs_fill_rectangle);
384 set_dev_proc(*pbdev, copy_mono, gsijs_copy_mono);
385 set_dev_proc(*pbdev, fill_mask, gsijs_fill_mask);
386 set_dev_proc(*pbdev, fill_path, gsijs_fill_path);
387 set_dev_proc(*pbdev, stroke_path, gsijs_stroke_path);
388
389 return code;
390 }
391
392 /* See if IJS server supports krgb. Return value: 0=false, 1=true. */
393 private int
gsijs_set_krgb_mode(gx_device_ijs * ijsdev)394 gsijs_set_krgb_mode(gx_device_ijs *ijsdev)
395 {
396 char buf[256];
397 int n_chan = ijsdev->color_info.num_components;
398 int code;
399
400 if (n_chan != 3)
401 return 0; /* no krgb support, not RGB colorspace */
402
403 buf[0] = 0;
404 code = ijs_client_enum_param(ijsdev->ctx, 0, "ColorSpace", buf, sizeof(buf)-1);
405 if (code >= 0)
406 buf[code] = 0;
407 if (strstr(buf, "KRGB") == NULL)
408 return 0; /* no krgb support */
409
410 return 1; /* krgb is supported */
411 }
412
413 /* ------ Private definitions ------ */
414
415 private int
gsijs_parse_wxh(const char * val,int size,double * pw,double * ph)416 gsijs_parse_wxh (const char *val, int size, double *pw, double *ph)
417 {
418 char buf[256];
419 char *tail;
420 int i;
421
422 for (i = 0; i < size; i++)
423 if (val[i] == 'x')
424 break;
425
426 if (i + 1 >= size)
427 return IJS_ESYNTAX;
428
429 if (i >= sizeof(buf))
430 return IJS_EBUF;
431
432 memcpy (buf, val, i);
433 buf[i] = 0;
434 *pw = strtod (buf, &tail);
435 if (tail == buf)
436 return IJS_ESYNTAX;
437
438 if (size - i > sizeof(buf))
439 return IJS_EBUF;
440
441 memcpy (buf, val + i + 1, size - i - 1);
442 buf[size - i - 1] = 0;
443 *ph = strtod (buf, &tail);
444 if (tail == buf)
445 return IJS_ESYNTAX;
446
447 return 0;
448 }
449
450 /**
451 * gsijs_set_generic_params: Set generic IJS parameters.
452 **/
453 private int
gsijs_set_generic_params(gx_device_ijs * ijsdev)454 gsijs_set_generic_params(gx_device_ijs *ijsdev)
455 {
456 char buf[256];
457 int code = 0;
458 int i, j;
459 char *value;
460
461 /* Split IjsParams into separate parameters and send to ijs server */
462 value = NULL;
463 for (i=0, j=0; (j < ijsdev->IjsParams_size) && (i < sizeof(buf)-1); j++) {
464 char ch = ijsdev->IjsParams[j];
465 if (ch == '\\') {
466 j++;
467 buf[i++] = ijsdev->IjsParams[j];
468 }
469 else {
470 if (ch == '=') {
471 buf[i++] = '\0';
472 value = &buf[i];
473 }
474 else
475 buf[i++] = ch;
476 if (ch == ',') {
477 buf[i-1] = '\0';
478 if (value)
479 gsijs_client_set_param(ijsdev, buf, value);
480 i = 0;
481 value = NULL;
482 }
483 }
484 }
485 if (value)
486 code = gsijs_client_set_param(ijsdev, buf, value);
487
488 if (code == 0 && ijsdev->Duplex_set) {
489 code = gsijs_client_set_param(ijsdev, "PS:Duplex",
490 ijsdev->Duplex ? "true" : "false");
491 }
492 if (code == 0 && ijsdev->IjsTumble_set) {
493 code = gsijs_client_set_param(ijsdev, "PS:Tumble",
494 ijsdev->IjsTumble ? "true" :
495 "false");
496 }
497 return code;
498 }
499
500 /**
501 * gsijs_set_margin_params: Do margin negotiation with IJS server.
502 **/
503 private int
gsijs_set_margin_params(gx_device_ijs * ijsdev)504 gsijs_set_margin_params(gx_device_ijs *ijsdev)
505 {
506 char buf[256];
507 int code = 0;
508 int i, j;
509 char *value;
510
511 /* Split IjsParams into separate parameters and send to ijs server */
512 value = NULL;
513 for (i=0, j=0; (j < ijsdev->IjsParams_size) && (i < sizeof(buf)-1); j++) {
514 char ch = ijsdev->IjsParams[j];
515 if (ch == '\\') {
516 j++;
517 buf[i++] = ijsdev->IjsParams[j];
518 }
519 else {
520 if (ch == '=') {
521 buf[i++] = '\0';
522 value = &buf[i];
523 }
524 else
525 buf[i++] = ch;
526 if (ch == ',') {
527 buf[i-1] = '\0';
528 if (value)
529 gsijs_client_set_param(ijsdev, buf, value);
530 i = 0;
531 value = NULL;
532 }
533 }
534 }
535 if (value)
536 code = gsijs_client_set_param(ijsdev, buf, value);
537
538 if (code == 0 && ijsdev->Duplex_set) {
539 code = gsijs_client_set_param(ijsdev, "Duplex",
540 ijsdev->Duplex ? "true" : "false");
541 }
542 if (code == 0 && ijsdev->IjsTumble_set) {
543 code = gsijs_client_set_param(ijsdev, "Tumble",
544 ijsdev->IjsTumble ? "true" :
545 "false");
546 }
547
548 if (code == 0) {
549 sprintf (buf, "%gx%g", ijsdev->MediaSize[0] * (1.0 / 72),
550 ijsdev->MediaSize[1] * (1.0 / 72));
551 code = ijs_client_set_param(ijsdev->ctx, 0, "PaperSize",
552 buf, strlen(buf));
553 }
554
555 if (code == 0) {
556 double printable_width, printable_height;
557 double printable_left, printable_top;
558 float m[4];
559
560 code = ijs_client_get_param(ijsdev->ctx, 0, "PrintableArea",
561 buf, sizeof(buf));
562 if (code == IJS_EUNKPARAM)
563 /* IJS server doesn't support margin negotiations.
564 That's ok. */
565 return 0;
566 else if (code >= 0) {
567 code = gsijs_parse_wxh (buf, code,
568 &printable_width, &printable_height);
569 }
570
571 if (code == 0) {
572 code = ijs_client_get_param(ijsdev->ctx, 0, "PrintableTopLeft",
573 buf, sizeof(buf));
574 if (code == IJS_EUNKPARAM)
575 return 0;
576 else if (code >= 0) {
577 code = gsijs_parse_wxh(buf, code,
578 &printable_left, &printable_top);
579 }
580 }
581
582 if (code == 0) {
583 m[0] = printable_left;
584 m[3] = printable_top;
585 m[2] = ijsdev->MediaSize[0] * (1.0 / 72) -
586 printable_left - printable_width;
587 m[1] = ijsdev->MediaSize[1] * (1.0 / 72) -
588 printable_top - printable_height;
589 gx_device_set_margins((gx_device *)ijsdev, m, true);
590 sprintf (buf, "%gx%g", printable_left, printable_top);
591 code = ijs_client_set_param(ijsdev->ctx, 0, "TopLeft",
592 buf, strlen(buf));
593 }
594 }
595
596 return code;
597 }
598
599 /**
600 * gsijs_set_resolution: Set resolution.
601 *
602 * The priority order, highest first, is: commandline -r switch,
603 * if specified; IJS get_param of Dpi; 72 dpi default.
604 *
605 * Because Ghostscript doesn't have a really good way to detect
606 * whether resolution was set on the command line, we set a
607 * low-probability resolution (DEFAULT_DPI) in the static
608 * initialization of the device, then detect whether it has been
609 * changed from that. This causes a minor infelicity: if DEFAULT_DPI
610 * is set on the command line, it is changed to the default here.
611 **/
612 private int
gsijs_set_resolution(gx_device_ijs * ijsdev)613 gsijs_set_resolution(gx_device_ijs *ijsdev)
614 {
615 char buf[256];
616 int code;
617 floatp x_dpi, y_dpi;
618 int width = ijsdev->width;
619 int height = ijsdev->height;
620 bool save_is_open = ijsdev->is_open;
621
622 if (ijsdev->HWResolution[0] != DEFAULT_DPI ||
623 ijsdev->HWResolution[1] != DEFAULT_DPI) {
624 /* Resolution has been set on command line. */
625 return 0;
626 }
627 code = ijs_client_get_param(ijsdev->ctx, 0, "Dpi",
628 buf, sizeof(buf));
629 if (code >= 0) {
630 int i;
631
632 for (i = 0; i < code; i++)
633 if (buf[i] == 'x')
634 break;
635 if (i == code) {
636 char *tail;
637
638 if (i == sizeof(buf))
639 code = IJS_EBUF;
640 buf[i] = 0;
641 x_dpi = y_dpi = strtod (buf, &tail);
642 if (tail == buf)
643 code = IJS_ESYNTAX;
644 } else {
645 double x, y;
646
647 code = gsijs_parse_wxh(buf, code, &x, &y);
648 x_dpi = x;
649 y_dpi = y;
650 }
651 }
652
653 if (code < 0) {
654 x_dpi = 72.0;
655 y_dpi = 72.0;
656 }
657
658 gx_device_set_resolution((gx_device *)ijsdev, x_dpi, y_dpi);
659
660 ijsdev->is_open = true;
661 code = gdev_prn_maybe_realloc_memory((gx_device_printer *)ijsdev,
662 &ijsdev->space_params,
663 width, height);
664 ijsdev->is_open = save_is_open;
665 return code;
666 }
667
668 /* Open the gsijs driver */
669 private int
gsijs_open(gx_device * dev)670 gsijs_open(gx_device *dev)
671 {
672 gx_device_ijs *ijsdev = (gx_device_ijs *)dev;
673 int code;
674 char buf[256];
675 bool use_outputfd;
676 int fd = -1;
677 long max_bitmap = ijsdev->space_params.MaxBitmap;
678
679 if (strlen(ijsdev->IjsServer) == 0) {
680 eprintf("ijs server not specified\n");
681 return gs_note_error(gs_error_ioerror);
682 }
683
684 ijsdev->space_params.MaxBitmap = 0; /* force banding */
685
686 /* Set create_buf_device in printer device, so that we can hook the banding playback procedures. */
687 ijsdev->printer_procs.buf_procs.create_buf_device = gsijs_create_buf_device;
688
689 /* Decide whether to use OutputFile or OutputFD. Note: how to
690 determine this is a tricky question, so we just allow the
691 user to set it.
692 */
693 use_outputfd = ijsdev->IjsUseOutputFD;
694
695 /* If using OutputFilename, we don't want to open the output file.
696 Leave that to the ijs server. */
697 ijsdev->OpenOutputFile = use_outputfd;
698
699 code = gdev_prn_open(dev);
700 if (code < 0)
701 return code;
702
703 ijsdev->space_params.MaxBitmap = max_bitmap;
704
705 if (use_outputfd) {
706 /* Note: dup() may not be portable to all interesting IJS
707 platforms. In that case, this branch should be #ifdef'ed out.
708 */
709 fd = dup(fileno(ijsdev->file));
710 }
711
712 /* WARNING: Ghostscript should be run with -dSAFER to stop
713 * someone changing the ijs server (e.g. running a shell).
714 */
715 ijsdev->ctx = ijs_invoke_server(ijsdev->IjsServer);
716 if (ijsdev->ctx == (IjsClientCtx *)NULL) {
717 eprintf1("Can't start ijs server \042%s\042\n", ijsdev->IjsServer);
718 return gs_note_error(gs_error_ioerror);
719 }
720
721 ijsdev->ijs_version = ijs_client_get_version (ijsdev->ctx);
722
723 if (ijs_client_open(ijsdev->ctx) < 0) {
724 eprintf("Can't open ijs\n");
725 return gs_note_error(gs_error_ioerror);
726 }
727 if (ijs_client_begin_job(ijsdev->ctx, 0) < 0) {
728 eprintf("Can't begin ijs job 0\n");
729 ijs_client_close(ijsdev->ctx);
730 return gs_note_error(gs_error_ioerror);
731 }
732
733 if (use_outputfd) {
734 /* Note: dup() may not be portable to all interesting IJS
735 platforms. In that case, this branch should be #ifdef'ed out.
736 */
737 sprintf(buf, "%d", fd);
738 ijs_client_set_param(ijsdev->ctx, 0, "OutputFD", buf, strlen(buf));
739 close(fd);
740 } else {
741 ijs_client_set_param(ijsdev->ctx, 0, "OutputFile",
742 ijsdev->fname, strlen(ijsdev->fname));
743 }
744
745 if (code >= 0 && ijsdev->DeviceManufacturer)
746 code = ijs_client_set_param(ijsdev->ctx, 0, "DeviceManufacturer",
747 ijsdev->DeviceManufacturer,
748 strlen(ijsdev->DeviceManufacturer));
749
750 if (code >= 0 && ijsdev->DeviceModel)
751 code = ijs_client_set_param(ijsdev->ctx, 0, "DeviceModel",
752 ijsdev->DeviceModel,
753 strlen(ijsdev->DeviceModel));
754
755 if (code >= 0)
756 code = gsijs_set_generic_params(ijsdev);
757
758 if (code >= 0)
759 code = gsijs_set_resolution(ijsdev);
760
761 if (code >= 0)
762 code = gsijs_set_margin_params(ijsdev);
763
764 if (code >= 0)
765 ijsdev->krgb_mode = gsijs_set_krgb_mode(ijsdev);
766
767 return code;
768 };
769
770 /* Close the gsijs driver */
771 private int
gsijs_close(gx_device * dev)772 gsijs_close(gx_device *dev)
773 {
774 gx_device_ijs *ijsdev = (gx_device_ijs *)dev;
775 int code;
776
777 /* ignore ijs errors on close */
778 ijs_client_end_job(ijsdev->ctx, 0);
779 ijs_client_close(ijsdev->ctx);
780 ijs_client_begin_cmd(ijsdev->ctx, IJS_CMD_EXIT);
781 ijs_client_send_cmd_wait(ijsdev->ctx);
782
783 code = gdev_prn_close(dev);
784 if (ijsdev->IjsParams)
785 gs_free(ijsdev->IjsParams, ijsdev->IjsParams_size, 1,
786 "gsijs_read_string_malloc");
787 if (ijsdev->ColorSpace)
788 gs_free(ijsdev->ColorSpace,
789 ijsdev->ColorSpace_size, 1,
790 "gsijs_read_string_malloc");
791 if (ijsdev->DeviceManufacturer)
792 gs_free(ijsdev->DeviceManufacturer,
793 ijsdev->DeviceManufacturer_size, 1,
794 "gsijs_read_string_malloc");
795 if (ijsdev->DeviceModel)
796 gs_free(ijsdev->DeviceModel, ijsdev->DeviceModel_size, 1,
797 "gsijs_read_string_malloc");
798 ijsdev->IjsParams = NULL;
799 ijsdev->IjsParams_size = 0;
800 ijsdev->DeviceManufacturer = NULL;
801 ijsdev->DeviceManufacturer_size = 0;
802 ijsdev->DeviceModel = NULL;
803 ijsdev->DeviceModel_size = 0;
804 return code;
805 }
806
807 /* This routine is entirely analagous to gdev_prn_print_scan_lines(),
808 but computes width instead of height. It is not specific to IJS,
809 and a strong case could be made for moving it into gdevprn.c. */
810 private int
gsijs_raster_width(gx_device * pdev)811 gsijs_raster_width(gx_device *pdev)
812 {
813 int width = pdev->width;
814 gs_matrix imat;
815 float xscale;
816 int right, offset, end;
817
818 (*dev_proc(pdev, get_initial_matrix)) (pdev, &imat);
819 xscale = imat.xx * 72.0;
820 right = (int)(dev_r_margin(pdev) * xscale);
821 offset = (int)(dev_x_offset(pdev) * xscale);
822 end = offset + width - right;
823 return min(width, end);
824 }
825
826 /* Print a page. Don't use normal printer gdev_prn_output_page
827 * because it opens the output file.
828 */
829 private int
gsijs_output_page(gx_device * dev,int num_copies,int flush)830 gsijs_output_page(gx_device *dev, int num_copies, int flush)
831 {
832 gx_device_ijs *ijsdev = (gx_device_ijs *)dev;
833 gx_device_printer *pdev = (gx_device_printer *)dev;
834 int raster = gdev_prn_raster(pdev);
835 int ijs_width, ijs_height;
836 int row_bytes, k_row_bytes=0;
837 int n_chan = pdev->color_info.num_components;
838 int krgb_mode = ijsdev->krgb_mode;
839 unsigned char *data;
840 char buf[256];
841 double xres = pdev->HWResolution[0];
842 double yres = pdev->HWResolution[1];
843 int code = 0;
844 int endcode = 0;
845 int status = 0;
846 int i, y;
847
848 if ((data = gs_alloc_bytes(pdev->memory, raster, "gsijs_output_page"))
849 == (unsigned char *)NULL)
850 return gs_note_error(gs_error_VMerror);
851
852 /* Determine bitmap width and height */
853 ijs_height = gdev_prn_print_scan_lines(dev);
854 ijs_width = gsijs_raster_width(dev);
855
856 row_bytes = (ijs_width * pdev->color_info.depth + 7) >> 3;
857
858 if (krgb_mode)
859 {
860 gx_device_clist_common *cdev = (gx_device_clist_common *)dev;
861 int band_height = cdev->page_info.band_params.BandHeight;
862 k_row_bytes = (ijs_width + 7) >> 3;
863
864 /* Create banding buffer for k plane. */
865 ijsdev->k_width = ijs_width;
866 ijsdev->k_band_size = band_height * k_row_bytes;
867 if ((ijsdev->k_band = gs_malloc(ijsdev->k_band_size, 1, "gsijs_output_page")) == (unsigned char *)NULL)
868 return gs_note_error(gs_error_VMerror);
869 }
870
871 /* Required page parameters */
872 sprintf(buf, "%d", n_chan);
873 gsijs_client_set_param(ijsdev, "NumChan", buf);
874 sprintf(buf, "%d", ijsdev->BitsPerSample);
875 gsijs_client_set_param(ijsdev, "BitsPerSample", buf);
876
877 /* This needs to become more sophisticated for DeviceN. */
878 strcpy(buf, (n_chan == 4) ? "DeviceCMYK" :
879 ((n_chan == 3) ? (krgb_mode ? "KRGB" : "DeviceRGB") : "DeviceGray"));
880 gsijs_client_set_param(ijsdev, "ColorSpace", buf);
881
882 sprintf(buf, "%d", ijs_width);
883 gsijs_client_set_param(ijsdev, "Width", buf);
884 sprintf(buf, "%d", ijs_height);
885 gsijs_client_set_param(ijsdev, "Height", buf);
886
887 sprintf(buf, "%gx%g", xres, yres);
888 gsijs_client_set_param(ijsdev, "Dpi", buf);
889
890 #ifdef KRGB_DEBUG
891 int kfd, rgbfd;
892 char sz[128];
893 kfd = open("/tmp/k.pbm", O_CREAT | O_TRUNC | O_RDWR, 0644);
894 rgbfd = open("/tmp/rgb.ppm", O_CREAT | O_TRUNC | O_RDWR, 0644);
895 snprintf(sz, sizeof(sz), "P4\n#gdevijs test\n%d\n%d\n", ijs_width, ijs_height);
896 write(kfd, sz, strlen(sz));
897 snprintf(sz, sizeof(sz), "P6\n#gdevijs test\n%d\n%d\n255\n", ijs_width, ijs_height);
898 write(rgbfd, sz, strlen(sz));
899 #endif
900
901 for (i=0; i<num_copies; i++) {
902 unsigned char *actual_data;
903 ijs_client_begin_cmd (ijsdev->ctx, IJS_CMD_BEGIN_PAGE);
904 status = ijs_client_send_cmd_wait(ijsdev->ctx);
905
906 for (y = 0; y < ijs_height; y++) {
907 if (krgb_mode)
908 code = gsijs_get_bits(pdev, y, data, &actual_data);
909 else
910 code = gdev_prn_get_bits(pdev, y, data, &actual_data);
911 if (code < 0)
912 break;
913 #ifdef KRGB_DEBUG
914 write(rgbfd, actual_data, row_bytes);
915 #endif
916 status = ijs_client_send_data_wait(ijsdev->ctx, 0, (char *)actual_data, row_bytes);
917 if (status)
918 break;
919
920 if (krgb_mode) {
921 code = gsijs_k_get_bits(pdev, y, &actual_data);
922 if (code < 0)
923 break;
924 #ifdef KRGB_DEBUG
925 write(kfd, actual_data, k_row_bytes);
926 #endif
927 status = ijs_client_send_data_wait(ijsdev->ctx, 0, (char *)actual_data, k_row_bytes);
928 if (status)
929 break;
930 }
931 }
932 ijs_client_begin_cmd(ijsdev->ctx, IJS_CMD_END_PAGE);
933 status = ijs_client_send_cmd_wait(ijsdev->ctx);
934 }
935
936 #ifdef KRGB_DEBUG
937 close(kfd);
938 close(rgbfd);
939 #endif
940
941 if(krgb_mode)
942 gs_free(ijsdev->k_band, ijsdev->k_band_size, 1, "gsijs_output_page");
943
944 gs_free_object(pdev->memory, data, "gsijs_output_page");
945
946 endcode = (pdev->buffer_space && !pdev->is_async_renderer ?
947 clist_finish_page(dev, flush) : 0);
948
949
950 if (endcode < 0)
951 return endcode;
952
953 if (code < 0)
954 return endcode;
955
956 if (status < 0)
957 return gs_note_error(gs_error_ioerror);
958
959 code = gx_finish_output_page(dev, num_copies, flush);
960 return code;
961 }
962
963
964 /**************************************************************************/
965
966 /* Get device parameters */
967 private int
gsijs_get_params(gx_device * dev,gs_param_list * plist)968 gsijs_get_params(gx_device *dev, gs_param_list *plist)
969 {
970 gx_device_ijs *ijsdev = (gx_device_ijs *)dev;
971 gs_param_string gps;
972 int code = gdev_prn_get_params(dev, plist);
973
974 if (code >= 0) {
975 param_string_from_transient_string(gps, ijsdev->IjsServer);
976 code = param_write_string(plist, "IjsServer", &gps);
977 }
978
979 if (code >= 0) {
980 if (ijsdev->DeviceManufacturer) {
981 param_string_from_transient_string(gps,
982 ijsdev->DeviceManufacturer);
983 code = param_write_string(plist, "DeviceManufacturer", &gps);
984 } else {
985 code = param_write_null(plist, "DeviceManufacturer");
986 }
987 }
988
989 if (code >= 0) {
990 if (ijsdev->DeviceModel) {
991 param_string_from_transient_string(gps, ijsdev->DeviceModel);
992 code = param_write_string(plist, "DeviceModel", &gps);
993 } else {
994 code = param_write_null(plist, "DeviceModel");
995 }
996 }
997
998 if (code >= 0) {
999 if (ijsdev->IjsParams) {
1000 param_string_from_transient_string(gps, ijsdev->IjsParams);
1001 code = param_write_string(plist, "IjsParams", &gps);
1002 } else {
1003 code = param_write_null(plist, "IjsParams");
1004 }
1005 }
1006
1007 if (code >= 0)
1008 code = param_write_int(plist, "BitsPerSample", &ijsdev->BitsPerSample);
1009
1010 if (code >= 0)
1011 code = param_write_bool(plist, "IjsUseOutputFD",
1012 &ijsdev->IjsUseOutputFD);
1013
1014 if (code >= 0) {
1015 if (ijsdev->IjsTumble_set) {
1016 code = param_write_bool(plist, "Tumble", &ijsdev->IjsTumble);
1017 } else {
1018 code = param_write_null(plist, "Tumble");
1019 }
1020 }
1021
1022 return code;
1023 }
1024
1025 private int
gsijs_read_int(gs_param_list * plist,gs_param_name pname,int * pval,int min_value,int max_value,bool only_when_closed)1026 gsijs_read_int(gs_param_list *plist, gs_param_name pname, int *pval,
1027 int min_value, int max_value, bool only_when_closed)
1028 {
1029 int code = 0;
1030 int new_value;
1031
1032 switch (code = param_read_int(plist, pname, &new_value)) {
1033 case 0:
1034 if (only_when_closed && (new_value != *pval)) {
1035 code = gs_error_rangecheck;
1036 goto e;
1037 }
1038 if ((new_value >= min_value) && (new_value <= max_value)) {
1039 *pval = new_value;
1040 break;
1041 }
1042 code = gs_note_error(gs_error_rangecheck);
1043 goto e;
1044 default:
1045 if (param_read_null(plist, pname) == 0)
1046 return 1;
1047 e:param_signal_error(plist, pname, code);
1048 case 1:
1049 ;
1050 }
1051 return code;
1052 }
1053
1054 private int
gsijs_read_bool(gs_param_list * plist,gs_param_name pname,bool * pval,bool only_when_closed)1055 gsijs_read_bool(gs_param_list *plist, gs_param_name pname, bool *pval,
1056 bool only_when_closed)
1057 {
1058 int code = 0;
1059 bool new_value;
1060
1061 switch (code = param_read_bool(plist, pname, &new_value)) {
1062 case 0:
1063 if (only_when_closed && (new_value != *pval)) {
1064 code = gs_error_rangecheck;
1065 goto e;
1066 }
1067 *pval = new_value;
1068 break;
1069 default:
1070 if (param_read_null(plist, pname) == 0) {
1071 return 1;
1072 }
1073 e:param_signal_error(plist, pname, code);
1074 case 1:
1075 ;
1076 }
1077 return code;
1078 }
1079
1080 private int
gsijs_read_string(gs_param_list * plist,gs_param_name pname,char * str,uint size,bool safety,bool only_when_closed)1081 gsijs_read_string(gs_param_list *plist, gs_param_name pname, char *str,
1082 uint size, bool safety, bool only_when_closed)
1083 {
1084 int code;
1085 gs_param_string new_value;
1086 int differs;
1087
1088 switch (code = param_read_string(plist, pname, &new_value)) {
1089 case 0:
1090 differs = bytes_compare(new_value.data, new_value.size,
1091 (const byte *)str, strlen(str));
1092 if (safety && differs) {
1093 code = gs_error_invalidaccess;
1094 goto e;
1095 }
1096 if (only_when_closed && differs) {
1097 code = gs_error_rangecheck;
1098 goto e;
1099 }
1100 if (new_value.size < size) {
1101 strncpy(str, (const char *)new_value.data, new_value.size);
1102 str[new_value.size+1] = '\0';
1103 break;
1104 }
1105 code = gs_note_error(gs_error_rangecheck);
1106 goto e;
1107 default:
1108 if (param_read_null(plist, pname) == 0)
1109 return 1;
1110 e:param_signal_error(plist, pname, code);
1111 case 1:
1112 ;
1113 }
1114 return code;
1115 }
1116
1117 private int
gsijs_read_string_malloc(gs_param_list * plist,gs_param_name pname,char ** str,int * size,bool only_when_closed)1118 gsijs_read_string_malloc(gs_param_list *plist, gs_param_name pname, char **str,
1119 int *size, bool only_when_closed)
1120 {
1121 int code;
1122 gs_param_string new_value;
1123 int differs;
1124
1125 switch (code = param_read_string(plist, pname, &new_value)) {
1126 case 0:
1127 differs = bytes_compare(new_value.data, new_value.size,
1128 (const byte *)(*str ? *str : ""),
1129 *str ? strlen(*str) : 0);
1130 if (only_when_closed && differs) {
1131 code = gs_error_rangecheck;
1132 goto e;
1133 }
1134 if (new_value.size >= *size) {
1135 if (*str)
1136 gs_free(str, *size, 1, "gsijs_read_string_malloc");
1137 *str = NULL;
1138 *size = 0;
1139 }
1140 *str = gs_malloc(new_value.size + 1, 1,
1141 "gsijs_read_string_malloc");
1142 if (*str == NULL) {
1143 code = gs_note_error(gs_error_VMerror);
1144 goto e;
1145 }
1146 *size = new_value.size + 1;
1147 strncpy(*str, (const char *)new_value.data, new_value.size);
1148 (*str)[new_value.size] = '\0';
1149 break;
1150 default:
1151 if (param_read_null(plist, pname) == 0)
1152 return 1;
1153 e:param_signal_error(plist, pname, code);
1154 case 1:
1155 ;
1156 }
1157 return code;
1158 }
1159
1160
1161 private int
gsijs_put_params(gx_device * dev,gs_param_list * plist)1162 gsijs_put_params(gx_device *dev, gs_param_list *plist)
1163 {
1164 gx_device_ijs *ijsdev = (gx_device_ijs *)dev;
1165 int code = 0;
1166 bool is_open = dev->is_open;
1167
1168 /* We allow duplex to be set in all cases. At some point, it may
1169 be worthwhile to query the device to see if it supports
1170 duplex. Note also that this code will get called even before
1171 the device has been opened, which is when the -DDuplex
1172 command line is processed. */
1173 if (ijsdev->Duplex_set < 0) {
1174 ijsdev->Duplex = 1;
1175 ijsdev->Duplex_set = 0;
1176 }
1177
1178 /* If a parameter must not be changed after the device is open,
1179 * the last parameter of gsijs_read_xxx() is is_open.
1180 * If a parameter may be changed at any time, it is false.
1181 */
1182 if (code >= 0)
1183 code = gsijs_read_string(plist, "IjsServer",
1184 ijsdev->IjsServer, sizeof(ijsdev->IjsServer),
1185 dev->LockSafetyParams, is_open);
1186
1187 if (code >= 0)
1188 code = gsijs_read_string_malloc(plist, "DeviceManufacturer",
1189 &ijsdev->DeviceManufacturer, &ijsdev->DeviceManufacturer_size,
1190 is_open);
1191
1192 if (code >= 0)
1193 code = gsijs_read_string_malloc(plist, "DeviceModel",
1194 &ijsdev->DeviceModel, &ijsdev->DeviceModel_size,
1195 is_open);
1196
1197 if (code >= 0)
1198 code = gsijs_read_string_malloc(plist, "IjsParams",
1199 &(ijsdev->IjsParams), &(ijsdev->IjsParams_size), is_open);
1200
1201 if (code >= 0)
1202 code = gsijs_read_int(plist, "BitsPerSample", &ijsdev->BitsPerSample,
1203 1, 16, is_open);
1204
1205 if (code >= 0)
1206 code = gsijs_read_bool(plist, "IjsUseOutputFD",
1207 &ijsdev->IjsUseOutputFD, is_open);
1208
1209 if (code >= 0) {
1210 code = gsijs_read_string_malloc(plist, "ProcessColorModel",
1211 &ijsdev->ColorSpace, &ijsdev->ColorSpace_size, is_open);
1212 }
1213
1214 if (code >= 0) {
1215 code = gsijs_read_bool(plist, "Tumble", &ijsdev->IjsTumble, false);
1216 if (code == 0)
1217 ijsdev->IjsTumble_set = true;
1218 }
1219
1220 if (code >= 0)
1221 code = gsijs_set_color_format(ijsdev);
1222
1223 if (code >= 0)
1224 code = gdev_prn_put_params(dev, plist);
1225
1226 if (code >= 0 && is_open) {
1227 code = gsijs_set_generic_params(ijsdev);
1228 if (code >= 0)
1229 code = gsijs_set_margin_params(ijsdev);
1230 if (code < 0)
1231 return gs_note_error(gs_error_ioerror);
1232 }
1233
1234 return code;
1235 }
1236
1237 private int
gsijs_client_set_param(gx_device_ijs * ijsdev,const char * key,const char * value)1238 gsijs_client_set_param(gx_device_ijs *ijsdev, const char *key,
1239 const char *value)
1240 {
1241 int code = ijs_client_set_param(ijsdev->ctx, 0 /* job id */,
1242 key, value, strlen(value));
1243 if (code < 0)
1244 dprintf2("ijs: Can't set parameter %s=%s\n", key, value);
1245 return code;
1246 }
1247
1248 private int
gsijs_set_color_format(gx_device_ijs * ijsdev)1249 gsijs_set_color_format(gx_device_ijs *ijsdev)
1250 {
1251 gx_device_color_info dci = ijsdev->color_info;
1252 int components; /* 1=gray, 3=RGB, 4=CMYK */
1253 int bpc = ijsdev->BitsPerSample; /* bits per component */
1254 int maxvalue;
1255 const char *ColorSpace = ijsdev->ColorSpace;
1256
1257 if (ColorSpace == NULL)
1258 ColorSpace = "DeviceRGB";
1259
1260 if (!strcmp (ColorSpace, "DeviceGray")) {
1261 components = 1;
1262 if (bpc == 1) {
1263 ijsdev->procs.map_rgb_color = gx_default_w_b_map_rgb_color;
1264 ijsdev->procs.map_color_rgb = gx_default_w_b_map_color_rgb;
1265 } else {
1266 ijsdev->procs.map_rgb_color = gx_default_gray_map_rgb_color;
1267 ijsdev->procs.map_color_rgb = gx_default_gray_map_color_rgb;
1268 }
1269 } else if (!strcmp (ColorSpace, "DeviceRGB")) {
1270 components = 3;
1271 ijsdev->procs.map_rgb_color = gx_default_rgb_map_rgb_color;
1272 ijsdev->procs.map_color_rgb = gx_default_rgb_map_color_rgb;
1273 } else if (!strcmp (ColorSpace, "DeviceCMYK")) {
1274 components = 4;
1275 ijsdev->procs.map_cmyk_color = cmyk_8bit_map_cmyk_color;
1276 ijsdev->procs.map_color_rgb = cmyk_8bit_map_color_rgb;
1277 } else {
1278 return -1;
1279 }
1280
1281 maxvalue = (1 << bpc) - 1;
1282 dci.num_components = components;
1283 dci.depth = bpc * components;
1284 dci.max_gray = maxvalue;
1285 dci.max_color = components > 1 ? maxvalue : 0;
1286 dci.dither_grays = maxvalue+1;
1287 dci.dither_colors = components > 1 ? maxvalue+1 : 0;
1288
1289 /* restore old anti_alias info */
1290 dci.anti_alias = ijsdev->color_info.anti_alias;
1291
1292 ijsdev->color_info = dci;
1293
1294 return 0;
1295 }
1296