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