1 /*
2  *   Gutenprint based raster filter for the Common UNIX Printing System.
3  *
4  *   Copyright 1993-2008 by Mike Sweet.
5  *
6  *   This program is free software; you can redistribute it and/or modify it
7  *   under the terms of the GNU General Public License as published by the Free
8  *   Software Foundation; either version 2 of the License, or (at your option)
9  *   any later version.
10  *
11  *   This program is distributed in the hope that it will be useful, but
12  *   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  *   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  *   for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program.  If not, see <https://www.gnu.org/licenses/>.
18  *
19  * Contents:
20  *
21  *   main()                    - Main entry and processing of driver.
22  *   cups_writefunc()          - Write data to a file...
23  *   cancel_job()              - Cancel the current job...
24  *   Image_get_appname()       - Get the application we are running.
25  *   Image_get_row()           - Get one row of the image.
26  *   Image_height()            - Return the height of an image.
27  *   Image_init()              - Initialize an image.
28  *   Image_conclude()          - Close the progress display.
29  *   Image_width()             - Return the width of an image.
30  */
31 
32 /*
33  * Include necessary headers...
34  */
35 
36 #if 0
37 #define ENABLE_CUPS_LOAD_SAVE_OPTIONS
38 #endif
39 
40 #ifdef HAVE_CONFIG_H
41 #include <config.h>
42 #endif
43 #include <cups/cups.h>
44 #include <cups/ppd.h>
45 #include <cups/raster.h>
46 #include <signal.h>
47 #include <string.h>
48 #include <stdlib.h>
49 #include <unistd.h>
50 #include <fcntl.h>
51 #include <errno.h>
52 #include <sys/times.h>
53 #include <strings.h>
54 #include <sys/time.h>
55 #ifdef HAVE_LIMITS_H
56 #include <limits.h>
57 #endif
58 #include "i18n.h"
59 #include <gutenprint/xml.h>
60 
61 /* Solaris with gcc has problems because gcc's limits.h doesn't #define */
62 /* this */
63 #ifndef CHAR_BIT
64 #define CHAR_BIT 8
65 #endif
66 
67 /*
68  * Structure for page raster data...
69  */
70 
71 #if (CUPS_VERSION_MAJOR > 1 || (CUPS_VERSION_MAJOR == 1 && CUPS_VERSION_MINOR > 1))
72 #define CUPS_HEADER_T cups_page_header2_t
73 #define CUPS_READ_HEADER cupsRasterReadHeader2
74 #else
75 #define CUPS_HEADER_T cups_page_header_t
76 #define CUPS_READ_HEADER cupsRasterReadHeader
77 #endif
78 
79 typedef struct
80 {
81   cups_raster_t		*ras;		/* Raster stream to read from */
82   int			page;		/* Current page number */
83   int			row;		/* Current row number */
84   int			left;
85   int			right;
86   int			bottom;
87   int			top;
88   int			width;
89   int			height;
90   int			left_trim;
91   int			right_trim;
92   int			top_trim;
93   int			bottom_trim;
94   int			adjusted_width;
95   int			adjusted_height;
96   stp_dimension_t	d_left;
97   stp_dimension_t	d_right;
98   stp_dimension_t	d_bottom;
99   stp_dimension_t	d_top;
100   stp_dimension_t	d_width;
101   stp_dimension_t	d_height;
102   stp_dimension_t	d_left_trim;
103   stp_dimension_t	d_right_trim;
104   stp_dimension_t	d_bottom_trim;
105   stp_dimension_t	d_top_trim;
106   int			last_percent;
107   int			shrink_to_fit;
108   CUPS_HEADER_T		header;		/* Page header from file */
109 } cups_image_t;
110 
111 static void	cups_writefunc(void *file, const char *buf, size_t bytes);
112 static void	cups_errfunc(void *file, const char *buf, size_t bytes);
113 static void	cups_dbgfunc(void *file, const char *buf, size_t bytes);
114 static void	cancel_job(int sig);
115 static const char *Image_get_appname(stp_image_t *image);
116 static stp_image_status_t Image_get_row(stp_image_t *image,
117 					unsigned char *data,
118 					size_t byte_limit, int row);
119 static int	Image_height(stp_image_t *image);
120 static int	Image_width(stp_image_t *image);
121 static void	Image_conclude(stp_image_t *image);
122 static void	Image_init(stp_image_t *image);
123 
124 static stp_image_t theImage =
125 {
126   Image_init,
127   NULL,				/* reset */
128   Image_width,
129   Image_height,
130   Image_get_row,
131   Image_get_appname,
132   Image_conclude,
133   NULL
134 };
135 
136 static volatile stp_image_status_t Image_status = STP_IMAGE_STATUS_OK;
137 static double total_bytes_printed = 0;
138 static int print_messages_as_errors = 0;
139 static int suppress_messages = 0;
140 static int suppress_verbose_messages = 0;
141 static const stp_string_list_t *po = NULL;
142 #ifdef ENABLE_CUPS_LOAD_SAVE_OPTIONS
143 static const char *save_file_name = NULL;
144 static const char *load_file_name = NULL;
145 #endif /* ENABLE_CUPS_LOAD_SAVE_OPTIONS */
146 
147 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
148 #pragma GCC diagnostic push
149 #pragma GCC diagnostic ignored "-Wcast-qual"
150 static inline void *
cast_safe(const void * ptr)151 cast_safe(const void *ptr)
152 {
153   return (void *)ptr;
154 }
155 #pragma GCC diagnostic pop
156 
157 static void
set_string_parameter(stp_vars_t * v,const char * name,const char * val)158 set_string_parameter(stp_vars_t *v, const char *name, const char *val)
159 {
160   if (! suppress_messages)
161     fprintf(stderr, "DEBUG: Gutenprint:   Set special string %s to %s\n", name, val);
162   stp_set_string_parameter(v, name, val);
163 }
164 
165 
166 static void
set_special_parameter(stp_vars_t * v,const char * name,int choice)167 set_special_parameter(stp_vars_t *v, const char *name, int choice)
168 {
169   stp_parameter_t desc;
170   stp_describe_parameter(v, name, &desc);
171   if (desc.p_type == STP_PARAMETER_TYPE_STRING_LIST)
172     {
173 #if 0
174       if (stp_check_string_parameter(v, name, STP_PARAMETER_ACTIVE))
175 	{
176 	  if (! suppress_messages)
177 	    fprintf(stderr, "DEBUG: Gutenprint:   Not overriding special parameter %s (%s)\n",
178 		    name, stp_get_string_parameter(v, name));
179 	}
180       else
181 #endif
182 	if (choice < 0)
183 	{
184 	  stp_clear_string_parameter(v, name);
185 	  if (! suppress_messages)
186 	    fprintf(stderr, "DEBUG: Gutenprint:   Clear special parameter %s\n",
187 		    name);
188 	}
189       else if (choice >= stp_string_list_count(desc.bounds.str))
190 	{
191 	  if (! suppress_messages)
192 	    stp_i18n_printf(po, _("ERROR: Unable to set Gutenprint option %s "
193 	                          "(%d > %d)!\n"), name, choice,
194 				  stp_string_list_count(desc.bounds.str));
195 	}
196       else
197 	{
198 	  stp_set_string_parameter
199 	    (v, name, stp_string_list_param(desc.bounds.str, choice)->name);
200 	  if (! suppress_messages)
201 	    fprintf(stderr, "DEBUG: Gutenprint:   Set special parameter %s to choice %d (%s)\n",
202 		    name, choice,
203 		    stp_string_list_param(desc.bounds.str, choice)->name);
204 	}
205     }
206   else
207     {
208       if (! suppress_messages)
209 	fprintf(stderr, "DEBUG: Gutenprint:   Unable to set special %s: not a string\n",
210 		name);
211     }
212   stp_parameter_description_destroy(&desc);
213 }
214 
215 static void
print_debug_block(const stp_vars_t * v,const cups_image_t * cups)216 print_debug_block(const stp_vars_t *v, const cups_image_t *cups)
217 {
218   fprintf(stderr, "DEBUG: Gutenprint: Page data:\n");
219   fprintf(stderr, "DEBUG: Gutenprint:   MediaClass = \"%s\"\n", cups->header.MediaClass);
220   fprintf(stderr, "DEBUG: Gutenprint:   MediaColor = \"%s\"\n", cups->header.MediaColor);
221   fprintf(stderr, "DEBUG: Gutenprint:   MediaType = \"%s\"\n", cups->header.MediaType);
222   fprintf(stderr, "DEBUG: Gutenprint:   OutputType = \"%s\"\n", cups->header.OutputType);
223 
224   fprintf(stderr, "DEBUG: Gutenprint:   AdvanceDistance = %d\n", cups->header.AdvanceDistance);
225   fprintf(stderr, "DEBUG: Gutenprint:   AdvanceMedia = %d\n", cups->header.AdvanceMedia);
226   fprintf(stderr, "DEBUG: Gutenprint:   Collate = %d\n", cups->header.Collate);
227   fprintf(stderr, "DEBUG: Gutenprint:   CutMedia = %d\n", cups->header.CutMedia);
228   fprintf(stderr, "DEBUG: Gutenprint:   Duplex = %d\n", cups->header.Duplex);
229   fprintf(stderr, "DEBUG: Gutenprint:   HWResolution = [ %d %d ]\n", cups->header.HWResolution[0],
230 	  cups->header.HWResolution[1]);
231   fprintf(stderr, "DEBUG: Gutenprint:   ImagingBoundingBox = [ %d %d %d %d ]\n",
232 	  cups->header.ImagingBoundingBox[0], cups->header.ImagingBoundingBox[1],
233 	  cups->header.ImagingBoundingBox[2], cups->header.ImagingBoundingBox[3]);
234   fprintf(stderr, "DEBUG: Gutenprint:   InsertSheet = %d\n", cups->header.InsertSheet);
235   fprintf(stderr, "DEBUG: Gutenprint:   Jog = %d\n", cups->header.Jog);
236   fprintf(stderr, "DEBUG: Gutenprint:   LeadingEdge = %d\n", cups->header.LeadingEdge);
237   fprintf(stderr, "DEBUG: Gutenprint:   Margins = [ %d %d ]\n", cups->header.Margins[0],
238 	  cups->header.Margins[1]);
239   fprintf(stderr, "DEBUG: Gutenprint:   ManualFeed = %d\n", cups->header.ManualFeed);
240   fprintf(stderr, "DEBUG: Gutenprint:   MediaPosition = %d\n", cups->header.MediaPosition);
241   fprintf(stderr, "DEBUG: Gutenprint:   MediaWeight = %d\n", cups->header.MediaWeight);
242   fprintf(stderr, "DEBUG: Gutenprint:   MirrorPrint = %d\n", cups->header.MirrorPrint);
243   fprintf(stderr, "DEBUG: Gutenprint:   NegativePrint = %d\n", cups->header.NegativePrint);
244   fprintf(stderr, "DEBUG: Gutenprint:   NumCopies = %d\n", cups->header.NumCopies);
245   fprintf(stderr, "DEBUG: Gutenprint:   Orientation = %d\n", cups->header.Orientation);
246   fprintf(stderr, "DEBUG: Gutenprint:   OutputFaceUp = %d\n", cups->header.OutputFaceUp);
247   fprintf(stderr, "DEBUG: Gutenprint:   PageSize = [ %d %d ]\n", cups->header.PageSize[0],
248 	  cups->header.PageSize[1]);
249   fprintf(stderr, "DEBUG: Gutenprint:   Separations = %d\n", cups->header.Separations);
250   fprintf(stderr, "DEBUG: Gutenprint:   TraySwitch = %d\n", cups->header.TraySwitch);
251   fprintf(stderr, "DEBUG: Gutenprint:   Tumble = %d\n", cups->header.Tumble);
252   fprintf(stderr, "DEBUG: Gutenprint:   cupsWidth = %d\n", cups->header.cupsWidth);
253   fprintf(stderr, "DEBUG: Gutenprint:   cupsHeight = %d\n", cups->header.cupsHeight);
254   fprintf(stderr, "DEBUG: Gutenprint:   cups->width = %d\n", cups->width);
255   fprintf(stderr, "DEBUG: Gutenprint:   cups->height = %d\n", cups->height);
256   fprintf(stderr, "DEBUG: Gutenprint:   cups->adjusted_width = %d\n", cups->adjusted_width);
257   fprintf(stderr, "DEBUG: Gutenprint:   cups->adjusted_height = %d\n", cups->adjusted_height);
258   fprintf(stderr, "DEBUG: Gutenprint:   cupsMediaType = %d\n", cups->header.cupsMediaType);
259   fprintf(stderr, "DEBUG: Gutenprint:   cupsBitsPerColor = %d\n", cups->header.cupsBitsPerColor);
260   fprintf(stderr, "DEBUG: Gutenprint:   cupsBitsPerPixel = %d\n", cups->header.cupsBitsPerPixel);
261   fprintf(stderr, "DEBUG: Gutenprint:   cupsBytesPerLine = %d\n", cups->header.cupsBytesPerLine);
262   fprintf(stderr, "DEBUG: Gutenprint:   cupsColorOrder = %d\n", cups->header.cupsColorOrder);
263   fprintf(stderr, "DEBUG: Gutenprint:   cupsColorSpace = %d\n", cups->header.cupsColorSpace);
264   fprintf(stderr, "DEBUG: Gutenprint:   cupsCompression = %d\n", cups->header.cupsCompression);
265   fprintf(stderr, "DEBUG: Gutenprint:   cupsRowCount = %d\n", cups->header.cupsRowCount);
266   fprintf(stderr, "DEBUG: Gutenprint:   cupsRowFeed = %d\n", cups->header.cupsRowFeed);
267   fprintf(stderr, "DEBUG: Gutenprint:   cupsRowStep = %d\n", cups->header.cupsRowStep);
268   fprintf(stderr, "DEBUG: Gutenprint:   shrink page to fit %d\n", cups->shrink_to_fit);
269   stp_vars_print_error(v, "DEBUG");
270   fprintf(stderr, "DEBUG: Gutenprint: End page data\n");
271 }
272 
273 static int
printer_supports_bw(const stp_vars_t * v)274 printer_supports_bw(const stp_vars_t *v)
275 {
276   stp_parameter_t desc;
277   int status = 0;
278   stp_describe_parameter(v, "PrintingMode", &desc);
279   if (stp_string_list_is_present(desc.bounds.str, "BW"))
280     status = 1;
281   stp_parameter_description_destroy(&desc);
282   return status;
283 }
284 
285 static void
validate_options(stp_vars_t * v,cups_image_t * cups)286 validate_options(stp_vars_t *v, cups_image_t *cups)
287 {
288   stp_parameter_list_t params = stp_get_parameter_list(v);
289   int nparams = stp_parameter_list_count(params);
290   int i;
291   if (! suppress_messages)
292     fprintf(stderr, "DEBUG: Gutenprint:   Validating options\n");
293   for (i = 0; i < nparams; i++)
294     {
295       const stp_parameter_t *param = stp_parameter_list_param(params, i);
296       stp_parameter_t desc;
297       stp_describe_parameter(v, param->name, &desc);
298       if (desc.p_type == STP_PARAMETER_TYPE_STRING_LIST)
299 	{
300 	  if (!stp_string_list_is_present
301 	      (desc.bounds.str, stp_get_string_parameter(v, desc.name)))
302 	    {
303 	      if (! suppress_messages)
304 		{
305 		  const char *val = stp_get_string_parameter(v, desc.name);
306 		  fprintf(stderr, "DEBUG: Gutenprint:     Clearing string %s (%s)\n",
307 			  desc.name, val ? val : "(null)");
308 		}
309 	      stp_clear_string_parameter(v, desc.name);
310 	      if (!desc.read_only && desc.is_mandatory && desc.is_active)
311 		{
312 		  if (! suppress_messages)
313 		    fprintf(stderr, "DEBUG: Gutenprint:     Setting default string %s to %s\n",
314 			    desc.name, desc.deflt.str ? desc.deflt.str : "(null)");
315 		  stp_set_string_parameter(v, desc.name, desc.deflt.str);
316 		  if (strcmp(desc.name, "PageSize") == 0)
317 		    {
318 		      const stp_papersize_t *ps =
319 			stp_describe_papersize(v, desc.deflt.str);
320 		      if (ps->width > 0)
321 			{
322 			  if (! suppress_messages)
323 			    fprintf(stderr, "DEBUG: Gutenprint:     Setting page width to %.3f\n",
324 				    ps->width);
325 			  if (ps->width < stp_get_page_width(v))
326 			    stp_set_page_width(v, ps->width);
327 			}
328 		      if (ps->height > 0)
329 			{
330 			  if (! suppress_messages)
331 			    fprintf(stderr, "DEBUG: Gutenprint:     Setting page height to %.3f\n",
332 				    ps->height);
333 			  if (ps->height < stp_get_page_height(v))
334 			    stp_set_page_height(v, ps->height);
335 			}
336 		    }
337 		}
338 	    }
339 	}
340       stp_parameter_description_destroy(&desc);
341     }
342   if (! suppress_messages)
343     fprintf(stderr, "DEBUG: Gutenprint:   Done validating options\n");
344   stp_parameter_list_destroy(params);
345 }
346 
347 static stp_vars_t *
initialize_page(cups_image_t * cups,const stp_vars_t * default_settings,const char * page_size_name)348 initialize_page(cups_image_t *cups, const stp_vars_t *default_settings,
349 		const char *page_size_name)
350 {
351   stp_dimension_t tmp_left, tmp_right, tmp_top, tmp_bottom;
352   stp_vars_t *v = stp_vars_create_copy(default_settings);
353 
354   if (! suppress_messages)
355     fprintf(stderr, "DEBUG: Gutenprint: Initialize page\n");
356 
357   if (cups->header.cupsBitsPerColor == 16)
358     set_string_parameter(v, "ChannelBitDepth", "16");
359   else
360     set_string_parameter(v, "ChannelBitDepth", "8");
361   switch (cups->header.cupsColorSpace)
362     {
363     case CUPS_CSPACE_W :
364       /* DyeSub photo printers don't support black & white ink! */
365       if (printer_supports_bw(v))
366 	set_string_parameter(v, "PrintingMode", "BW");
367       set_string_parameter(v, "InputImageType", "Whitescale");
368       break;
369     case CUPS_CSPACE_K :
370       /* DyeSub photo printers don't support black & white ink! */
371       if (printer_supports_bw(v))
372 	set_string_parameter(v, "PrintingMode", "BW");
373       set_string_parameter(v, "InputImageType", "Grayscale");
374       break;
375     case CUPS_CSPACE_RGB :
376       set_string_parameter(v, "PrintingMode", "Color");
377       set_string_parameter(v, "InputImageType", "RGB");
378       break;
379     case CUPS_CSPACE_CMY :
380       set_string_parameter(v, "PrintingMode", "Color");
381       set_string_parameter(v, "InputImageType", "CMY");
382       break;
383     case CUPS_CSPACE_CMYK :
384       set_string_parameter(v, "PrintingMode", "Color");
385       set_string_parameter(v, "InputImageType", "CMYK");
386       break;
387     case CUPS_CSPACE_KCMY :
388       set_string_parameter(v, "PrintingMode", "Color");
389       set_string_parameter(v, "InputImageType", "KCMY");
390       break;
391     default :
392       stp_i18n_printf(po, _("ERROR: Gutenprint detected a bad colorspace "
393                             "(%d)!\n"), cups->header.cupsColorSpace);
394       break;
395     }
396 
397   set_special_parameter(v, "Resolution", cups->header.cupsCompression - 1);
398 
399   set_special_parameter(v, "Quality", cups->header.cupsRowFeed - 1);
400 
401   if (strlen(cups->header.MediaClass) > 0)
402     set_string_parameter(v, "InputSlot", cups->header.MediaClass);
403 
404   if (strlen(cups->header.MediaType) > 0)
405     set_string_parameter(v, "MediaType", cups->header.MediaType);
406 
407   if (! suppress_messages)
408     fprintf(stderr, "DEBUG: Gutenprint:   PageSize = %dx%d\n", cups->header.PageSize[0],
409 	    cups->header.PageSize[1]);
410 
411   if (page_size_name)
412     {
413       if (strcmp(page_size_name, "Custom") == 0)
414 	{
415 	  if (!suppress_messages)
416 	    fprintf(stderr, "DEBUG: Gutenprint:   Using custom page size for (%d, %d)\n",
417 		    cups->header.PageSize[1], cups->header.PageSize[0]);
418 	  stp_set_page_width(v, cups->header.PageSize[0]);
419 	  stp_set_page_height(v, cups->header.PageSize[1]);
420 	}
421       else if (stp_describe_papersize(v, page_size_name))
422 	{
423 	  stp_dimension_t width, height;
424 	  if (!suppress_messages)
425 	    fprintf(stderr, "DEBUG: Gutenprint:   Using page size %s with (%d, %d)\n",
426 		    page_size_name, cups->header.PageSize[1], cups->header.PageSize[0]);
427 	  set_string_parameter(v, "PageSize", page_size_name);
428 	  stp_get_media_size(v, &width, &height);
429 	  if (width > 0)
430 	    stp_set_page_width(v, width);
431 	  else
432 	    stp_set_page_width(v, cups->header.PageSize[0]);
433 	  if (height > 0)
434 	    stp_set_page_height(v, height);
435 	  else
436 	    stp_set_page_height(v, cups->header.PageSize[1]);
437 	}
438       else
439 	{
440 	  if (!suppress_messages)
441 	    fprintf(stderr, "DEBUG: Gutenprint:   Can't find page size %s with (%d, %d), using custom page size\n",
442 		    page_size_name, cups->header.PageSize[1], cups->header.PageSize[0]);
443 	  stp_set_page_width(v, cups->header.PageSize[0]);
444 	  stp_set_page_height(v, cups->header.PageSize[1]);
445 	}
446     }
447   else
448     {
449       if (! suppress_messages)
450 	fprintf(stderr, "DEBUG: Gutenprint:   No named media size for (%d, %d)\n",
451 		cups->header.PageSize[1], cups->header.PageSize[0]);
452       stp_set_page_width(v, cups->header.PageSize[0]);
453       stp_set_page_height(v, cups->header.PageSize[1]);
454     }
455 
456  /*
457   * Duplex
458   * Note that the names MUST match those in the printer driver(s)
459   */
460 
461   if (cups->header.Duplex != 0)
462     {
463       if (cups->header.Tumble != 0)
464         set_string_parameter(v, "Duplex", "DuplexTumble");
465       else
466         set_string_parameter(v, "Duplex", "DuplexNoTumble");
467     }
468 
469   cups->shrink_to_fit =
470     (stp_check_int_parameter(v, "CUPSShrinkPage", STP_PARAMETER_ACTIVE) ?
471      stp_get_int_parameter(v, "CUPSShrinkPage") : 0);
472 
473   set_string_parameter(v, "JobMode", "Job");
474   validate_options(v, cups);
475   stp_get_media_size(v, &(cups->d_width), &(cups->d_height));
476   stp_get_maximum_imageable_area(v, &tmp_left, &tmp_right,
477 				 &tmp_bottom, &tmp_top);
478   stp_get_imageable_area(v, &(cups->d_left), &(cups->d_right),
479 			 &(cups->d_bottom), &(cups->d_top));
480   if (! suppress_messages)
481     {
482       fprintf(stderr, "DEBUG: Gutenprint:   limits w %.3f l %.3f r %.3f  h %.3f t %.3f b %.3f\n",
483 	      cups->d_width, cups->d_left, cups->d_right, cups->d_height, cups->d_top, cups->d_bottom);
484       fprintf(stderr, "DEBUG: Gutenprint:   max limits l %.3f r %.3f t %.3f b %.3f\n",
485 	      tmp_left, tmp_right, tmp_top, tmp_bottom);
486     }
487 
488   if (tmp_left < 0)
489     tmp_left = 0;
490   if (tmp_top < 0)
491     tmp_top = 0;
492   if (tmp_right > tmp_left + cups->d_width)
493     tmp_right = cups->d_width;
494   if (tmp_bottom > tmp_top + cups->d_height)
495     tmp_bottom = cups->d_height;
496   if (tmp_left < cups->d_left)
497     {
498       if (cups->shrink_to_fit != 1)
499 	{
500 	  cups->d_left_trim = cups->d_left - tmp_left;
501 	  tmp_left = cups->d_left;
502 	}
503       else
504 	cups->d_left_trim = 0;
505       if (! suppress_messages)
506 	fprintf(stderr, "DEBUG: Gutenprint:   left margin %.3f\n", cups->d_left_trim);
507     }
508   else
509     {
510       cups->d_left_trim = 0;
511       if (! suppress_messages)
512 	fprintf(stderr, "DEBUG: Gutenprint:   Adjusting left margin from %.3f to %.3f\n",
513 		cups->d_left, tmp_left);
514       cups->d_left = tmp_left;
515     }
516   if (tmp_right > cups->d_right)
517     {
518       if (cups->shrink_to_fit != 1)
519 	{
520 	  cups->d_right_trim = tmp_right - cups->d_right;
521 	  tmp_right = cups->d_right;
522 	}
523       else
524 	cups->d_right_trim = 0;
525       if (! suppress_messages)
526 	fprintf(stderr, "DEBUG: Gutenprint:   right margin %.3f\n", cups->d_right_trim);
527     }
528   else
529     {
530       cups->d_right_trim = 0;
531       if (! suppress_messages)
532 	fprintf(stderr, "DEBUG: Gutenprint:   Adjusting right margin from %.3f to %.3f\n",
533 		cups->d_right, tmp_right);
534       cups->d_right = tmp_right;
535     }
536   if (tmp_top < cups->d_top)
537     {
538       if (cups->shrink_to_fit != 1)
539 	{
540 	  cups->d_top_trim = cups->d_top - tmp_top;
541 	  tmp_top = cups->d_top;
542 	}
543       else
544 	cups->d_top_trim = 0;
545       if (! suppress_messages)
546 	fprintf(stderr, "DEBUG: Gutenprint:   top margin %.3f\n", cups->d_top_trim);
547     }
548   else
549     {
550       cups->d_top_trim = 0;
551       if (! suppress_messages)
552 	fprintf(stderr, "DEBUG: Gutenprint:   Adjusting top margin from %.3f to %.3f\n",
553 		cups->d_top, tmp_top);
554       cups->d_top = tmp_top;
555     }
556   if (tmp_bottom > cups->d_bottom)
557     {
558       if (cups->shrink_to_fit != 1)
559 	{
560 	  cups->d_bottom_trim = tmp_bottom - cups->d_bottom;
561 	  tmp_bottom = cups->d_bottom;
562 	}
563       else
564 	cups->d_bottom_trim = 0;
565       if (! suppress_messages)
566 	fprintf(stderr, "DEBUG: Gutenprint:   bottom margin %.3f\n", cups->d_bottom_trim);
567     }
568   else
569     {
570       cups->d_bottom_trim = 0;
571       if (! suppress_messages)
572 	fprintf(stderr, "DEBUG: Gutenprint:   Adjusting bottom margin from %.3f to %.3f\n",
573 		cups->d_bottom, tmp_bottom);
574       cups->d_bottom = tmp_bottom;
575     }
576 
577   if (cups->shrink_to_fit == 2)
578     {
579       stp_dimension_t t_left, t_right, t_bottom, t_top;
580       stp_get_imageable_area(v, &(t_left), &(t_right), &(t_bottom), &(t_top));
581       stp_set_width(v, t_right - t_left);
582       stp_set_height(v, t_bottom - t_top);
583       stp_set_left(v, t_left);
584       stp_set_top(v, t_top);
585     }
586   else
587     {
588       stp_set_width(v, cups->d_right - cups->d_left);
589       stp_set_height(v, cups->d_bottom - cups->d_top);
590       stp_set_left(v, cups->d_left);
591       stp_set_top(v, cups->d_top);
592     }
593 
594   cups->d_right = cups->d_width - cups->d_right;
595   if (cups->shrink_to_fit == 1)
596     cups->d_width = tmp_right - tmp_left;
597   else
598     cups->d_width = cups->d_width - cups->d_left - cups->d_right;
599   cups->width = cups->header.HWResolution[0] * cups->d_width / 72;
600   cups->left = cups->header.HWResolution[0] * cups->d_left / 72;
601   cups->right = cups->header.HWResolution[0] * cups->d_right / 72;
602   cups->left_trim = cups->header.HWResolution[0] * cups->d_left_trim / 72;
603   cups->right_trim = cups->header.HWResolution[0] * cups->d_right_trim / 72;
604   cups->adjusted_width = cups->width;
605   if (cups->adjusted_width > cups->header.cupsWidth)
606     cups->adjusted_width = cups->header.cupsWidth;
607 
608   cups->d_bottom = cups->d_height - cups->d_bottom;
609   if (cups->shrink_to_fit == 1)
610     cups->d_height = tmp_bottom - tmp_top;
611   else
612     cups->d_height = cups->d_height - cups->d_top - cups->d_bottom;
613   cups->height = cups->header.HWResolution[1] * cups->d_height / 72;
614   cups->top = cups->header.HWResolution[1] * cups->d_top / 72;
615   cups->bottom = cups->header.HWResolution[1] * cups->d_bottom / 72;
616   cups->top_trim = cups->header.HWResolution[1] * cups->d_top_trim / 72;
617   cups->bottom_trim = cups->header.HWResolution[1] * cups->d_bottom_trim / 72;
618   cups->adjusted_height = cups->height;
619   if (cups->adjusted_height > cups->header.cupsHeight)
620     cups->adjusted_height = cups->header.cupsHeight;
621   if (! suppress_messages)
622     {
623       fprintf(stderr, "DEBUG: Gutenprint:   CUPS settings w %d l %d r %d  h %d t %d b %d\n",
624 	      cups->width, cups->left, cups->right,
625 	      cups->height, cups->top, cups->bottom);
626       fprintf(stderr, "DEBUG: Gutenprint:        adjusted w %d h %d\n",
627 	      cups->adjusted_width, cups->adjusted_height);
628 
629     }
630 
631   if (! suppress_messages)
632     fprintf(stderr, "DEBUG: Gutenprint: End initialize page\n");
633   return v;
634 }
635 
636 static void
purge_excess_data(cups_image_t * cups)637 purge_excess_data(cups_image_t *cups)
638 {
639   char *buffer = stp_malloc(cups->header.cupsBytesPerLine);
640   if (buffer)
641     {
642       if (! suppress_messages && ! suppress_verbose_messages )
643 	fprintf(stderr, "DEBUG2: Gutenprint: Purging %d row%s\n",
644 		cups->header.cupsHeight - cups->row,
645 		((cups->header.cupsHeight - cups->row) == 1 ? "" : "s"));
646       while (cups->row < cups->header.cupsHeight)
647 	{
648 	  cupsRasterReadPixels(cups->ras, (unsigned char *)buffer,
649 			       cups->header.cupsBytesPerLine);
650 	  cups->row ++;
651 	}
652     }
653   stp_free(buffer);
654 }
655 
656 static void
set_all_options(stp_vars_t * v,cups_option_t * options,int num_options,ppd_file_t * ppd)657 set_all_options(stp_vars_t *v, cups_option_t *options, int num_options,
658 		ppd_file_t *ppd)
659 {
660   stp_parameter_list_t params = stp_get_parameter_list(v);
661   int nparams = stp_parameter_list_count(params);
662   int i;
663   const char *val;		/* CUPS option value */
664   ppd_option_t *ppd_option;
665   if (! suppress_messages)
666     fprintf(stderr, "DEBUG: Gutenprint: Set options:\n");
667   val = cupsGetOption("StpiShrinkOutput", num_options, options);
668   if (!val)
669     {
670       ppd_option = ppdFindOption(ppd, "StpiShrinkOutput");
671       if (ppd_option)
672 	val = ppd_option->defchoice;
673     }
674   if (val)
675     {
676       if (!strcasecmp(val, "crop"))
677 	stp_set_int_parameter(v, "CUPSShrinkPage", 0);
678       else if (!strcasecmp(val, "expand"))
679 	stp_set_int_parameter(v, "CUPSShrinkPage", 2);
680       else
681 	stp_set_int_parameter(v, "CUPSShrinkPage", 1);
682     }
683   else
684     stp_set_int_parameter(v, "CUPSShrinkPage", 1);
685   for (i = 0; i < nparams; i++)
686     {
687       const stp_parameter_t *param = stp_parameter_list_param(params, i);
688       stp_parameter_t desc;
689       char *ppd_option_name = stp_malloc(strlen(param->name) + 8);	/* StpFineFOO\0 */
690 
691       stp_describe_parameter(v, param->name, &desc);
692       if (desc.p_type == STP_PARAMETER_TYPE_DOUBLE)
693 	{
694 	  sprintf(ppd_option_name, "Stp%s", desc.name);
695 	  val = cupsGetOption(ppd_option_name, num_options, options);
696 	  if (!val)
697 	    {
698 	      ppd_option = ppdFindOption(ppd, ppd_option_name);
699 	      if (ppd_option)
700 		val = ppd_option->defchoice;
701 	    }
702 	  if (val && !strncasecmp(val, "Custom.", 7))
703 	    {
704 	      double dval = atof(val + 7);
705 
706 	      if (! suppress_messages)
707 		fprintf(stderr, "DEBUG: Gutenprint:   Set float %s to %f\n",
708 			desc.name, dval);
709 	      if (dval > desc.bounds.dbl.upper)
710 		dval = desc.bounds.dbl.upper;
711 	      stp_set_float_parameter(v, desc.name, dval);
712             }
713 	  else if (val && strlen(val) > 0 && strcmp(val, "None") != 0)
714 	    {
715 	      double fine_val = 0;
716 	      if (strchr(val, (int) '.'))
717 		{
718 		  fine_val = atof(val);
719 		  if (! suppress_messages)
720 		    fprintf(stderr, "DEBUG: Gutenprint:   Set float %s to %f (%s)\n",
721 			    desc.name, fine_val, val);
722 		}
723 	      else
724 		{
725 		  double coarse_val = atof(val) * 0.001;
726 		  sprintf(ppd_option_name, "StpFine%s", desc.name);
727 		  val = cupsGetOption(ppd_option_name, num_options, options);
728 		  if (!val)
729 		    {
730 		      ppd_option = ppdFindOption(ppd, ppd_option_name);
731 		      if (ppd_option)
732 			val = ppd_option->defchoice;
733 		    }
734 		  if (val && strlen(val) > 0 && strcmp(val, "None") != 0)
735 		    fine_val = atof(val) * 0.001;
736 		  if (! suppress_messages)
737 		    fprintf(stderr, "DEBUG: Gutenprint:   Set float %s to %f + %f\n",
738 			    desc.name, coarse_val, fine_val);
739 		  fine_val += coarse_val;
740 		}
741 	      if (fine_val > desc.bounds.dbl.upper)
742 		fine_val = desc.bounds.dbl.upper;
743 	      if (fine_val < desc.bounds.dbl.lower)
744 		fine_val = desc.bounds.dbl.lower;
745 	      stp_set_float_parameter(v, desc.name, fine_val);
746 	    }
747 	}
748       else
749 	{
750 	  sprintf(ppd_option_name, "Stp%s", desc.name);
751 	  val = cupsGetOption(ppd_option_name, num_options, options);
752 	  if (!val)
753 	    {
754 	      ppd_option = ppdFindOption(ppd, ppd_option_name);
755 	      if (ppd_option)
756 		val = ppd_option->defchoice;
757 	    }
758 	  if (val && ((strlen(val) > 0 && strcmp(val, "None") != 0) ||
759 		      (desc.p_type == STP_PARAMETER_TYPE_STRING_LIST)))
760 	    {
761 	      stp_curve_t *curve;
762 	      stp_raw_t *raw;
763 	      switch (desc.p_type)
764 		{
765 		case STP_PARAMETER_TYPE_STRING_LIST:
766 		  if (! suppress_messages)
767 		    fprintf(stderr, "DEBUG: Gutenprint:   Set string %s to %s\n",
768 			    desc.name, val);
769 		  set_string_parameter(v, desc.name, val);
770 		  break;
771 		case STP_PARAMETER_TYPE_INT:
772                   if (!strncasecmp(val, "Custom.", 7))
773 		    val += 7;
774 
775 		  if (! suppress_messages)
776 		    fprintf(stderr, "DEBUG: Gutenprint:   Set int %s to %s (%d)\n",
777 			    desc.name, val, atoi(val));
778 		  stp_set_int_parameter(v, desc.name, atoi(val));
779 		  break;
780 		case STP_PARAMETER_TYPE_DIMENSION:
781                   if (!strncasecmp(val, "Custom.", 7))
782 		    val += 7;
783 
784 		  if (! suppress_messages)
785 		    fprintf(stderr, "DEBUG: Gutenprint:   Set dimension %s to %s (%d)\n",
786 			    desc.name, val, atoi(val));
787 
788 		  stp_set_dimension_parameter(v, desc.name, atoi(val));
789 		  break;
790 		case STP_PARAMETER_TYPE_BOOLEAN:
791 		  if (! suppress_messages)
792 		    fprintf(stderr, "DEBUG: Gutenprint:   Set bool %s to %s (%d)\n",
793 			    desc.name, val, strcasecmp(val, "true") == 0 ? 1 : 0);
794 		  stp_set_boolean_parameter
795 		    (v, desc.name, strcasecmp(val, "true") == 0 ? 1 : 0);
796 		  break;
797 		case STP_PARAMETER_TYPE_CURVE:
798 		  curve = stp_curve_create_from_string(val);
799 		  if (! suppress_messages)
800 		    fprintf(stderr, "DEBUG: Gutenprint:   Set curve %s to %s\n",
801 			    desc.name, curve ? val : "(NULL)");
802 		  if (curve)
803 		    {
804 		      stp_set_curve_parameter(v, desc.name, curve);
805 		      stp_curve_destroy(curve);
806 		    }
807 		  break;
808 		case STP_PARAMETER_TYPE_RAW: /* figure this out later, too */
809 		  raw = stp_xmlstrtoraw(val);
810 		  if (! suppress_messages)
811 		    fprintf(stderr, "DEBUG: Gutenprint:   Set raw %s to %s\n",
812 			    desc.name, raw ? val : "(NULL)");
813 		  if (raw)
814 		    {
815 		      stp_set_raw_parameter(v, desc.name, raw->data, raw->bytes);
816 		      stp_free(cast_safe(raw->data));
817 		      stp_free(raw);
818 		    }
819 		  break;
820 		case STP_PARAMETER_TYPE_FILE: /* Probably not, security hole */
821 		  if (! suppress_messages)
822 		    fprintf(stderr, "DEBUG: Gutenprint:   Ignoring option %s %s type %d\n",
823 			    desc.name, val, desc.p_type);
824 		  break;
825 		default:
826 		  break;
827 		}
828 	    }
829 	  else if (val)
830 	    {
831 	      if (! suppress_messages)
832 		fprintf(stderr, "DEBUG: Gutenprint:     Not setting %s to '%s'\n",
833 			desc.name, val);
834 	    }
835 	  else
836 	    {
837 	      if (! suppress_messages)
838 		fprintf(stderr, "DEBUG: Gutenprint:     Not setting %s to (null)\n",
839 			desc.name);
840 	    }
841 	}
842       stp_parameter_description_destroy(&desc);
843       stp_free(ppd_option_name);
844     }
845   if (! suppress_messages)
846     fprintf(stderr, "DEBUG: Gutenprint: End options\n");
847   stp_parameter_list_destroy(params);
848 }
849 
850 #ifdef ENABLE_CUPS_LOAD_SAVE_OPTIONS
851 static void
save_options(const char * save_name,const stp_vars_t * v)852 save_options(const char *save_name, const stp_vars_t *v)
853 {
854   FILE *f_options;
855   int i;
856   stp_vars_t *c = stp_vars_create();
857   stp_parameter_list_t params = stp_get_parameter_list(v);
858   stp_parameter_t desc;
859   stp_mxml_node_t *mxml = NULL;
860   int param_count;
861 
862   if (!params)
863     {
864       stp_vars_destroy(c);
865       return;
866     }
867   f_options = fopen(save_name, "w");
868   if (!f_options)
869     {
870       stp_parameter_list_destroy(params);
871       stp_vars_destroy(c);
872       return;
873     }
874   param_count = stp_parameter_list_count(params);
875   stp_set_driver(c, stp_get_driver(v));
876   if (!suppress_messages)
877     fprintf(stderr, "DEBUG: Gutenprint: Saving parameters to %s\n", save_name);
878   for (i = 0; i < param_count; i++)
879     {
880       const stp_parameter_t *lparam =
881 	stp_parameter_list_param(params, i);
882       stp_describe_parameter(v, lparam->name, &desc);
883       if (desc.read_only || !strcmp(desc.name, "ChannelBitDepth") ||
884 	  !stp_parameter_has_category_value(v, &desc, "Color", "Yes"))
885 	{
886 	  if (!suppress_messages)
887 	    fprintf(stderr, "DEBUG: Gutenprint:    skipping non-color %s\n",
888 		    desc.name);
889 	  stp_parameter_description_destroy(&desc);
890 	  continue;
891 	}
892       switch (desc.p_type)
893 	{
894 	case STP_PARAMETER_TYPE_STRING_LIST:
895 	  if (stp_check_string_parameter(v, desc.name,
896 					 STP_PARAMETER_DEFAULTED))
897 	    {
898 	      if (!suppress_messages)
899 		fprintf(stderr, "DEBUG: Gutenprint:  SAVING string %s %s\n",
900 			desc.name, stp_get_string_parameter(v, desc.name));
901 	      stp_set_string_parameter(c, desc.name,
902 				       stp_get_string_parameter(v, desc.name));
903 	    }
904 	  else if (desc.is_mandatory)
905 	    {
906 	      if (!suppress_messages)
907 		fprintf(stderr, "DEBUG: Gutenprint:  SAVING defaulted string %s %s\n",
908 			desc.name, desc.deflt.str);
909 	      stp_set_string_parameter(c, desc.name, desc.deflt.str);
910 	    }
911 	  else if (!suppress_messages)
912 	    fprintf(stderr, "DEBUG: Gutenprint:    skipping string %s\n", desc.name);
913 	  break;
914 	case STP_PARAMETER_TYPE_RAW:
915 	  if (stp_check_raw_parameter(v, desc.name,
916 				      STP_PARAMETER_DEFAULTED))
917 	    {
918 	      const stp_raw_t *raw = stp_get_raw_parameter(v, desc.name);
919 	      if (!suppress_messages)
920 		fprintf(stderr, "DEBUG: Gutenprint:  SAVING raw %s\n", desc.name);
921 	      stp_set_raw_parameter(c, desc.name, raw->data, raw->bytes);
922 	    }
923 	  else if (!suppress_messages)
924 	    fprintf(stderr, "DEBUG: Gutenprint:    skipping raw %s\n",
925 		    desc.name);
926 	  break;
927 	case STP_PARAMETER_TYPE_BOOLEAN:
928 	  if (stp_check_boolean_parameter(v, desc.name, STP_PARAMETER_DEFAULTED))
929 	    {
930 	      if (!suppress_messages)
931 		fprintf(stderr, "DEBUG: Gutenprint:  SAVING bool %s %d\n",
932 			desc.name, stp_get_boolean_parameter(v, desc.name));
933 	      stp_set_boolean_parameter(c, desc.name,
934 					stp_get_boolean_parameter(v, desc.name));
935 	    }
936 	  else if (desc.is_mandatory)
937 	    {
938 	      if (!suppress_messages)
939 		fprintf(stderr, "DEBUG: Gutenprint:  SAVING defaulted bool %s %d\n",
940 			desc.name, desc.deflt.boolean);
941 	      stp_set_boolean_parameter(c, desc.name, desc.deflt.boolean);
942 	    }
943 	  else if (!suppress_messages)
944 	    fprintf(stderr, "DEBUG: Gutenprint:    skipping bool %s\n", desc.name);
945 	  break;
946 	case STP_PARAMETER_TYPE_INT:
947 	  if (stp_check_int_parameter(v, desc.name, STP_PARAMETER_DEFAULTED))
948 	    {
949 	      if (!suppress_messages)
950 		fprintf(stderr, "DEBUG: Gutenprint:  SAVING int %s %d\n",
951 			desc.name, stp_get_int_parameter(v, desc.name));
952 	      stp_set_int_parameter(c, desc.name, stp_get_int_parameter(v, desc.name));
953 	    }
954 	  else if (desc.is_mandatory)
955 	    {
956 	      if (!suppress_messages)
957 		fprintf(stderr, "DEBUG: Gutenprint:  SAVING defaulted int %s %d\n",
958 			desc.name, desc.deflt.integer);
959 	      stp_set_int_parameter(c, desc.name, desc.deflt.integer);
960 	    }
961 	  else if (!suppress_messages)
962 	    fprintf(stderr, "DEBUG: Gutenprint:    skipping int %s\n", desc.name);
963 	  break;
964 	case STP_PARAMETER_TYPE_DOUBLE:
965 	  if (stp_check_float_parameter(v, desc.name, STP_PARAMETER_DEFAULTED))
966 	    {
967 	      if (!suppress_messages)
968 		fprintf(stderr, "DEBUG: Gutenprint:  SAVING float %s %f\n",
969 			desc.name, stp_get_float_parameter(v, desc.name));
970 	      stp_set_float_parameter(c, desc.name,
971 				      stp_get_float_parameter(v, desc.name));
972 	    }
973 	  else if (desc.is_mandatory)
974 	    {
975 	      if (!suppress_messages)
976 		fprintf(stderr, "DEBUG: Gutenprint:  SAVING defaulted float %s %f\n",
977 			desc.name, desc.deflt.dbl);
978 	      stp_set_float_parameter(c, desc.name, desc.deflt.dbl);
979 	    }
980 	  else if (!suppress_messages)
981 	    fprintf(stderr, "DEBUG: Gutenprint:    skipping float %s\n", desc.name);
982 	  break;
983 	case STP_PARAMETER_TYPE_DIMENSION:
984 	  if (stp_check_dimension_parameter(v, desc.name, STP_PARAMETER_DEFAULTED))
985 	    {
986 	      if (!suppress_messages)
987 		fprintf(stderr, "DEBUG: Gutenprint:  SAVING dimension %s %d\n",
988 			desc.name, stp_get_dimension_parameter(v, desc.name));
989 	      stp_set_dimension_parameter(c, desc.name,
990 					  stp_get_dimension_parameter(v, desc.name));
991 	    }
992 	  else if (desc.is_mandatory)
993 	    {
994 	      if (!suppress_messages)
995 		fprintf(stderr, "DEBUG: Gutenprint:  SAVING defaulted dimension %s %d\n",
996 			desc.name, desc.deflt.dimension);
997 	      stp_set_dimension_parameter(c, desc.name, desc.deflt.dimension);
998 	    }
999 	  else if (!suppress_messages)
1000 	    fprintf(stderr, "DEBUG: Gutenprint:    skipping dimension %s\n", desc.name);
1001 	  break;
1002 	case STP_PARAMETER_TYPE_CURVE:
1003 	  if (stp_check_curve_parameter(v, desc.name, STP_PARAMETER_DEFAULTED))
1004 	    {
1005 	      if (!suppress_messages)
1006 		fprintf(stderr, "DEBUG: Gutenprint:  SAVING curve %s\n", desc.name);
1007 	      stp_set_curve_parameter(c, desc.name,
1008 				      stp_get_curve_parameter(v, desc.name));
1009 	    }
1010 	  else if (desc.is_mandatory)
1011 	    {
1012 	      if (!suppress_messages)
1013 		fprintf(stderr, "DEBUG: Gutenprint:  SAVING defaulted curve %s\n", desc.name);
1014 	      stp_set_curve_parameter(c, desc.name, desc.deflt.curve);
1015 	    }
1016 	  else if (!suppress_messages)
1017 	    fprintf(stderr, "DEBUG: Gutenprint:    skipping curve %s\n",
1018 		    desc.name);
1019 	  break;
1020 	default:
1021 	  if (!suppress_messages)
1022 	    fprintf(stderr, "DEBUG: Gutenprint:   Ignoring unknown type parameter %s (%d)\n",
1023 		    desc.name, desc.p_type);
1024 	  break;
1025 	}
1026       stp_parameter_description_destroy(&desc);
1027     }
1028   stp_parameter_list_destroy(params);
1029   mxml = stp_xmltree_create_from_vars(c);
1030   if (mxml)
1031     {
1032       fputs("<?xml version=\"1.0\"?>\n\n", f_options);
1033       stp_mxmlSaveFile(mxml, f_options, STP_MXML_NO_CALLBACK);
1034       stp_mxmlDelete(mxml);
1035     }
1036   (void) fclose(f_options);
1037   stp_vars_destroy(c);
1038   if (!suppress_messages)
1039     fprintf(stderr, "DEBUG: Gutenprint: Done saving parameters to %s\n", save_name);
1040 }
1041 
1042 static stp_vars_t *
load_options(const char * load_name)1043 load_options(const char *load_name)
1044 {
1045   FILE *f_options = fopen(load_name, "r");
1046   if (f_options)
1047     {
1048       stp_vars_t *settings = NULL;
1049       stp_mxml_node_t *mxml;
1050       mxml = stp_mxmlLoadFile(NULL, f_options, STP_MXML_NO_CALLBACK);
1051       if (mxml)
1052 	{
1053 	  stp_mxml_node_t *nxml =
1054 	    stp_mxmlFindElement(mxml, mxml, "vars", NULL, NULL,
1055 				STP_MXML_DESCEND);
1056 	  if (nxml)
1057 	    {
1058 	      settings = stp_vars_create_from_xmltree_ref(nxml->child, mxml);
1059 	      if (! suppress_messages)
1060 		fprintf(stderr, "DEBUG: Gutenprint: loading options from %s\n",
1061 			load_file_name);
1062 	      if (! suppress_messages)
1063 		stp_vars_print_error(settings, "DEBUG");
1064 	    }
1065 	}
1066       else
1067 	fprintf(stderr, "DEBUG: Unable to load options from %s\n",
1068 		load_file_name);
1069       fclose(f_options);
1070       return settings;
1071     }
1072   return NULL;
1073 }
1074 
1075 #endif /* ENABLE_CUPS_LOAD_SAVE_OPTIONS */
1076 
1077 /*
1078  * 'main()' - Main entry and processing of driver.
1079  */
1080 
1081 int					/* O - Exit status */
main(int argc,char * argv[])1082 main(int  argc,				/* I - Number of command-line arguments */
1083      char *argv[])			/* I - Command-line arguments */
1084 {
1085   int			fd;		/* File descriptor */
1086   cups_image_t		cups;		/* CUPS image */
1087   const char		*ppdfile;	/* PPD environment variable */
1088   ppd_file_t		*ppd;		/* PPD file */
1089   ppd_size_t		*size;
1090   const stp_printer_t	*printer;	/* Printer driver */
1091   int			num_options;	/* Number of CUPS options */
1092   cups_option_t		*options;	/* CUPS options */
1093   stp_vars_t		*v = NULL;
1094   stp_vars_t		*default_settings;
1095   int			initialized_job = 0;
1096   const char            *version_id;
1097   struct tms		tms;
1098   long			clocks_per_sec;
1099   struct timeval	t1, t2;
1100   char			*page_size_name = NULL;
1101   int			aborted = 0;
1102 #ifdef ENABLE_CUPS_LOAD_SAVE_OPTIONS
1103   stp_vars_t		*loaded_settings = NULL;
1104 #endif /* ENABLE_CUPS_LOAD_SAVE_OPTIONS */
1105 
1106 
1107  /*
1108   * Don't buffer error/status messages...
1109   */
1110 
1111   setbuf(stderr, NULL);
1112 
1113   if (getenv("STP_SUPPRESS_MESSAGES"))
1114     suppress_messages = 1;
1115 
1116   if (getenv("STP_SUPPRESS_VERBOSE_MESSAGES"))
1117     suppress_verbose_messages = 1;
1118 
1119  /*
1120   * Initialize libgutenprint
1121   */
1122 
1123   po = stp_i18n_load(getenv("LANG"));
1124 
1125   theImage.rep = &cups;
1126 
1127   (void) gettimeofday(&t1, NULL);
1128   stp_set_global_errfunc(cups_errfunc);
1129   stp_set_global_dbgfunc(cups_dbgfunc);
1130   stp_set_global_errdata(stderr);
1131   stp_set_global_dbgdata(stderr);
1132   stp_init();
1133   version_id = stp_get_version();
1134   default_settings = stp_vars_create();
1135   stp_set_outfunc(default_settings, cups_writefunc);
1136   stp_set_outdata(default_settings, stdout);
1137 
1138  /*
1139   * Check for valid arguments...
1140   */
1141   if (argc < 6 || argc > 7)
1142   {
1143    /*
1144     * We don't have the correct number of arguments; write an error message
1145     * and return.
1146     */
1147 
1148     stp_i18n_printf(po, _("Usage: rastertoprinter job-id user title copies "
1149                           "options [file]\n"));
1150     return (1);
1151   }
1152 
1153   if (! suppress_messages)
1154     {
1155       fprintf(stderr, "DEBUG: Gutenprint: ============================================================\n");
1156       fprintf(stderr, "DEBUG: Gutenprint: VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV\n");
1157       fprintf(stderr, "DEBUG: Gutenprint: %s Starting\n", version_id);
1158       fprintf(stderr, "DEBUG: Gutenprint: command line: %s '%s' '%s' '%s' '%s' %s%s%s%s\n",
1159 	      argv[0], argv[1], argv[2], argv[3], argv[4], "<args>",
1160 	      argc >= 7 ? " '" : "",
1161 	      argc >= 7 ? argv[6] : "",
1162 	      argc >= 7 ? "'" : "");
1163     }
1164 
1165  /*
1166   * Get the PPD file...
1167   */
1168 
1169   if ((ppdfile = getenv("PPD")) == NULL)
1170   {
1171     stp_i18n_printf(po, _("ERROR: No PPD file, unable to continue!\n"));
1172     return (1);
1173   }
1174   if (! suppress_messages)
1175     fprintf(stderr, "DEBUG: Gutenprint: using PPD file %s\n", ppdfile);
1176 
1177   if ((ppd = ppdOpenFile(ppdfile)) == NULL)
1178   {
1179     stp_i18n_printf(po, _("ERROR: Gutenprint was unable to load PPD file "
1180                           "\"%s\"!\n"), ppdfile);
1181     return (1);
1182   }
1183 
1184   if (ppd->modelname == NULL)
1185   {
1186     stp_i18n_printf(po, _("ERROR: Gutenprint did not find a ModelName "
1187                           "attribute in PPD file \"%s\"!\n"), ppdfile);
1188     ppdClose(ppd);
1189     return (1);
1190   }
1191 
1192   if (ppd->nickname == NULL)
1193   {
1194     stp_i18n_printf(po, _("ERROR: Gutenprint did not find a NickName attribute "
1195                           "in PPD file \"%s\"!\n"), ppdfile);
1196     ppdClose(ppd);
1197     return (1);
1198   }
1199   else if (strlen(ppd->nickname) <
1200 	   strlen(ppd->modelname) + strlen(CUPS_PPD_NICKNAME_STRING) + 3)
1201   {
1202     stp_i18n_printf(po, _("ERROR: Gutenprint found a corrupted NickName "
1203                           "attribute in PPD file \"%s\"!\n"), ppdfile);
1204     ppdClose(ppd);
1205     return (1);
1206   }
1207   else if (strcmp(ppd->nickname + strlen(ppd->modelname) +
1208 		  strlen(CUPS_PPD_NICKNAME_STRING), version_id) != 0 &&
1209 	   (strlen(ppd->nickname + strlen(ppd->modelname) +
1210 		   strlen(CUPS_PPD_NICKNAME_STRING)) < strlen(version_id) ||
1211 	    !((strncmp(ppd->nickname + strlen(ppd->modelname) +
1212 		      strlen(CUPS_PPD_NICKNAME_STRING), version_id,
1213 		      strlen(version_id)) == 0) &&
1214 	      *(ppd->nickname + strlen(ppd->modelname) +
1215 		strlen(CUPS_PPD_NICKNAME_STRING)) != ' ')))
1216   {
1217     stp_i18n_printf(po, _("ERROR: The PPD version (%s) is not compatible with "
1218                           "Gutenprint %s.  Please run `%scups-genppdupdate' as administrator.\n"),
1219 	            ppd->nickname+strlen(ppd->modelname)+strlen(CUPS_PPD_NICKNAME_STRING),
1220 	            version_id, SBINDIR);
1221     fprintf(stderr, "DEBUG: Gutenprint: If you have upgraded your version of Gutenprint\n");
1222     fprintf(stderr, "DEBUG: Gutenprint: recently, you must reinstall all printer queues.\n");
1223     fprintf(stderr, "DEBUG: Gutenprint: If the previous installed version of Gutenprint\n");
1224     fprintf(stderr, "DEBUG: Gutenprint: was 5.0.0 or higher, you can use the `cups-genppdupdate'\n");
1225     fprintf(stderr, "DEBUG: Gutenprint: program to do this; if the previous installed version\n");
1226     fprintf(stderr, "DEBUG: Gutenprint: was older, you can use the Modify Printer command via\n");
1227     fprintf(stderr, "DEBUG: Gutenprint: the CUPS web interface: http://localhost:631/printers.\n");
1228     ppdClose(ppd);
1229     return 1;
1230   }
1231 
1232  /*
1233   * Get the STP options, if any...
1234   */
1235 
1236   num_options = cupsParseOptions(argv[5], 0, &options);
1237   ppdMarkDefaults(ppd);
1238   cupsMarkOptions(ppd, num_options, options);
1239   size = ppdPageSize(ppd, NULL);
1240 
1241   if (size)
1242     page_size_name = stp_strdup(size->name);
1243 
1244   if (! suppress_messages)
1245     fprintf(stderr, "DEBUG: Gutenprint: CUPS option count is %d (%d bytes)\n",
1246 	    num_options, (int)strlen(argv[5]));
1247 
1248   if (num_options > 0)
1249     {
1250       int i;
1251       for (i = 0; i < num_options; i++)
1252 	{
1253 	  if (! suppress_messages)
1254 	    fprintf(stderr, "DEBUG: Gutenprint:  CUPS option %d %s = %s\n",
1255 		    i, options[i].name, options[i].value);
1256 #ifdef ENABLE_CUPS_LOAD_SAVE_OPTIONS
1257 	  if (!strcmp(options[i].name, "SaveFileName"))
1258 	    save_file_name = options[i].value;
1259 	  if (!strcmp(options[i].name, "LoadFileName"))
1260 	    load_file_name = options[i].value;
1261 #endif /* ENABLE_CUPS_LOAD_SAVE_OPTIONS */
1262 	}
1263     }
1264 
1265  /*
1266   * Figure out which driver to use...
1267   */
1268 
1269   printer = stp_get_printer_by_driver(ppd->modelname);
1270   if (!printer)
1271     printer = stp_get_printer_by_long_name(ppd->modelname);
1272 
1273   if (printer == NULL)
1274     {
1275       stp_i18n_printf(po, _("ERROR: Unable to find Gutenprint driver named "
1276                             "\"%s\"!\n"), ppd->modelname);
1277       ppdClose(ppd);
1278       return (1);
1279     }
1280   if (! suppress_messages)
1281     fprintf(stderr, "DEBUG: Gutenprint: Driver %s\n", ppd->modelname);
1282 
1283  /*
1284   * Open the page stream...
1285   */
1286 
1287   if (argc == 7)
1288   {
1289     if ((fd = open(argv[6], O_RDONLY)) == -1)
1290     {
1291       stp_i18n_printf(po, _("ERROR: Gutenprint was unable to open raster file "
1292                             "\"%s\" - %s"), argv[6], strerror(errno));
1293       sleep(1);
1294       return (1);
1295     }
1296   }
1297   else
1298     fd = 0;
1299   if (! suppress_messages)
1300     fprintf(stderr, "DEBUG: Gutenprint: Using fd %d\n", fd);
1301 
1302   stp_set_printer_defaults(default_settings, printer);
1303 #ifdef ENABLE_CUPS_LOAD_SAVE_OPTIONS
1304   if (load_file_name)
1305     loaded_settings = load_options(load_file_name);
1306 #endif /* ENABLE_CUPS_LOAD_SAVE_OPTIONS */
1307   stp_set_float_parameter(default_settings, "AppGamma", 1.0);
1308   set_all_options(default_settings, options, num_options, ppd);
1309 
1310   cupsFreeOptions(num_options, options);
1311   ppdClose(ppd);
1312 
1313   cups.ras = cupsRasterOpen(fd, CUPS_RASTER_READ);
1314 
1315  /*
1316   * Process pages as needed...
1317   */
1318 
1319   cups.page = 0;
1320 
1321   if (! suppress_messages)
1322     fprintf(stderr, "DEBUG: Gutenprint: About to start printing loop.\n");
1323 
1324   /*
1325    * Read the first page header, which we need in order to set up
1326    * the page.
1327    */
1328   signal(SIGTERM, cancel_job);
1329   while (CUPS_READ_HEADER(cups.ras, &cups.header))
1330     {
1331       /*
1332        * We don't know how many pages we're going to print, and
1333        * we need to call stp_end_job at the completion of the job.
1334        * Therefore, we need to keep v in scope after the termination
1335        * of the loop to permit calling stp_end_job then.  Therefore,
1336        * we have to free the previous page's stp_vars_t at the start
1337        * of the loop.
1338        */
1339       if (v)
1340 	stp_vars_destroy(v);
1341 
1342       /*
1343        * Setup printer driver variables...
1344        */
1345       if (! suppress_messages)
1346 	{
1347 	  fprintf(stderr, "DEBUG: Gutenprint: ================ Printing page %d      ================\n", cups.page + 1);
1348 	  fprintf(stderr, "PAGE: %d %d\n", cups.page + 1, cups.header.NumCopies);
1349 	}
1350       v = initialize_page(&cups, default_settings, page_size_name);
1351 #ifdef ENABLE_CUPS_LOAD_SAVE_OPTIONS
1352       if (loaded_settings)
1353 	stp_copy_vars_from(v, loaded_settings);
1354       if (save_file_name)
1355 	{
1356 	  save_options(save_file_name, v);
1357 	  save_file_name = NULL;
1358 	}
1359 #endif /* ENABLE_CUPS_LOAD_SAVE_OPTIONS */
1360       if (! suppress_messages)
1361 	{
1362 	  fprintf(stderr, "DEBUG: Gutenprint: Interim page settings:\n");
1363 	  stp_vars_print_error(v, "DEBUG");
1364 	}
1365 
1366       stp_merge_printvars(v, stp_printer_get_defaults(printer));
1367 
1368       /* Pass along Collation settings */
1369       stp_set_boolean_parameter(v, "Collate", cups.header.Collate);
1370       stp_set_boolean_parameter_active(v, "Collate", STP_PARAMETER_ACTIVE);
1371       /* Pass along Copy settings */
1372       stp_set_int_parameter(v, "NumCopies", cups.header.NumCopies);
1373       stp_set_int_parameter_active(v, "NumCopies", STP_PARAMETER_ACTIVE);
1374       /* Pass along the page number */
1375       stp_set_int_parameter(v, "PageNumber", cups.page);
1376       cups.row = 0;
1377       if (! suppress_messages)
1378 	print_debug_block(v, &cups);
1379       print_messages_as_errors = 1;
1380 
1381       if (!initialized_job)
1382 	{
1383 	  stp_start_job(v, &theImage);
1384 	  initialized_job = 1;
1385 	}
1386 
1387       if (!stp_print(v, &theImage))
1388 	{
1389 	  if (Image_status != STP_IMAGE_STATUS_ABORT)
1390 	    {
1391 	      fprintf(stderr, "DEBUG: Gutenprint: Options failed to verify.\n");
1392 	      fprintf(stderr, "DEBUG: Gutenprint: Make sure that you are using ESP Ghostscript rather\n");
1393 	      fprintf(stderr, "DEBUG: Gutenprint: than GNU or AFPL Ghostscript with CUPS.\n");
1394 	      fprintf(stderr, "DEBUG: Gutenprint: If this is not the cause, set LogLevel to debug to identify the problem.\n");
1395 	    }
1396 	    aborted = 1;
1397 	  break;
1398 	}
1399       print_messages_as_errors = 0;
1400 
1401       fflush(stdout);
1402 
1403       /*
1404        * Purge any remaining bitmap data...
1405        */
1406       if (cups.row < cups.header.cupsHeight)
1407 	purge_excess_data(&cups);
1408       if (! suppress_messages)
1409 	fprintf(stderr, "DEBUG: Gutenprint: ================ Done printing page %d ================\n", cups.page + 1);
1410       cups.page ++;
1411     }
1412   if (v)
1413     {
1414       if (! suppress_messages)
1415 	fprintf(stderr, "DEBUG: Gutenprint: %s job\n",
1416 		aborted ? "Aborted" : "Ending");
1417       stp_end_job(v, &theImage);
1418       fflush(stdout);
1419       stp_vars_destroy(v);
1420     }
1421   cupsRasterClose(cups.ras);
1422   (void) times(&tms);
1423   (void) gettimeofday(&t2, NULL);
1424   clocks_per_sec = sysconf(_SC_CLK_TCK);
1425   fprintf(stderr, "DEBUG: Gutenprint: stats %.0fB, %.3fu, %.3fs, %.3fel\n",
1426 	  total_bytes_printed,
1427 	  (double) tms.tms_utime / clocks_per_sec,
1428 	  (double) tms.tms_stime / clocks_per_sec,
1429 	  (double) (t2.tv_sec - t1.tv_sec) +
1430 	  ((double) (t2.tv_usec - t1.tv_usec)) / 1000000.0);
1431   if (!suppress_messages)
1432     {
1433       fprintf(stderr, "DEBUG: Gutenprint: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
1434       fprintf(stderr, "DEBUG: Gutenprint: ============================================================\n");
1435     }
1436   stp_vars_destroy(default_settings);
1437   if (page_size_name)
1438     stp_free(page_size_name);
1439   if (fd != 0)
1440     close(fd);
1441   return aborted ? 1 : 0;
1442 }
1443 
1444 
1445 /*
1446  * 'cups_writefunc()' - Write data to a file...
1447  */
1448 
1449 static void
cups_writefunc(void * file,const char * buf,size_t bytes)1450 cups_writefunc(void *file, const char *buf, size_t bytes)
1451 {
1452   FILE *prn = (FILE *)file;
1453   total_bytes_printed += bytes;
1454   fwrite(buf, 1, bytes, prn);
1455 }
1456 
1457 static void
cups_errfunc(void * file,const char * buf,size_t bytes)1458 cups_errfunc(void *file, const char *buf, size_t bytes)
1459 {
1460   size_t next_nl = 0;
1461   size_t where = 0;
1462   FILE *prn = (FILE *)file;
1463   while (where < bytes)
1464     {
1465       if (bytes - where > 6 && strncmp(buf, "ERROR:", 6) == 0)
1466 	{
1467 	  fputs("ERROR: Gutenprint:", prn);
1468 	  buf += 6;
1469 	}
1470       else if (print_messages_as_errors)
1471 	fputs("ERROR: Gutenprint: ", prn);
1472       else if (strncmp(buf, "DEBUG", 5) != 0)
1473 	fputs("DEBUG: Gutenprint: ", prn);
1474       while (next_nl < bytes)
1475 	{
1476 	  if (buf[next_nl++] == '\n')
1477 	    break;
1478 	}
1479       fwrite(buf + where, 1, next_nl - where, prn);
1480       where = next_nl;
1481     }
1482 }
1483 
1484 static void
cups_dbgfunc(void * file,const char * buf,size_t bytes)1485 cups_dbgfunc(void *file, const char *buf, size_t bytes)
1486 {
1487   size_t next_nl = 0;
1488   size_t where = 0;
1489   FILE *prn = (FILE *)file;
1490   while (where < bytes)
1491     {
1492       if (bytes - where > 6 && strncmp(buf, "ERROR:", 6) == 0)
1493 	{
1494 	  fputs("ERROR: Gutenprint:", prn);
1495 	  buf += 6;
1496 	}
1497       else if (strncmp(buf, "DEBUG", 5) != 0)
1498 	fputs("DEBUG: Gutenprint: ", prn);
1499       while (next_nl < bytes)
1500 	{
1501 	  if (buf[next_nl++] == '\n')
1502 	    break;
1503 	}
1504       fwrite(buf + where, 1, next_nl - where, prn);
1505       where = next_nl;
1506     }
1507 }
1508 
1509 
1510 /*
1511  * 'cancel_job()' - Cancel the current job...
1512  */
1513 
1514 static void
cancel_job(int sig)1515 cancel_job(int sig)			/* I - Signal */
1516 {
1517   (void)sig;
1518   Image_status = STP_IMAGE_STATUS_ABORT;
1519 }
1520 
1521 /*
1522  * 'Image_get_appname()' - Get the application we are running.
1523  */
1524 
1525 static const char *				/* O - Application name */
Image_get_appname(stp_image_t * image)1526 Image_get_appname(stp_image_t *image)		/* I - Image */
1527 {
1528   (void)image;
1529 
1530   return ("CUPS driver based on Gutenprint");
1531 }
1532 
1533 
1534 /*
1535  * 'Image_get_row()' - Get one row of the image.
1536  */
1537 
1538 static void
throwaway_data(int amount,cups_image_t * cups)1539 throwaway_data(int amount, cups_image_t *cups)
1540 {
1541   unsigned char trash[4096];	/* Throwaway */
1542   int block_count = amount / 4096;
1543   int leftover = amount % 4096;
1544   while (block_count > 0)
1545     {
1546       cupsRasterReadPixels(cups->ras, trash, 4096);
1547       block_count--;
1548     }
1549   if (leftover)
1550     cupsRasterReadPixels(cups->ras, trash, leftover);
1551 }
1552 
1553 static stp_image_status_t
Image_get_row(stp_image_t * image,unsigned char * data,size_t byte_limit,int row)1554 Image_get_row(stp_image_t   *image,	/* I - Image */
1555 	      unsigned char *data,	/* O - Row */
1556 	      size_t	    byte_limit,	/* I - how many bytes in data */
1557 	      int           row)	/* I - Row number (unused) */
1558 {
1559   cups_image_t	*cups;			/* CUPS image */
1560   int		i;			/* Looping var */
1561   int 		bytes_per_line;
1562   int		margin;
1563   stp_image_status_t tmp_image_status = Image_status;
1564   unsigned char *orig = data;           /* Temporary pointer */
1565   static int warned = 0;                /* Error warning printed? */
1566   int new_percent;
1567   int left_margin, right_margin;
1568 
1569   if ((cups = (cups_image_t *)(image->rep)) == NULL)
1570     {
1571       stp_i18n_printf(po, _("ERROR: Gutenprint image is not initialized!  "
1572                             "Please report this bug to "
1573 			    "gimp-print-devel@lists.sourceforge.net\n"));
1574       return STP_IMAGE_STATUS_ABORT;
1575     }
1576   bytes_per_line =
1577     ((cups->adjusted_width * cups->header.cupsBitsPerPixel) + CHAR_BIT - 1) /
1578     CHAR_BIT;
1579 
1580   left_margin = ((cups->left_trim * cups->header.cupsBitsPerPixel) + CHAR_BIT - 1) /
1581     CHAR_BIT;
1582   right_margin = ((cups->right_trim * cups->header.cupsBitsPerPixel) + CHAR_BIT - 1) /
1583     CHAR_BIT;
1584   margin = cups->header.cupsBytesPerLine - left_margin - bytes_per_line -
1585     right_margin;
1586 
1587   if (cups->row < cups->header.cupsHeight)
1588   {
1589     if (! suppress_messages && ! suppress_verbose_messages)
1590       fprintf(stderr, "DEBUG2: Gutenprint: Reading %d %d\n",
1591 	      bytes_per_line, cups->row);
1592     while (cups->row <= row && cups->row < cups->header.cupsHeight)
1593       {
1594 	if (left_margin > 0)
1595 	  {
1596 	    if (! suppress_messages && ! suppress_verbose_messages)
1597 	      fprintf(stderr, "DEBUG2: Gutenprint: Tossing left %d (%d)\n",
1598 		      left_margin, cups->left_trim);
1599 	    throwaway_data(left_margin, cups);
1600 	  }
1601 	cupsRasterReadPixels(cups->ras, data, bytes_per_line);
1602 	cups->row ++;
1603 	if (margin + right_margin > 0)
1604 	  {
1605 	    if (! suppress_messages && ! suppress_verbose_messages)
1606 	      fprintf(stderr, "DEBUG2: Gutenprint: Tossing right %d (%d) + %d\n",
1607 		      right_margin, cups->right_trim, margin);
1608 	    throwaway_data(margin + right_margin, cups);
1609 	  }
1610       }
1611   }
1612   else
1613     {
1614       switch (cups->header.cupsColorSpace)
1615 	{
1616 	case CUPS_CSPACE_K:
1617 	case CUPS_CSPACE_CMYK:
1618 	case CUPS_CSPACE_KCMY:
1619 	case CUPS_CSPACE_CMY:
1620 	  memset(data, 0, bytes_per_line);
1621 	  break;
1622 	case CUPS_CSPACE_RGB:
1623 	case CUPS_CSPACE_W:
1624 	  memset(data, ((1 << CHAR_BIT) - 1), bytes_per_line);
1625 	  break;
1626 	default:
1627 	  stp_i18n_printf(po, _("ERROR: Gutenprint detected a bad colorspace "
1628 	                        "(%d)!\n"), cups->header.cupsColorSpace);
1629 	  return STP_IMAGE_STATUS_ABORT;
1630 	}
1631     }
1632 
1633   /*
1634    * This exists to print non-ADSC input which has messed up the job
1635    * input, such as that generated by psnup.  The output is barely
1636    * legible, but it's better than the garbage output otherwise.
1637    */
1638   data = orig;
1639   if (cups->header.cupsBitsPerPixel == 1)
1640     {
1641       if (warned == 0)
1642 	{
1643 	  fputs(_("WARNING: Gutenprint detected a bad color depth (1).  "
1644 		  "Output quality is degraded.  Are you using psnup or "
1645 		  "non-ADSC PostScript?\n"), stderr);
1646 	  warned = 1;
1647 	}
1648       for (i = cups->adjusted_width - 1; i >= 0; i--)
1649 	{
1650 	  if ( (data[i/8] >> (7 - i%8)) &0x1)
1651 	    data[i]=255;
1652 	  else
1653 	    data[i]=0;
1654 	}
1655     }
1656 
1657   new_percent = (int) (100.0 * cups->row / cups->header.cupsHeight);
1658   if (new_percent > cups->last_percent)
1659     {
1660       if (! suppress_verbose_messages)
1661 	{
1662 	  stp_i18n_printf(po, _("INFO: Printing page %d, %d%%\n"),
1663 			  cups->page + 1, new_percent);
1664 	  fprintf(stderr, "ATTR: job-media-progress=%d\n", new_percent);
1665 	}
1666       cups->last_percent = new_percent;
1667     }
1668 
1669   if (tmp_image_status != STP_IMAGE_STATUS_OK)
1670     {
1671       if (! suppress_messages)
1672 	fprintf(stderr, "DEBUG: Gutenprint: Image status %d\n", tmp_image_status);
1673     }
1674   return tmp_image_status;
1675 }
1676 
1677 
1678 /*
1679  * 'Image_height()' - Return the height of an image.
1680  */
1681 
1682 static int				/* O - Height in pixels */
Image_height(stp_image_t * image)1683 Image_height(stp_image_t *image)	/* I - Image */
1684 {
1685   cups_image_t	*cups;		/* CUPS image */
1686 
1687 
1688   if ((cups = (cups_image_t *)(image->rep)) == NULL)
1689     return (0);
1690 
1691   if (! suppress_messages)
1692     fprintf(stderr, "DEBUG: Gutenprint: Image_height %d\n", cups->adjusted_height);
1693   return (cups->adjusted_height);
1694 }
1695 
1696 
1697 /*
1698  * 'Image_init()' - Initialize an image.
1699  */
1700 
1701 static void
Image_init(stp_image_t * image)1702 Image_init(stp_image_t *image)		/* I - Image */
1703 {
1704   cups_image_t	*cups;		/* CUPS image */
1705 
1706   if ((cups = (cups_image_t *)(image->rep)) == NULL)
1707     return;
1708   cups->last_percent = 0;
1709 
1710   if (! suppress_messages)
1711     stp_i18n_printf(po, _("INFO: Starting page %d...\n"), cups->page + 1);
1712   /* cups->page + 1 because users expect 1-based counting */
1713 }
1714 
1715 /*
1716  * 'Image_progress_conclude()' - Close the progress display.
1717  */
1718 
1719 static void
Image_conclude(stp_image_t * image)1720 Image_conclude(stp_image_t *image)	/* I - Image */
1721 {
1722   cups_image_t	*cups;		/* CUPS image */
1723 
1724 
1725   if ((cups = (cups_image_t *)(image->rep)) == NULL)
1726     return;
1727 
1728   if (! suppress_messages)
1729     stp_i18n_printf(po, _("INFO: Finished page %d...\n"), cups->page + 1);
1730 }
1731 
1732 /*
1733  * 'Image_width()' - Return the width of an image.
1734  */
1735 
1736 static int				/* O - Width in pixels */
Image_width(stp_image_t * image)1737 Image_width(stp_image_t *image)	/* I - Image */
1738 {
1739   cups_image_t	*cups;		/* CUPS image */
1740 
1741 
1742   if ((cups = (cups_image_t *)(image->rep)) == NULL)
1743     return (0);
1744 
1745   if (! suppress_messages)
1746     fprintf(stderr, "DEBUG: Gutenprint: Image_width %d\n", cups->adjusted_width);
1747   return (cups->adjusted_width);
1748 }
1749