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