• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * CUPS raster to PWG raster format filter for CUPS.
3  *
4  * Copyright 2011, 2014-2017 Apple Inc.
5  *
6  * These coded instructions, statements, and computer programs are the
7  * property of Apple Inc. and are protected by Federal copyright law.
8  * Distribution and use rights are outlined in the file "LICENSE.txt"
9  * which should have been included with this file.  If this file is
10  * missing or damaged, see the license at "http://www.cups.org/".
11  *
12  * This file is subject to the Apple OS-Developed Software exception.
13  */
14 
15 /*
16  * Include necessary headers...
17  */
18 
19 #include <cups/cups-private.h>
20 #include <cups/ppd-private.h>
21 #include <cups/raster.h>
22 #include <unistd.h>
23 #include <fcntl.h>
24 
25 
26 /*
27  * 'main()' - Main entry for filter.
28  */
29 
30 int					/* O - Exit status */
main(int argc,char * argv[])31 main(int  argc,				/* I - Number of command-line args */
32      char *argv[])			/* I - Command-line arguments */
33 {
34   const char		*final_content_type;
35 					/* FINAL_CONTENT_TYPE env var */
36   int			fd;		/* Raster file */
37   cups_raster_t		*inras,		/* Input raster stream */
38 			*outras;	/* Output raster stream */
39   cups_page_header2_t	inheader,	/* Input raster page header */
40 			outheader;	/* Output raster page header */
41   unsigned		y;		/* Current line */
42   unsigned char		*line;		/* Line buffer */
43   unsigned		page = 0,	/* Current page */
44 			page_width,	/* Actual page width */
45 			page_height,	/* Actual page height */
46 			page_top,	/* Top margin */
47 			page_bottom,	/* Bottom margin */
48 			page_left,	/* Left margin */
49 			linesize,	/* Bytes per line */
50 			lineoffset;	/* Offset into line */
51   unsigned char		white;		/* White pixel */
52   ppd_file_t		*ppd;		/* PPD file */
53   ppd_attr_t		*back;		/* cupsBackSide attribute */
54   _ppd_cache_t		*cache;		/* PPD cache */
55   pwg_size_t		*pwg_size;	/* PWG media size */
56   pwg_media_t		*pwg_media;	/* PWG media name */
57   int	 		num_options;	/* Number of options */
58   cups_option_t		*options = NULL;/* Options */
59   const char		*val;		/* Option value */
60 
61 
62   if (argc < 6 || argc > 7)
63   {
64     puts("Usage: rastertopwg job user title copies options [filename]");
65     return (1);
66   }
67   else if (argc == 7)
68   {
69     if ((fd = open(argv[6], O_RDONLY)) < 0)
70     {
71       perror("ERROR: Unable to open print file");
72       return (1);
73     }
74   }
75   else
76     fd = 0;
77 
78   if ((final_content_type = getenv("FINAL_CONTENT_TYPE")) == NULL)
79     final_content_type = "image/pwg-raster";
80 
81   inras  = cupsRasterOpen(fd, CUPS_RASTER_READ);
82   outras = cupsRasterOpen(1, !strcmp(final_content_type, "image/pwg-raster") ? CUPS_RASTER_WRITE_PWG : CUPS_RASTER_WRITE_APPLE);
83 
84   ppd   = ppdOpenFile(getenv("PPD"));
85   back  = ppdFindAttr(ppd, "cupsBackSide", NULL);
86 
87   num_options = cupsParseOptions(argv[5], 0, &options);
88 
89   ppdMarkDefaults(ppd);
90   cupsMarkOptions(ppd, num_options, options);
91 
92   cache = ppd ? ppd->cache : NULL;
93 
94   while (cupsRasterReadHeader2(inras, &inheader))
95   {
96    /*
97     * Show page device dictionary...
98     */
99 
100     fprintf(stderr, "DEBUG: Duplex = %d\n", inheader.Duplex);
101     fprintf(stderr, "DEBUG: HWResolution = [ %d %d ]\n", inheader.HWResolution[0], inheader.HWResolution[1]);
102     fprintf(stderr, "DEBUG: ImagingBoundingBox = [ %d %d %d %d ]\n", inheader.ImagingBoundingBox[0], inheader.ImagingBoundingBox[1], inheader.ImagingBoundingBox[2], inheader.ImagingBoundingBox[3]);
103     fprintf(stderr, "DEBUG: Margins = [ %d %d ]\n", inheader.Margins[0], inheader.Margins[1]);
104     fprintf(stderr, "DEBUG: ManualFeed = %d\n", inheader.ManualFeed);
105     fprintf(stderr, "DEBUG: MediaPosition = %d\n", inheader.MediaPosition);
106     fprintf(stderr, "DEBUG: NumCopies = %d\n", inheader.NumCopies);
107     fprintf(stderr, "DEBUG: Orientation = %d\n", inheader.Orientation);
108     fprintf(stderr, "DEBUG: PageSize = [ %d %d ]\n", inheader.PageSize[0], inheader.PageSize[1]);
109     fprintf(stderr, "DEBUG: cupsWidth = %d\n", inheader.cupsWidth);
110     fprintf(stderr, "DEBUG: cupsHeight = %d\n", inheader.cupsHeight);
111     fprintf(stderr, "DEBUG: cupsMediaType = %d\n", inheader.cupsMediaType);
112     fprintf(stderr, "DEBUG: cupsBitsPerColor = %d\n", inheader.cupsBitsPerColor);
113     fprintf(stderr, "DEBUG: cupsBitsPerPixel = %d\n", inheader.cupsBitsPerPixel);
114     fprintf(stderr, "DEBUG: cupsBytesPerLine = %d\n", inheader.cupsBytesPerLine);
115     fprintf(stderr, "DEBUG: cupsColorOrder = %d\n", inheader.cupsColorOrder);
116     fprintf(stderr, "DEBUG: cupsColorSpace = %d\n", inheader.cupsColorSpace);
117     fprintf(stderr, "DEBUG: cupsCompression = %d\n", inheader.cupsCompression);
118 
119    /*
120     * Compute the real raster size...
121     */
122 
123     page ++;
124 
125     fprintf(stderr, "PAGE: %d %d\n", page, inheader.NumCopies);
126 
127     page_width  = (unsigned)(inheader.cupsPageSize[0] * inheader.HWResolution[0] / 72.0);
128     page_height = (unsigned)(inheader.cupsPageSize[1] * inheader.HWResolution[1] / 72.0);
129     page_left   = (unsigned)(inheader.cupsImagingBBox[0] * inheader.HWResolution[0] / 72.0);
130     page_bottom = (unsigned)(inheader.cupsImagingBBox[1] * inheader.HWResolution[1] / 72.0);
131     page_top    = page_height - page_bottom - inheader.cupsHeight;
132     linesize    = (page_width * inheader.cupsBitsPerPixel + 7) / 8;
133     lineoffset  = page_left * inheader.cupsBitsPerPixel / 8; /* Round down */
134 
135     if (page_left > page_width || page_top > page_height || page_bottom > page_height)
136     {
137       _cupsLangPrintFilter(stderr, "ERROR", _("Unsupported raster data."));
138       fprintf(stderr, "DEBUG: Bad bottom/left/top margin on page %d.\n", page);
139       return (1);
140     }
141 
142     switch (inheader.cupsColorSpace)
143     {
144       case CUPS_CSPACE_W :
145       case CUPS_CSPACE_RGB :
146       case CUPS_CSPACE_SW :
147       case CUPS_CSPACE_SRGB :
148       case CUPS_CSPACE_ADOBERGB :
149           white = 255;
150 	  break;
151 
152       case CUPS_CSPACE_K :
153       case CUPS_CSPACE_CMYK :
154       case CUPS_CSPACE_DEVICE1 :
155       case CUPS_CSPACE_DEVICE2 :
156       case CUPS_CSPACE_DEVICE3 :
157       case CUPS_CSPACE_DEVICE4 :
158       case CUPS_CSPACE_DEVICE5 :
159       case CUPS_CSPACE_DEVICE6 :
160       case CUPS_CSPACE_DEVICE7 :
161       case CUPS_CSPACE_DEVICE8 :
162       case CUPS_CSPACE_DEVICE9 :
163       case CUPS_CSPACE_DEVICEA :
164       case CUPS_CSPACE_DEVICEB :
165       case CUPS_CSPACE_DEVICEC :
166       case CUPS_CSPACE_DEVICED :
167       case CUPS_CSPACE_DEVICEE :
168       case CUPS_CSPACE_DEVICEF :
169           white = 0;
170 	  break;
171 
172       default :
173 	  _cupsLangPrintFilter(stderr, "ERROR", _("Unsupported raster data."));
174 	  fprintf(stderr, "DEBUG: Unsupported cupsColorSpace %d on page %d.\n",
175 	          inheader.cupsColorSpace, page);
176 	  return (1);
177     }
178 
179     if (inheader.cupsColorOrder != CUPS_ORDER_CHUNKED)
180     {
181       _cupsLangPrintFilter(stderr, "ERROR", _("Unsupported raster data."));
182       fprintf(stderr, "DEBUG: Unsupported cupsColorOrder %d on page %d.\n",
183               inheader.cupsColorOrder, page);
184       return (1);
185     }
186 
187     if (inheader.cupsBitsPerPixel != 1 &&
188         inheader.cupsBitsPerColor != 8 && inheader.cupsBitsPerColor != 16)
189     {
190       _cupsLangPrintFilter(stderr, "ERROR", _("Unsupported raster data."));
191       fprintf(stderr, "DEBUG: Unsupported cupsBitsPerColor %d on page %d.\n",
192               inheader.cupsBitsPerColor, page);
193       return (1);
194     }
195 
196     memcpy(&outheader, &inheader, sizeof(outheader));
197     outheader.cupsWidth        = page_width;
198     outheader.cupsHeight       = page_height;
199     outheader.cupsBytesPerLine = linesize;
200 
201     outheader.cupsInteger[14]  = 0;	/* VendorIdentifier */
202     outheader.cupsInteger[15]  = 0;	/* VendorLength */
203 
204     if ((val = cupsGetOption("print-content-optimize", num_options,
205                              options)) != NULL)
206     {
207       if (!strcmp(val, "automatic"))
208         strlcpy(outheader.OutputType, "Automatic",
209                 sizeof(outheader.OutputType));
210       else if (!strcmp(val, "graphics"))
211         strlcpy(outheader.OutputType, "Graphics", sizeof(outheader.OutputType));
212       else if (!strcmp(val, "photo"))
213         strlcpy(outheader.OutputType, "Photo", sizeof(outheader.OutputType));
214       else if (!strcmp(val, "text"))
215         strlcpy(outheader.OutputType, "Text", sizeof(outheader.OutputType));
216       else if (!strcmp(val, "text-and-graphics"))
217         strlcpy(outheader.OutputType, "TextAndGraphics",
218                 sizeof(outheader.OutputType));
219       else
220       {
221         fputs("DEBUG: Unsupported print-content-optimize value.\n", stderr);
222         outheader.OutputType[0] = '\0';
223       }
224     }
225 
226     if ((val = cupsGetOption("print-quality", num_options, options)) != NULL)
227     {
228       unsigned quality = (unsigned)atoi(val);		/* print-quality value */
229 
230       if (quality >= IPP_QUALITY_DRAFT && quality <= IPP_QUALITY_HIGH)
231 	outheader.cupsInteger[8] = quality;
232       else
233       {
234 	fprintf(stderr, "DEBUG: Unsupported print-quality %d.\n", quality);
235 	outheader.cupsInteger[8] = 0;
236       }
237     }
238 
239     if ((val = cupsGetOption("print-rendering-intent", num_options,
240                              options)) != NULL)
241     {
242       if (!strcmp(val, "absolute"))
243         strlcpy(outheader.cupsRenderingIntent, "Absolute",
244                 sizeof(outheader.cupsRenderingIntent));
245       else if (!strcmp(val, "automatic"))
246         strlcpy(outheader.cupsRenderingIntent, "Automatic",
247                 sizeof(outheader.cupsRenderingIntent));
248       else if (!strcmp(val, "perceptual"))
249         strlcpy(outheader.cupsRenderingIntent, "Perceptual",
250                 sizeof(outheader.cupsRenderingIntent));
251       else if (!strcmp(val, "relative"))
252         strlcpy(outheader.cupsRenderingIntent, "Relative",
253                 sizeof(outheader.cupsRenderingIntent));
254       else if (!strcmp(val, "relative-bpc"))
255         strlcpy(outheader.cupsRenderingIntent, "RelativeBpc",
256                 sizeof(outheader.cupsRenderingIntent));
257       else if (!strcmp(val, "saturation"))
258         strlcpy(outheader.cupsRenderingIntent, "Saturation",
259                 sizeof(outheader.cupsRenderingIntent));
260       else
261       {
262         fputs("DEBUG: Unsupported print-rendering-intent value.\n", stderr);
263         outheader.cupsRenderingIntent[0] = '\0';
264       }
265     }
266 
267     if (inheader.cupsPageSizeName[0] &&
268         (pwg_size = _ppdCacheGetSize(cache, inheader.cupsPageSizeName)) != NULL)
269     {
270       strlcpy(outheader.cupsPageSizeName, pwg_size->map.pwg,
271 	      sizeof(outheader.cupsPageSizeName));
272     }
273     else
274     {
275       pwg_media = pwgMediaForSize((int)(2540.0 * inheader.cupsPageSize[0] / 72.0),
276 				  (int)(2540.0 * inheader.cupsPageSize[1] / 72.0));
277 
278       if (pwg_media)
279         strlcpy(outheader.cupsPageSizeName, pwg_media->pwg,
280                 sizeof(outheader.cupsPageSizeName));
281       else
282       {
283         fprintf(stderr, "DEBUG: Unsupported PageSize %.2fx%.2f.\n",
284                 inheader.cupsPageSize[0], inheader.cupsPageSize[1]);
285         outheader.cupsPageSizeName[0] = '\0';
286       }
287     }
288 
289     if (inheader.Duplex && !(page & 1) &&
290         back && _cups_strcasecmp(back->value, "Normal"))
291     {
292       if (_cups_strcasecmp(back->value, "Flipped"))
293       {
294         if (inheader.Tumble)
295         {
296 	  outheader.cupsInteger[1] = ~0U;/* CrossFeedTransform */
297 	  outheader.cupsInteger[2] = 1;	/* FeedTransform */
298 
299 	  outheader.cupsInteger[3] = page_width - page_left -
300 	                             inheader.cupsWidth;
301 					/* ImageBoxLeft */
302 	  outheader.cupsInteger[4] = page_top;
303 					/* ImageBoxTop */
304 	  outheader.cupsInteger[5] = page_width - page_left;
305       					/* ImageBoxRight */
306 	  outheader.cupsInteger[6] = page_height - page_bottom;
307       					/* ImageBoxBottom */
308         }
309         else
310         {
311 	  outheader.cupsInteger[1] = 1;	/* CrossFeedTransform */
312 	  outheader.cupsInteger[2] = ~0U;/* FeedTransform */
313 
314 	  outheader.cupsInteger[3] = page_left;
315 					/* ImageBoxLeft */
316 	  outheader.cupsInteger[4] = page_bottom;
317 					/* ImageBoxTop */
318 	  outheader.cupsInteger[5] = page_left + inheader.cupsWidth;
319       					/* ImageBoxRight */
320 	  outheader.cupsInteger[6] = page_height - page_top;
321       					/* ImageBoxBottom */
322         }
323       }
324       else if (_cups_strcasecmp(back->value, "ManualTumble"))
325       {
326         if (inheader.Tumble)
327         {
328 	  outheader.cupsInteger[1] = ~0U;/* CrossFeedTransform */
329 	  outheader.cupsInteger[2] = ~0U;/* FeedTransform */
330 
331 	  outheader.cupsInteger[3] = page_width - page_left -
332 	                             inheader.cupsWidth;
333 					/* ImageBoxLeft */
334 	  outheader.cupsInteger[4] = page_bottom;
335 					/* ImageBoxTop */
336 	  outheader.cupsInteger[5] = page_width - page_left;
337       					/* ImageBoxRight */
338 	  outheader.cupsInteger[6] = page_height - page_top;
339       					/* ImageBoxBottom */
340         }
341         else
342         {
343 	  outheader.cupsInteger[1] = 1;	/* CrossFeedTransform */
344 	  outheader.cupsInteger[2] = 1;	/* FeedTransform */
345 
346 	  outheader.cupsInteger[3] = page_left;
347 					/* ImageBoxLeft */
348 	  outheader.cupsInteger[4] = page_top;
349 					/* ImageBoxTop */
350 	  outheader.cupsInteger[5] = page_left + inheader.cupsWidth;
351       					/* ImageBoxRight */
352 	  outheader.cupsInteger[6] = page_height - page_bottom;
353       					/* ImageBoxBottom */
354         }
355       }
356       else if (_cups_strcasecmp(back->value, "Rotated"))
357       {
358         if (inheader.Tumble)
359         {
360 	  outheader.cupsInteger[1] = ~0U;/* CrossFeedTransform */
361 	  outheader.cupsInteger[2] = ~0U;/* FeedTransform */
362 
363 	  outheader.cupsInteger[3] = page_width - page_left -
364 	                             inheader.cupsWidth;
365 					/* ImageBoxLeft */
366 	  outheader.cupsInteger[4] = page_bottom;
367 					/* ImageBoxTop */
368 	  outheader.cupsInteger[5] = page_width - page_left;
369       					/* ImageBoxRight */
370 	  outheader.cupsInteger[6] = page_height - page_top;
371       					/* ImageBoxBottom */
372         }
373         else
374         {
375 	  outheader.cupsInteger[1] = 1;	/* CrossFeedTransform */
376 	  outheader.cupsInteger[2] = 1;	/* FeedTransform */
377 
378 	  outheader.cupsInteger[3] = page_left;
379 					/* ImageBoxLeft */
380 	  outheader.cupsInteger[4] = page_top;
381 					/* ImageBoxTop */
382 	  outheader.cupsInteger[5] = page_left + inheader.cupsWidth;
383       					/* ImageBoxRight */
384 	  outheader.cupsInteger[6] = page_height - page_bottom;
385       					/* ImageBoxBottom */
386         }
387       }
388       else
389       {
390        /*
391         * Unsupported value...
392         */
393 
394         fputs("DEBUG: Unsupported cupsBackSide value.\n", stderr);
395 
396 	outheader.cupsInteger[1] = 1;	/* CrossFeedTransform */
397 	outheader.cupsInteger[2] = 1;	/* FeedTransform */
398 
399 	outheader.cupsInteger[3] = page_left;
400 					/* ImageBoxLeft */
401 	outheader.cupsInteger[4] = page_top;
402 					/* ImageBoxTop */
403 	outheader.cupsInteger[5] = page_left + inheader.cupsWidth;
404       					/* ImageBoxRight */
405 	outheader.cupsInteger[6] = page_height - page_bottom;
406       					/* ImageBoxBottom */
407       }
408     }
409     else
410     {
411       outheader.cupsInteger[1] = 1;	/* CrossFeedTransform */
412       outheader.cupsInteger[2] = 1;	/* FeedTransform */
413 
414       outheader.cupsInteger[3] = page_left;
415 					/* ImageBoxLeft */
416       outheader.cupsInteger[4] = page_top;
417 					/* ImageBoxTop */
418       outheader.cupsInteger[5] = page_left + inheader.cupsWidth;
419       					/* ImageBoxRight */
420       outheader.cupsInteger[6] = page_height - page_bottom;
421       					/* ImageBoxBottom */
422     }
423 
424     if (!cupsRasterWriteHeader2(outras, &outheader))
425     {
426       _cupsLangPrintFilter(stderr, "ERROR", _("Error sending raster data."));
427       fprintf(stderr, "DEBUG: Unable to write header for page %d.\n", page);
428       return (1);
429     }
430 
431    /*
432     * Copy raster data...
433     */
434 
435     if (linesize < inheader.cupsBytesPerLine)
436       linesize = inheader.cupsBytesPerLine;
437 
438     if ((lineoffset + inheader.cupsBytesPerLine) > linesize)
439       lineoffset = linesize - inheader.cupsBytesPerLine;
440 
441     line = malloc(linesize);
442 
443     memset(line, white, linesize);
444     for (y = page_top; y > 0; y --)
445       if (!cupsRasterWritePixels(outras, line, outheader.cupsBytesPerLine))
446       {
447 	_cupsLangPrintFilter(stderr, "ERROR", _("Error sending raster data."));
448 	fprintf(stderr, "DEBUG: Unable to write line %d for page %d.\n",
449 	        page_top - y + 1, page);
450 	return (1);
451       }
452 
453     for (y = inheader.cupsHeight; y > 0; y --)
454     {
455       if (cupsRasterReadPixels(inras, line + lineoffset, inheader.cupsBytesPerLine) != inheader.cupsBytesPerLine)
456       {
457 	_cupsLangPrintFilter(stderr, "ERROR", _("Error reading raster data."));
458 	fprintf(stderr, "DEBUG: Unable to read line %d for page %d.\n",
459 	        inheader.cupsHeight - y + page_top + 1, page);
460 	return (1);
461       }
462 
463       if (!cupsRasterWritePixels(outras, line, outheader.cupsBytesPerLine))
464       {
465 	_cupsLangPrintFilter(stderr, "ERROR", _("Error sending raster data."));
466 	fprintf(stderr, "DEBUG: Unable to write line %d for page %d.\n",
467 	        inheader.cupsHeight - y + page_top + 1, page);
468 	return (1);
469       }
470     }
471 
472     memset(line, white, linesize);
473     for (y = page_bottom; y > 0; y --)
474       if (!cupsRasterWritePixels(outras, line, outheader.cupsBytesPerLine))
475       {
476 	_cupsLangPrintFilter(stderr, "ERROR", _("Error sending raster data."));
477 	fprintf(stderr, "DEBUG: Unable to write line %d for page %d.\n",
478 	        page_bottom - y + page_top + inheader.cupsHeight + 1, page);
479 	return (1);
480       }
481 
482     free(line);
483   }
484 
485   cupsRasterClose(inras);
486   if (fd)
487     close(fd);
488 
489   cupsRasterClose(outras);
490 
491   return (0);
492 }
493