1 /*
2 *
3 * Print plug-in Adobe PostScript driver for the GIMP.
4 *
5 * Copyright 1997-2002 Michael Sweet (mike@easysw.com) and
6 * Robert Krawitz (rlk@alum.mit.edu)
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the Free
10 * Software Foundation; either version 2 of the License, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22 /*
23 * This file must include only standard C header files. The core code must
24 * compile on generic platforms that don't support glib, gimp, gtk, etc.
25 */
26
27 #ifdef HAVE_CONFIG_H
28 #include <config.h>
29 #endif
30 #include <gutenprint/gutenprint.h>
31 #include <gutenprint/gutenprint-intl-internal.h>
32 #include "gutenprint-internal.h"
33 #include <time.h>
34 #include <string.h>
35 #include <math.h>
36 #ifdef HAVE_LIMITS_H
37 #include <limits.h>
38 #endif
39 #include <stdio.h>
40 #include <unistd.h>
41 #include <strings.h>
42 #include "xmlppd.h"
43
44 #ifdef _MSC_VER
45 #define strncasecmp(s,t,n) _strnicmp(s,t,n)
46 #define strcasecmp(s,t) _stricmp(s,t)
47 #endif
48
49 /*
50 * Local variables...
51 */
52
53 static char *m_ppd_file = NULL;
54 static stp_mxml_node_t *m_ppd = NULL;
55
56
57 /*
58 * Local functions...
59 */
60
61 static void ps_hex(const stp_vars_t *, unsigned short *, int);
62 static void ps_ascii85(const stp_vars_t *, unsigned short *, int, int);
63
64 static const stp_parameter_t the_parameters[] =
65 {
66 {
67 "PPDFile", N_("PPDFile"), "Color=Yes,Category=Basic Printer Setup",
68 N_("PPD File"),
69 STP_PARAMETER_TYPE_FILE, STP_PARAMETER_CLASS_FEATURE,
70 STP_PARAMETER_LEVEL_BASIC, 1, 1, STP_CHANNEL_NONE, 1, 0
71 },
72 {
73 "PageSize", N_("Page Size"), "Color=No,Category=Basic Printer Setup",
74 N_("Size of the paper being printed to"),
75 STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_CORE,
76 STP_PARAMETER_LEVEL_BASIC, 1, 1, STP_CHANNEL_NONE, 1, 0
77 },
78 {
79 "ModelName", N_("Model Name"), "Color=Yes,Category=Basic Printer Setup",
80 N_("PPD File Model Name"),
81 STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_CORE,
82 STP_PARAMETER_LEVEL_INTERNAL, 0, 0, STP_CHANNEL_NONE, 0, 0
83 },
84 {
85 "PrintingMode", N_("Printing Mode"), "Color=Yes,Category=Core Parameter",
86 N_("Printing Output Mode"),
87 STP_PARAMETER_TYPE_STRING_LIST, STP_PARAMETER_CLASS_CORE,
88 STP_PARAMETER_LEVEL_BASIC, 1, 1, STP_CHANNEL_NONE, 1, 0
89 },
90 };
91
92 static const int the_parameter_count =
93 sizeof(the_parameters) / sizeof(const stp_parameter_t);
94
95 static int
ps_option_to_param(const stp_vars_t * v,stp_parameter_t * param,stp_mxml_node_t * option)96 ps_option_to_param(const stp_vars_t *v, stp_parameter_t *param,
97 stp_mxml_node_t *option)
98 {
99 const char *group_text = stp_mxmlElementGetAttr(option, "grouptext");
100
101 if (group_text != NULL)
102 param->category = group_text;
103 else
104 param->category = NULL;
105
106 param->text = stp_mxmlElementGetAttr(option, "text");
107 param->help = stp_mxmlElementGetAttr(option, "text");
108 if (stp_mxmlElementGetAttr(option, "stptype"))
109 {
110 const char *default_value = stp_mxmlElementGetAttr(option, "default");
111 double stp_default_value = strtod(stp_mxmlElementGetAttr(option, "stpdefault"), 0);
112 double lower_bound = strtod(stp_mxmlElementGetAttr(option, "stplower"), NULL);
113 double upper_bound = strtod(stp_mxmlElementGetAttr(option, "stpupper"), NULL);
114 param->p_type = atoi(stp_mxmlElementGetAttr(option, "stptype"));
115 param->is_mandatory = atoi(stp_mxmlElementGetAttr(option, "stpmandatory"));
116 param->p_class = atoi(stp_mxmlElementGetAttr(option, "stpclass"));
117 param->p_level = atoi(stp_mxmlElementGetAttr(option, "stplevel"));
118 param->channel = (unsigned char) atoi(stp_mxmlElementGetAttr(option, "stpchannel"));
119 param->read_only = 0;
120 param->is_active = 1;
121 param->verify_this_parameter = 1;
122 param->name = stp_mxmlElementGetAttr(option, "stpname");
123 stp_dprintf(STP_DBG_PS, v,
124 "Gutenprint parameter %s type %d mandatory %d class %d level %d channel %d default %s %f",
125 param->name, param->p_type, param->is_mandatory,
126 param->p_class, param->p_level, param->channel,
127 default_value, stp_default_value);
128 switch (param->p_type)
129 {
130 case STP_PARAMETER_TYPE_DOUBLE:
131 param->deflt.dbl = stp_default_value;
132 param->bounds.dbl.upper = upper_bound;
133 param->bounds.dbl.lower = lower_bound;
134 stp_dprintf(STP_DBG_PS, v, " %.3f %.3f %.3f\n",
135 param->deflt.dbl, param->bounds.dbl.upper,
136 param->bounds.dbl.lower);
137 break;
138 case STP_PARAMETER_TYPE_DIMENSION:
139 param->deflt.dimension = atoi(default_value);
140 param->bounds.dimension.upper = (stp_dimension_t) upper_bound;
141 param->bounds.dimension.lower = (stp_dimension_t) lower_bound;
142 stp_dprintf(STP_DBG_PS, v, " %f %f %f\n",
143 param->deflt.dimension, param->bounds.dimension.upper,
144 param->bounds.dimension.lower);
145 break;
146 case STP_PARAMETER_TYPE_INT:
147 param->deflt.integer = atoi(default_value);
148 param->bounds.integer.upper = (int) upper_bound;
149 param->bounds.integer.lower = (int) lower_bound;
150 stp_dprintf(STP_DBG_PS, v, " %d %d %d\n",
151 param->deflt.integer, param->bounds.integer.upper,
152 param->bounds.integer.lower);
153 break;
154 case STP_PARAMETER_TYPE_BOOLEAN:
155 param->deflt.boolean = strcasecmp(default_value, "true") == 0 ? 1 : 0;
156 stp_dprintf(STP_DBG_PS, v, " %d\n", param->deflt.boolean);
157 break;
158 default:
159 stp_dprintf(STP_DBG_PS, v, "\n");
160 break;
161 }
162 }
163 else
164 {
165 const char *ui = stp_mxmlElementGetAttr(option, "ui");
166 param->name = stp_mxmlElementGetAttr(option, "name");
167 if (strcasecmp(ui, "Boolean") == 0)
168 param->p_type = STP_PARAMETER_TYPE_BOOLEAN;
169 else
170 param->p_type = STP_PARAMETER_TYPE_STRING_LIST;
171 if (strcmp(param->name, "PageSize") == 0)
172 param->p_class = STP_PARAMETER_CLASS_CORE;
173 else
174 param->p_class = STP_PARAMETER_CLASS_FEATURE;
175 param->p_level = STP_PARAMETER_LEVEL_BASIC;
176 param->is_mandatory = 1;
177 param->is_active = 1;
178 param->channel = -1;
179 param->verify_this_parameter = 1;
180 param->read_only = 0;
181 }
182
183 return 0;
184 }
185
186 /*
187 * 'ps_parameters()' - Return the parameter values for the given parameter.
188 */
189
190 static int
ppd_whitespace_callback(stp_mxml_node_t * node,int where)191 ppd_whitespace_callback(stp_mxml_node_t *node, int where)
192 {
193 return 0;
194 }
195
196 static int
check_ppd_file(const stp_vars_t * v)197 check_ppd_file(const stp_vars_t *v)
198 {
199 const char *ppd_file = stp_get_file_parameter(v, "PPDFile");
200
201 if (ppd_file == NULL || ppd_file[0] == 0)
202 {
203 stp_dprintf(STP_DBG_PS, v, "Empty PPD file\n");
204 return 0;
205 }
206 else if (m_ppd_file && strcmp(m_ppd_file, ppd_file) == 0)
207 {
208 stp_dprintf(STP_DBG_PS, v, "Not replacing PPD file %s\n", m_ppd_file);
209 return 1;
210 }
211 else
212 {
213 stp_dprintf(STP_DBG_PS, v, "Replacing PPD file %s with %s\n",
214 m_ppd_file ? m_ppd_file : "(null)",
215 ppd_file ? ppd_file : "(null)");
216 if (m_ppd != NULL)
217 stp_mxmlDelete(m_ppd);
218 m_ppd = NULL;
219
220 if (m_ppd_file)
221 stp_free(m_ppd_file);
222 m_ppd_file = NULL;
223
224 if ((m_ppd = stpi_xmlppd_read_ppd_file(ppd_file)) == NULL)
225 {
226 stp_eprintf(v, "Unable to open PPD file %s\n", ppd_file);
227 return 0;
228 }
229 if (stp_get_debug_level() & STP_DBG_PS)
230 {
231 char *ppd_stuff = stp_mxmlSaveAllocString(m_ppd, ppd_whitespace_callback);
232 stp_dprintf(STP_DBG_PS, v, "%s", ppd_stuff);
233 stp_free(ppd_stuff);
234 }
235
236 m_ppd_file = stp_strdup(ppd_file);
237 return 1;
238 }
239 }
240
241
242 static stp_parameter_list_t
ps_list_parameters(const stp_vars_t * v)243 ps_list_parameters(const stp_vars_t *v)
244 {
245 stp_parameter_list_t *ret = stp_parameter_list_create();
246 stp_mxml_node_t *option;
247 int i;
248 int status = check_ppd_file(v);
249 stp_dprintf(STP_DBG_PS, v, "Adding parameters from %s (%d)\n",
250 m_ppd_file ? m_ppd_file : "(null)", status);
251
252 for (i = 0; i < the_parameter_count; i++)
253 stp_parameter_list_add_param(ret, &(the_parameters[i]));
254
255 if (status)
256 {
257 int num_options = stpi_xmlppd_find_option_count(m_ppd);
258 stp_dprintf(STP_DBG_PS, v, "Found %d parameters\n", num_options);
259 for (i=0; i < num_options; i++)
260 {
261 /* MEMORY LEAK!!! */
262 stp_parameter_t *param = stp_malloc(sizeof(stp_parameter_t));
263 option = stpi_xmlppd_find_option_index(m_ppd, i);
264 if (option)
265 {
266 ps_option_to_param(v, param, option);
267 if (param->p_type != STP_PARAMETER_TYPE_INVALID &&
268 strcmp(param->name, "PageRegion") != 0 &&
269 strcmp(param->name, "PageSize") != 0)
270 {
271 stp_dprintf(STP_DBG_PS, v, "Adding parameter %s %s\n",
272 param->name, param->text);
273 stp_parameter_list_add_param(ret, param);
274 }
275 else
276 stp_free(param);
277 }
278 }
279 }
280 return ret;
281 }
282
283 static void
ps_parameters_internal(const stp_vars_t * v,const char * name,stp_parameter_t * description)284 ps_parameters_internal(const stp_vars_t *v, const char *name,
285 stp_parameter_t *description)
286 {
287 int i;
288 stp_mxml_node_t *option;
289 int status = 0;
290 int num_choices;
291 const char *defchoice;
292
293 description->p_type = STP_PARAMETER_TYPE_INVALID;
294 description->deflt.str = 0;
295 description->is_active = 0;
296
297 if (name == NULL)
298 return;
299
300 status = check_ppd_file(v);
301
302 for (i = 0; i < the_parameter_count; i++)
303 {
304 if (strcmp(name, the_parameters[i].name) == 0)
305 {
306 stp_fill_parameter_settings(description, &(the_parameters[i]));
307 if (strcmp(name, "PPDFile") == 0)
308 description->is_active = 1;
309 else if (strcmp(name, "ModelName") == 0)
310 {
311 const char *nickname;
312 description->bounds.str = stp_string_list_create();
313 if (m_ppd && stp_mxmlElementGetAttr(m_ppd, "nickname"))
314 nickname = stp_mxmlElementGetAttr(m_ppd, "nickname");
315 else
316 nickname = _("None; please provide a PPD file");
317 stp_string_list_add_string_unsafe(description->bounds.str,
318 nickname, nickname);
319 description->deflt.str = nickname;
320 description->is_active = 1;
321 return;
322 }
323 else if (strcmp(name, "PrintingMode") == 0)
324 {
325 if (! m_ppd || strcmp(stp_mxmlElementGetAttr(m_ppd, "color"), "1") == 0)
326 {
327 description->bounds.str = stp_string_list_create();
328 stp_string_list_add_string
329 (description->bounds.str, "Color", _("Color"));
330 stp_string_list_add_string
331 (description->bounds.str, "BW", _("Black and White"));
332 description->deflt.str =
333 stp_string_list_param(description->bounds.str, 0)->name;
334 description->is_active = 1;
335 }
336 else
337 description->is_active = 0;
338 return;
339 }
340 }
341 }
342
343 if (!status && strcmp(name, "PageSize") != 0)
344 return;
345 if ((option = stpi_xmlppd_find_option_named(m_ppd, name)) == NULL)
346 {
347 if (strcmp(name, "PageSize") == 0)
348 {
349 /* Provide a default set of page sizes */
350 description->bounds.str = stp_string_list_create();
351 stp_string_list_add_string
352 (description->bounds.str, "Letter", _("Letter"));
353 stp_string_list_add_string
354 (description->bounds.str, "A4", _("A4"));
355 stp_string_list_add_string
356 (description->bounds.str, "Custom", _("Custom"));
357 description->deflt.str =
358 stp_string_list_param(description->bounds.str, 0)->name;
359 description->is_active = 1;
360 return;
361 }
362 else
363 {
364 char *tmp = stp_malloc(strlen(name) + 4);
365 strcpy(tmp, "Stp");
366 strncat(tmp, name, strlen(name) + 3);
367 if ((option = stpi_xmlppd_find_option_named(m_ppd, tmp)) == NULL)
368 {
369 stp_dprintf(STP_DBG_PS, v, "no parameter %s", name);
370 stp_free(tmp);
371 return;
372 }
373 stp_free(tmp);
374 }
375 }
376
377 ps_option_to_param(v, description, option);
378 if (description->p_type != STP_PARAMETER_TYPE_STRING_LIST)
379 return;
380 num_choices = atoi(stp_mxmlElementGetAttr(option, "num_choices"));
381 defchoice = stp_mxmlElementGetAttr(option, "default");
382 description->bounds.str = stp_string_list_create();
383
384 stp_dprintf(STP_DBG_PS, v, "describe parameter %s, output name=[%s] text=[%s] category=[%s] choices=[%d] default=[%s]\n",
385 name, description->name, description->text,
386 description->category, num_choices, defchoice);
387
388 /* Describe all choices for specified option. */
389 for (i=0; i < num_choices; i++)
390 {
391 stp_mxml_node_t *choice = stpi_xmlppd_find_choice_index(option, i);
392 const char *choice_name = stp_mxmlElementGetAttr(choice, "name");
393 const char *choice_text = stp_mxmlElementGetAttr(choice, "text");
394 stp_string_list_add_string(description->bounds.str, choice_name, choice_text);
395 stp_dprintf(STP_DBG_PS, v, " parameter %s, choice %d [%s] [%s]",
396 name, i, choice_name, choice_text);
397 if (strcmp(choice_name, defchoice) == 0)
398 {
399 stp_dprintf(STP_DBG_PS, v,
400 " parameter %s, choice %d [%s] DEFAULT\n",
401 name, i, choice_name);
402 description->deflt.str = choice_name;
403 }
404 }
405
406 if (!description->deflt.str)
407 {
408 stp_dprintf(STP_DBG_PS, v,
409 " parameter %s, defaulting to [%s]",
410 name, stp_string_list_param(description->bounds.str, 0)->name);
411 description->deflt.str = stp_string_list_param(description->bounds.str, 0)->name;
412 }
413 if (stp_string_list_count(description->bounds.str) > 0)
414 description->is_active = 1;
415 return;
416 }
417
418 static void
ps_parameters(const stp_vars_t * v,const char * name,stp_parameter_t * description)419 ps_parameters(const stp_vars_t *v, const char *name,
420 stp_parameter_t *description)
421 {
422 #ifdef HAVE_LOCALE_H
423 char *locale = stp_strdup(setlocale(LC_ALL, NULL));
424 setlocale(LC_ALL, "C");
425 #endif
426 ps_parameters_internal(v, name, description);
427 #ifdef HAVE_LOCALE_H
428 setlocale(LC_ALL, locale);
429 stp_free(locale);
430 #endif
431 }
432
433 /*
434 * 'ps_media_size()' - Return the size of the page.
435 */
436
437 static void
ps_media_size_internal(const stp_vars_t * v,stp_dimension_t * width,stp_dimension_t * height)438 ps_media_size_internal(const stp_vars_t *v, /* I */
439 stp_dimension_t *width, /* O - Width in points */
440 stp_dimension_t *height) /* O - Height in points */
441 {
442 const char *pagesize = stp_get_string_parameter(v, "PageSize");
443 int status = check_ppd_file(v);
444 if (!pagesize)
445 pagesize = "";
446
447 stp_dprintf(STP_DBG_PS, v,
448 "ps_media_size(%d, \'%s\', \'%s\', %p, %p)\n",
449 stp_get_model_id(v), m_ppd_file, pagesize,
450 (void *) width, (void *) height);
451
452 stp_default_media_size(v, width, height);
453
454 if (status)
455 {
456 stp_mxml_node_t *paper = stpi_xmlppd_find_page_size(m_ppd, pagesize);
457 if (paper)
458 {
459 *width = atoi(stp_mxmlElementGetAttr(paper, "width"));
460 *height = atoi(stp_mxmlElementGetAttr(paper, "height"));
461 }
462 else
463 {
464 *width = 0;
465 *height = 0;
466 }
467 }
468
469 stp_dprintf(STP_DBG_PS, v, "dimensions %f %f\n", *width, *height);
470 return;
471 }
472
473 static const stp_papersize_t *
ps_describe_papersize(const stp_vars_t * v,const char * name)474 ps_describe_papersize(const stp_vars_t *v, const char *name)
475 {
476 int status = check_ppd_file(v);
477 if (status)
478 {
479 stp_mxml_node_t *paper = stpi_xmlppd_find_page_size(m_ppd, name);
480 if (paper)
481 {
482 const char *papersize_list_name = m_ppd_file ? m_ppd_file : "NOPPD";
483 stp_papersize_list_t *ourlist =
484 stpi_find_papersize_list_named(papersize_list_name);
485 const stp_papersize_t *papersize;
486 const stp_papersize_t *standard_papersize =
487 stpi_get_listed_papersize(name, "standard");
488
489 if (! ourlist)
490 ourlist = stpi_new_papersize_list(papersize_list_name);
491
492 papersize = stpi_get_papersize_by_name(ourlist, name);
493 if (! papersize)
494 {
495 stp_papersize_t *npapersize = stp_malloc(sizeof(stp_papersize_t));
496 npapersize->name = stp_strdup(name);
497 npapersize->text = stp_strdup(name);
498 npapersize->comment = NULL;
499 /*
500 * Note that we used the width and height from the PPD file,
501 * not from the standard definition. This is so that if the
502 * PPD file is for another driver that uses slightly different
503 * dimensions than we do that our description matches that of
504 * driver in use.
505 */
506 npapersize->width = atof(stp_mxmlElementGetAttr(paper, "width"));
507 npapersize->height = atof(stp_mxmlElementGetAttr(paper, "height"));
508 /*
509 * Only use auxiliary information from our list if our paper size
510 * really is substantially the same as what the PPD file says!
511 */
512 if (standard_papersize &&
513 fabs(npapersize->width - standard_papersize->width) < 1 &&
514 fabs(npapersize->height - standard_papersize->height) < 1)
515 {
516 npapersize->paper_unit = standard_papersize->paper_unit;
517 npapersize->paper_size_type = standard_papersize->paper_size_type;
518 npapersize->top = standard_papersize->top;
519 npapersize->left = standard_papersize->left;
520 npapersize->bottom = standard_papersize->bottom;
521 npapersize->right = standard_papersize->right;
522 }
523 else
524 {
525 npapersize->top = 0;
526 npapersize->left = 0;
527 npapersize->bottom = 0;
528 npapersize->right = 0;
529 npapersize->paper_unit = PAPERSIZE_ENGLISH_STANDARD;
530 npapersize->paper_size_type = PAPERSIZE_TYPE_STANDARD;
531 }
532 if (stpi_papersize_create(ourlist, npapersize))
533 return npapersize;
534 }
535 return papersize;
536 }
537 }
538 return NULL;
539 }
540
541 static void
ps_media_size(const stp_vars_t * v,stp_dimension_t * width,stp_dimension_t * height)542 ps_media_size(const stp_vars_t *v, stp_dimension_t *width, stp_dimension_t *height)
543 {
544 #ifdef HAVE_LOCALE_H
545 char *locale = stp_strdup(setlocale(LC_ALL, NULL));
546 setlocale(LC_ALL, "C");
547 #endif
548 ps_media_size_internal(v, width, height);
549 #ifdef HAVE_LOCALE_H
550 setlocale(LC_ALL, locale);
551 stp_free(locale);
552 #endif
553 }
554
555 /*
556 * 'ps_imageable_area()' - Return the imageable area of the page.
557 */
558
559 static void
ps_imageable_area_internal(const stp_vars_t * v,int use_max_area,stp_dimension_t * left,stp_dimension_t * right,stp_dimension_t * bottom,stp_dimension_t * top)560 ps_imageable_area_internal(const stp_vars_t *v, /* I */
561 int use_max_area, /* I - Use maximum area */
562 stp_dimension_t *left, /* O - Left position in points */
563 stp_dimension_t *right, /* O - Right position in points */
564 stp_dimension_t *bottom, /* O - Bottom position in points */
565 stp_dimension_t *top) /* O - Top position in points */
566 {
567 stp_dimension_t width, height;
568 const char *pagesize = stp_get_string_parameter(v, "PageSize");
569 if (!pagesize)
570 pagesize = "";
571
572 /* Set some defaults. */
573 ps_media_size_internal(v, &width, &height);
574 *left = 0;
575 *right = width;
576 *top = 0;
577 *bottom = height;
578
579 if (check_ppd_file(v))
580 {
581 stp_mxml_node_t *paper = stpi_xmlppd_find_page_size(m_ppd, pagesize);
582 if (paper)
583 {
584 double pleft = atoi(stp_mxmlElementGetAttr(paper, "left"));
585 double pright = atoi(stp_mxmlElementGetAttr(paper, "right"));
586 double ptop = atoi(stp_mxmlElementGetAttr(paper, "top"));
587 double pbottom = atoi(stp_mxmlElementGetAttr(paper, "bottom"));
588 stp_dprintf(STP_DBG_PS, v, "size=l %f r %f b %f t %f h %f w %f\n",
589 pleft, pright, pbottom, ptop, height, width);
590 *left = (stp_dimension_t) pleft;
591 *right = (stp_dimension_t) pright;
592 *top = height - (stp_dimension_t) ptop;
593 *bottom = height - (stp_dimension_t) pbottom;
594 stp_dprintf(STP_DBG_PS, v, ">>>> l %f r %f b %f t %f h %f w %f\n",
595 *left, *right, *bottom, *top, height, width);
596 }
597 }
598
599 if (use_max_area)
600 {
601 if (*left > 0)
602 *left = 0;
603 if (*right < width)
604 *right = width;
605 if (*top > 0)
606 *top = 0;
607 if (*bottom < height)
608 *bottom = height;
609 }
610
611 stp_dprintf(STP_DBG_PS, v, "pagesize %s max_area=%d l %f r %f b %f t %f h %f w %f\n",
612 pagesize ? pagesize : "(null)",
613 use_max_area, *left, *right, *bottom, *top, width, height);
614
615 return;
616 }
617
618 static void
ps_imageable_area(const stp_vars_t * v,stp_dimension_t * left,stp_dimension_t * right,stp_dimension_t * bottom,stp_dimension_t * top)619 ps_imageable_area(const stp_vars_t *v, /* I */
620 stp_dimension_t *left, /* O - Left position in points */
621 stp_dimension_t *right, /* O - Right position in points */
622 stp_dimension_t *bottom, /* O - Bottom position in points */
623 stp_dimension_t *top) /* O - Top position in points */
624 {
625 #ifdef HAVE_LOCALE_H
626 char *locale = stp_strdup(setlocale(LC_ALL, NULL));
627 setlocale(LC_ALL, "C");
628 #endif
629 ps_imageable_area_internal(v, 0, left, right, bottom, top);
630 #ifdef HAVE_LOCALE_H
631 setlocale(LC_ALL, locale);
632 stp_free(locale);
633 #endif
634 }
635
636 static void
ps_maximum_imageable_area(const stp_vars_t * v,stp_dimension_t * left,stp_dimension_t * right,stp_dimension_t * bottom,stp_dimension_t * top)637 ps_maximum_imageable_area(const stp_vars_t *v, /* I */
638 stp_dimension_t *left, /* O - Left position in points */
639 stp_dimension_t *right, /* O - Right position in points */
640 stp_dimension_t *bottom, /* O - Bottom position in points */
641 stp_dimension_t *top) /* O - Top position in points */
642 {
643 #ifdef HAVE_LOCALE_H
644 char *locale = stp_strdup(setlocale(LC_ALL, NULL));
645 setlocale(LC_ALL, "C");
646 #endif
647 ps_imageable_area_internal(v, 1, left, right, bottom, top);
648 #ifdef HAVE_LOCALE_H
649 setlocale(LC_ALL, locale);
650 stp_free(locale);
651 #endif
652 }
653
654 static void
ps_limit(const stp_vars_t * v,stp_dimension_t * width,stp_dimension_t * height,stp_dimension_t * min_width,stp_dimension_t * min_height)655 ps_limit(const stp_vars_t *v, /* I */
656 stp_dimension_t *width,
657 stp_dimension_t *height,
658 stp_dimension_t *min_width,
659 stp_dimension_t *min_height)
660 {
661 *width = (stp_dimension_t) INT_MAX;
662 *height = (stp_dimension_t) INT_MAX;
663 *min_width = 1;
664 *min_height = 1;
665 }
666
667 /*
668 * This is really bogus...
669 */
670 static void
ps_describe_resolution_internal(const stp_vars_t * v,stp_resolution_t * x,stp_resolution_t * y)671 ps_describe_resolution_internal(const stp_vars_t *v, stp_resolution_t *x, stp_resolution_t *y)
672 {
673 const char *resolution = stp_get_string_parameter(v, "Resolution");
674 *x = -1;
675 *y = -1;
676 if (resolution)
677 {
678 int tx = -1;
679 int ty = -1;
680 sscanf(resolution, "%dx%d", &tx, &ty);
681 *x = (stp_resolution_t) tx;
682 *y = (stp_resolution_t) ty;
683 }
684 return;
685 }
686
687 static void
ps_describe_resolution(const stp_vars_t * v,stp_resolution_t * x,stp_resolution_t * y)688 ps_describe_resolution(const stp_vars_t *v, stp_resolution_t *x, stp_resolution_t *y)
689 {
690 #ifdef HAVE_LOCALE_H
691 char *locale = stp_strdup(setlocale(LC_ALL, NULL));
692 setlocale(LC_ALL, "C");
693 #endif
694 ps_describe_resolution_internal(v, x, y);
695 #ifdef HAVE_LOCALE_H
696 setlocale(LC_ALL, locale);
697 stp_free(locale);
698 #endif
699 }
700
701 static const char *
ps_describe_output(const stp_vars_t * v)702 ps_describe_output(const stp_vars_t *v)
703 {
704 const char *print_mode = stp_get_string_parameter(v, "PrintingMode");
705 const char *input_image_type = stp_get_string_parameter(v, "InputImageType");
706 if (print_mode && strcmp(print_mode, "Color") == 0)
707 {
708 if (input_image_type && (strcmp(input_image_type, "CMYK") == 0 ||
709 strcmp(input_image_type, "KCMY") == 0))
710 return "CMYK";
711 else
712 return "RGB";
713 }
714 else
715 return "Whitescale";
716 }
717
718 static stp_string_list_t *
ps_external_options(const stp_vars_t * v)719 ps_external_options(const stp_vars_t *v)
720 {
721 stp_parameter_list_t param_list = ps_list_parameters(v);
722 stp_string_list_t *answer;
723 char *tmp;
724 char *ppd_name = NULL;
725 int i;
726 #ifdef HAVE_LOCALE_H
727 char *locale;
728 #endif
729 if (! param_list)
730 return NULL;
731 answer = stp_string_list_create();
732 #ifdef HAVE_LOCALE_H
733 locale = stp_strdup(setlocale(LC_ALL, NULL));
734 setlocale(LC_ALL, "C");
735 #endif
736 for (i = 0; i < stp_parameter_list_count(param_list); i++)
737 {
738 const stp_parameter_t *param = stp_parameter_list_param(param_list, i);
739 stp_parameter_t desc;
740 stp_describe_parameter(v, param->name, &desc);
741 if (desc.is_active)
742 {
743 stp_mxml_node_t *option;
744 if (m_ppd &&
745 (option = stpi_xmlppd_find_option_named(m_ppd, desc.name)) == NULL)
746 {
747 ppd_name = stp_malloc(strlen(desc.name) + 4);
748 strcpy(ppd_name, "Stp");
749 strncat(ppd_name, desc.name, strlen(desc.name) + 3);
750 if ((option = stpi_xmlppd_find_option_named(m_ppd, ppd_name)) == NULL)
751 {
752 stp_dprintf(STP_DBG_PS, v, "no parameter %s", desc.name);
753 STP_SAFE_FREE(ppd_name);
754 }
755 }
756 switch (desc.p_type)
757 {
758 case STP_PARAMETER_TYPE_STRING_LIST:
759 if (stp_get_string_parameter(v, desc.name) &&
760 strcmp(stp_get_string_parameter(v, desc.name),
761 desc.deflt.str))
762 {
763 stp_dprintf(STP_DBG_PS, v, "Adding string parameter %s (%s): %s %s\n",
764 desc.name, ppd_name ? ppd_name : "(null)",
765 stp_get_string_parameter(v, desc.name),
766 desc.deflt.str);
767 stp_string_list_add_string(answer,
768 ppd_name ? ppd_name : desc.name,
769 stp_get_string_parameter(v, desc.name));
770 }
771 break;
772 case STP_PARAMETER_TYPE_INT:
773 if (stp_get_int_parameter(v, desc.name) != desc.deflt.integer)
774 {
775 stp_dprintf(STP_DBG_PS, v, "Adding integer parameter %s (%s): %d %d\n",
776 desc.name, ppd_name ? ppd_name : "(null)",
777 stp_get_int_parameter(v, desc.name),
778 desc.deflt.integer);
779 stp_asprintf(&tmp, "%d", stp_get_int_parameter(v, desc.name));
780 stp_string_list_add_string(answer,
781 ppd_name ? ppd_name : desc.name,
782 tmp);
783 stp_free(tmp);
784 }
785 break;
786 case STP_PARAMETER_TYPE_BOOLEAN:
787 if (stp_get_boolean_parameter(v, desc.name) != desc.deflt.boolean)
788 {
789 stp_dprintf(STP_DBG_PS, v, "Adding boolean parameter %s (%s): %d %d\n",
790 desc.name, ppd_name ? ppd_name : "(null)",
791 stp_get_boolean_parameter(v, desc.name),
792 desc.deflt.boolean);
793 stp_asprintf(&tmp, "%s",
794 stp_get_boolean_parameter(v, desc.name) ?
795 "True" : "False");
796 stp_string_list_add_string(answer,
797 ppd_name ? ppd_name : desc.name,
798 tmp);
799 stp_free(tmp);
800 }
801 break;
802 case STP_PARAMETER_TYPE_DOUBLE:
803 if (fabs(stp_get_float_parameter(v, desc.name) - desc.deflt.dbl) > .00001)
804 {
805 stp_dprintf(STP_DBG_PS, v, "Adding float parameter %s (%s): %.3f %.3f\n",
806 desc.name, ppd_name ? ppd_name : "(null)",
807 stp_get_float_parameter(v, desc.name),
808 desc.deflt.dbl);
809 stp_asprintf(&tmp, "%.3f",
810 stp_get_float_parameter(v, desc.name));
811 stp_string_list_add_string(answer,
812 ppd_name ? ppd_name : desc.name,
813 tmp);
814 stp_free(tmp);
815 }
816 break;
817 case STP_PARAMETER_TYPE_DIMENSION:
818 if (stp_get_dimension_parameter(v, desc.name) !=
819 desc.deflt.dimension)
820 {
821 stp_dprintf(STP_DBG_PS, v, "Adding dimension parameter %s (%s): %f %f\n",
822 desc.name, ppd_name ? ppd_name : "(null)",
823 stp_get_dimension_parameter(v, desc.name),
824 desc.deflt.dimension);
825 stp_asprintf(&tmp, "%f",
826 stp_get_dimension_parameter(v, desc.name));
827 stp_string_list_add_string(answer,
828 ppd_name ? ppd_name : desc.name,
829 tmp);
830 stp_free(tmp);
831 }
832 break;
833 default:
834 break;
835 }
836 STP_SAFE_FREE(ppd_name);
837 }
838 stp_parameter_description_destroy(&desc);
839 }
840 #ifdef HAVE_LOCALE_H
841 setlocale(LC_ALL, locale);
842 stp_free(locale);
843 #endif
844 return answer;
845 }
846
847 /*
848 * 'ps_print_device_settings()' - output postscript code from PPD into the
849 * postscript stream.
850 */
851
852 static void
ps_print_device_settings(stp_vars_t * v)853 ps_print_device_settings(stp_vars_t *v)
854 {
855 int i;
856 stp_parameter_list_t param_list = ps_list_parameters(v);
857 if (! param_list)
858 return;
859 stp_puts("%%BeginSetup\n", v);
860 for (i = 0; i < stp_parameter_list_count(param_list); i++)
861 {
862 const stp_parameter_t *param = stp_parameter_list_param(param_list, i);
863 stp_parameter_t desc;
864 stp_describe_parameter(v, param->name, &desc);
865 if (desc.is_active)
866 {
867 switch (desc.p_type)
868 {
869 case STP_PARAMETER_TYPE_STRING_LIST:
870 case STP_PARAMETER_TYPE_BOOLEAN:
871 {
872 const char *val=NULL;
873 const char *defval=NULL;
874
875 /* If this is a bool parameter, set val to "True" or "False" - otherwise fetch from string parameter. */
876 if(desc.p_type==STP_PARAMETER_TYPE_BOOLEAN)
877 {
878 val=stp_get_boolean_parameter(v,desc.name) ? "True" : "False";
879 defval=desc.deflt.boolean ? "True" : "False";
880 }
881 else
882 {
883 val=stp_get_string_parameter(v,desc.name);
884 defval=desc.deflt.str;
885 }
886
887 /* We only include the option's code if it's set to a value other than the default. */
888 if(val && defval && (strcmp(val,defval)!=0))
889 {
890 if(m_ppd)
891 {
892 /* If we have a PPD xml tree we hunt for the appropriate "option" and "choice"... */
893 stp_mxml_node_t *node=m_ppd;
894 node=stp_mxmlFindElement(node,node, "option", "name", desc.name, STP_MXML_DESCEND);
895 if(node)
896 {
897 node=stp_mxmlFindElement(node,node, "choice", "name", val, STP_MXML_DESCEND);
898 if(node && node->child)
899 {
900 if(node->child->value.opaque && (strlen(node->child->value.opaque)>1))
901 {
902 /* If we have opaque data for the child, we use %%BeginFeature and copy the code verbatim. */
903 stp_puts("[{\n", v);
904 stp_zprintf(v, "%%%%BeginFeature: *%s %s\n", desc.name, val);
905 if(node->child->value.opaque)
906 stp_puts(node->child->value.opaque,v);
907 stp_puts("\n%%EndFeature\n", v);
908 stp_puts("} stopped cleartomark\n", v);
909 }
910 else
911 {
912 /* If we don't have code, we use %%IncludeFeature instead. */
913 stp_puts("[{\n", v);
914 stp_zprintf(v, "%%%%IncludeFeature: *%s %s\n", desc.name, val);
915 if(node->child->value.opaque)
916 stp_puts(node->child->value.opaque,v);
917 stp_puts("} stopped cleartomark\n", v);
918 }
919 }
920 }
921 }
922 }
923 }
924 break;
925 case STP_PARAMETER_TYPE_INT:
926 if(stp_get_int_parameter(v,desc.name)!=desc.deflt.integer)
927 {
928 stp_puts("[{\n", v);
929 stp_zprintf(v, "%%%%IncludeFeature: *%s %d\n", desc.name,
930 stp_get_int_parameter(v, desc.name));
931 stp_puts("} stopped cleartomark\n", v);
932 }
933 break;
934 case STP_PARAMETER_TYPE_DOUBLE:
935 if(stp_get_float_parameter(v,desc.name)!=desc.deflt.dbl)
936 {
937 stp_puts("[{\n", v);
938 stp_zprintf(v, "%%%%IncludeFeature: *%s %f\n", desc.name,
939 stp_get_float_parameter(v, desc.name));
940 stp_puts("} stopped cleartomark\n", v);
941 }
942 break;
943 case STP_PARAMETER_TYPE_DIMENSION:
944 if(stp_get_dimension_parameter(v,desc.name)!=desc.deflt.dimension)
945 {
946 stp_puts("[{\n", v);
947 stp_zprintf(v, "%%%%IncludeFeature: *%s %f\n", desc.name,
948 stp_get_dimension_parameter(v, desc.name));
949 stp_puts("} stopped cleartomark\n", v);
950 }
951 break;
952 default:
953 break;
954 }
955 }
956 stp_parameter_description_destroy(&desc);
957 }
958 stp_puts("%%EndSetup\n", v);
959 stp_parameter_list_destroy(param_list);
960 }
961
962 /*
963 * 'ps_print()' - Print an image to a PostScript printer.
964 */
965
966 static int
ps_print_internal(stp_vars_t * v,stp_image_t * image)967 ps_print_internal(stp_vars_t *v, stp_image_t *image)
968 {
969 int status = 1;
970 int model = stp_get_model_id(v);
971 const char *print_mode = stp_get_string_parameter(v, "PrintingMode");
972 const char *input_image_type = stp_get_string_parameter(v, "InputImageType");
973 unsigned short *out = NULL;
974 stp_dimension_t top = stp_get_top(v);
975 stp_dimension_t left = stp_get_left(v);
976 int y; /* Looping vars */
977 stp_dimension_t page_left, /* Left margin of page */
978 page_right, /* Right margin of page */
979 page_top, /* Top of page */
980 page_bottom, /* Bottom of page */
981 page_width, /* Width of page */
982 page_height, /* Height of page */
983 paper_width, /* Width of physical page */
984 paper_height; /* Height of physical page */
985 int out_width, /* Width of image on page */
986 out_height, /* Height of image on page */
987 out_channels, /* Output bytes per pixel */
988 out_ps_height, /* Output height (Level 2 output) */
989 out_offset; /* Output offset (Level 2 output) */
990 time_t curtime; /* Current time of day */
991 unsigned zero_mask;
992 int image_height,
993 image_width;
994 int color_out = 0;
995 int cmyk_out = 0;
996
997 if (print_mode && strcmp(print_mode, "Color") == 0)
998 color_out = 1;
999 if (color_out &&
1000 input_image_type && (strcmp(input_image_type, "CMYK") == 0 ||
1001 strcmp(input_image_type, "KCMY") == 0))
1002 cmyk_out = 1;
1003
1004 stp_image_init(image);
1005
1006 /*
1007 * Compute the output size...
1008 */
1009
1010 out_width = stp_get_width(v);
1011 out_height = stp_get_height(v);
1012
1013 ps_imageable_area_internal(v, 0, &page_left, &page_right, &page_bottom, &page_top);
1014 ps_media_size_internal(v, &paper_width, &paper_height);
1015 page_width = page_right - page_left;
1016 page_height = page_bottom - page_top;
1017
1018 image_height = stp_image_height(image);
1019 image_width = stp_image_width(image);
1020
1021 /*
1022 * Output a standard PostScript header with DSC comments...
1023 */
1024
1025 curtime = stpi_time(NULL);
1026
1027 top = paper_height - top;
1028
1029 stp_dprintf(STP_DBG_PS, v,
1030 "out_width = %d, out_height = %d\n", out_width, out_height);
1031 stp_dprintf(STP_DBG_PS, v,
1032 "page_left = %f, page_right = %f, page_bottom = %f, page_top = %f\n",
1033 page_left, page_right, page_bottom, page_top);
1034 stp_dprintf(STP_DBG_PS, v, "left = %f, top = %f\n", left, top);
1035 stp_dprintf(STP_DBG_PS, v, "page_width = %f, page_height = %f\n",
1036 page_width, page_height);
1037
1038 stp_dprintf(STP_DBG_PS, v, "bounding box l %f b %f r %f t %f\n",
1039 page_left, paper_height - page_bottom,
1040 page_right, paper_height - page_top);
1041
1042 stp_puts("%!PS-Adobe-3.0\n", v);
1043 #ifdef HAVE_CONFIG_H
1044 stp_zprintf(v, "%%%%Creator: %s/Gutenprint %s (%s)\n",
1045 stp_image_get_appname(image), VERSION, RELEASE_DATE);
1046 #else
1047 stp_zprintf(v, "%%%%Creator: %s/Gutenprint\n", stp_image_get_appname(image));
1048 #endif
1049 stp_zprintf(v, "%%%%CreationDate: %s", ctime(&curtime));
1050 stp_zprintf(v, "%%%%BoundingBox: %f %f %f %f\n",
1051 page_left, paper_height - page_bottom,
1052 page_right, paper_height - page_top);
1053 stp_puts("%%DocumentData: Clean7Bit\n", v);
1054 stp_zprintf(v, "%%%%LanguageLevel: %d\n", model + 1);
1055 stp_puts("%%Pages: 1\n", v);
1056 stp_puts("%%Orientation: Portrait\n", v);
1057 stp_puts("%%EndComments\n", v);
1058
1059 ps_print_device_settings(v);
1060
1061 /*
1062 * Output the page...
1063 */
1064
1065 stp_puts("%%Page: 1 1\n", v);
1066 stp_puts("gsave\n", v);
1067
1068 stp_zprintf(v, "%f %f translate\n", left, top);
1069
1070 /* Force locale to "C", because decimal numbers in Postscript must
1071 always be printed with a decimal point rather than the
1072 locale-specific setting. */
1073
1074 stp_zprintf(v, "%.3f %.3f scale\n",
1075 (double)out_width / ((double)image_width),
1076 (double)out_height / ((double)image_height));
1077
1078 stp_channel_reset(v);
1079 stp_channel_add(v, 0, 0, 1.0);
1080 if (color_out)
1081 {
1082 stp_channel_add(v, 1, 0, 1.0);
1083 stp_channel_add(v, 2, 0, 1.0);
1084 if (cmyk_out)
1085 {
1086 stp_channel_add(v, 3, 0, 1.0);
1087 stp_set_string_parameter(v, "STPIOutputType", "CMYK");
1088 }
1089 else
1090 stp_set_string_parameter(v, "STPIOutputType", "RGB");
1091 }
1092 else
1093 stp_set_string_parameter(v, "STPIOutputType", "Whitescale");
1094
1095 stp_set_boolean_parameter(v, "SimpleGamma", 1);
1096
1097 out_channels = stp_color_init(v, image, 256);
1098
1099 if (model == 0)
1100 {
1101 stp_zprintf(v, "/picture %d string def\n", image_width * out_channels);
1102
1103 stp_zprintf(v, "%d %d 8\n", image_width, image_height);
1104
1105 stp_puts("[ 1 0 0 -1 0 1 ]\n", v);
1106
1107 if (cmyk_out)
1108 stp_puts("{currentfile picture readhexstring pop} false 4 colorimage\n", v);
1109 else if (color_out)
1110 stp_puts("{currentfile picture readhexstring pop} false 3 colorimage\n", v);
1111 else
1112 stp_puts("{currentfile picture readhexstring pop} image\n", v);
1113
1114 for (y = 0; y < image_height; y ++)
1115 {
1116 if (stp_color_get_row(v, image, y, &zero_mask))
1117 {
1118 status = 2;
1119 break;
1120 }
1121
1122 out = stp_channel_get_input(v);
1123
1124 /* Convert from KCMY to CMYK */
1125 if (cmyk_out)
1126 {
1127 int x;
1128 unsigned short *pos = out;
1129 for (x = 0; x < image_width; x++, pos += 4)
1130 {
1131 unsigned short p0 = pos[0];
1132 pos[0] = pos[1];
1133 pos[1] = pos[2];
1134 pos[2] = pos[3];
1135 pos[3] = p0;
1136 }
1137 }
1138 ps_hex(v, out, image_width * out_channels);
1139 }
1140 }
1141 else
1142 {
1143 unsigned short *tmp_buf =
1144 stp_malloc(sizeof(unsigned short) * (image_width * out_channels + 4));
1145 if (cmyk_out)
1146 stp_puts("/DeviceCMYK setcolorspace\n", v);
1147 else if (color_out)
1148 stp_puts("/DeviceRGB setcolorspace\n", v);
1149 else
1150 stp_puts("/DeviceGray setcolorspace\n", v);
1151
1152 stp_puts("<<\n", v);
1153 stp_puts("\t/ImageType 1\n", v);
1154
1155 stp_zprintf(v, "\t/Width %d\n", image_width);
1156 stp_zprintf(v, "\t/Height %d\n", image_height);
1157 stp_puts("\t/BitsPerComponent 8\n", v);
1158
1159 if (cmyk_out)
1160 stp_puts("\t/Decode [ 0 1 0 1 0 1 0 1 ]\n", v);
1161 else if (color_out)
1162 stp_puts("\t/Decode [ 0 1 0 1 0 1 ]\n", v);
1163 else
1164 stp_puts("\t/Decode [ 0 1 ]\n", v);
1165
1166 stp_puts("\t/DataSource currentfile /ASCII85Decode filter\n", v);
1167
1168 if ((image_width * 72 / out_width) < 100)
1169 stp_puts("\t/Interpolate true\n", v);
1170
1171 stp_puts("\t/ImageMatrix [ 1 0 0 -1 0 1 ]\n", v);
1172
1173 stp_puts(">>\n", v);
1174 stp_puts("image\n", v);
1175
1176 for (y = 0, out_offset = 0; y < image_height; y ++)
1177 {
1178 unsigned short *where;
1179 /* FIXME!!! */
1180 if (stp_color_get_row(v, image, y /*, out + out_offset */ , &zero_mask))
1181 {
1182 status = 2;
1183 break;
1184 }
1185 out = stp_channel_get_input(v);
1186 if (out_offset > 0)
1187 {
1188 memcpy(tmp_buf + out_offset, out,
1189 image_width * out_channels * sizeof(unsigned short));
1190 where = tmp_buf;
1191 }
1192 else
1193 where = out;
1194
1195 /* Convert from KCMY to CMYK */
1196 if (cmyk_out)
1197 {
1198 int x;
1199 unsigned short *pos = where;
1200 for (x = 0; x < image_width; x++, pos += 4)
1201 {
1202 unsigned short p0 = pos[0];
1203 pos[0] = pos[1];
1204 pos[1] = pos[2];
1205 pos[2] = pos[3];
1206 pos[3] = p0;
1207 }
1208 }
1209
1210 out_ps_height = out_offset + image_width * out_channels;
1211
1212 if (y < (image_height - 1))
1213 {
1214 ps_ascii85(v, where, out_ps_height & ~3, 0);
1215 out_offset = out_ps_height & 3;
1216 }
1217 else
1218 {
1219 ps_ascii85(v, where, out_ps_height, 1);
1220 out_offset = 0;
1221 }
1222
1223 if (out_offset > 0)
1224 memcpy(tmp_buf, where + out_ps_height - out_offset,
1225 out_offset * sizeof(unsigned short));
1226 }
1227 stp_free(tmp_buf);
1228 }
1229 stp_image_conclude(image);
1230
1231 stp_puts("grestore\n", v);
1232 stp_puts("showpage\n", v);
1233 stp_puts("%%Trailer\n", v);
1234 stp_puts("%%EOF\n", v);
1235 return status;
1236 }
1237
1238 static int
ps_print(const stp_vars_t * v,stp_image_t * image)1239 ps_print(const stp_vars_t *v, stp_image_t *image)
1240 {
1241 int status;
1242 #ifdef HAVE_LOCALE_H
1243 char *locale;
1244 #endif
1245 stp_vars_t *nv = stp_vars_create_copy(v);
1246 if (!stp_verify(nv))
1247 {
1248 stp_eprintf(nv, "Print options not verified; cannot print.\n");
1249 return 0;
1250 }
1251 #ifdef HAVE_LOCALE_H
1252 locale = stp_strdup(setlocale(LC_ALL, NULL));
1253 setlocale(LC_ALL, "C");
1254 #endif
1255 status = ps_print_internal(nv, image);
1256 #ifdef HAVE_LOCALE_H
1257 setlocale(LC_ALL, locale);
1258 stp_free(locale);
1259 #endif
1260 stp_vars_destroy(nv);
1261 return status;
1262 }
1263
1264
1265 /*
1266 * 'ps_hex()' - Print binary data as a series of hexadecimal numbers.
1267 */
1268
1269 static void
ps_hex(const stp_vars_t * v,unsigned short * data,int length)1270 ps_hex(const stp_vars_t *v, /* I - File to print to */
1271 unsigned short *data, /* I - Data to print */
1272 int length) /* I - Number of bytes to print */
1273 {
1274 int col; /* Current column */
1275 static const char *hex = "0123456789ABCDEF";
1276
1277 col = 0;
1278 while (length > 0)
1279 {
1280 unsigned char pixel = (*data & 0xff00) >> 8;
1281 /*
1282 * Put the hex chars out to the file; note that we don't use stp_zprintf()
1283 * for speed reasons...
1284 */
1285
1286 stp_putc(hex[pixel >> 4], v);
1287 stp_putc(hex[pixel & 15], v);
1288
1289 data ++;
1290 length --;
1291
1292 col += 2;
1293 if (col >= 72)
1294 {
1295 col = 0;
1296 stp_putc('\n', v);
1297 }
1298 }
1299
1300 if (col > 0)
1301 stp_putc('\n', v);
1302 }
1303
1304
1305 /*
1306 * 'ps_ascii85()' - Print binary data as a series of base-85 numbers.
1307 */
1308
1309 static void
ps_ascii85(const stp_vars_t * v,unsigned short * data,int length,int last_line)1310 ps_ascii85(const stp_vars_t *v, /* I - File to print to */
1311 unsigned short *data, /* I - Data to print */
1312 int length, /* I - Number of bytes to print */
1313 int last_line) /* I - Last line of raster data? */
1314 {
1315 int i; /* Looping var */
1316 unsigned b; /* Binary data word */
1317 unsigned char c[5]; /* ASCII85 encoded chars */
1318 static int column = 0; /* Current column */
1319
1320 #define OUTBUF_SIZE 4096
1321 unsigned char outbuffer[OUTBUF_SIZE+10];
1322 int outp=0;
1323
1324 while (length > 3)
1325 {
1326 unsigned char d0 = (data[0] & 0xff00) >> 8;
1327 unsigned char d1 = (data[1] & 0xff00) >> 8;
1328 unsigned char d2 = (data[2] & 0xff00) >> 8;
1329 unsigned char d3 = (data[3] & 0xff00) >> 8;
1330 b = (((((d0 << 8) | d1) << 8) | d2) << 8) | d3;
1331
1332 if (b == 0)
1333 {
1334 outbuffer[outp++]='z';
1335 column ++;
1336 }
1337 else
1338 {
1339 outbuffer[outp+4] = (b % 85) + '!';
1340 b /= 85;
1341 outbuffer[outp+3] = (b % 85) + '!';
1342 b /= 85;
1343 outbuffer[outp+2] = (b % 85) + '!';
1344 b /= 85;
1345 outbuffer[outp+1] = (b % 85) + '!';
1346 b /= 85;
1347 outbuffer[outp] = b + '!';
1348
1349 outp+=5;
1350 column += 5;
1351 }
1352
1353 if (column > 72)
1354 {
1355 outbuffer[outp++]='\n';
1356 column = 0;
1357 }
1358
1359 if(outp>=OUTBUF_SIZE)
1360 {
1361 stp_zfwrite((const char *)outbuffer, outp, 1, v);
1362 outp=0;
1363 }
1364
1365 data += 4;
1366 length -= 4;
1367 }
1368
1369 if(outp)
1370 stp_zfwrite((const char *)outbuffer, outp, 1, v);
1371
1372 if (last_line)
1373 {
1374 if (length > 0)
1375 {
1376 for (b = 0, i = length; i > 0; b = (b << 8) | data[0], data ++, i --);
1377
1378 c[4] = (b % 85) + '!';
1379 b /= 85;
1380 c[3] = (b % 85) + '!';
1381 b /= 85;
1382 c[2] = (b % 85) + '!';
1383 b /= 85;
1384 c[1] = (b % 85) + '!';
1385 b /= 85;
1386 c[0] = b + '!';
1387
1388 stp_zfwrite((const char *)c, length + 1, 1, v);
1389 }
1390
1391 stp_puts("~>\n", v);
1392 column = 0;
1393 }
1394 }
1395
1396
1397 static const stp_printfuncs_t print_ps_printfuncs =
1398 {
1399 ps_list_parameters,
1400 ps_parameters,
1401 ps_media_size,
1402 ps_imageable_area,
1403 ps_maximum_imageable_area,
1404 ps_limit,
1405 ps_print,
1406 ps_describe_resolution,
1407 ps_describe_output,
1408 stp_verify_printer_params,
1409 NULL,
1410 NULL,
1411 ps_external_options,
1412 ps_describe_papersize
1413 };
1414
1415
1416 static stp_family_t print_ps_module_data =
1417 {
1418 &print_ps_printfuncs,
1419 NULL
1420 };
1421
1422
1423 static int
print_ps_module_init(void)1424 print_ps_module_init(void)
1425 {
1426 return stpi_family_register(print_ps_module_data.printer_list);
1427 }
1428
1429
1430 static int
print_ps_module_exit(void)1431 print_ps_module_exit(void)
1432 {
1433 return stpi_family_unregister(print_ps_module_data.printer_list);
1434 }
1435
1436
1437 /* Module header */
1438 #define stp_module_version print_ps_LTX_stp_module_version
1439 #define stp_module_data print_ps_LTX_stp_module_data
1440
1441 stp_module_version_t stp_module_version = {0, 0};
1442
1443 stp_module_t stp_module_data =
1444 {
1445 "ps",
1446 VERSION,
1447 "Postscript family driver",
1448 STP_MODULE_CLASS_FAMILY,
1449 NULL,
1450 print_ps_module_init,
1451 print_ps_module_exit,
1452 (void *) &print_ps_module_data
1453 };
1454